TDE core libraries
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

360 lines
10 KiB

  1. #include <libxslt/xsltconfig.h>
  2. #include <libxslt/xsltInternals.h>
  3. #include <libxslt/transform.h>
  4. #include <libxslt/xsltutils.h>
  5. #include <libxml/xmlIO.h>
  6. #include <libxml/parserInternals.h>
  7. #include <libxml/catalog.h>
  8. #include <kdebug.h>
  9. #include <kstandarddirs.h>
  10. #include <tqdir.h>
  11. #include <tqregexp.h>
  12. #include <xslt.h>
  13. #include <kinstance.h>
  14. #include "tdeio_help.h"
  15. #include <tdelocale.h>
  16. #include <assert.h>
  17. #include <kfilterbase.h>
  18. #include <kfilterdev.h>
  19. #include <tqtextcodec.h>
  20. #include <stdlib.h>
  21. #include <config.h>
  22. #include <stdarg.h>
  23. #include <klibloader.h>
  24. #include <kcharsets.h>
  25. #include <gzip/kgzipfilter.h>
  26. #include <bzip2/kbzip2filter.h>
  27. #include <klibloader.h>
  28. #include <tqvaluevector.h>
  29. #if !defined( SIMPLE_XSLT )
  30. extern HelpProtocol *slave;
  31. #define INFO( x ) if (slave) slave->infoMessage(x);
  32. #else
  33. #define INFO( x )
  34. #endif
  35. int writeToQString(void * context, const char * buffer, int len)
  36. {
  37. TQString *t = (TQString*)context;
  38. *t += TQString::fromUtf8(buffer, len);
  39. return len;
  40. }
  41. int closeQString(void * context) {
  42. TQString *t = (TQString*)context;
  43. *t += '\n';
  44. return 0;
  45. }
  46. TQString transform( const TQString &pat, const TQString& tss,
  47. const TQValueVector<const char *> &params )
  48. {
  49. TQString parsed;
  50. INFO(i18n("Parsing stylesheet"));
  51. xsltStylesheetPtr style_sheet =
  52. xsltParseStylesheetFile((const xmlChar *)tss.latin1());
  53. if ( !style_sheet ) {
  54. return parsed;
  55. }
  56. if (style_sheet->indent == 1)
  57. xmlIndentTreeOutput = 1;
  58. else
  59. xmlIndentTreeOutput = 0;
  60. INFO(i18n("Parsing document"));
  61. xmlDocPtr doc = xmlParseFile( pat.latin1() );
  62. xsltTransformContextPtr ctxt;
  63. ctxt = xsltNewTransformContext(style_sheet, doc);
  64. if (ctxt == NULL)
  65. return parsed;
  66. INFO(i18n("Applying stylesheet"));
  67. TQValueVector<const char *> p = params;
  68. p.append( NULL );
  69. xmlDocPtr res = xsltApplyStylesheet(style_sheet, doc, const_cast<const char **>(&p[0]));
  70. xmlFreeDoc(doc);
  71. if (res != NULL) {
  72. xmlOutputBufferPtr outp = xmlOutputBufferCreateIO(writeToQString, (xmlOutputCloseCallback)closeQString, &parsed, 0);
  73. outp->written = 0;
  74. INFO(i18n("Writing document"));
  75. xsltSaveResultTo ( outp, res, style_sheet );
  76. xmlOutputBufferFlush(outp);
  77. xmlFreeDoc(res);
  78. }
  79. xsltFreeStylesheet(style_sheet);
  80. if (parsed.isEmpty())
  81. parsed = " "; // avoid error message
  82. return parsed;
  83. }
  84. /*
  85. xmlParserInputPtr meinExternalEntityLoader(const char *URL, const char *ID,
  86. xmlParserCtxtPtr ctxt) {
  87. xmlParserInputPtr ret = NULL;
  88. // fprintf(stderr, "loading %s %s %s\n", URL, ID, ctxt->directory);
  89. if (URL == NULL) {
  90. if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
  91. ctxt->sax->warning(ctxt,
  92. "failed to load external entity \"%s\"\n", ID);
  93. return(NULL);
  94. }
  95. if (!qstrcmp(ID, "-//OASIS//DTD DocBook XML V4.1.2//EN"))
  96. URL = "docbook/xml-dtd-4.1.2/docbookx.dtd";
  97. if (!qstrcmp(ID, "-//OASIS//DTD XML DocBook V4.1.2//EN"))
  98. URL = "docbook/xml-dtd-4.1.2/docbookx.dtd";
  99. TQString file;
  100. if (TDEStandardDirs::exists( TQDir::currentDirPath() + "/" + URL ) )
  101. file = TQDir::currentDirPath() + "/" + URL;
  102. else
  103. file = locate("dtd", URL);
  104. ret = xmlNewInputFromFile(ctxt, file.latin1());
  105. if (ret == NULL) {
  106. if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
  107. ctxt->sax->warning(ctxt,
  108. "failed to load external entity \"%s\"\n", URL);
  109. }
  110. return(ret);
  111. }
  112. */
  113. TQString splitOut(const TQString &parsed, int index)
  114. {
  115. int start_index = index + 1;
  116. while (parsed.at(start_index - 1) != '>') start_index++;
  117. int inside = 0;
  118. TQString filedata;
  119. while (true) {
  120. int endindex = parsed.find("</FILENAME>", index);
  121. int startindex = parsed.find("<FILENAME ", index) + 1;
  122. // kdDebug() << "FILENAME " << startindex << " " << endindex << " " << inside << " " << parsed.mid(startindex + 18, 15)<< " " << parsed.length() << endl;
  123. if (startindex > 0) {
  124. if (startindex < endindex) {
  125. // kdDebug() << "finding another" << endl;
  126. index = startindex + 8;
  127. inside++;
  128. } else {
  129. index = endindex + 8;
  130. inside--;
  131. }
  132. } else {
  133. inside--;
  134. index = endindex + 1;
  135. }
  136. if (inside == 0) {
  137. filedata = parsed.mid(start_index, endindex - start_index);
  138. break;
  139. }
  140. }
  141. index = filedata.find("<FILENAME ");
  142. if (index > 0) {
  143. int endindex = filedata.findRev("</FILENAME>");
  144. while (filedata.at(endindex) != '>') endindex++;
  145. endindex++;
  146. filedata = filedata.left(index) + filedata.mid(endindex);
  147. }
  148. // filedata.replace(TQRegExp(">"), "\n>");
  149. return filedata;
  150. }
  151. void fillInstance(TDEInstance &ins, const TQString &srcdir) {
  152. TQString catalogs;
  153. if ( srcdir.isEmpty() ) {
  154. catalogs += ins.dirs()->findResource("data", "ksgmltools2/customization/catalog.xml");
  155. catalogs += ':';
  156. catalogs += ins.dirs()->findResource("data", "ksgmltools2/docbook/xml-dtd-4.2/catalog.xml");
  157. ins.dirs()->addResourceType("dtd", TDEStandardDirs::kde_default("data") + "ksgmltools2");
  158. } else {
  159. catalogs += srcdir +"/customization/catalog.xml:" + srcdir + "/docbook/xml-dtd-4.2/catalog.xml";
  160. ins.dirs()->addResourceDir("dtd", srcdir);
  161. }
  162. xmlLoadCatalogs(catalogs.latin1());
  163. }
  164. extern "C" void *init_kbzip2filter();
  165. static TQIODevice *getBZip2device(const TQString &fileName )
  166. {
  167. TQFile * f = new TQFile( fileName );
  168. KLibFactory * factory = static_cast<KLibFactory*>(init_kbzip2filter());
  169. KFilterBase * base = static_cast<KFilterBase*>( factory->create(0, "bzip2" ) );
  170. if ( base )
  171. {
  172. base->setDevice(TQT_TQIODEVICE(f), true);
  173. return new KFilterDev(base, true);
  174. }
  175. return 0;
  176. }
  177. bool saveToCache( const TQString &contents, const TQString &filename )
  178. {
  179. TQIODevice *fd = ::getBZip2device(filename);
  180. if ( !fd )
  181. return false;
  182. if (!fd->open(IO_WriteOnly))
  183. {
  184. delete fd;
  185. return false;
  186. }
  187. fd->writeBlock( contents.utf8() );
  188. fd->close();
  189. delete fd;
  190. return true;
  191. }
  192. static bool readCache( const TQString &filename,
  193. const TQString &cache, TQString &output)
  194. {
  195. kdDebug( 7119 ) << "verifyCache " << filename << " " << cache << endl;
  196. if ( !compareTimeStamps( filename, cache ) )
  197. return false;
  198. if ( !compareTimeStamps( locate( "dtd", "customization/tde-chunk.xsl"), cache ) )
  199. return false;
  200. kdDebug( 7119 ) << "create filter" << endl;
  201. TQIODevice *fd = ::getBZip2device(cache);
  202. if ( !fd )
  203. return false;
  204. if (!fd->open(IO_ReadOnly))
  205. {
  206. delete fd;
  207. TQFile::remove(cache);
  208. return false;
  209. }
  210. kdDebug( 7119 ) << "reading" << endl;
  211. char buffer[32000];
  212. int n;
  213. TQCString text;
  214. // Also end loop in case of error, when -1 is returned
  215. while ( ( n = fd->readBlock(buffer, 31900) ) > 0)
  216. {
  217. buffer[n] = 0;
  218. text += buffer;
  219. }
  220. kdDebug( 7119 ) << "read " << text.length() << endl;
  221. fd->close();
  222. output = TQString::fromUtf8( text );
  223. delete fd;
  224. if (n == -1)
  225. return false;
  226. kdDebug( 7119 ) << "finished " << endl;
  227. return true;
  228. }
  229. TQString lookForCache( const TQString &filename )
  230. {
  231. kdDebug() << "lookForCache " << filename << endl;
  232. assert( filename.endsWith( ".docbook" ) );
  233. assert( filename.at( 0 ) == '/' );
  234. TQString cache = filename.left( filename.length() - 7 );
  235. TQString output;
  236. if ( readCache( filename, cache + "cache.bz2", output) )
  237. return output;
  238. if ( readCache( filename,
  239. locateLocal( "cache",
  240. "tdeio_help" + cache +
  241. "cache.bz2" ), output ) )
  242. return output;
  243. return TQString::null;
  244. }
  245. bool compareTimeStamps( const TQString &older, const TQString &newer )
  246. {
  247. TQFileInfo _older( older );
  248. TQFileInfo _newer( newer );
  249. assert( _older.exists() );
  250. if ( !_newer.exists() )
  251. return false;
  252. return ( _newer.lastModified() > _older.lastModified() );
  253. }
  254. TQCString fromUnicode( const TQString &data )
  255. {
  256. TQTextCodec *locale = TQTextCodec::codecForLocale();
  257. TQCString result;
  258. char buffer[30000];
  259. uint buffer_len = 0;
  260. uint len = 0;
  261. uint offset = 0;
  262. const int part_len = 5000;
  263. TQString part;
  264. while ( offset < data.length() )
  265. {
  266. part = data.mid( offset, part_len );
  267. TQCString test = locale->fromUnicode( part );
  268. if ( locale->toUnicode( test ) == part ) {
  269. result += test;
  270. offset += part_len;
  271. continue;
  272. }
  273. len = part.length();
  274. buffer_len = 0;
  275. for ( uint i = 0; i < len; i++ ) {
  276. TQCString test = locale->fromUnicode( part.mid( i, 1 ) );
  277. if ( locale->toUnicode( test ) == part.mid( i, 1 ) ) {
  278. if (buffer_len + test.length() + 1 > sizeof(buffer))
  279. break;
  280. strcpy( buffer + buffer_len, test.data() );
  281. buffer_len += test.length();
  282. } else {
  283. TQString res;
  284. res.sprintf( "&#%d;", TQChar(part.at( i )).unicode() );
  285. test = locale->fromUnicode( res );
  286. if (buffer_len + test.length() + 1 > sizeof(buffer))
  287. break;
  288. strcpy( buffer + buffer_len, test.data() );
  289. buffer_len += test.length();
  290. }
  291. }
  292. result += TQCString( buffer, buffer_len + 1);
  293. offset += part_len;
  294. }
  295. return result;
  296. }
  297. void replaceCharsetHeader( TQString &output )
  298. {
  299. TQString name = TQTextCodec::codecForLocale()->name();
  300. name.replace( TQString( "ISO " ), "iso-" );
  301. output.replace( TQString( "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">" ),
  302. TQString( "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%1\">" ).arg( name ) );
  303. }