1 /***************************************************************************
2 Copyright (C) 2020 Robby Stephenson <robby@periapsis.org>
3 ***************************************************************************/
4
5 /***************************************************************************
6 * *
7 * This program is free software; you can redistribute it and/or *
8 * modify it under the terms of the GNU General Public License as *
9 * published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) version 3 or any later version *
11 * accepted by the membership of KDE e.V. (or its successor approved *
12 * by the membership of KDE e.V.), which shall act as a proxy *
13 * defined in Section 14 of version 3 of the license. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
22 * *
23 ***************************************************************************/
24
25 #include "tellicoxmlreader.h"
26 #include "tellico_xml.h"
27 #include "xmlstatehandler.h"
28 #include "../collection.h"
29 #include "../tellico_debug.h"
30
31 #include <KLocalizedString>
32
33 using Tellico::Import::TellicoXmlReader;
34
TellicoXmlReader()35 TellicoXmlReader::TellicoXmlReader() : m_data(new SAX::StateData) {
36 m_handlers.push(new SAX::RootHandler(m_data));
37 }
38
~TellicoXmlReader()39 TellicoXmlReader::~TellicoXmlReader() {
40 delete m_data;
41 m_data = nullptr;
42 qDeleteAll(m_handlers);
43 m_handlers.clear();
44 }
45
readNext(const QByteArray & data_)46 bool TellicoXmlReader::readNext(const QByteArray& data_) {
47 Q_ASSERT(!m_handlers.isEmpty());
48 if(m_handlers.isEmpty()) {
49 return false;
50 }
51
52 m_xml.addData(data_);
53 while(!m_xml.atEnd()) {
54 const auto tokenType = m_xml.readNext();
55 switch(tokenType) {
56 case QXmlStreamReader::StartElement:
57 handleStart();
58 break;
59 case QXmlStreamReader::EndElement:
60 handleEnd();
61 break;
62 case QXmlStreamReader::Characters:
63 handleCharacters();
64 break;
65 case QXmlStreamReader::Invalid:
66 if(m_xml.error() != QXmlStreamReader::PrematureEndOfDocumentError) {
67 myDebug() << "Error!" << m_xml.errorString();
68 }
69 continue; // break out of while loop
70 default:
71 // not handling anything else
72 break;
73 }
74 }
75 // success is no error or error being simply premature end of document
76 return !m_xml.hasError() || m_xml.error() == QXmlStreamReader::PrematureEndOfDocumentError;
77 }
78
errorString() const79 QString TellicoXmlReader::errorString() const {
80 // for custom errors, include the line and column number
81 return m_xml.error() == QXmlStreamReader::CustomError ?
82 QString::fromLatin1("Fatal parsing error in line %1, column %2. %3")
83 .arg(m_xml.lineNumber())
84 .arg(m_xml.columnNumber())
85 .arg(m_xml.errorString()) :
86 m_xml.errorString();
87 }
88
isNotWellFormed() const89 bool TellicoXmlReader::isNotWellFormed() const {
90 return m_xml.error() == QXmlStreamReader::NotWellFormedError;
91 }
92
collection() const93 Tellico::Data::CollPtr TellicoXmlReader::collection() const {
94 return m_data->coll;
95 }
96
hasImages() const97 bool TellicoXmlReader::hasImages() const {
98 return m_data->hasImages;
99 }
100
setLoadImages(bool loadImages_)101 void TellicoXmlReader::setLoadImages(bool loadImages_) {
102 m_data->loadImages = loadImages_;
103 }
104
setShowImageLoadErrors(bool showImageErrors_)105 void TellicoXmlReader::setShowImageLoadErrors(bool showImageErrors_) {
106 m_data->showImageLoadErrors = showImageErrors_;
107 }
108
handleStart()109 void TellicoXmlReader::handleStart() {
110 SAX::StateHandler* handler = m_handlers.top()->nextHandler(m_xml.namespaceUri(), m_xml.name());
111 Q_ASSERT(handler);
112 m_handlers.push(handler);
113 if(!handler->start(m_xml.namespaceUri(), m_xml.name(), m_xml.attributes())) {
114 m_xml.raiseError(m_data->error);
115 }
116 }
117
handleEnd()118 void TellicoXmlReader::handleEnd() {
119 m_data->text = m_data->text.trimmed();
120 SAX::StateHandler* handler = m_handlers.pop();
121 if(!handler->end(m_xml.namespaceUri(), m_xml.name())) {
122 m_xml.raiseError(m_data->error);
123 }
124 // need to reset character data, too
125 m_data->text.clear();
126 delete handler;
127 }
128
handleCharacters()129 void TellicoXmlReader::handleCharacters() {
130 m_data->text.append(m_xml.text());
131 }
132