1
/* This file is part of the KDE libraries
2
Copyright (C) 2001 Malte Starostik <malte@kde.org>
4
This library is free software; you can redistribute it and/or
5
modify it under the terms of the GNU Library General Public
6
License as published by the Free Software Foundation; either
7
version 2 of the License, or (at your option) any later version.
9
This library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
Library General Public License for more details.
14
You should have received a copy of the GNU Library General Public License
15
along with this library; see the file COPYING.LIB. If not, write to
16
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17
Boston, MA 02111-1307, USA.
20
// $Id: gscreator.cpp,v 1.19.2.1 2004/03/19 15:10:56 waba Exp $
23
/* This function gets a path of a DVI, EPS, PS or PDF file and
24
produces a PNG-Thumbnail which is stored as a QImage
26
The program works as follows
28
1. Test if file is a DVI file
30
2. Create a child process (1), in which the
31
file is to be changed into a PNG
33
3. Child-process (1) :
35
4. If file is DVI continue with 6
37
5. If file is no DVI continue with 9
39
6. Create another child process (2), in which the DVI is
40
turned into PS using dvips
42
7. Parent process (2) :
43
Turn the recently created PS file into a PNG file using gs
47
9. Turn the PS,PDF or EPS file into a PNG file using gs
49
10. Parent process (1)
50
store data in a QImage
62
#ifdef HAVE_SYS_SELECT_H
63
#include <sys/select.h>
74
#include "gscreator.h"
80
ThumbCreator *new_creator()
86
// This PS snippet will be prepended to the actual file so that only
87
// the first page is output.
88
static const char *prolog =
90
"/.showpage.orig /showpage load def\n"
91
"/.showpage.firstonly {\n"
95
"/showpage { .showpage.firstonly } def\n";
97
static const char * gsargs[] = {
116
static const char *dvipsargs[] = {
127
static bool correctDVI(const QString& filename);
131
bool got_sig_term = false;
132
void handle_sigterm( int ) {
138
bool GSCreator::create(const QString &path, int, int, QImage &img)
140
// The code in the loop (when testing whether got_sig_term got set)
141
// should read some variation of:
142
// parentJob()->wasKilled()
144
// Unfortunatelly, that's currently impossible without breaking BIC.
145
// So we need to catch the signal ourselves.
146
// Otherwise, on certain funny PS files (for example
147
// http://www.tjhsst.edu/~Eedanaher/pslife/life.ps )
148
// gs would run forever after we were dead.
149
// #### Reconsider for KDE 4 ###
150
// (24/12/03 - luis_pedro)
152
typedef void ( *sighandler_t )( int );
153
// according to linux's "man signal" the above typedef is a gnu extension
154
sighandler_t oldhandler = signal( SIGTERM, handle_sigterm );
160
QByteArray data(1024);
164
// Test if file is DVI
165
bool no_dvi =!correctDVI(path);
168
if (pipe(input) == -1) {
171
if (pipe(output) == -1) {
181
// close(STDERR_FILENO);
183
// find first zero entry in gsargs and put the filename
184
// or - (stdin) there, if DVI
185
const char **arg = gsargs;
186
QCString fname = QFile::encodeName( path );
194
// find first zero entry in dvipsargs and put the filename there
202
pid_t pid_two = fork();
204
// Child process (2), reopen stdout on the pipe "dvipipe" and exec dvips
212
dup2( dvipipe[1], STDOUT_FILENO);
214
execvp(dvipsargs[0], const_cast<char *const *>(dvipsargs));
217
else if(pid_two != -1){
222
dup2( dvipipe[0], STDIN_FILENO);
223
dup2( output[1], STDOUT_FILENO);
225
execvp(gsargs[0], const_cast<char *const *>(gsargs));
229
// fork() (2) failed, close these
236
// Reopen stdin/stdout on the pipes and exec gs
240
dup2(input[0], STDIN_FILENO);
241
dup2(output[1], STDOUT_FILENO);
243
execvp(gsargs[0], const_cast<char *const *>(gsargs));
247
else if (pid != -1) {
248
// Parent process, write first-page-only-hack (the hack is not
249
// used if DVI) and read the png output
252
int count = write(input[1], prolog, strlen(prolog));
254
if (count == static_cast<int>(strlen(prolog))) {
259
FD_SET(output[0], &fds);
264
got_sig_term = false;
265
if (select(output[0] + 1, &fds, 0, 0, &tv) <= 0) {
266
if ( ( errno == EINTR || errno == EAGAIN ) && !got_sig_term ) continue;
267
break; // error, timeout or master wants us to quit (SIGTERM)
269
if (FD_ISSET(output[0], &fds)) {
270
count = read(output[0], data.data() + offset, 1024);
274
if (count) // prepare for next block
277
data.resize(offset + 1024);
287
if (!ok) // error or timeout, gs probably didn't exit yet
293
if (waitpid(pid, &status, 0) != pid || (status != 0 && status != 256) )
297
// fork() (1) failed, close these
304
int l = img.loadFromData( data );
307
oldhandler != SIG_ERR &&
308
oldhandler != SIG_DFL &&
309
oldhandler != SIG_IGN ) {
310
oldhandler( SIGTERM ); // propagate the signal. Other things might rely on it
312
if ( oldhandler != SIG_ERR ) signal( SIGTERM, oldhandler );
317
ThumbCreator::Flags GSCreator::flags() const
319
return static_cast<Flags>(DrawFrame);
323
// Quick function to check if the filename corresponds to a valid DVI
324
// file. Returns true if <filename> is a DVI file, false otherwise.
326
static bool correctDVI(const QString& filename)
329
if (!f.open(IO_ReadOnly))
332
unsigned char test[4];
333
if ( f.readBlock( (char *)test,2)<2 || test[0] != 247 || test[1] != 2 )
337
if ( n < 134 ) // Too short for a dvi file
341
unsigned char trailer[4] = { 0xdf,0xdf,0xdf,0xdf };
343
if ( f.readBlock( (char *)test, 4 )<4 || strncmp( (char *)test, (char*) trailer, 4 ) )
345
// We suppose now that the dvi file is complete and OK