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

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