summaryrefslogtreecommitdiffstats
path: root/filters/olefilters/olefilter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'filters/olefilters/olefilter.cpp')
-rw-r--r--filters/olefilters/olefilter.cpp525
1 files changed, 525 insertions, 0 deletions
diff --git a/filters/olefilters/olefilter.cpp b/filters/olefilters/olefilter.cpp
new file mode 100644
index 000000000..ae0395a94
--- /dev/null
+++ b/filters/olefilters/olefilter.cpp
@@ -0,0 +1,525 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 Werner Trobin <trobin@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+DESCRIPTION
+
+ When reading, the point of this module is toperform a depth-first traversal
+ of an OLE file. This ensures that a parent object is processed only after
+ its child objects have been processed.
+*/
+
+#include <olefilter.h>
+
+#include <tqfile.h>
+#include <tdetempfile.h>
+#include <kgenericfactory.h>
+#include <kmimetype.h>
+#include <KoFilterChain.h>
+#include <KoDocumentInfo.h>
+
+//#include <excelfilter.h>
+#include <powerpointfilter.h>
+//#include <wordfilter.h>
+//#include <hancomwordfilter.h>
+
+#include <myfile.h>
+
+const int OLEFilter::s_area = 30510;
+
+class OLEFilterFactory : KGenericFactory<OLEFilter, KoFilter>
+{
+public:
+ OLEFilterFactory(void) : KGenericFactory<OLEFilter, KoFilter> ("olefilter")
+ {}
+protected:
+ virtual void setupTranslations( void )
+ {
+ TDEGlobal::locale()->insertCatalogue( "kofficefilters" );
+ }
+};
+
+K_EXPORT_COMPONENT_FACTORY( libolefilter, OLEFilterFactory() )
+
+OLEFilter::OLEFilter(KoFilter *, const char *, const TQStringList&) :
+ KoEmbeddingFilter(), numPic( 0 ),
+ docfile( 0 ), m_embeddeeData( 0 ),
+ m_embeddeeLength( 0 ), success( true )
+{
+ olefile.data=0L;
+}
+
+OLEFilter::~OLEFilter()
+{
+ delete [] olefile.data;
+ delete docfile;
+}
+
+KoFilter::ConversionStatus OLEFilter::convert( const TQCString& from, const TQCString& to )
+{
+ if(to!="application/x-kword" &&
+ to!="application/x-kspread" &&
+ to!="application/x-kpresenter")
+ return KoFilter::NotImplemented;
+ if(from!="application/vnd.ms-word" &&
+ from!="application/vnd.ms-excel" &&
+ from!="application/msword" &&
+ from!="application/msexcel" &&
+ from!="application/mspowerpoint" &&
+ from!="application/x-hancomword")
+ return KoFilter::NotImplemented;
+
+ TQFile in(m_chain->inputFile());
+ if(!in.open(IO_ReadOnly)) {
+ kdError(s_area) << "OLEFilter::filter(): Unable to open input" << endl;
+ in.close();
+ return KoFilter::FileNotFound;
+ }
+
+ // Open the OLE 2 file. [TODO] Is it really the best way to
+ // read all the stuff without buffer?
+ olefile.length=in.size();
+ olefile.data=new unsigned char[olefile.length];
+ in.readBlock((char*)olefile.data, olefile.length);
+ in.close();
+
+ docfile=new KLaola(olefile);
+ if(!docfile->isOk()) {
+ kdError(s_area) << "OLEFilter::filter(): Unable to read input file correctly!" << endl;
+ delete [] olefile.data;
+ olefile.data=0L;
+ return KoFilter::StupidError;
+ }
+
+ // Recursively convert the file
+ convert( "" );
+ if ( success )
+ return KoFilter::OK;
+ else
+ return KoFilter::StupidError;
+}
+
+void OLEFilter::commSlotDelayStream( const char* delay )
+{
+ emit internalCommDelayStream( delay );
+}
+
+void OLEFilter::commSlotShapeID( unsigned int& shapeID )
+{
+ emit internalCommShapeID( shapeID );
+}
+
+void OLEFilter::slotSavePart(
+ const TQString &nameIN,
+ TQString &storageId,
+ TQString &mimeType,
+ const TQString &extension,
+ unsigned int length,
+ const char *data)
+{
+ if(nameIN.isEmpty())
+ return;
+
+ int id = internalPartReference( nameIN );
+
+ if (id != -1)
+ {
+ // The part is already there, this is a lookup operation
+ // -> return the part id.
+ storageId = TQString::number( id );
+ mimeType = internalPartMimeType( nameIN );
+ }
+ else
+ {
+ // Set up the variables for the template method callback
+ m_embeddeeData = data;
+ m_embeddeeLength = length;
+
+ TQString srcMime( KoEmbeddingFilter::mimeTypeByExtension( extension ) );
+ if ( srcMime == KMimeType::defaultMimeType() )
+ kdWarning( s_area ) << "Couldn't determine the mimetype from the extension" << endl;
+
+ KoFilter::ConversionStatus status;
+ TQCString destMime( mimeType.latin1() );
+ storageId = TQString::number( embedPart( srcMime.latin1(), destMime, status, nameIN ) );
+
+ // copy back what the method returned
+ mimeType = destMime;
+
+ // Reset the variables to be on the safe side
+ m_embeddeeData = 0;
+ m_embeddeeLength = 0;
+
+ if ( status != KoFilter::OK )
+ kdDebug(s_area) << "Huh??? Couldn't convert that file" << endl;
+ }
+}
+
+void OLEFilter::slotSaveDocumentInformation(
+ const TQString &fullName,
+ const TQString &title,
+ const TQString &company,
+ const TQString &email,
+ const TQString &telephone,
+ const TQString &fax,
+ const TQString &postalCode,
+ const TQString &country,
+ const TQString &city,
+ const TQString &street,
+ const TQString &docTitle,
+ const TQString &docAbstract)
+{
+ KoDocumentInfo *info = new KoDocumentInfo();
+ KoDocumentInfoAuthor *author = static_cast<KoDocumentInfoAuthor *>(info->page("author"));
+ KoDocumentInfoAbout *about = static_cast<KoDocumentInfoAbout *>(info->page("about"));
+ author->setFullName(fullName);
+ author->setTitle(title);
+ author->setCompany(company);
+ author->setEmail(email);
+ author->setTelephoneHome(telephone);
+ author->setFax(fax);
+ author->setCountry(postalCode);
+ author->setPostalCode(country);
+ author->setCity(city);
+ author->setStreet(street);
+ about->setTitle(docTitle);
+ about->setTitle(docAbstract);
+
+ KoStoreDevice* docInfo = m_chain->storageFile( "documentinfo.xml", KoStore::Write );
+
+ if(!docInfo)
+ {
+ kdError(s_area) << "OLEFilter::slotSaveDocumentInformation(): Could not open documentinfo.xml!" << endl;
+ return;
+ }
+
+ TQCString data = info->save().toCString();
+ // Important: don't use data.length() here. It's slow, and dangerous (in case of a '\0' somewhere)
+ // The -1 is because we don't want to write the final \0.
+ TQ_LONG length = data.size()-1;
+
+ if(docInfo->writeBlock(data, length) != length)
+ kdError(s_area) << "OLEFilter::slotSaveDocumentInformation(): Could not write to KoStore!" << endl;
+}
+
+void OLEFilter::slotSavePic(
+ const TQString &nameIN,
+ TQString &storageId,
+ const TQString &extension,
+ unsigned int length,
+ const char *data)
+{
+ if(nameIN.isEmpty())
+ return;
+
+ TQMap<TQString, TQString>::ConstIterator it = imageMap.find(nameIN);
+
+ if (it != imageMap.end())
+ // The key is already here - return the part id.
+ storageId = it.data();
+ else
+ {
+ // It's not here, so let's generate one.
+ storageId = TQString( "pictures/picture%1.%2" ).arg( numPic++ ).arg( extension );
+ imageMap.insert(nameIN, storageId);
+ KoStoreDevice* pic = m_chain->storageFile( storageId, KoStore::Write );
+ if(!pic)
+ {
+ success = false;
+ kdError(s_area) << "OLEFilter::slotSavePic(): Could not open KoStore!" << endl;
+ return;
+ }
+ // Write it to the gzipped tar file
+ // Let's hope we never have to save images bigger than 2GB :-)
+ bool ret = pic->writeBlock(data, length) == static_cast<int>( length );
+ if (!ret)
+ kdError(s_area) << "OLEFilter::slotSavePic(): Could not write to KoStore!" << endl;
+ }
+}
+
+// ##### Only used for lookup now!
+void OLEFilter::slotPart(
+ const TQString& nameIN,
+ TQString &storageId,
+ TQString &mimeType)
+{
+ if (nameIN.isEmpty())
+ return;
+
+ int id = internalPartReference( nameIN );
+
+ if (id != -1)
+ {
+ // The key is already here - return the part id.
+ storageId = TQString::number( id );
+ mimeType = internalPartMimeType( nameIN );
+ }
+ else
+ kdWarning( s_area ) << "slotPart() can be used for lookup operations only" << endl;
+}
+
+// Don't forget the delete [] the stream.data ptr!
+void OLEFilter::slotGetStream(const int &handle, myFile &stream) {
+ stream=docfile->stream(handle);
+}
+
+// I can't guarantee that you get the right stream as the names
+// in a OLE 2 file are not unique! (searching only the current dir!)
+// Don't forget the delete [] the stream.data ptr!
+void OLEFilter::slotGetStream(const TQString &name, myFile &stream) {
+
+ KLaola::NodeList handle;
+
+ handle=docfile->find(name, true); // search only in current dir!
+
+ if (handle.count()==1)
+ stream=docfile->stream(handle.at(0));
+ else {
+ stream.data=0L;
+ stream.length=0;
+ }
+}
+
+void OLEFilter::savePartContents( TQIODevice* file )
+{
+ if ( m_embeddeeData != 0 && m_embeddeeLength != 0 )
+ file->writeBlock( m_embeddeeData, m_embeddeeLength );
+}
+
+// The recursive method to do all the work
+void OLEFilter::convert( const TQCString& mimeTypeHint )
+{
+ KLaola::NodeList list=docfile->parseCurrentDir();
+ KLaola::OLENode *node;
+ bool onlyDirs=true;
+
+ // Search for the directories
+ for(node=list.first(); node!=0; node=list.next()) {
+ if(node->isDirectory()) { // It's a dir!
+ if(docfile->enterDir(node)) {
+ // Go one level deeper, but don't increase the depth
+ // for ObjectPools.
+ if (node->name() == "ObjectPool")
+ convert( "" );
+ else {
+ // Get the storage name of the part (dirname==key), and associate the
+ // mimeType with it for later use.
+ TQCString mimeHint( mimeTypeHelper() );
+ if ( mimeHint.isEmpty() )
+ mimeHint = "application/x-kword"; // will be converted to a dummy KWord part
+ startInternalEmbedding( node->name(), mimeHint );
+ convert( mimeHint );
+ endInternalEmbedding();
+ }
+ docfile->leaveDir();
+ }
+ }
+ else
+ onlyDirs=false; // To prevent useless looping in the next loop
+ }
+
+ if(!onlyDirs) {
+ TQStringList nodeNames;
+ TQCString mimeType;
+ if ( !mimeTypeHint.isEmpty() )
+ mimeType = mimeTypeHint;
+ else
+ mimeType = mimeTypeHelper();
+
+ FilterBase *myFilter=0L;
+
+ #if 0
+ if ( mimeType == "application/x-kword" ) {
+ // WinWord (or dummy).
+
+ myFile main;
+ KLaola::NodeList tmp;
+ tmp=docfile->find("WordDocument", true);
+
+ if(tmp.count()==1) {
+ // okay, not a dummy
+ main=docfile->stream(tmp.at(0));
+
+ myFile table0, table1, data;
+ tmp=docfile->find("0Table", true);
+ if(tmp.count()==1)
+ table0=docfile->stream(tmp.at(0));
+
+ tmp=docfile->find("1Table", true);
+ if(tmp.count()==1)
+ table1=docfile->stream(tmp.at(0));
+
+ tmp=docfile->find("Data", true);
+ if(tmp.count()==1)
+ data=docfile->stream(tmp.at(0));
+
+ myFilter=new WordFilter(main, table0, table1, data);
+
+ // forward the internal communication calls
+ connect( this, TQT_SIGNAL( internalCommShapeID( unsigned int& ) ), myFilter, TQT_SIGNAL( internalCommShapeID( unsigned int& ) ) );
+ connect( this, TQT_SIGNAL( internalCommDelayStream( const char* ) ), myFilter, TQT_SIGNAL( internalCommDelayStream( const char* ) ) );
+ }
+ }
+ else if ( mimeType == "application/x-kspread" ) {
+ // Excel.
+
+ myFile workbook;
+ KLaola::NodeList tmp;
+
+ tmp = docfile->find( "Workbook", true );
+ if ( tmp.count() == 1 )
+ workbook = docfile->stream( tmp.at( 0 ) );
+ else {
+ tmp = docfile->find( "Book", true );
+ if ( tmp.count() == 1 )
+ workbook = docfile->stream( tmp.at( 0 ) );
+ }
+ myFilter=new ExcelFilter(workbook);
+ }
+ else
+ #endif
+ if ( mimeType == "application/x-kpresenter" ) {
+ // Powerpoint.
+
+ myFile main, currentUser, pictures, summary, documentSummary;
+ KLaola::NodeList tmp;
+
+ tmp=docfile->find("PowerPoint Document", true);
+ if(tmp.count()==1)
+ main=docfile->stream(tmp.at(0));
+
+ tmp=docfile->find("Current User", true);
+ if(tmp.count()==1)
+ currentUser=docfile->stream(tmp.at(0));
+
+ tmp=docfile->find("Pictures", true);
+ if(tmp.count()==1)
+ pictures=docfile->stream(tmp.at(0));
+
+ tmp=docfile->find("SummaryInformation", true);
+ if(tmp.count()==1)
+ summary=docfile->stream(tmp.at(0));
+
+ tmp=docfile->find("DocumentSummaryInformation", true);
+ if(tmp.count()==1)
+ documentSummary=docfile->stream(tmp.at(0));
+
+ myFilter=new PowerPointFilter(main, currentUser, pictures);
+ }
+ #if 0
+ else if ( mimeType == "application/x-hancomword" ) {
+ // HancomWord 6
+ myFile prvText;
+ KLaola::NodeList tmp;
+
+ tmp = docfile->find( "PrvText", true );
+ if( tmp.count() == 1 ) prvText = docfile->stream( tmp.at( 0 ) );
+
+ myFilter = new HancomWordFilter( prvText );
+ }
+ #endif
+
+ if(!myFilter) {
+ // Unknown type. We turn it into a dummy kword document...
+ node = list.first();
+ do {
+ nodeNames.prepend(node->name());
+ node = list.next();
+ } while ( node );
+
+ kdWarning(s_area) << "cannot convert \"" << nodeNames.join(",") << "\"" << endl;
+ myFilter=new FilterBase(nodeNames);
+ }
+
+ // connect SIGNALs&SLOTs
+ connectCommon(&myFilter);
+
+ // Launch the filtering process...
+ success=myFilter->filter();
+ // ...and fetch the file
+ TQCString file;
+ if(!myFilter->plainString()) {
+ const TQDomDocument * const part=myFilter->part();
+ file=part->toCString();
+ }
+ else
+ file=myFilter->CString();
+
+ KoStoreDevice* dev = m_chain->storageFile( "root", KoStore::Write );
+ if(!dev) {
+ success=false;
+ kdError(s_area) << "OLEFilter::convert(): Could not open KoStore!" << endl;
+ return;
+ }
+
+ // Write it to the gzipped tar file
+ bool ret = dev->writeBlock(file.data(), file.size()-1) == static_cast<TQ_LONG>( file.size() - 1 );
+ if (!ret)
+ kdError(s_area) << "OLEFilter::slotSavePic(): Could not write to KoStore!" << endl;
+ delete myFilter;
+ }
+}
+
+void OLEFilter::connectCommon(FilterBase **myFilter) {
+ TQObject::connect(
+ *myFilter,
+ TQT_SIGNAL(signalSaveDocumentInformation(const TQString &, const TQString &, const TQString &, const TQString &, const TQString &, const TQString &, const TQString &, const TQString &, const TQString &, const TQString &, const TQString &, const TQString &)),
+ this,
+ TQT_SLOT(slotSaveDocumentInformation(const TQString &, const TQString &, const TQString &, const TQString &, const TQString &, const TQString &, const TQString &, const TQString &, const TQString &, const TQString &, const TQString &, const TQString &)));
+
+ TQObject::connect(
+ *myFilter,
+ TQT_SIGNAL(signalSavePic(const TQString &, TQString &, const TQString &, unsigned int, const char *)),
+ this,
+ TQT_SLOT(slotSavePic(const TQString &, TQString &, const TQString &, unsigned int, const char *)));
+ TQObject::connect(
+ *myFilter,
+ TQT_SIGNAL(signalSavePart(const TQString &, TQString &, TQString &, const TQString &, unsigned int, const char *)),
+ this,
+ TQT_SLOT(slotSavePart(const TQString &, TQString &, TQString &, const TQString &, unsigned int, const char *)));
+ TQObject::connect(*myFilter, TQT_SIGNAL(signalPart(const TQString&, TQString &, TQString &)),
+ this, TQT_SLOT(slotPart(const TQString&, TQString &, TQString &)));
+ TQObject::connect(*myFilter, TQT_SIGNAL(signalGetStream(const int &, myFile &)), this,
+ TQT_SLOT(slotGetStream(const int &, myFile &)));
+ TQObject::connect(*myFilter, TQT_SIGNAL(signalGetStream(const TQString &, myFile &)), this,
+ TQT_SLOT(slotGetStream(const TQString &, myFile &)));
+ TQObject::connect(*myFilter, TQT_SIGNAL(sigProgress(int)), this, TQT_SIGNAL(sigProgress(int)));
+}
+
+TQCString OLEFilter::mimeTypeHelper()
+{
+ KLaola::NodeList list = docfile->parseCurrentDir();
+ KLaola::OLENode* node = list.first();
+
+ // ###### FIXME: Shaheed, please add additional mimetypes here
+ while ( node ) {
+ if ( node->name() == "WordDocument" )
+ return "application/x-kword";
+ else if ( node->name() == "Workbook" || node->name() == "Book" )
+ return "application/x-kspread";
+ else if ( node->name() == "PowerPoint Document" )
+ return "application/x-kpresenter";
+ else if ( node->name() == "PrvText" || node->name() == "BodyText" )
+ return "application/x-hancomword";
+ else
+ node = list.next();
+ }
+ kdWarning( s_area ) << "No known mimetype detected" << endl;
+ return "";
+}
+
+#include <olefilter.moc>