1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7 
8 #include <algorithm>
9 
10 #include "loadsaveplugin.h"
11 #include "commonstrings.h"
12 #include "scribuscore.h"
13 
14 #include "plugins/formatidlist.h"
15 
16 #include <QList>
17 #include <QMessageBox>
18 
19 QList<FileFormat> LoadSavePlugin::formats;
20 
LoadSavePlugin()21 LoadSavePlugin::LoadSavePlugin() :
22 	undoManager(UndoManager::instance())
23 {
24 }
25 
~LoadSavePlugin()26 LoadSavePlugin::~LoadSavePlugin()
27 {
28 }
29 
30 // STATIC method - return a list of all existing formats
supportedFormats()31 const QList<FileFormat> & LoadSavePlugin::supportedFormats()
32 {
33 	return formats;
34 }
35 
getFormatById(const int id)36 const FileFormat * LoadSavePlugin::getFormatById(const int id)
37 {
38 	QList<FileFormat>::iterator it(findFormat(id));
39 	if (it == formats.end())
40 		return nullptr;
41 	return &(*it);
42 }
43 
getFormatByID(int id)44 FileFormat * LoadSavePlugin::getFormatByID(int id)
45 {
46 	QList<FileFormat>::iterator it(findFormat(id));
47 	if (it == formats.end())
48 		return nullptr;
49 	return &(*it);
50 }
51 
getFormatByExt(const QString & ext)52 FileFormat* LoadSavePlugin::getFormatByExt(const QString& ext)
53 {
54 	QList<FileFormat>::iterator it(findFormat(ext));
55 	if (it == formats.end())
56 		return nullptr;
57 	return &(*it);
58 }
59 
fileDialogLoadFilter()60 QStringList LoadSavePlugin::fileDialogLoadFilter()
61 {
62 	return getDialogFilter(true);
63 }
64 
fileDialogSaveFilter()65 QStringList LoadSavePlugin::fileDialogSaveFilter()
66 {
67 	return getDialogFilter(false);
68 }
69 
getExtensionsForColors(const int id)70 QStringList LoadSavePlugin::getExtensionsForColors(const int id)
71 {
72 	QList<FileFormat>::const_iterator it(findFormat(id));
73 	QList<FileFormat>::const_iterator itEnd(formats.constEnd());
74 	QStringList filterList;
75 	// We know the list is sorted by id, then priority, so we can just take the
76 	// highest priority entry for each ID, and we can start with the first entry
77 	// in the list.
78 	//First, check if we even have any plugins to load with
79 	if (it != itEnd)
80 	{
81 		if ((it->load) && (it->colorReading))
82 			filterList.append(it->fileExtensions);
83 		unsigned int lastID = it->formatId;
84 		++it;
85 		for ( ; it != itEnd ; ++it)
86 		{
87 			// Find the next load/save (as appropriate) plugin for the next format type
88 			if (((it->load) && (it->colorReading)) && (it->formatId > lastID))
89 			{
90 				// And add it to the filter list, since we know it's
91 				// the highest priority because of the sort order.
92 				filterList.append(it->fileExtensions);
93 				lastID = it->formatId;
94 			}
95 		}
96 	}
97 	else
98 		qDebug("%s", tr("No File Loader Plugins Found").toLocal8Bit().data());
99 	// Avoid duplicate entries in the list
100 	QSet<QString> fSet(filterList.begin(), filterList.end());
101 	filterList = fSet.values();
102 	std::sort(filterList.begin(), filterList.end());
103 	return filterList;
104 }
105 
getExtensionsForImport(const int id)106 QStringList LoadSavePlugin::getExtensionsForImport(const int id)
107 {
108 	QList<FileFormat>::const_iterator it(findFormat(id));
109 	QList<FileFormat>::const_iterator itEnd(formats.constEnd());
110 	QStringList filterList;
111 	// We know the list is sorted by id, then priority, so we can just take the
112 	// highest priority entry for each ID, and we can start with the first entry
113 	// in the list.
114 	//First, check if we even have any plugins to load with
115 	if (it != itEnd)
116 	{
117 		if (it->load)
118 			filterList.append(it->fileExtensions);
119 		unsigned int lastID = it->formatId;
120 		++it;
121 		for ( ; it != itEnd ; ++it)
122 		{
123 			// Find the next load/save (as appropriate) plugin for the next format type
124 			if ((it->load) && (it->formatId > lastID))
125 			{
126 				// And add it to the filter list, since we know it's
127 				// the highest priority because of the sort order.
128 				filterList.append(it->fileExtensions);
129 				lastID = it->formatId;
130 			}
131 		}
132 	}
133 	else
134 		qDebug("%s", tr("No File Loader Plugins Found").toLocal8Bit().data());
135 	// Avoid duplicate entries in the list
136 	QSet<QString> fSet(filterList.begin(), filterList.end());
137 	filterList = fSet.values();
138 	std::sort(filterList.begin(), filterList.end());
139 	return filterList;
140 }
141 
getExtensionsForPreview(const int id)142 QStringList LoadSavePlugin::getExtensionsForPreview(const int id)
143 {
144 	QList<FileFormat>::const_iterator it(findFormat(id));
145 	QList<FileFormat>::const_iterator itEnd(formats.constEnd());
146 	QStringList filterList;
147 	// We know the list is sorted by id, then priority, so we can just take the
148 	// highest priority entry for each ID, and we can start with the first entry
149 	// in the list.
150 	//First, check if we even have any plugins to load with
151 	if (it != itEnd)
152 	{
153 		if ((it->load) && (it->thumb))
154 			filterList.append(it->fileExtensions);
155 		unsigned int lastID = it->formatId;
156 		++it;
157 		for ( ; it != itEnd ; ++it)
158 		{
159 			// Find the next load/save (as appropriate) plugin for the next format type
160 			if (((it->load) && (it->thumb)) && (it->formatId > lastID))
161 			{
162 				// And add it to the filter list, since we know it's
163 				// the highest priority because of the sort order.
164 				filterList.append(it->fileExtensions);
165 				lastID = it->formatId;
166 			}
167 		}
168 	}
169 	else
170 		qDebug("%s", tr("No File Loader Plugins Found").toLocal8Bit().data());
171 	// Avoid duplicate entries in the list
172 	QSet<QString> fSet(filterList.begin(), filterList.end());
173 	filterList = fSet.values();
174 	std::sort(filterList.begin(), filterList.end());
175 	return filterList;
176 }
177 
getDialogFilter(bool forLoad)178 const QStringList LoadSavePlugin::getDialogFilter(bool forLoad)
179 {
180 	QList<FileFormat>::const_iterator it(formats.constBegin());
181 	QList<FileFormat>::const_iterator itEnd(formats.constEnd());
182 	QStringList filterList;
183 	// We know the list is sorted by id, then priority, so we can just take the
184 	// highest priority entry for each ID, and we can start with the first entry
185 	// in the list.
186 	//First, check if we even have any plugins to load with
187 	if (it == itEnd)
188 	{
189 		qDebug("%s", tr("No File Loader Plugins Found").toLocal8Bit().data());
190 		return filterList;
191 	}
192 	unsigned int lastID = 0;
193 	QStringList scribusList;
194 	while (it != itEnd)
195 	{
196 		// Find the next load/save (as appropriate) plugin for the next format type
197 		if ((forLoad ? it->load : it->save) && (it->formatId > lastID))
198 		{
199 			// And add it to the filter list, since we know it's
200 			// the highest priority because of the sort order.
201 			// #11294, sort them and keep Scribus ones at the top
202 			if(it->nativeScribus)
203 				scribusList.append(it->filter);
204 			else
205 				filterList.append(it->filter);
206 			lastID = it->formatId;
207 		}
208 		++it;
209 	}
210 	filterList.sort(Qt::CaseInsensitive);
211 	filterList.append( tr("All Files (*)"));
212 	return scribusList+filterList;
213 }
214 
saveFile(const QString &,const FileFormat &)215 bool LoadSavePlugin::saveFile(const QString & /* fileName */,
216 							  const FileFormat & /* fmt */)
217 {
218 	return false;
219 }
220 
loadElements(const QString &,const QString &,int,double,double,bool)221 bool LoadSavePlugin::loadElements(const QString &  /*data*/, const QString&  /*fileDir*/, int /*toLayer*/, double /*Xp_in*/, double /*Yp_in*/, bool /*loc*/)
222 {
223 	return false;
224 }
225 
savePalette(const QString &)226 bool LoadSavePlugin::savePalette(const QString &  /*fileName*/)
227 {
228 	return false;
229 }
230 
saveElements(double,double,double,double,Selection *,QByteArray &)231 QString LoadSavePlugin::saveElements(double /*xp*/, double /*yp*/, double /*wp*/, double  /*hp*/, Selection* /*selection*/, QByteArray & /*prevData*/)
232 {
233 	return "";
234 }
235 
loadPalette(const QString &)236 bool LoadSavePlugin::loadPalette(const QString &  /*fileName*/)
237 {
238 	return false;
239 }
240 
setFileReadError()241 void LoadSavePlugin::setFileReadError()
242 {
243 	m_lastError = tr("An error occurred while opening file or file is damaged");
244 }
245 
setDomParsingError(const QString & msg,int line,int column)246 void LoadSavePlugin::setDomParsingError(const QString& msg, int line, int column)
247 {
248 	m_lastError = tr("An error occurred while parsing file at line %1, column %2 :\n%3").arg(line).arg(column).arg(msg);
249 }
250 
lastSavedFile()251 const QString& LoadSavePlugin::lastSavedFile()
252 {
253 	return m_lastSavedFile;
254 }
255 
loadFile(const QString &,const FileFormat &,int,int)256 bool LoadSavePlugin::loadFile(const QString & /* fileName */,
257 							  const FileFormat & /* fmt */,
258 							  int /* flags */,
259 							  int /* index */)
260 {
261 	return false;
262 }
263 
checkFlags(int flags)264 bool LoadSavePlugin::checkFlags(int flags)
265 {
266 	int numFlags = 0;
267 	// Only one of the following flags must be set:
268 	// lfCreateDoc, lfUseCurrentPage, lfInsertPage
269 	if( flags & lfCreateDoc )
270 		numFlags++;
271 	if( flags & lfUseCurrentPage )
272 		numFlags++;
273 	if( flags & lfInsertPage )
274 		numFlags++;
275 	return numFlags <= 1;
276 }
277 
registerFormat(FileFormat & fmt)278 void LoadSavePlugin::registerFormat(FileFormat & fmt)
279 {
280 	// We insert the format in a very specific location so that the formats
281 	// list is sorted by ascending id, then descending priority.
282 	// We first look for entries with equal or greater ID, then equal or
283 	// lesser priority, and insert before the first item that is of either:
284 	//     - Equal ID and lesser or equal priority; or
285 	//     - Greater ID
286 	// If we don't find one, we insert before the end iterator, ie append.
287 	if (fmt.formatId == 0) // only for custom plugins
288 	{
289 		uint id = FORMATID_FIRSTUSER;
290 		if (!formats.isEmpty())
291 		{
292 			QList<FileFormat>::iterator it(formats.begin());
293 			QList<FileFormat>::iterator itEnd(formats.end());
294 			id = FORMATID_FIRSTUSER - 1;
295 			while (it != itEnd)
296 			{
297 				id = qMax(it->formatId, id);
298 				++it;
299 			}
300 			id++;
301 		}
302 		fmt.formatId = id;
303 		formats.append(fmt);
304 	}
305 	else
306 	{
307 		QList<FileFormat>::iterator it(formats.begin());
308 		QList<FileFormat>::iterator itEnd(formats.end());
309 		while (it != itEnd)
310 		{
311 			if ( ( (it->formatId == fmt.formatId) && (it->priority <= fmt.priority) ) ||
312 				(it->formatId > fmt.formatId))
313 					break;
314 			++it;
315 		}
316 		formats.insert(it, fmt);
317 	}
318 	//qDebug("Format: Id: %3u, Prio: %3hu, Name: %s", fmt.formatId, fmt.priority, fmt.trName.toLocal8Bit().data() );
319 	//printFormatList(); // DEBUG
320 }
321 
322 // static debugging function - prints the human readable format list
printFormatList()323 void LoadSavePlugin::printFormatList()
324 {
325 	qDebug("Current format list:");
326 	QList<FileFormat>::const_iterator it(formats.constBegin());
327 	QList<FileFormat>::const_iterator itEnd(formats.constEnd());
328 	for ( ; it != itEnd ; ++it)
329 	{
330 		qDebug("    Format: Id: %3u, Prio: %3hu, Name: %s",  it->formatId, it->priority, it->trName.toLocal8Bit().data() );
331 	}
332 	qDebug("Done");
333 }
334 
unregisterFormat(unsigned int id)335 void LoadSavePlugin::unregisterFormat(unsigned int id)
336 {
337 	QList<FileFormat>::iterator it(findFormat(id, this));
338 	Q_ASSERT(it != formats.end());
339 	formats.erase(it);
340 }
341 
unregisterAll()342 void LoadSavePlugin::unregisterAll()
343 {
344 	QList<FileFormat>::iterator it(formats.begin());
345 	while (it != formats.end())
346 	{
347 		if (it->plug == this)
348 			it = formats.erase(it);
349 		else
350 			++it;
351 	}
352 }
353 
354 QList<FileFormat>::iterator
findFormat(unsigned int id,LoadSavePlugin * plug,QList<FileFormat>::iterator it)355 LoadSavePlugin::findFormat(unsigned int id, LoadSavePlugin* plug, QList<FileFormat>::iterator it)
356 {
357 	QList<FileFormat>::iterator itEnd(formats.end());
358 	for ( ; it != itEnd ; ++it)
359 	{
360 		if ((it->formatId == id) && ((plug == nullptr) || (plug == it->plug)))
361 			return it;
362 	}
363 	return itEnd;
364 }
365 
366 QList<FileFormat>::iterator
findFormat(const QString & extension,LoadSavePlugin * plug,QList<FileFormat>::iterator it)367 LoadSavePlugin::findFormat(const QString& extension, LoadSavePlugin* plug, QList<FileFormat>::iterator it)
368 {
369 	QList<FileFormat>::iterator itEnd(formats.end());
370 	for ( ; it != itEnd ; ++it)
371 	{
372 		if ((it->fileExtensions.contains(extension.toLower())) && ((plug == nullptr) || (plug == it->plug)) )
373 			return it;
374 	}
375 	return itEnd;
376 }
377 
378 
setupTargets(ScribusDoc * targetDoc,ScribusView * targetView,ScribusMainWindow * targetMW,QProgressBar * targetMWPRogressBar,SCFonts * targetAvailableFonts)379 void LoadSavePlugin::setupTargets(ScribusDoc *targetDoc, ScribusView* targetView, ScribusMainWindow* targetMW, QProgressBar* targetMWPRogressBar, SCFonts* targetAvailableFonts)
380 {
381 	m_Doc = targetDoc;
382 	m_View = targetView;
383 	m_ScMW = targetMW;
384 	m_mwProgressBar = targetMWPRogressBar;
385 	m_AvailableFonts = targetAvailableFonts;
386 }
387 
getReplacedFontData(bool &,QMap<QString,QString> &,QList<ScFace> &)388 void LoadSavePlugin::getReplacedFontData(bool & /*getNewReplacement*/, QMap<QString,QString> &/*getReplacedFonts*/, QList<ScFace> &/*getDummyScFaces*/)
389 {
390 }
391 
loadPage(const QString &,int,bool,const QString &)392 bool LoadSavePlugin::loadPage(const QString& /*fileName*/, int /*pageNumber*/, bool /*Mpage*/, const QString& /*renamedPageName*/)
393 {
394 	return false;
395 }
396 
readStyles(const QString &,ScribusDoc *,StyleSet<ParagraphStyle> &)397 bool LoadSavePlugin::readStyles(const QString& /*fileName*/, ScribusDoc* /*doc*/, StyleSet<ParagraphStyle> &/*docParagraphStyles*/)
398 {
399 	return false;
400 }
401 
readCharStyles(const QString &,ScribusDoc *,StyleSet<CharStyle> &)402 bool LoadSavePlugin::readCharStyles(const QString& /*fileName*/, ScribusDoc* /*doc*/, StyleSet<CharStyle> &/*docCharStyles*/)
403 {
404 	return false;
405 }
406 
readLineStyles(const QString &,QHash<QString,multiLine> *)407 bool LoadSavePlugin::readLineStyles(const QString& /*fileName*/, QHash<QString,multiLine>* /*Sty*/)
408 {
409 	return false;
410 }
411 
readColors(const QString &,ColorList &)412 bool LoadSavePlugin::readColors(const QString& /*fileName*/, ColorList & /*colors*/)
413 {
414 	return false;
415 }
416 
readPageCount(const QString &,int *,int *,QStringList &)417 bool LoadSavePlugin::readPageCount(const QString& /*fileName*/, int* /*num1*/, int* /*num2*/, QStringList & /*masterPageNames*/)
418 {
419 	return false;
420 }
421 
readThumbnail(const QString &)422 QImage LoadSavePlugin::readThumbnail(const QString& /*fileName*/)
423 {
424 	return QImage();
425 }
426 
loadStory(const QByteArray &,StoryText &,PageItem *)427 bool LoadSavePlugin::loadStory(const QByteArray& /*data*/, StoryText& /*story*/, PageItem* /*item*/)
428 {
429 	return false;
430 }
431 
saveStory(StoryText &,PageItem *,QByteArray &)432 bool LoadSavePlugin::saveStory(StoryText& /*story*/, PageItem* /*item*/, QByteArray& /*data*/)
433 {
434 	return false;
435 }
436 
loadFile(const QString & fileName,int flags,int index) const437 bool FileFormat::loadFile(const QString & fileName, int flags, int index) const
438 {
439 	if (plug && load)
440 	{
441 		plug->clearLastError();
442 		bool success = plug->loadFile(fileName, *this, flags, index);
443 		if (!success && plug->hasLastError())
444 		{
445 			if (ScCore->usingGUI())
446 			{
447 				ScMessageBox::warning(ScCore->primaryMainWindow(), CommonStrings::trWarning, plug->lastError());
448 			}
449 			else
450 			{
451 				qDebug() << plug->lastError();
452 			}
453 		}
454 		return success;
455 	}
456 	return false;
457 }
458 
saveFile(const QString & fileName) const459 bool FileFormat::saveFile(const QString & fileName) const
460 {
461 	return (plug && save) ? plug->saveFile(fileName, *this) : false;
462 }
463 
savePalette(const QString & fileName) const464 bool FileFormat::savePalette(const QString & fileName) const
465 {
466 	return (plug && save) ? plug->savePalette(fileName) : false;
467 }
468 
saveElements(double xp,double yp,double wp,double hp,Selection * selection,QByteArray & prevData) const469 QString FileFormat::saveElements(double xp, double yp, double wp, double hp, Selection* selection, QByteArray &prevData) const
470 {
471 	return (plug && save) ? plug->saveElements(xp, yp, wp, hp, selection, prevData) : "";
472 }
473 
FileFormat()474 FileFormat::FileFormat()
475 {
476 }
477 
FileFormat(LoadSavePlugin * plug)478 FileFormat::FileFormat(LoadSavePlugin* plug) :
479 	plug(plug)
480 {
481 }
482 
loadElements(const QString & data,const QString & fileDir,int toLayer,double Xp_in,double Yp_in,bool loc) const483 bool FileFormat::loadElements(const QString& data, const QString& fileDir, int toLayer, double Xp_in, double Yp_in, bool loc) const
484 {
485 	return (plug && load) ? plug->loadElements(data, fileDir, toLayer, Xp_in, Yp_in, loc) : false;
486 }
487 
loadPalette(const QString & fileName) const488 bool FileFormat::loadPalette(const QString & fileName) const
489 {
490 	return (plug && load) ? plug->loadPalette(fileName) : false;
491 }
492 
lastSavedFile() const493 QString FileFormat::lastSavedFile() const
494 {
495 	if (plug)
496 		return plug->lastSavedFile();
497 	return QString();
498 }
499 
setupTargets(ScribusDoc * targetDoc,ScribusView * targetView,ScribusMainWindow * targetMW,QProgressBar * targetMWPRogressBar,SCFonts * targetAvailableFonts) const500 void FileFormat::setupTargets(ScribusDoc *targetDoc, ScribusView* targetView, ScribusMainWindow* targetMW, QProgressBar* targetMWPRogressBar, SCFonts* targetAvailableFonts) const
501 {
502 	if (plug)
503 		plug->setupTargets(targetDoc, targetView, targetMW, targetMWPRogressBar, targetAvailableFonts);
504 }
505 
getReplacedFontData(bool & getNewReplacement,QMap<QString,QString> & getReplacedFonts,QList<ScFace> & getDummyScFaces) const506 void FileFormat::getReplacedFontData(bool & getNewReplacement, QMap<QString,QString> &getReplacedFonts, QList<ScFace> &getDummyScFaces) const
507 {
508 	if (plug)
509 		plug->getReplacedFontData(getNewReplacement, getReplacedFonts, getDummyScFaces);
510 }
511 
loadPage(const QString & fileName,int pageNumber,bool Mpage,const QString & renamedPageName) const512 bool FileFormat::loadPage(const QString & fileName, int pageNumber, bool Mpage, const QString& renamedPageName) const
513 {
514 	if (!plug || !load)
515 		return false;
516 	plug->clearLastError();
517 	bool success = plug->loadPage(fileName, pageNumber, Mpage, renamedPageName);
518 	if (!success && plug->hasLastError())
519 	{
520 		if (ScCore->usingGUI())
521 			ScMessageBox::warning(ScCore->primaryMainWindow(), CommonStrings::trWarning, plug->lastError());
522 		else
523 			qDebug() << plug->lastError();
524 	}
525 	return success;
526 }
527 
readStyles(const QString & fileName,ScribusDoc * doc,StyleSet<ParagraphStyle> & docParagraphStyles) const528 bool FileFormat::readStyles(const QString& fileName, ScribusDoc* doc, StyleSet<ParagraphStyle> &docParagraphStyles) const
529 {
530 	return (plug && load) ? plug->readStyles(fileName, doc, docParagraphStyles) : false;
531 }
532 
readCharStyles(const QString & fileName,ScribusDoc * doc,StyleSet<CharStyle> & docCharStyles) const533 bool FileFormat::readCharStyles(const QString& fileName, ScribusDoc* doc, StyleSet<CharStyle> &docCharStyles) const
534 {
535 	return (plug && load) ? plug->readCharStyles(fileName, doc, docCharStyles) : false;
536 }
537 
readLineStyles(const QString & fileName,QHash<QString,multiLine> * Sty) const538 bool FileFormat::readLineStyles(const QString& fileName, QHash<QString, multiLine> *Sty) const
539 {
540 	return (plug && load) ? plug->readLineStyles(fileName, Sty) : false;
541 }
542 
readColors(const QString & fileName,ColorList & colors) const543 bool FileFormat::readColors(const QString& fileName, ColorList & colors) const
544 {
545 	return (plug && load) ? plug->readColors(fileName, colors) : false;
546 }
547 
readPageCount(const QString & fileName,int * num1,int * num2,QStringList & masterPageNames) const548 bool FileFormat::readPageCount(const QString& fileName, int *num1, int *num2, QStringList & masterPageNames) const
549 {
550 	return (plug && load) ? plug->readPageCount(fileName, num1, num2, masterPageNames) : false;
551 }
552 
readThumbnail(const QString & fileName) const553 QImage FileFormat::readThumbnail(const QString& fileName) const
554 {
555 	return (plug && load && thumb) ? plug->readThumbnail(fileName) : QImage();
556 }
557 
loadStory(const QByteArray & data,StoryText & story,PageItem * item) const558 bool  FileFormat::loadStory(const QByteArray& data, StoryText& story, PageItem* item) const
559 {
560 	return (plug && load) ? plug->loadStory(data, story, item) : false;
561 }
562 
saveStory(StoryText & story,PageItem * item,QByteArray & data) const563 bool  FileFormat::saveStory(StoryText& story, PageItem* item, QByteArray& data) const
564 {
565 	return plug ? plug->saveStory(story, item, data) : false;
566 }
567