diff options
Diffstat (limited to 'src/translators/tellicosaximporter.cpp')
-rw-r--r-- | src/translators/tellicosaximporter.cpp | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/src/translators/tellicosaximporter.cpp b/src/translators/tellicosaximporter.cpp new file mode 100644 index 0000000..de60c63 --- /dev/null +++ b/src/translators/tellicosaximporter.cpp @@ -0,0 +1,293 @@ +/*************************************************************************** + copyright : (C) 2008 by Robby Stephenson + email : [email protected] + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of version 2 of the GNU General Public License as * + * published by the Free Software Foundation; * + * * + ***************************************************************************/ + +// before tellicosaxmporter.h because of QT_NO_CAST_ASCII issues +#include "tellicoxmlhandler.h" +#include "tellicosaximporter.h" +#include "tellico_xml.h" +#include "../collectionfactory.h" +#include "../collections/bibtexcollection.h" +#include "../entry.h" +#include "../field.h" +#include "../imagefactory.h" +#include "../image.h" +#include "../isbnvalidator.h" +#include "../latin1literal.h" +#include "../tellico_strings.h" +#include "../tellico_kernel.h" +#include "../tellico_utils.h" +#include "../tellico_debug.h" +#include "../progressmanager.h" + +#include <tdelocale.h> +#include <kmdcodec.h> +#include <kzip.h> +#include <tdeapplication.h> + +#include <tqbuffer.h> +#include <tqfile.h> +#include <tqtimer.h> + +using Tellico::Import::TellicoSaxImporter; + +TellicoSaxImporter::TellicoSaxImporter(const KURL& url_, bool loadAllImages_) : DataImporter(url_), + m_coll(0), m_loadAllImages(loadAllImages_), m_format(Unknown), m_modified(false), + m_cancelled(false), m_hasImages(false), m_buffer(0), m_zip(0), m_imgDir(0) { +} + +TellicoSaxImporter::TellicoSaxImporter(const TQString& text_) : DataImporter(text_), + m_coll(0), m_loadAllImages(true), m_format(Unknown), m_modified(false), + m_cancelled(false), m_hasImages(false), m_buffer(0), m_zip(0), m_imgDir(0) { +} + +TellicoSaxImporter::~TellicoSaxImporter() { + if(m_zip) { + m_zip->close(); + } + delete m_zip; + m_zip = 0; + delete m_buffer; + m_buffer = 0; +} + +Tellico::Data::CollPtr TellicoSaxImporter::collection() { + if(m_coll) { + return m_coll; + } + + TQCString s; // read first 5 characters + if(source() == URL) { + if(!fileRef().open()) { + return 0; + } + TQIODevice* f = fileRef().file(); + for(uint i = 0; i < 5; ++i) { + s += static_cast<char>(f->getch()); + } + f->reset(); + } else { + if(data().size() < 5) { + m_format = Error; + return 0; + } + s = TQCString(data(), 6); + } + + // need to decide if the data is xml text, or a zip file + // if the first 5 characters are <?xml then treat it like text + if(s[0] == '<' && s[1] == '?' && s[2] == 'x' && s[3] == 'm' && s[4] == 'l') { + m_format = XML; + loadXMLData(source() == URL ? fileRef().file()->readAll() : data(), true); + } else { + m_format = Zip; + loadZipData(); + } + return m_coll; +} + +void TellicoSaxImporter::loadXMLData(const TQByteArray& data_, bool loadImages_) { + ProgressItem& item = ProgressManager::self()->newProgressItem(this, progressLabel(), true); + item.setTotalSteps(data_.size()); + connect(&item, SIGNAL(signalCancelled(ProgressItem*)), SLOT(slotCancel())); + ProgressItem::Done done(this); + + const bool showProgress = options() & ImportProgress; + + TellicoXMLHandler handler; + handler.setLoadImages(loadImages_); + + TQXmlSimpleReader reader; + reader.setContentHandler(&handler); + + TQXmlInputSource source; + bool success = reader.parse(&source, true); + + const uint blockSize = data_.size()/100 + 1; + uint pos = 0; + TQByteArray block; + + while(success && !m_cancelled && pos < data_.size()) { + uint size = TQMIN(blockSize, data_.size() - pos); + block.setRawData(data_.data() + pos, size); + source.setData(block); + success = reader.parseContinue(); + block.resetRawData(data_.data() + pos, size); + pos += blockSize; + if(showProgress) { + ProgressManager::self()->setProgress(this, pos); + kapp->processEvents(); + } + } + + if(!success) { + m_format = Error; + TQString error; + if(!url().isEmpty()) { + error = i18n(errorLoad).arg(url().fileName()) + TQChar('\n'); + } + error += handler.errorString(); + myDebug() << error << endl; + setStatusMessage(error); + return; + } + + if(!m_cancelled) { + m_hasImages = handler.hasImages(); + m_coll = handler.collection(); + } +} + +void TellicoSaxImporter::loadZipData() { + delete m_buffer; + delete m_zip; + if(source() == URL) { + m_buffer = 0; + m_zip = new KZip(fileRef().fileName()); + } else { + m_buffer = new TQBuffer(data()); + m_zip = new KZip(m_buffer); + } + if(!m_zip->open(IO_ReadOnly)) { + setStatusMessage(i18n(errorLoad).arg(url().fileName())); + m_format = Error; + delete m_zip; + m_zip = 0; + delete m_buffer; + m_buffer = 0; + return; + } + + const KArchiveDirectory* dir = m_zip->directory(); + if(!dir) { + TQString str = i18n(errorLoad).arg(url().fileName()) + TQChar('\n'); + str += i18n("The file is empty."); + setStatusMessage(str); + m_format = Error; + m_zip->close(); + delete m_zip; + m_zip = 0; + delete m_buffer; + m_buffer = 0; + return; + } + + // main file was changed from bookcase.xml to tellico.xml as of version 0.13 + const KArchiveEntry* entry = dir->entry(TQString::fromLatin1("tellico.xml")); + if(!entry) { + entry = dir->entry(TQString::fromLatin1("bookcase.xml")); + } + if(!entry || !entry->isFile()) { + TQString str = i18n(errorLoad).arg(url().fileName()) + TQChar('\n'); + str += i18n("The file contains no collection data."); + setStatusMessage(str); + m_format = Error; + m_zip->close(); + delete m_zip; + m_zip = 0; + delete m_buffer; + m_buffer = 0; + return; + } + + const TQByteArray xmlData = static_cast<const KArchiveFile*>(entry)->data(); + loadXMLData(xmlData, false); + if(!m_coll) { + m_format = Error; + m_zip->close(); + delete m_zip; + m_zip = 0; + delete m_buffer; + m_buffer = 0; + return; + } + + if(m_cancelled) { + m_zip->close(); + delete m_zip; + m_zip = 0; + delete m_buffer; + m_buffer = 0; + return; + } + + const KArchiveEntry* imgDirEntry = dir->entry(TQString::fromLatin1("images")); + if(!imgDirEntry || !imgDirEntry->isDirectory()) { + m_zip->close(); + delete m_zip; + m_zip = 0; + delete m_buffer; + m_buffer = 0; + return; + } + m_imgDir = static_cast<const KArchiveDirectory*>(imgDirEntry); + m_images.clear(); + m_images.add(m_imgDir->entries()); + m_hasImages = !m_images.isEmpty(); + + // if all the images are not to be loaded, then we're done + if(!m_loadAllImages) { +// myLog() << "TellicoSaxImporter::loadZipData() - delayed loading for " << m_images.count() << " images" << endl; + return; + } + + const TQStringList images = static_cast<const KArchiveDirectory*>(imgDirEntry)->entries(); + const uint stepSize = TQMAX(s_stepSize, images.count()/100); + + uint j = 0; + for(TQStringList::ConstIterator it = images.begin(); !m_cancelled && it != images.end(); ++it, ++j) { + const KArchiveEntry* file = m_imgDir->entry(*it); + if(file && file->isFile()) { + ImageFactory::addImage(static_cast<const KArchiveFile*>(file)->data(), + (*it).section('.', -1).upper(), (*it)); + m_images.remove(*it); + } + if(j%stepSize == 0) { + kapp->processEvents(); + } + } + + if(m_images.isEmpty()) { + // give it some time + TQTimer::singleShot(3000, this, SLOT(deleteLater())); + } +} + +bool TellicoSaxImporter::hasImages() const { + return m_hasImages; +} + +bool TellicoSaxImporter::loadImage(const TQString& id_) { +// myLog() << "TellicoSaxImporter::loadImage() - id = " << id_ << endl; + if(m_format != Zip || !m_imgDir) { + return false; + } + const KArchiveEntry* file = m_imgDir->entry(id_); + if(!file || !file->isFile()) { + return false; + } + TQString newID = ImageFactory::addImage(static_cast<const KArchiveFile*>(file)->data(), + id_.section('.', -1).upper(), id_); + m_images.remove(id_); + if(m_images.isEmpty()) { + // give it some time + TQTimer::singleShot(3000, this, SLOT(deleteLater())); + } + return !newID.isEmpty(); +} + +void TellicoSaxImporter::slotCancel() { + m_cancelled = true; + m_format = Cancel; +} + +#include "tellicosaximporter.moc" |