1 /************************************************************************
2 **
3 ** Copyright (C) 2016-2020 Kevin B. Hendricks, Stratford, Ontario, Canada
4 ** Copyright (C) 2009-2011 Strahinja Markovic <strahinja.markovic@gmail.com>
5 **
6 ** This file is part of Sigil.
7 **
8 ** Sigil is free software: you can redistribute it and/or modify
9 ** it under the terms of the GNU General Public License as published by
10 ** the Free Software Foundation, either version 3 of the License, or
11 ** (at your option) any later version.
12 **
13 ** Sigil is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ** GNU General Public License for more details.
17 **
18 ** You should have received a copy of the GNU General Public License
19 ** along with Sigil. If not, see <http://www.gnu.org/licenses/>.
20 **
21 *************************************************************************/
22
23 #include <QtCore/QBuffer>
24 #include <QtCore/QDir>
25 #include <QtCore/QFileInfo>
26 #include <QtCore/QObject>
27
28 #include "BookManipulation/CleanSource.h"
29 #include "Exporters/NCXWriter.h"
30 #include "ResourceObjects/NCXResource.h"
31 #include "Misc/SettingsStore.h"
32 #include "Misc/Utility.h"
33 #include "sigil_constants.h"
34
35 static const QString TEMPLATE_TEXT =
36 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
37 "<!DOCTYPE ncx PUBLIC \"-//NISO//DTD ncx 2005-1//EN\"\n"
38 " \"http://www.daisy.org/z3986/2005/ncx-2005-1.dtd\">\n"
39 "<ncx xmlns=\"http://www.daisy.org/z3986/2005/ncx/\" version=\"2005-1\">\n"
40 " <head>\n"
41 " <meta name=\"dtb:uid\" content=\"ID_UNKNOWN\" />\n"
42 " <meta name=\"dtb:depth\" content=\"0\" />\n"
43 " <meta name=\"dtb:totalPageCount\" content=\"0\" />\n"
44 " <meta name=\"dtb:maxPageNumber\" content=\"0\" />\n"
45 " </head>\n"
46 "<docTitle>\n"
47 " <text>Unknown</text>\n"
48 "</docTitle>\n"
49 "<navMap>\n"
50 "<navPoint id=\"navPoint-1\" playOrder=\"1\">\n"
51 " <navLabel>\n"
52 " <text>%1</text>\n"
53 " </navLabel>\n"
54 " <content src=\"%2\" />\n"
55 "</navPoint>\n"
56 "</navMap>\n"
57 "</ncx>";
58
59
60 // under xhtml5 / epub3 no doctype is allowed for the ncx
61 static const QString TEMPLATE3_TEXT =
62 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
63 "<ncx xmlns=\"http://www.daisy.org/z3986/2005/ncx/\" version=\"2005-1\">\n"
64 " <head>\n"
65 " <meta name=\"dtb:uid\" content=\"ID_UNKNOWN\" />\n"
66 " <meta name=\"dtb:depth\" content=\"0\" />\n"
67 " <meta name=\"dtb:totalPageCount\" content=\"0\" />\n"
68 " <meta name=\"dtb:maxPageNumber\" content=\"0\" />\n"
69 " </head>\n"
70 "<docTitle>\n"
71 " <text>Unknown</text>\n"
72 "</docTitle>\n"
73 "<navMap>\n"
74 "<navPoint id=\"navPoint-1\" playOrder=\"1\">\n"
75 " <navLabel>\n"
76 " <text>%1</text>\n"
77 " </navLabel>\n"
78 " <content src=\"%2\" />\n"
79 "</navPoint>\n"
80 "</navMap>\n"
81 "</ncx>";
82
83
NCXResource(const QString & mainfolder,const QString & fullfilepath,const QString & version,QObject * parent)84 NCXResource::NCXResource(const QString &mainfolder,
85 const QString &fullfilepath,
86 const QString & version,
87 QObject *parent)
88 : XMLResource(mainfolder, fullfilepath, parent)
89 {
90 FillWithDefaultText(version, "OEBPS/Text");
91 }
92
93 // a rename of the ncx should only need updating in the opf
94 // which should happen automagically via signals and slots here
RenameTo(const QString & new_filename)95 bool NCXResource::RenameTo(const QString &new_filename)
96 {
97 bool successful = Resource::RenameTo(new_filename);
98 return successful;
99 }
100
101
102 // a move of the ncx should need updating in the ncx and opf
103 // which should happen automagically via signals and slots here
MoveTo(const QString & newbookpath)104 bool NCXResource::MoveTo(const QString &newbookpath)
105 {
106 bool successful = Resource::MoveTo(newbookpath);
107 return successful;
108 }
109
110
Type() const111 Resource::ResourceType NCXResource::Type() const
112 {
113 return Resource::NCXResourceType;
114 }
115
116
SetMainID(const QString & main_id)117 void NCXResource::SetMainID(const QString &main_id)
118 {
119 SetText(GetText().replace("ID_UNKNOWN", main_id));
120 }
121
122
GenerateNCXFromBookContents(const Book * book)123 bool NCXResource::GenerateNCXFromBookContents(const Book *book)
124 {
125 bool is_changed = false;
126 QByteArray raw_ncx;
127 QBuffer buffer(&raw_ncx);
128 buffer.open(QIODevice::WriteOnly);
129 NCXWriter ncx(book, buffer);
130 ncx.WriteXMLFromHeadings();
131 buffer.close();
132 QString new_text = CleanSource::ProcessXML(QString::fromUtf8(raw_ncx.constData(), raw_ncx.size()),"application/x-dtbncx+xml");
133 QString existing_text = GetText();
134
135 // Only update the resource if have changed. Note that this is_changed trick will not
136 // work after first loading an EPUB, because the metadata elements have their attributes
137 // in swapped in a different order from the xhtml processing.
138 if (new_text != existing_text) {
139 SetText(new_text);
140 is_changed = true;
141 }
142
143 return is_changed;
144 }
145
146
GenerateNCXFromTOCContents(const Book * book,TOCModel * toc_model)147 void NCXResource::GenerateNCXFromTOCContents(const Book *book, TOCModel *toc_model)
148 {
149 GenerateNCXFromTOCEntries(book, toc_model->GetRootTOCEntry());
150 }
151
GenerateNCXFromTOCEntries(const Book * book,TOCModel::TOCEntry toc_root_entry)152 void NCXResource::GenerateNCXFromTOCEntries(const Book *book, TOCModel::TOCEntry toc_root_entry)
153 {
154 QByteArray raw_ncx;
155 QBuffer buffer(&raw_ncx);
156 buffer.open(QIODevice::WriteOnly);
157 NCXWriter ncx(book, buffer, toc_root_entry);
158 ncx.WriteXML();
159 buffer.close();
160 SetText(CleanSource::ProcessXML(QString::fromUtf8(raw_ncx.constData(), raw_ncx.size()), "application/x-dtbncx+xml"));
161 }
162
163
FillWithDefaultText(const QString & version,const QString & default_text_folder)164 void NCXResource::FillWithDefaultText(const QString &version, const QString &default_text_folder)
165 {
166 QString first_section_bookpath = FIRST_SECTION_NAME;
167 if (!default_text_folder.isEmpty()) first_section_bookpath = default_text_folder + "/" + FIRST_SECTION_NAME;
168 FillWithDefaultTextToBookPath(version, first_section_bookpath);
169 SaveToDisk();
170 }
171
172
FillWithDefaultTextToBookPath(const QString & version,const QString & start_bookpath)173 void NCXResource::FillWithDefaultTextToBookPath(const QString &version, const QString &start_bookpath)
174 {
175 QString epubversion = version;
176 if (epubversion.isEmpty()) {
177 SettingsStore ss;
178 epubversion = ss.defaultVersion();
179 }
180 QString ncxbookpath = GetRelativePath();
181 QString texthref = Utility::URLEncodePath(Utility::buildRelativePath(ncxbookpath, start_bookpath));
182 if (epubversion.startsWith('2')) {
183 SetText(TEMPLATE_TEXT.arg(tr("Start")).arg(texthref));
184 } else {
185 SetText(TEMPLATE3_TEXT.arg(tr("Start")).arg(texthref));
186 }
187 // Make sure the file exists on disk.
188 // Among many reasons, this also solves the problem
189 // with the Book Browser not displaying an icon for this resource.
190 SaveToDisk();
191 }
192
193