/*************************************************************************** copyright : (C) 2008 by Robby Stephenson email : robby@periapsis.org ***************************************************************************/ /*************************************************************************** * * * 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 TQT_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, TQ_SIGNAL(signalCancelled(ProgressItem*)), TQ_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, TQ_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, TQ_SLOT(deleteLater())); } return !newID.isEmpty(); } void TellicoSaxImporter::slotCancel() { m_cancelled = true; m_format = Cancel; } #include "tellicosaximporter.moc"