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 <tqdir.h>
00011 #include <tqregexp.h>
00012 #include <xslt.h>
00013 #include <kinstance.h>
00014 #include "tdeio_help.h"
00015 #include <tdelocale.h>
00016 #include <assert.h>
00017 #include <kfilterbase.h>
00018 #include <kfilterdev.h>
00019 #include <tqtextcodec.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 <tqvaluevector.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 TQString *t = (TQString*)context;
00040 *t += TQString::fromUtf8(buffer, len);
00041 return len;
00042 }
00043
00044 int closeQString(void * context) {
00045 TQString *t = (TQString*)context;
00046 *t += '\n';
00047 return 0;
00048 }
00049
00050 TQString transform( const TQString &pat, const TQString& tss,
00051 const TQValueVector<const char *> ¶ms )
00052 {
00053 TQString 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 TQValueVector<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 = " ";
00095 return parsed;
00096 }
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133 TQString splitOut(const TQString &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 TQString filedata;
00141
00142 while (true) {
00143 int endindex = parsed.find("</FILENAME>", index);
00144 int startindex = parsed.find("<FILENAME ", index) + 1;
00145
00146
00147
00148 if (startindex > 0) {
00149 if (startindex < endindex) {
00150
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
00179 return filedata;
00180 }
00181
00182 void fillInstance(TDEInstance &ins, const TQString &srcdir) {
00183 TQString catalogs;
00184
00185 if ( srcdir.isEmpty() ) {
00186 catalogs += ins.dirs()->findResource("data", "ksgmltools2/customization/catalog.xml");
00187 catalogs += ':';
00188 catalogs += ins.dirs()->findResource("data", "ksgmltools2/docbook/xml-dtd-4.2/catalog.xml");
00189 ins.dirs()->addResourceType("dtd", TDEStandardDirs::kde_default("data") + "ksgmltools2");
00190 } else {
00191 catalogs += srcdir +"/customization/catalog.xml:" + srcdir + "/docbook/xml-dtd-4.2/catalog.xml";
00192 ins.dirs()->addResourceDir("dtd", srcdir);
00193 }
00194
00195 xmlLoadCatalogs(catalogs.latin1());
00196 }
00197
00198 extern "C" void *init_kbzip2filter();
00199
00200 static TQIODevice *getBZip2device(const TQString &fileName )
00201 {
00202 TQFile * f = new TQFile( 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(TQT_TQIODEVICE(f), true);
00209 return new KFilterDev(base, true);
00210 }
00211 return 0;
00212 }
00213
00214 bool saveToCache( const TQString &contents, const TQString &filename )
00215 {
00216 TQIODevice *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 TQString &filename,
00233 const TQString &cache, TQString &output)
00234 {
00235 kdDebug( 7119 ) << "verifyCache " << filename << " " << cache << endl;
00236 if ( !compareTimeStamps( filename, cache ) )
00237 return false;
00238 if ( !compareTimeStamps( locate( "dtd", "customization/tde-chunk.xsl"), cache ) )
00239 return false;
00240
00241 kdDebug( 7119 ) << "create filter" << endl;
00242 TQIODevice *fd = ::getBZip2device(cache);
00243 if ( !fd )
00244 return false;
00245
00246 if (!fd->open(IO_ReadOnly))
00247 {
00248 delete fd;
00249 TQFile::remove(cache);
00250 return false;
00251 }
00252
00253 kdDebug( 7119 ) << "reading" << endl;
00254
00255 char buffer[32000];
00256 int n;
00257 TQCString text;
00258
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 = TQString::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 TQString lookForCache( const TQString &filename )
00279 {
00280 kdDebug() << "lookForCache " << filename << endl;
00281 assert( filename.endsWith( ".docbook" ) );
00282 assert( filename.at( 0 ) == '/' );
00283
00284 TQString cache = filename.left( filename.length() - 7 );
00285 TQString output;
00286 if ( readCache( filename, cache + "cache.bz2", output) )
00287 return output;
00288 if ( readCache( filename,
00289 locateLocal( "cache",
00290 "tdeio_help" + cache +
00291 "cache.bz2" ), output ) )
00292 return output;
00293
00294 return TQString::null;
00295 }
00296
00297 bool compareTimeStamps( const TQString &older, const TQString &newer )
00298 {
00299 TQFileInfo _older( older );
00300 TQFileInfo _newer( newer );
00301 assert( _older.exists() );
00302 if ( !_newer.exists() )
00303 return false;
00304 return ( _newer.lastModified() > _older.lastModified() );
00305 }
00306
00307 TQCString fromUnicode( const TQString &data )
00308 {
00309 TQTextCodec *locale = TQTextCodec::codecForLocale();
00310 TQCString 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 TQString part;
00318
00319 while ( offset < data.length() )
00320 {
00321 part = data.mid( offset, part_len );
00322 TQCString 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 TQCString 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 TQString res;
00339 res.sprintf( "&#%d;", TQChar(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 += TQCString( buffer, buffer_len + 1);
00348 offset += part_len;
00349 }
00350 return result;
00351 }
00352
00353 void replaceCharsetHeader( TQString &output )
00354 {
00355 TQString name = TQTextCodec::codecForLocale()->name();
00356 name.replace( TQString( "ISO " ), "iso-" );
00357 output.replace( TQString( "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">" ),
00358 TQString( "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%1\">" ).arg( name ) );
00359 }