• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDocTools

xslt.cpp

Go to the documentation of this file.
00001 #include "xslt.h"
00002 
00003 #include <libxslt/xsltconfig.h>
00004 #include <libxslt/xsltInternals.h>
00005 #include <libxslt/transform.h>
00006 #include <libxslt/xsltutils.h>
00007 #include <libxml/xmlIO.h>
00008 #include <libxml/parserInternals.h>
00009 #include <libxml/catalog.h>
00010 #include <kdebug.h>
00011 #include <kstandarddirs.h>
00012 #include <QtCore/QDate>
00013 #include <QtCore/QDir>
00014 #include <QtCore/QRegExp>
00015 #include <kcomponentdata.h>
00016 #include <klocale.h>
00017 #include <assert.h>
00018 #include <kfilterbase.h>
00019 #include <kfilterdev.h>
00020 #include <QtCore/QTextCodec>
00021 #include <stdlib.h>
00022 #include <config.h>
00023 #include <stdarg.h>
00024 #include <klibloader.h>
00025 #include <kcharsets.h>
00026 #include <kurl.h>
00027 
00028 
00029 #if !defined( SIMPLE_XSLT )
00030 extern HelpProtocol *slave;
00031 #define INFO( x ) if (slave) slave->infoMessage(x);
00032 #else
00033 #define INFO( x )
00034 #endif
00035 
00036 int writeToQString(void * context, const char * buffer, int len)
00037 {
00038     QString *t = (QString*)context;
00039     *t += QString::fromUtf8(buffer, len);
00040     return len;
00041 }
00042 
00043 int closeQString(void * context) {
00044     QString *t = (QString*)context;
00045     *t += '\n';
00046     return 0;
00047 }
00048 
00049 QString transform( const QString &pat, const QString& tss,
00050                    const QVector<const char *> &params )
00051 {
00052     QString parsed;
00053 
00054     INFO(i18n("Parsing stylesheet"));
00055 
00056     xsltStylesheetPtr style_sheet =
00057         xsltParseStylesheetFile((const xmlChar *)tss.toLatin1().data());
00058 
00059     if ( !style_sheet ) {
00060         return parsed;
00061     }
00062     if (style_sheet->indent == 1)
00063         xmlIndentTreeOutput = 1;
00064     else
00065         xmlIndentTreeOutput = 0;
00066 
00067     INFO(i18n("Parsing document"));
00068 
00069     xmlDocPtr doc = xmlParseFile( pat.toLatin1() );
00070     xsltTransformContextPtr ctxt;
00071 
00072     ctxt = xsltNewTransformContext(style_sheet, doc);
00073     if (ctxt == NULL)
00074         return parsed;
00075 
00076     INFO(i18n("Applying stylesheet"));
00077     QVector<const char *> p = params;
00078     p.append( NULL );
00079     xmlDocPtr res = xsltApplyStylesheet(style_sheet, doc, const_cast<const char **>(&p[0]));
00080     xmlFreeDoc(doc);
00081     if (res != NULL) {
00082         xmlOutputBufferPtr outp = xmlOutputBufferCreateIO(writeToQString, (xmlOutputCloseCallback)closeQString, &parsed, 0);
00083         outp->written = 0;
00084         INFO(i18n("Writing document"));
00085         xsltSaveResultTo ( outp, res, style_sheet );
00086         xmlOutputBufferFlush(outp);
00087         xmlFreeDoc(res);
00088     }
00089     xsltFreeStylesheet(style_sheet);
00090 
00091     if (parsed.isEmpty())
00092     parsed = " "; // avoid error message
00093     return parsed;
00094 }
00095 
00096 /*
00097 xmlParserInputPtr meinExternalEntityLoader(const char *URL, const char *ID,
00098                        xmlParserCtxtPtr ctxt) {
00099     xmlParserInputPtr ret = NULL;
00100 
00101     // fprintf(stderr, "loading %s %s %s\n", URL, ID, ctxt->directory);
00102 
00103     if (URL == NULL) {
00104         if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
00105             ctxt->sax->warning(ctxt,
00106                     "failed to load external entity \"%s\"\n", ID);
00107         return(NULL);
00108     }
00109     if (!qstrcmp(ID, "-//OASIS//DTD DocBook XML V4.1.2//EN"))
00110         URL = "docbook/xml-dtd-4.1.2/docbookx.dtd";
00111     if (!qstrcmp(ID, "-//OASIS//DTD XML DocBook V4.1.2//EN"))
00112     URL = "docbook/xml-dtd-4.1.2/docbookx.dtd";
00113 
00114     QString file;
00115     if (KStandardDirs::exists( QDir::currentPath() + "/" + URL ) )
00116         file = QDir::currentPath() + "/" + URL;
00117     else
00118         file = locate("dtd", URL);
00119 
00120     ret = xmlNewInputFromFile(ctxt, file.toLatin1().constData());
00121     if (ret == NULL) {
00122         if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
00123             ctxt->sax->warning(ctxt,
00124 
00125                 "failed to load external entity \"%s\"\n", URL);
00126     }
00127     return(ret);
00128 }
00129 */
00130 
00131 QString splitOut(const QString &parsed, int index)
00132 {
00133     int start_index = index + 1;
00134     while (parsed.at(start_index - 1) != '>') start_index++;
00135 
00136     int inside = 0;
00137 
00138     QString filedata;
00139 
00140     while (true) {
00141         int endindex = parsed.indexOf("</FILENAME>", index);
00142         int startindex = parsed.indexOf("<FILENAME ", index) + 1;
00143 
00144 //        kDebug() << "FILENAME " << startindex << " " << endindex << " " << inside << " " << parsed.mid(startindex + 18, 15)<< " " << parsed.length();
00145 
00146         if (startindex > 0) {
00147             if (startindex < endindex) {
00148                 //              kDebug() << "finding another";
00149                 index = startindex + 8;
00150                 inside++;
00151             } else {
00152                 index = endindex + 8;
00153                 inside--;
00154             }
00155         } else {
00156             inside--;
00157             index = endindex + 1;
00158         }
00159 
00160         if (inside == 0) {
00161             filedata = parsed.mid(start_index, endindex - start_index);
00162             break;
00163         }
00164 
00165     }
00166 
00167     index = filedata.indexOf("<FILENAME ");
00168 
00169     if (index > 0) {
00170         int endindex = filedata.lastIndexOf("</FILENAME>");
00171         while (filedata.at(endindex) != '>') endindex++;
00172         endindex++;
00173         filedata = filedata.left(index) + filedata.mid(endindex);
00174     }
00175 
00176     // filedata.replace(QRegExp(">"), "\n>");
00177     return filedata;
00178 }
00179 
00180 void fillInstance(KComponentData &ins, const QString &srcdir)
00181 {
00182     QByteArray catalogs;
00183 
00184     if ( srcdir.isEmpty() ) {
00185         catalogs += KUrl::fromLocalFile( ins.dirs()->findResource("data", "ksgmltools2/customization/catalog.xml") ).toEncoded();
00186         catalogs += ' ';
00187         catalogs += KUrl::fromLocalFile( ins.dirs()->findResource("data", "ksgmltools2/docbook/xml-dtd-4.2/catalog.xml") ).toEncoded();
00188         ins.dirs()->addResourceType("dtd", "data", "ksgmltools2/");
00189     } else {
00190         catalogs += KUrl::fromLocalFile( srcdir +"/customization/catalog.xml" ).toEncoded();
00191         catalogs += ' ';
00192         catalogs += KUrl::fromLocalFile( srcdir + "/docbook/xml-dtd-4.2/catalog.xml" ).toEncoded();
00193         ins.dirs()->addResourceDir("dtd", srcdir);
00194     }
00195 
00196     setenv( "XML_CATALOG_FILES", catalogs.constData(), 1 );
00197     xmlInitializeCatalog();
00198 }
00199 
00200 static QIODevice *getBZip2device(const QString &fileName )
00201 {
00202     return KFilterDev::deviceForFile(fileName);
00203 }
00204 
00205 bool saveToCache( const QString &contents, const QString &filename )
00206 {
00207     QIODevice *fd = ::getBZip2device(filename);
00208     if ( !fd )
00209         return false;
00210 
00211     if (!fd->open(QIODevice::WriteOnly))
00212     {
00213        delete fd;
00214        return false;
00215     }
00216 
00217     fd->write( contents.toUtf8() );
00218     fd->close();
00219     delete fd;
00220     return true;
00221 }
00222 
00223 static bool readCache( const QString &filename,
00224                        const QString &cache, QString &output)
00225 {
00226     kDebug( 7119 ) << filename << " " << cache;
00227     KGlobal::dirs()->addResourceType("dtd", "data", "ksgmltools2/");
00228     if ( !compareTimeStamps( filename, cache ) )
00229         return false;
00230     if ( !compareTimeStamps( KStandardDirs::locate( "dtd", "customization/kde-chunk.xsl"), cache ) )
00231         return false;
00232 
00233     kDebug( 7119 ) << "create filter";
00234     QIODevice *fd = ::getBZip2device(cache);
00235     if ( !fd )
00236         return false;
00237 
00238     if (!fd->open(QIODevice::ReadOnly))
00239     {
00240        delete fd;
00241        QFile::remove(cache);
00242        return false;
00243     }
00244 
00245     kDebug( 7119 ) << "reading";
00246 
00247     char buffer[32000];
00248     int n;
00249     QByteArray text;
00250     // Also end loop in case of error, when -1 is returned
00251     while ( ( n = fd->read(buffer, 31900) ) > 0)
00252     {
00253         buffer[n] = 0;
00254         text += buffer;
00255     }
00256     kDebug( 7119 ) << "read " << text.length();
00257     fd->close();
00258 
00259     output = QString::fromUtf8( text );
00260     delete fd;
00261 
00262     if (n == -1)
00263         return false;
00264 
00265     kDebug( 7119 ) << "finished ";
00266 
00267     return true;
00268 }
00269 
00270 QString lookForCache( const QString &filename )
00271 {
00272     kDebug() << "lookForCache " << filename;
00273     assert( filename.endsWith( ".docbook" ) );
00274     assert( QDir::isAbsolutePath(filename));
00275     QString cache = filename.left( filename.length() - 7 );
00276     QString output;
00277     if ( readCache( filename, cache + "cache.bz2", output) )
00278         return output;
00279 #ifdef Q_WS_WIN
00280     QFileInfo fi(filename);
00281     // make sure filenames do not contain the base path, otherwise
00282     // accessing user data from another location invalids cached files.
00283     // Accessing user data under a different path is possible
00284     // when using usb sticks - this may affect unix/mac systems also
00285     cache = '/' + fi.absolutePath().remove(KStandardDirs::installPath("html"),Qt::CaseInsensitive).replace('/','_') + '_' + fi.baseName() + '.';
00286 #endif
00287     if ( readCache( filename,
00288                     KStandardDirs::locateLocal( "cache",
00289                                  "kio_help" + cache +
00290                                  "cache.bz2" ), output ) )
00291         return output;
00292 
00293     return QString();
00294 }
00295 
00296 bool compareTimeStamps( const QString &older, const QString &newer )
00297 {
00298     QFileInfo _older( older );
00299     QFileInfo _newer( newer );
00300     assert( _older.exists() );
00301     if ( !_newer.exists() )
00302         return false;
00303     return ( _newer.lastModified() > _older.lastModified() );
00304 }
00305 
00306 QByteArray fromUnicode( const QString &data )
00307 {
00308 #ifdef Q_WS_WIN
00309     return data.toUtf8();
00310 #else
00311     QTextCodec *locale = QTextCodec::codecForLocale();
00312     QByteArray result;
00313     char buffer[30000];
00314     uint buffer_len = 0;
00315     uint len = 0;
00316     int offset = 0;
00317     const int part_len = 5000;
00318 
00319     QString part;
00320 
00321     while ( offset < data.length() )
00322     {
00323         part = data.mid( offset, part_len );
00324         QByteArray test = locale->fromUnicode( part );
00325         if ( locale->toUnicode( test ) == part ) {
00326             result += test;
00327             offset += part_len;
00328             continue;
00329         }
00330         len = part.length();
00331         buffer_len = 0;
00332         for ( uint i = 0; i < len; i++ ) {
00333             QByteArray test = locale->fromUnicode( part.mid( i, 1 ) );
00334             if ( locale->toUnicode( test ) == part.mid( i, 1 ) ) {
00335                 if (buffer_len + test.length() + 1 > sizeof(buffer))
00336                    break;
00337                 strcpy( buffer + buffer_len, test.data() );
00338                 buffer_len += test.length();
00339             } else {
00340                 QString res;
00341                 res.sprintf( "&#%d;", part.at( i ).unicode() );
00342                 test = locale->fromUnicode( res );
00343                 if (buffer_len + test.length() + 1 > sizeof(buffer))
00344                    break;
00345                 strcpy( buffer + buffer_len, test.data() );
00346                 buffer_len += test.length();
00347             }
00348         }
00349         result += QByteArray( buffer, buffer_len + 1);
00350         offset += part_len;
00351     }
00352     return result;
00353 #endif  
00354 }
00355 
00356 void replaceCharsetHeader( QString &output )
00357 {
00358     QString name;
00359 #ifdef Q_WS_WIN
00360     name = "utf-8"; 
00361     // may be required for all xml output 
00362     if (output.contains("<table-of-contents>"))
00363         output.replace( QString( "<?xml version=\"1.0\"?>" ),
00364                         QString( "<?xml version=\"1.0\" encoding=\"%1\"?>").arg( name ) );
00365 #else                    
00366     name = QTextCodec::codecForLocale()->name();
00367     name.replace( QString( "ISO " ), "iso-" );
00368     output.replace( QString( "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">" ),
00369                     QString( "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%1\">" ).arg( name ) );
00370 #endif    
00371 }

KDocTools

Skip menu "KDocTools"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal