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

KDocTools

xslt.cpp

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

KDocTools

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

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
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