summaryrefslogtreecommitdiffstats
path: root/kfile-plugins/ps
diff options
context:
space:
mode:
Diffstat (limited to 'kfile-plugins/ps')
-rw-r--r--kfile-plugins/ps/Makefile.am26
-rw-r--r--kfile-plugins/ps/gscreator.cpp619
-rw-r--r--kfile-plugins/ps/gscreator.h42
-rw-r--r--kfile-plugins/ps/gsthumbnail.desktop60
-rw-r--r--kfile-plugins/ps/kfile_ps.cpp124
-rw-r--r--kfile-plugins/ps/kfile_ps.desktop66
-rw-r--r--kfile-plugins/ps/kfile_ps.h50
7 files changed, 987 insertions, 0 deletions
diff --git a/kfile-plugins/ps/Makefile.am b/kfile-plugins/ps/Makefile.am
new file mode 100644
index 00000000..9c5b20a3
--- /dev/null
+++ b/kfile-plugins/ps/Makefile.am
@@ -0,0 +1,26 @@
+## Makefile.am for the ps file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = -I$(top_srcdir)/kghostview $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_ps.h gscreator.h
+
+kde_module_LTLIBRARIES = kfile_ps.la gsthumbnail.la
+
+kfile_ps_la_SOURCES = kfile_ps.cpp
+kfile_ps_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_ps_la_LIBADD = $(LIB_KIO) ../../kghostview/libdscparse.la
+
+gsthumbnail_la_SOURCES = gscreator.cpp
+gsthumbnail_la_LIBADD = $(LIB_KDECORE) ../../kghostview/libdscparse.la
+gsthumbnail_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/kfile_ps.pot
+
+services_DATA = kfile_ps.desktop gsthumbnail.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/ps/gscreator.cpp b/kfile-plugins/ps/gscreator.cpp
new file mode 100644
index 00000000..33cbc141
--- /dev/null
+++ b/kfile-plugins/ps/gscreator.cpp
@@ -0,0 +1,619 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001 Malte Starostik <malte@kde.org>
+
+ Handling of EPS previews Copyright (C) 2003 Philipp Hullmann <phull@gmx.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/* This function gets a path of a DVI, EPS, PS or PDF file and
+ produces a PNG-Thumbnail which is stored as a QImage
+
+ The program works as follows
+
+ 1. Test if file is a DVI file
+
+ 2. Create a child process (1), in which the
+ file is to be changed into a PNG
+
+ 3. Child-process (1) :
+
+ 4. If file is DVI continue with 6
+
+ 5. If file is no DVI continue with 9
+
+ 6. Create another child process (2), in which the DVI is
+ turned into PS using dvips
+
+ 7. Parent process (2) :
+ Turn the recently created PS file into a PNG file using gs
+
+ 8. continue with 10
+
+ 9. Turn the PS,PDF or EPS file into a PNG file using gs
+
+ 10. Parent process (1)
+ store data in a QImage
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <kdemacros.h>
+
+#include <qcolor.h>
+#include <qfile.h>
+#include <qimage.h>
+#include <qregexp.h>
+
+
+#include "gscreator.h"
+#include "dscparse_adapter.h"
+#include "dscparse.h"
+
+extern "C"
+{
+ KDE_EXPORT ThumbCreator *new_creator()
+ {
+ return new GSCreator;
+ }
+}
+
+// This PS snippet will be prepended to the actual file so that only
+// the first page is output.
+static const char *psprolog =
+ "%!PS-Adobe-3.0\n"
+ "/.showpage.orig /showpage load def\n"
+ "/.showpage.firstonly {\n"
+ " .showpage.orig\n"
+ " quit\n"
+ "} def\n"
+ "/showpage { .showpage.firstonly } def\n";
+
+// This is the code recommended by Adobe tech note 5002 for including
+// EPS files.
+static const char *epsprolog =
+ "%!PS-Adobe-3.0\n"
+ "userdict begin /pagelevel save def /showpage { } def\n"
+ "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit\n"
+ "[ ] 0 setdash newpath false setoverprint false setstrokeadjust\n";
+
+static const char * gsargs_ps[] = {
+ "gs",
+ "-sDEVICE=png16m",
+ "-sOutputFile=-",
+ "-dSAFER",
+ "-dPARANOIDSAFER",
+ "-dNOPAUSE",
+ "-dFirstPage=1",
+ "-dLastPage=1",
+ "-q",
+ "-",
+ 0, // file name
+ "-c",
+ "showpage",
+ "-c",
+ "quit",
+ 0
+};
+
+static const char * gsargs_eps[] = {
+ "gs",
+ "-sDEVICE=png16m",
+ "-sOutputFile=-",
+ "-dSAFER",
+ "-dPARANOIDSAFER",
+ "-dNOPAUSE",
+ 0, // page size
+ 0, // resolution
+ "-q",
+ "-",
+ 0, // file name
+ "-c",
+ "pagelevel",
+ "-c",
+ "restore",
+ "-c",
+ "end",
+ "-c",
+ "showpage",
+ "-c",
+ "quit",
+ 0
+};
+
+static const char *dvipsargs[] = {
+ "dvips",
+ "-n",
+ "1",
+ "-q",
+ "-o",
+ "-",
+ 0, // file name
+ 0
+};
+
+static bool correctDVI(const QString& filename);
+
+
+namespace {
+ bool got_sig_term = false;
+ void handle_sigterm( int ) {
+ got_sig_term = true;
+ }
+}
+
+
+bool GSCreator::create(const QString &path, int width, int height, QImage &img)
+{
+// The code in the loop (when testing whether got_sig_term got set)
+// should read some variation of:
+// parentJob()->wasKilled()
+//
+// Unfortunatelly, that's currently impossible without breaking BIC.
+// So we need to catch the signal ourselves.
+// Otherwise, on certain funny PS files (for example
+// http://www.tjhsst.edu/~Eedanaher/pslife/life.ps )
+// gs would run forever after we were dead.
+// #### Reconsider for KDE 4 ###
+// (24/12/03 - luis_pedro)
+//
+ typedef void ( *sighandler_t )( int );
+ // according to linux's "man signal" the above typedef is a gnu extension
+ sighandler_t oldhandler = signal( SIGTERM, handle_sigterm );
+
+ int input[2];
+ int output[2];
+ int dvipipe[2];
+
+ QByteArray data(1024);
+
+ bool ok = false;
+
+ // Test if file is DVI
+ bool no_dvi =!correctDVI(path);
+
+ if (pipe(input) == -1) {
+ return false;
+ }
+ if (pipe(output) == -1) {
+ close(input[0]);
+ close(input[1]);
+ return false;
+ }
+
+ KDSC dsc;
+ endComments = false;
+ dsc.setCommentHandler(this);
+
+ if (no_dvi)
+ {
+ FILE* fp = fopen(QFile::encodeName(path), "r");
+ if (fp == 0) return false;
+
+ char buf[4096];
+ int count;
+ while ((count = fread(buf, sizeof(char), 4096, fp)) != 0
+ && !endComments) {
+ dsc.scanData(buf, count);
+ }
+ fclose(fp);
+
+ if (dsc.pjl() || dsc.ctrld()) {
+ // this file is a mess.
+ return false;
+ }
+ }
+
+ const bool is_encapsulated = no_dvi &&
+ (path.find(QRegExp("\\.epsi?$", false, false)) > 0) &&
+ (dsc.bbox()->width() > 0) && (dsc.bbox()->height() > 0) &&
+ (dsc.page_count() <= 1);
+
+ char translation[64] = "";
+ char pagesize[32] = "";
+ char resopt[32] = "";
+ std::auto_ptr<KDSCBBOX> bbox = dsc.bbox();
+ if (is_encapsulated) {
+ // GhostScript's rendering at the extremely low resolutions
+ // required for thumbnails leaves something to be desired. To
+ // get nicer images, we render to four times the required
+ // resolution and let QImage scale the result.
+ const int hres = (width * 72) / bbox->width();
+ const int vres = (height * 72) / bbox->height();
+ const int resolution = (hres > vres ? vres : hres) * 4;
+ const int gswidth = ((bbox->urx() - bbox->llx()) * resolution) / 72;
+ const int gsheight = ((bbox->ury() - bbox->lly()) * resolution) / 72;
+
+ snprintf(pagesize, 31, "-g%ix%i", gswidth, gsheight);
+ snprintf(resopt, 31, "-r%i", resolution);
+ snprintf(translation, 63,
+ " 0 %i sub 0 %i sub translate\n", bbox->llx(),
+ bbox->lly());
+ }
+
+ const CDSC_PREVIEW_TYPE previewType =
+ static_cast<CDSC_PREVIEW_TYPE>(dsc.preview());
+
+ switch (previewType) {
+ case CDSC_TIFF:
+ case CDSC_WMF:
+ case CDSC_PICT:
+ // FIXME: these should take precedence, since they can hold
+ // color previews, which EPSI can't (or can it?).
+ break;
+ case CDSC_EPSI:
+ {
+ const int xscale = bbox->width() / width;
+ const int yscale = bbox->height() / height;
+ const int scale = xscale < yscale ? xscale : yscale;
+ if (getEPSIPreview(path,
+ dsc.beginpreview(),
+ dsc.endpreview(),
+ img,
+ bbox->width() / scale,
+ bbox->height() / scale))
+ return true;
+ // If the preview extraction routine fails, gs is used to
+ // create a thumbnail.
+ }
+ break;
+ case CDSC_NOPREVIEW:
+ default:
+ // need to run ghostscript in these cases
+ break;
+ }
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ // Child process (1)
+
+ // close(STDERR_FILENO);
+
+ // find first zero entry in gsargs and put the filename
+ // or - (stdin) there, if DVI
+ const char **gsargs = gsargs_ps;
+ const char **arg = gsargs;
+
+ if (no_dvi && is_encapsulated) {
+ gsargs = gsargs_eps;
+ arg = gsargs;
+
+ // find first zero entry and put page size there
+ while (*arg) ++arg;
+ *arg = pagesize;
+
+ // find second zero entry and put resolution there
+ while (*arg) ++arg;
+ *arg = resopt;
+ }
+
+ // find next zero entry and put the filename there
+ QCString fname = QFile::encodeName( path );
+ while (*arg)
+ ++arg;
+ if( no_dvi )
+ *arg = fname.data();
+ else
+ *arg = "-";
+
+ // find first zero entry in dvipsargs and put the filename there
+ arg = dvipsargs;
+ while (*arg)
+ ++arg;
+ *arg = fname.data();
+
+ if( !no_dvi ){
+ pipe(dvipipe);
+ pid_t pid_two = fork();
+ if( pid_two == 0 ){
+ // Child process (2), reopen stdout on the pipe "dvipipe" and exec dvips
+
+ close(input[0]);
+ close(input[1]);
+ close(output[0]);
+ close(output[1]);
+ close(dvipipe[0]);
+
+ dup2( dvipipe[1], STDOUT_FILENO);
+
+ execvp(dvipsargs[0], const_cast<char *const *>(dvipsargs));
+ exit(1);
+ }
+ else if(pid_two != -1){
+ close(input[1]);
+ close(output[0]);
+ close(dvipipe[1]);
+
+ dup2( dvipipe[0], STDIN_FILENO);
+ dup2( output[1], STDOUT_FILENO);
+
+ execvp(gsargs[0], const_cast<char *const *>(gsargs));
+ exit(1);
+ }
+ else{
+ // fork() (2) failed, close these
+ close(dvipipe[0]);
+ close(dvipipe[1]);
+ }
+
+ }
+ else if( no_dvi ){
+ // Reopen stdin/stdout on the pipes and exec gs
+ close(input[1]);
+ close(output[0]);
+
+ dup2(input[0], STDIN_FILENO);
+ dup2(output[1], STDOUT_FILENO);
+
+ execvp(gsargs[0], const_cast<char *const *>(gsargs));
+ exit(1);
+ }
+ }
+ else if (pid != -1) {
+ // Parent process, write first-page-only-hack (the hack is not
+ // used if DVI) and read the png output
+ close(input[0]);
+ close(output[1]);
+ const char *prolog;
+ if (is_encapsulated)
+ prolog = epsprolog;
+ else
+ prolog = psprolog;
+ int count = write(input[1], prolog, strlen(prolog));
+ if (is_encapsulated)
+ write(input[1], translation, strlen(translation));
+
+ close(input[1]);
+ if (count == static_cast<int>(strlen(prolog))) {
+ int offset = 0;
+ while (!ok) {
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(output[0], &fds);
+ struct timeval tv;
+ tv.tv_sec = 20;
+ tv.tv_usec = 0;
+
+ got_sig_term = false;
+ if (select(output[0] + 1, &fds, 0, 0, &tv) <= 0) {
+ if ( ( errno == EINTR || errno == EAGAIN ) && !got_sig_term ) continue;
+ break; // error, timeout or master wants us to quit (SIGTERM)
+ }
+ if (FD_ISSET(output[0], &fds)) {
+ count = read(output[0], data.data() + offset, 1024);
+ if (count == -1)
+ break;
+ else
+ if (count) // prepare for next block
+ {
+ offset += count;
+ data.resize(offset + 1024);
+ }
+ else // got all data
+ {
+ data.resize(offset);
+ ok = true;
+ }
+ }
+ }
+ }
+ if (!ok) // error or timeout, gs probably didn't exit yet
+ {
+ kill(pid, SIGTERM);
+ }
+
+ int status = 0;
+ if (waitpid(pid, &status, 0) != pid || (status != 0 && status != 256) )
+ ok = false;
+ }
+ else {
+ // fork() (1) failed, close these
+ close(input[0]);
+ close(input[1]);
+ close(output[1]);
+ }
+ close(output[0]);
+
+ int l = img.loadFromData( data );
+
+ if ( got_sig_term &&
+ oldhandler != SIG_ERR &&
+ oldhandler != SIG_DFL &&
+ oldhandler != SIG_IGN ) {
+ oldhandler( SIGTERM ); // propagate the signal. Other things might rely on it
+ }
+ if ( oldhandler != SIG_ERR ) signal( SIGTERM, oldhandler );
+
+ return ok && l;
+}
+
+ThumbCreator::Flags GSCreator::flags() const
+{
+ return static_cast<Flags>(DrawFrame);
+}
+
+void GSCreator::comment(Name name)
+{
+ switch (name) {
+ case EndPreview:
+ case BeginProlog:
+ case Page:
+ endComments = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+// Quick function to check if the filename corresponds to a valid DVI
+// file. Returns true if <filename> is a DVI file, false otherwise.
+
+static bool correctDVI(const QString& filename)
+{
+ QFile f(filename);
+ if (!f.open(IO_ReadOnly))
+ return FALSE;
+
+ unsigned char test[4];
+ if ( f.readBlock( (char *)test,2)<2 || test[0] != 247 || test[1] != 2 )
+ return FALSE;
+
+ int n = f.size();
+ if ( n < 134 ) // Too short for a dvi file
+ return FALSE;
+ f.at( n-4 );
+
+ unsigned char trailer[4] = { 0xdf,0xdf,0xdf,0xdf };
+
+ if ( f.readBlock( (char *)test, 4 )<4 || strncmp( (char *)test, (char*) trailer, 4 ) )
+ return FALSE;
+ // We suppose now that the dvi file is complete and OK
+ return TRUE;
+}
+
+bool GSCreator::getEPSIPreview(const QString &path, long start, long
+ end, QImage &outimg, int imgwidth, int imgheight)
+{
+ FILE *fp;
+ fp = fopen(QFile::encodeName(path), "r");
+ if (fp == 0) return false;
+
+ const long previewsize = end - start + 1;
+
+ char *buf = (char *) malloc(previewsize);
+ fseek(fp, start, SEEK_SET);
+ int count = fread(buf, sizeof(char), previewsize - 1, fp);
+ fclose(fp);
+ buf[previewsize - 1] = 0;
+ if (count != previewsize - 1)
+ {
+ free(buf);
+ return false;
+ }
+
+ QString previewstr = QString::fromLatin1(buf);
+ free(buf);
+
+ int offset = 0;
+ while ((offset < previewsize) && !(previewstr[offset].isDigit())) offset++;
+ int digits = 0;
+ while ((offset + digits < previewsize) && previewstr[offset + digits].isDigit()) digits++;
+ int width = previewstr.mid(offset, digits).toInt();
+ offset += digits + 1;
+ while ((offset < previewsize) && !(previewstr[offset].isDigit())) offset++;
+ digits = 0;
+ while ((offset + digits < previewsize) && previewstr[offset + digits].isDigit()) digits++;
+ int height = previewstr.mid(offset, digits).toInt();
+ offset += digits + 1;
+ while ((offset < previewsize) && !(previewstr[offset].isDigit())) offset++;
+ digits = 0;
+ while ((offset + digits < previewsize) && previewstr[offset + digits].isDigit()) digits++;
+ int depth = previewstr.mid(offset, digits).toInt();
+
+ // skip over the rest of the BeginPreview comment
+ while ((offset < previewsize) &&
+ previewstr[offset] != '\n' &&
+ previewstr[offset] != '\r') offset++;
+ while ((offset < previewsize) && previewstr[offset] != '%') offset++;
+
+ unsigned int imagedepth;
+ switch (depth) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ imagedepth = 8;
+ break;
+ case 12: // valid, but not (yet) supported
+ default: // illegal value
+ return false;
+ }
+
+ unsigned int colors = (1U << depth);
+ QImage img(width, height, imagedepth, colors);
+ img.setAlphaBuffer(false);
+
+ if (imagedepth <= 8) {
+ for (unsigned int gray = 0; gray < colors; gray++) {
+ unsigned int grayvalue = (255U * (colors - 1 - gray)) /
+ (colors - 1);
+ img.setColor(gray, qRgb(grayvalue, grayvalue, grayvalue));
+ }
+ }
+
+ const unsigned int bits_per_scan_line = width * depth;
+ unsigned int bytes_per_scan_line = bits_per_scan_line / 8;
+ if (bits_per_scan_line % 8) bytes_per_scan_line++;
+ const unsigned int bindatabytes = height * bytes_per_scan_line;
+ QMemArray<unsigned char> bindata(bindatabytes);
+
+ for (unsigned int i = 0; i < bindatabytes; i++) {
+ if (offset >= previewsize)
+ return false;
+
+ while (!isxdigit(previewstr[offset].latin1()) &&
+ offset < previewsize)
+ offset++;
+
+ bool ok = false;
+ bindata[i] = static_cast<unsigned char>(previewstr.mid(offset, 2).toUInt(&ok, 16));
+ if (!ok)
+ return false;
+
+ offset += 2;
+ }
+
+ for (int scanline = 0; scanline < height; scanline++) {
+ unsigned char *scanlineptr = img.scanLine(scanline);
+
+ for (int pixelindex = 0; pixelindex < width; pixelindex++) {
+ unsigned char pixelvalue = 0;
+ const unsigned int bitoffset =
+ scanline * bytes_per_scan_line * 8U + pixelindex * depth;
+ for (int depthindex = 0; depthindex < depth;
+ depthindex++) {
+ const unsigned int byteindex = (bitoffset + depthindex) / 8U;
+ const unsigned int bitindex =
+ 7 - ((bitoffset + depthindex) % 8U);
+ const unsigned char bitvalue =
+ (bindata[byteindex] & static_cast<unsigned char>(1U << bitindex)) >> bitindex;
+ pixelvalue |= (bitvalue << depthindex);
+ }
+ scanlineptr[pixelindex] = pixelvalue;
+ }
+ }
+
+ outimg = img.convertDepth(32).smoothScale(imgwidth, imgheight);
+
+ return true;
+}
diff --git a/kfile-plugins/ps/gscreator.h b/kfile-plugins/ps/gscreator.h
new file mode 100644
index 00000000..b91fb0b0
--- /dev/null
+++ b/kfile-plugins/ps/gscreator.h
@@ -0,0 +1,42 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _GSCREATOR_H_
+#define _GSCREATOR_H_
+
+#include <kio/thumbcreator.h>
+#include "dscparse_adapter.h"
+
+class GSCreator : public ThumbCreator, public KDSCCommentHandler
+{
+public:
+ GSCreator() {};
+ virtual bool create(const QString &path, int, int, QImage &img);
+ virtual Flags flags() const;
+ void comment(Name name);
+
+private:
+ static bool getEPSIPreview(const QString &path,
+ long start, long end,
+ QImage &outimg,
+ int imgwidth, int imgheight);
+ bool endComments;
+};
+
+#endif
diff --git a/kfile-plugins/ps/gsthumbnail.desktop b/kfile-plugins/ps/gsthumbnail.desktop
new file mode 100644
index 00000000..0211020e
--- /dev/null
+++ b/kfile-plugins/ps/gsthumbnail.desktop
@@ -0,0 +1,60 @@
+[Desktop Entry]
+Type=Service
+Name=PostScript, PDF and DVI Files
+Name[ar]=ملفات الــ PostScript ، PDF و DVI
+Name[br]=Restroù PostScript, PDF ha DVI
+Name[bs]=Postscript, PDF i DVI datoteke
+Name[ca]=Fitxers PostScript, PDF i DVI
+Name[cs]=Postscriptové, PDF a DVI soubory
+Name[cy]=Ffeiliau PostScript, PDF a DVI
+Name[da]=PostScript, PDF- og DVI-filer
+Name[de]=PostScript-, PDF- und DVI-Dateien
+Name[el]=Αρχεία PostScript, PDF και DVI
+Name[eo]=Postskriptaj, PDF- kaj DVI-dosieroj
+Name[es]=Archivos PostScript, PDF y DVI
+Name[et]=PostScript-, PDF- ja DVI-failid
+Name[eu]=PostScript, PDF eta DVI fitxategiak
+Name[fa]=پرونده‌های PostScript، PDF و DVI
+Name[fi]=PostScript-, PDF- ja DVI-tiedostot
+Name[fr]=Fichiers PostScript, PDF et DVI
+Name[ga]=Comhaid PostScript, PDF agus DVI
+Name[gl]=Ficheiros PostScript, PDF e DVI
+Name[he]=קבצי PostScript, PDF ו־DVI
+Name[hu]=PostScript-, PDF- és DVI-fájlok
+Name[is]=PostScript PDF og DVI skrár
+Name[it]=File PostScript, PDF e DVI
+Name[ja]=Postscript,PDF,DVIファイル
+Name[kk]=PostScript, PDF және DVI файлдары
+Name[km]=ឯកសារ PostScript, PDF និង DVI
+Name[lt]=Postscript, PDF ir DVI bylos
+Name[ms]=PostScript, PDF dan Fail DVI
+Name[nb]=PostScript, PDF og DVI filer
+Name[nds]=PostScript-, PDF- un DVI-Dateien
+Name[ne]=पोष्टस्क्रिप्ट, PDF र DVI फाइल
+Name[nl]=PostScript-, DVI- en PDF-bestanden
+Name[nn]=PostScript-, PDF- og DVI-filer
+Name[pl]=Pliki PostScript, PDF i DVI
+Name[pt]=Ficheiros PostScript, PDF e DVI
+Name[pt_BR]=Arquivos PostScript, PDF e DVI
+Name[ro]=Fişiere PostScript, PDF şi DVI
+Name[ru]=Файлы PostScript, PDF и DVI
+Name[se]=PostScript-, PDF- ja DVI-fiillat
+Name[sk]=PostScript, PDF a DVI súbory
+Name[sl]=Datoteke PostScript, PDF in DVI
+Name[sr]=PostScript, PDF и DVI фајлови
+Name[sr@Latn]=PostScript, PDF i DVI fajlovi
+Name[sv]=Postscript, PDF och DVI-filer
+Name[ta]= போஸ்ட்கிரிப்ட், பிடிஃப் மற்றும் டிவிஐ கோப்புகள்
+Name[tg]=Файлҳои PostScript, PDF ва DVI
+Name[th]=แฟ้ม PDF, DVI และ โพสต์สคริปต์
+Name[tr]=PostScript, PDF ve DVI Dosyaları
+Name[uk]=Файли PostScript, PDF та DVI
+Name[uz]=PostScript, PDF va DVI fayllari
+Name[uz@cyrillic]=PostScript, PDF ва DVI файллари
+Name[zh_CN]=PostScript、PDF 和 DVI 文件
+Name[zh_HK]=PostScript 、PDF 及 DVI 檔案
+Name[zh_TW]=PostScript,PDF 與 DVI 檔
+ServiceTypes=ThumbCreator
+MimeTypes=application/x-dvi,application/postscript,application/pdf,image/x-eps
+X-KDE-Library=gsthumbnail
+CacheThumbnail=true
diff --git a/kfile-plugins/ps/kfile_ps.cpp b/kfile-plugins/ps/kfile_ps.cpp
new file mode 100644
index 00000000..6d3caa31
--- /dev/null
+++ b/kfile-plugins/ps/kfile_ps.cpp
@@ -0,0 +1,124 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Wilco Greven <greven@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#include "kfile_ps.h"
+
+#include <qfile.h>
+
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+typedef KGenericFactory<KPSPlugin> PSFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_ps, PSFactory("kfile_ps"))
+
+KPSPlugin::KPSPlugin(QObject *parent, const char *name,
+ const QStringList &preferredItems) :
+ KFilePlugin( parent, name, preferredItems )
+{
+ kdDebug(7034) << "ps plugin\n";
+
+ // set up our mimetypes
+ makeMimeTypeInfo( "application/postscript" );
+ makeMimeTypeInfo( "image/x-eps" );
+}
+
+void KPSPlugin::makeMimeTypeInfo( const char* mimeType )
+{
+ KFileMimeTypeInfo* info = addMimeTypeInfo( mimeType );
+
+ // general group
+ KFileMimeTypeInfo::GroupInfo* group = addGroupInfo(info, "General", i18n("General"));
+ addItemInfo(group, "Title", i18n("Title"), QVariant::String);
+ addItemInfo(group, "Creator", i18n("Creator"), QVariant::String);
+ addItemInfo(group, "CreationDate", i18n("Creation Date"), QVariant::String);
+ addItemInfo(group, "For", i18n("For"), QVariant::String);
+ addItemInfo(group, "Pages", i18n("Pages"), QVariant::UInt);
+}
+
+bool KPSPlugin::readInfo( KFileMetaInfo& info, uint /* what */)
+{
+ _info = info;
+ _group = appendGroup(info, "General");
+ _endComments = false;
+ _setData = 0;
+
+ _dsc = new KDSC;
+ _dsc->setCommentHandler( this );
+ FILE* fp = fopen( QFile::encodeName( info.path() ), "r" );
+ if( fp == 0 )
+ return false;
+
+ char buf[4096];
+ int count;
+ while( ( count = fread( buf, sizeof(char), sizeof( buf ), fp ) ) ) {
+ if ( !_dsc->scanData( buf, count ) ) break;
+ if ( _endComments || _setData == 5 ) break; // Change if new item scanned
+ }
+ fclose( fp );
+ delete _dsc;
+ _dsc = 0;
+
+ return _setData > 0;
+}
+
+void KPSPlugin::comment( Name name )
+{
+ switch( name )
+ {
+ case Title:
+ appendItem(_group, "Title", _dsc->dsc_title());
+ ++_setData;
+ break;
+ case Creator:
+ appendItem(_group, "Creator", _dsc->dsc_creator());
+ ++_setData;
+ break;
+ case CreationDate:
+ appendItem(_group, "CreationDate", _dsc->dsc_date());
+ ++_setData;
+ break;
+ case For:
+ appendItem(_group, "For", _dsc->dsc_for());
+ ++_setData;
+ break;
+ case Pages: {
+ int pages = _dsc->page_pages();
+ if (pages)
+ {
+ appendItem(_group, "Pages", pages);
+ ++_setData;
+ }
+ }
+ break;
+
+ // Right now we watch for 5 elements:
+ // Title, Creator, CreationDate, For, Pages
+ //
+ // If you add another one(s), please update the 5 in "_setData == 5" above
+ //
+ case EndComments: _endComments = true;
+ default: ; // Ignore
+ }
+}
+
+#include "kfile_ps.moc"
+
diff --git a/kfile-plugins/ps/kfile_ps.desktop b/kfile-plugins/ps/kfile_ps.desktop
new file mode 100644
index 00000000..75b3e055
--- /dev/null
+++ b/kfile-plugins/ps/kfile_ps.desktop
@@ -0,0 +1,66 @@
+[Desktop Entry]
+Type=Service
+Name=PostScript Info
+Name[af]=Postscript Inligting
+Name[ar]=معلومات PostScript
+Name[br]=Procinfo PostScript
+Name[ca]=Informació de PostScript
+Name[cs]=PostScript info
+Name[cy]=Gwybodaeth PostScript
+Name[da]=PostScript-info
+Name[de]=PostScript-Info
+Name[el]=Πληροφορίες PostScript
+Name[eo]=Postskriptinformo
+Name[es]=Info PostScript
+Name[et]=PostScript info
+Name[fa]=اطلاعات PostScript
+Name[fi]=PostScript-tiedot
+Name[fr]=Informations PostScript
+Name[gl]=Inf. PostScript
+Name[he]=מידע PostScript
+Name[hi]=पोस्टस्क्रिप्ट जानकारी
+Name[hr]=Postscript informacije
+Name[hu]=PostScript-jellemzők
+Name[is]=PostScript upplýsingar
+Name[it]=Informazioni PostScript
+Name[ja]=PostScript 情報
+Name[kk]=PostScript мәліметі
+Name[km]=ព័ត៌មាន PostScript
+Name[lt]=PostScript informacija
+Name[lv]=Postscript Info
+Name[ms]=Maklumat PostScript
+Name[nb]=PostScript-info
+Name[nds]=PostScript-Info
+Name[ne]=पोष्टस्क्रिप्ट सूचना
+Name[nl]=PostScript-info
+Name[nn]=PostScript-info
+Name[nso]=Tshedimoso ya PostScript
+Name[pa]=PostScript ਜਾਣਕਾਰੀ
+Name[pl]=Informacja o pliku PostScriptu
+Name[pt]=Informação do PostScript
+Name[pt_BR]=Informação sobre PostScript
+Name[ro]=Informaţii PostScript
+Name[ru]=Информация о PostScript
+Name[se]=PostScript-dieđut
+Name[sl]=Podatki o PostScriptu
+Name[sr]=PostScript информације
+Name[sr@Latn]=PostScript informacije
+Name[sv]=Postscript-information
+Name[ta]=முன் எழுத்தாக்க தகவல்
+Name[tg]=Иттилоот оиди PostScript
+Name[th]=ข้อมูลโพสต์สคริปต์
+Name[tr]=PostScript Bilgisi
+Name[uk]=Інформація про PostScript
+Name[uz]=PostScript haqida maʼlumot
+Name[uz@cyrillic]=PostScript ҳақида маълумот
+Name[ven]=Mafhungo a mabammbiri a poso
+Name[wa]=Informåcion sol documint PostScript
+Name[xh]=Ulwazi Lwe PostScript
+Name[zh_CN]=PostScript 信息
+Name[zh_HK]=PostScript 資訊
+Name[zh_TW]=PostScript 資訊
+Name[zu]=Ulwazi Lwesi-PostScript
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_ps
+MimeType=application/postscript;image/x-eps
+PreferredItems=Title,Creator,CreationDate,For,Pages
diff --git a/kfile-plugins/ps/kfile_ps.h b/kfile-plugins/ps/kfile_ps.h
new file mode 100644
index 00000000..339020d1
--- /dev/null
+++ b/kfile-plugins/ps/kfile_ps.h
@@ -0,0 +1,50 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Wilco Greven <greven@kde.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#ifndef __KFILE_PS_H__
+#define __KFILE_PS_H__
+
+#include <kfilemetainfo.h>
+
+#include "dscparse_adapter.h"
+
+class QStringList;
+
+class KPSPlugin: public KFilePlugin, public KDSCCommentHandler
+{
+ Q_OBJECT
+public:
+ KPSPlugin( QObject *parent, const char *name,
+ const QStringList& preferredItems );
+
+ virtual bool readInfo( KFileMetaInfo& info, uint what);
+
+ void comment( Name );
+ void makeMimeTypeInfo( const char* mimeType );
+
+private:
+ KFileMetaInfo _info;
+ KFileMetaInfoGroup _group;
+ KDSC* _dsc;
+ bool _endComments;
+ int _setData;
+};
+
+#endif