OSDN Git Service

imported svgpart and thumbnailers
authorIvailo Monev <xakepa10@gmail.com>
Thu, 27 Nov 2014 14:05:13 +0000 (14:05 +0000)
committerIvailo Monev <xakepa10@gmail.com>
Thu, 27 Nov 2014 14:05:13 +0000 (14:05 +0000)
24 files changed:
CMakeLists.txt
svgpart/CMakeLists.txt [new file with mode: 0644]
svgpart/COPYING [new file with mode: 0644]
svgpart/Messages.sh [new file with mode: 0755]
svgpart/svgpart.cpp [new file with mode: 0644]
svgpart/svgpart.desktop [new file with mode: 0644]
svgpart/svgpart.h [new file with mode: 0644]
svgpart/svgpart.rc [new file with mode: 0644]
thumbnailers/CMakeLists.txt [new file with mode: 0644]
thumbnailers/COPYING [new file with mode: 0644]
thumbnailers/COPYING.LIB [new file with mode: 0644]
thumbnailers/ps/CMakeLists.txt [new file with mode: 0644]
thumbnailers/ps/Messages.sh [new file with mode: 0644]
thumbnailers/ps/dscparse.cpp [new file with mode: 0644]
thumbnailers/ps/dscparse.h [new file with mode: 0644]
thumbnailers/ps/dscparse_adapter.cpp [new file with mode: 0644]
thumbnailers/ps/dscparse_adapter.h [new file with mode: 0644]
thumbnailers/ps/gscreator.cpp [new file with mode: 0644]
thumbnailers/ps/gscreator.h [new file with mode: 0644]
thumbnailers/ps/gsthumbnail.desktop [new file with mode: 0644]
thumbnailers/raw/CMakeLists.txt [new file with mode: 0644]
thumbnailers/raw/rawcreator.cpp [new file with mode: 0644]
thumbnailers/raw/rawcreator.h [new file with mode: 0644]
thumbnailers/raw/rawthumbnail.desktop [new file with mode: 0644]

index d1c9512..56ca299 100644 (file)
@@ -42,3 +42,5 @@ macro_optional_add_subdirectory (kuser)
 macro_optional_add_subdirectory (okular)
 macro_optional_add_subdirectory (partitionmanager)
 macro_optional_add_subdirectory (print-manager)
+macro_optional_add_subdirectory (svgpart)
+macro_optional_add_subdirectory (thumbnailers)
diff --git a/svgpart/CMakeLists.txt b/svgpart/CMakeLists.txt
new file mode 100644 (file)
index 0000000..8e9dcc2
--- /dev/null
@@ -0,0 +1,20 @@
+project(svgpart)
+
+find_package(KDE4 REQUIRED)
+include(KDE4Defaults)
+include(MacroLibrary)
+
+add_definitions(${QT_DEFINITIONS} ${QT_QTDBUS_DEFINITIONS} ${KDE4_DEFINITIONS})
+include_directories(${QDBUS_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${KDE4_INCLUDES})
+
+set(svgpart_SRCS
+       svgpart.cpp
+       )
+
+kde4_add_plugin(svgpart ${svgpart_SRCS})
+
+target_link_libraries(svgpart ${KDE4_KPARTS_LIBS})
+
+install(TARGETS svgpart DESTINATION ${PLUGIN_INSTALL_DIR})
+install(FILES svgpart.desktop DESTINATION ${SERVICES_INSTALL_DIR})
+install(FILES svgpart.rc DESTINATION ${DATA_INSTALL_DIR}/svgpart)
diff --git a/svgpart/COPYING b/svgpart/COPYING
new file mode 100644 (file)
index 0000000..d511905
--- /dev/null
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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; either version 2 of the License, or
+    (at your option) any later version.
+
+    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; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/svgpart/Messages.sh b/svgpart/Messages.sh
new file mode 100755 (executable)
index 0000000..afee094
--- /dev/null
@@ -0,0 +1,3 @@
+#! /bin/sh
+$EXTRACTRC *.rc >> rc.cpp
+$XGETTEXT *.cpp -o $podir/svgpart.pot
diff --git a/svgpart/svgpart.cpp b/svgpart/svgpart.cpp
new file mode 100644 (file)
index 0000000..0edbec3
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+Copyright 2007 Aurélien Gâteau
+
+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; either version 2
+of the License, or (at your option) any later version.
+
+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; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+*/
+#include "svgpart.moc"
+
+// Qt
+#include <QGraphicsScene>
+#include <QGraphicsSvgItem>
+#include <QGraphicsView>
+#include <QSvgRenderer>
+
+// KDE
+#include <kaboutdata.h>
+#include <kactioncollection.h>
+#include <kgenericfactory.h>
+#include <kstandardaction.h>
+
+// Local
+
+static KAboutData createAboutData()
+{
+       KAboutData aboutData( "svgpart", 0, ki18n("SVG Part"),
+               "1.0", ki18n("A KPart to display SVG images"),
+               KAboutData::License_GPL,
+               ki18n("Copyright 2007, Aurélien Gâteau <aurelien.gateau@free.fr>"));
+       return aboutData;
+}
+
+//Factory Code
+K_PLUGIN_FACTORY( SvgPartFactory, registerPlugin< SvgPart >(); )
+K_EXPORT_PLUGIN( SvgPartFactory( createAboutData() ) )
+
+
+SvgPart::SvgPart(QWidget* parentWidget, QObject* parent, const QVariantList&)
+: KParts::ReadOnlyPart(parent)
+{
+       mRenderer = new QSvgRenderer(this);
+       mScene = new QGraphicsScene(this);
+       mView = new QGraphicsView(mScene, parentWidget);
+       mView->setFrameStyle(QFrame::NoFrame);
+       mView->setDragMode(QGraphicsView::ScrollHandDrag);
+       mItem = 0;
+       setWidget(mView);
+
+       KStandardAction::actualSize(this, SLOT(zoomActualSize()), actionCollection());
+       KStandardAction::zoomIn(this, SLOT(zoomIn()), actionCollection());
+       KStandardAction::zoomOut(this, SLOT(zoomOut()), actionCollection());
+       setXMLFile("svgpart/svgpart.rc");
+}
+
+
+bool SvgPart::openFile() {
+       if (!mRenderer->load(localFilePath())) {
+               return false;
+       }
+       mItem = new QGraphicsSvgItem();
+       mItem->setSharedRenderer(mRenderer);
+       mScene->addItem(mItem);
+       return true;
+}
+
+
+bool SvgPart::closeUrl() {
+       delete mItem;
+       mItem = 0;
+       return KParts::ReadOnlyPart::closeUrl();
+}
+
+
+void SvgPart::zoomIn() {
+       setZoom(zoom() * 2);
+}
+
+
+void SvgPart::zoomOut() {
+       setZoom(zoom() / 2);
+}
+
+
+void SvgPart::zoomActualSize() {
+       setZoom(1.0);
+}
+
+
+qreal SvgPart::zoom() const {
+       return mView->matrix().m11();
+}
+
+
+void SvgPart::setZoom(qreal value) {
+       QMatrix matrix;
+       matrix.scale(value, value);
+       mView->setMatrix(matrix);
+}
diff --git a/svgpart/svgpart.desktop b/svgpart/svgpart.desktop
new file mode 100644 (file)
index 0000000..249387c
--- /dev/null
@@ -0,0 +1,67 @@
+[Desktop Entry]
+Type=Service
+Name=Svg Part
+Name[ar]=جزء Svg
+Name[ast]=Parte SVG
+Name[bg]=Модул за Svg
+Name[bs]=SVG dio
+Name[ca]=Svg Part
+Name[ca@valencia]=Svg Part
+Name[cs]=SVG komponenta
+Name[da]=Svg Part
+Name[de]=SVG-Komponente
+Name[el]=Τμήμα Svg
+Name[en_GB]=Svg Part
+Name[eo]=Svg komponanto
+Name[es]=Parte SVG
+Name[et]=Svg komponent
+Name[eu]=SVGren zatia
+Name[fi]=SVG-osa
+Name[fr]=Composant SVG
+Name[ga]=Comhpháirt Svg
+Name[gl]=Compoñente de SVG
+Name[hne]=एसवीजी पार्ट
+Name[hr]=Svg Part
+Name[hu]=SVG objektum
+Name[ia]=Parte de SVG
+Name[is]=Svg hlutur
+Name[it]=Componente SVG
+Name[ja]=SVG コンポーネント
+Name[kk]=Svg компоненті
+Name[km]=ផ្នែក Svg
+Name[ko]=Svg 부분
+Name[ku]=Beşa Svg
+Name[lt]=Svg Part
+Name[lv]=Svg daļa
+Name[mr]=Svg भाग
+Name[nb]=Svg-del
+Name[nds]=SVG-Komponent
+Name[nl]=SVG-component
+Name[nn]=SVG-del
+Name[pa]=Svg ਭਾਗ
+Name[pl]=Moduł SVG
+Name[pt]=Componente de SVG
+Name[pt_BR]=Componente SVG
+Name[ro]=Componentă SVG
+Name[ru]=Компонент просмотра Svg
+Name[si]=Svg Part
+Name[sk]=Svg komponent
+Name[sl]=Sestavni del SVG
+Name[sr]=СВГ део
+Name[sr@ijekavian]=СВГ део
+Name[sr@ijekavianlatin]=SVG deo
+Name[sr@latin]=SVG deo
+Name[sv]=SVG-delprogram
+Name[th]=ส่วนจัดการ Svg
+Name[tr]=Svg Parçacığı
+Name[ug]=Svg Part
+Name[uk]=Компонент Svg
+Name[vi]=Phần nhúng đọc SVG
+Name[x-test]=xxSvg Partxx
+Name[zh_CN]=Svg 组件
+Name[zh_TW]=Svg 部件
+MimeType=image/svg+xml;image/svg+xml-compressed;
+ServiceTypes=KParts/ReadOnlyPart
+X-KDE-Library=svgpart
+InitialPreference=12
+Icon=image-svg+xml
diff --git a/svgpart/svgpart.h b/svgpart/svgpart.h
new file mode 100644 (file)
index 0000000..cb2a1e2
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+Copyright 2007 Aurélien Gâteau
+
+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; either version 2
+of the License, or (at your option) any later version.
+
+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; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+*/
+#ifndef SVGPART_H
+#define SVGPART_H
+
+// KDE
+#include <kparts/part.h>
+
+
+class QGraphicsScene;
+class QGraphicsSvgItem;
+class QGraphicsView;
+class QSvgRenderer;
+
+class SvgPart : public KParts::ReadOnlyPart {
+       Q_OBJECT
+public:
+       SvgPart(QWidget* parentWidget, QObject* parent, const QVariantList&);
+
+       virtual bool closeUrl();
+
+protected:
+       virtual bool openFile();
+
+private Q_SLOTS:
+       void zoomActualSize();
+       void zoomIn();
+       void zoomOut();
+
+private:
+       QGraphicsScene* mScene;
+       QGraphicsView* mView;
+       QGraphicsSvgItem* mItem;
+       QSvgRenderer* mRenderer;
+
+       qreal zoom() const;
+       void setZoom(qreal);
+};
+
+#endif /* SVGPART_H */
diff --git a/svgpart/svgpart.rc b/svgpart/svgpart.rc
new file mode 100644 (file)
index 0000000..bd858c4
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="SvgPart" version="2">
+<MenuBar>
+       <Menu name="view"><text>&amp;View</text>
+               <Action name="view_actual_size"/>
+<!--
+               <Action name="view_zoom_to_fit"/>
+-->
+               <Action name="view_zoom_in"/>
+               <Action name="view_zoom_out"/>
+       </Menu>
+</MenuBar>
+<ToolBar name="mainToolBar"><text>Main Toolbar</text>
+       <Action name="view_actual_size"/>
+<!--
+       <Action name="view_zoom_to_fit"/>
+-->
+       <Action name="view_zoom_in"/>
+       <Action name="view_zoom_out"/>
+</ToolBar>
+</kpartgui>
+
diff --git a/thumbnailers/CMakeLists.txt b/thumbnailers/CMakeLists.txt
new file mode 100644 (file)
index 0000000..47bd2fb
--- /dev/null
@@ -0,0 +1,23 @@
+project(kdegraphics-thumbnailers)
+
+find_package(KDE4 REQUIRED)
+include(KDE4Defaults)
+include(MacroLibrary)
+include(MacroOptionalAddSubdirectory)
+
+add_definitions(${QT_DEFINITIONS} ${KDE4_DEFINITIONS} -DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS)
+include_directories(${KDE4_INCLUDES})
+
+macro_optional_find_package(Kexiv2)
+macro_optional_find_package(Kdcraw)
+
+macro_log_feature(KEXIV2_FOUND "libkexiv2" "A library for reading and writing image metadata" "www.kde.org" FALSE "" "Required to build the RAW thumbnailer")
+macro_log_feature(KDCRAW_FOUND "libkdcraw" "A library for accessing raw files" "www.kde.org" FALSE "" "Required to build the RAW thumbnailer")
+
+macro_optional_add_subdirectory(ps)
+
+if(KEXIV2_FOUND AND KDCRAW_FOUND)
+macro_optional_add_subdirectory(raw)
+endif()
+
+macro_display_feature_log()
diff --git a/thumbnailers/COPYING b/thumbnailers/COPYING
new file mode 100644 (file)
index 0000000..d511905
--- /dev/null
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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; either version 2 of the License, or
+    (at your option) any later version.
+
+    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; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/thumbnailers/COPYING.LIB b/thumbnailers/COPYING.LIB
new file mode 100644 (file)
index 0000000..2676d08
--- /dev/null
@@ -0,0 +1,481 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+                   51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/thumbnailers/ps/CMakeLists.txt b/thumbnailers/ps/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b6643a3
--- /dev/null
@@ -0,0 +1,17 @@
+########### next target ###############
+
+set(gsthumbnail_PART_SRCS gscreator.cpp dscparse.cpp dscparse_adapter.cpp)
+
+
+kde4_add_plugin(gsthumbnail ${gsthumbnail_PART_SRCS})
+
+
+target_link_libraries(gsthumbnail  ${KDE4_KDECORE_LIBS} ${KDE4_KIO_LIBS} ${QT_QTGUI_LIBRARY} )
+
+install(TARGETS gsthumbnail  DESTINATION ${PLUGIN_INSTALL_DIR} )
+
+
+########### install files ###############
+
+install( FILES gsthumbnail.desktop  DESTINATION  ${SERVICES_INSTALL_DIR} )
+
diff --git a/thumbnailers/ps/Messages.sh b/thumbnailers/ps/Messages.sh
new file mode 100644 (file)
index 0000000..1eaefe0
--- /dev/null
@@ -0,0 +1,2 @@
+#! /bin/sh
+$XGETTEXT *.cpp -o $podir/kfile_ps.pot
diff --git a/thumbnailers/ps/dscparse.cpp b/thumbnailers/ps/dscparse.cpp
new file mode 100644 (file)
index 0000000..c1f68bd
--- /dev/null
@@ -0,0 +1,3429 @@
+/* Copyright (C) 2000-2001, Ghostgum Software Pty Ltd.  All rights reserved.
+    
+  This file is part of GSview.
+   
+  This file is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
+  to anyone for the consequences of using it or for whether it serves any
+  particular purpose or works at all, unless he says so in writing.  Refer
+  to the GNU General Public License for full details.
+   
+  Everyone is granted permission to copy, modify and redistribute this
+  file, but only under the conditions described in the GNU General
+  Public License.  A copy of this license is supposed to have been given
+  to you along with this file so you can know your rights and
+  responsibilities.  It should be in a file named COPYING.  Among other
+  things, the copyright notice and this notice must be preserved on all
+  copies.
+*/
+
+/* $Id$ */
+
+/* dscparse.c - DSC parser  */
+
+/*
+ * This is a DSC parser, based on the DSC 3.0 spec, 
+ * with a few DSC 2.1 additions for page size.
+ *
+ * Current limitations:
+ * %%+ may be used after any comment in the comment or trailer, 
+ * but is currently only supported by
+ *   %%DocumentMedia
+ *
+ * DSC 2.1 additions (discontinued in DSC 3.0):
+ * %%DocumentPaperColors: 
+ * %%DocumentPaperForms: 
+ * %%DocumentPaperSizes: 
+ * %%DocumentPaperWeights: 
+ * %%PaperColor:   (ignored)
+ * %%PaperForm:    (ignored)
+ * %%PaperSize: 
+ * %%PaperWeight:  (ignored)
+ *
+ * Other additions for defaults or page section
+ % %%ViewingOrientation: xx xy yx yy
+*/
+
+#include <stdio.h>     /* for sprintf(), not file I/O */
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define MAXSTR 256
+
+#include "dscparse.h"
+
+/* Macros for comparing string literals
+ * For maximum speed, the length of the second macro argument is
+ * computed at compile time.
+ * THE SECOND MACRO ARGUMENT MUST BE A STRING LITERAL.
+ */
+#define COMPARE(p,str) (strncmp((const char *)(p), (str), sizeof(str)-1)==0)
+#define IS_DSC(line, str) (COMPARE((line), (str)))
+
+/* Macros for comparing the first one or two characters */
+#define IS_WHITE(ch) (((ch)==' ') || ((ch)=='\t'))
+#define IS_EOL(ch) (((ch)=='\r') || ((ch)=='\n'))
+#define IS_WHITE_OR_EOL(ch) (IS_WHITE(ch) || IS_EOL(ch))
+#define IS_BLANK(str) (IS_EOL(str[0]))
+#define NOT_DSC_LINE(str) (((str)[0]!='%') || ((str)[1]!='%'))
+
+/* Macros for document offset to start and end of line */
+#define DSC_START(dsc)  ((dsc)->data_offset + (dsc)->data_index - (dsc)->line_length)
+#define DSC_END(dsc)  ((dsc)->data_offset + (dsc)->data_index)
+
+/* dsc_scan_SECTION() functions return one of 
+ * CDSC_ERROR, CDSC_OK, CDSC_NOTDSC 
+ * or one of the following
+ */
+/* The line should be passed on to the next section parser. */
+#define CDSC_PROPAGATE 10
+
+/* If document is DOS EPS and we haven't read 30 bytes, ask for more. */
+#define CDSC_NEEDMORE 11
+
+/* local prototypes */
+dsc_private void * dsc_memalloc(P2(CDSC *dsc, size_t size));
+dsc_private void dsc_memfree(P2(CDSC*dsc, void *ptr));
+dsc_private CDSC * dsc_init2(P1(CDSC *dsc));
+dsc_private void dsc_reset(P1(CDSC *dsc));
+dsc_private void dsc_section_join(P3(unsigned long begin, unsigned long *pend, unsigned long **pplast));
+dsc_private int dsc_read_line(P1(CDSC *dsc));
+dsc_private int dsc_read_doseps(P1(CDSC *dsc));
+dsc_private char * dsc_alloc_string(P3(CDSC *dsc, const char *str, int len));
+dsc_private char * dsc_add_line(P3(CDSC *dsc, const char *line, unsigned int len));
+dsc_private char * dsc_copy_string(P5(char *str, unsigned int slen, 
+    char *line, unsigned int len, unsigned int *offset));
+dsc_private GSDWORD dsc_get_dword(P1(const unsigned char *buf));
+dsc_private GSWORD dsc_get_word(P1(const unsigned char *buf));
+dsc_private int dsc_get_int(P3(const char *line, unsigned int len, unsigned int *offset));
+dsc_private float dsc_get_real(P3(const char *line, unsigned int len, 
+    unsigned int *offset));
+dsc_private int dsc_stricmp(P2(const char *s, const char *t));
+dsc_private void dsc_unknown(P1(CDSC *dsc)); 
+dsc_private GSBOOL dsc_is_section(char *line);
+dsc_private int dsc_parse_pages(P1(CDSC *dsc));
+dsc_private int dsc_parse_bounding_box(P3(CDSC *dsc, CDSCBBOX** pbbox, int offset));
+dsc_private int dsc_parse_float_bounding_box(P3(CDSC *dsc, CDSCFBBOX** pfbbox, int offset));
+dsc_private int dsc_parse_orientation(P3(CDSC *dsc, unsigned int *porientation, 
+    int offset));
+dsc_private int dsc_parse_order(P1(CDSC *dsc));
+dsc_private int dsc_parse_media(P2(CDSC *dsc, const CDSCMEDIA **page_media));
+dsc_private int dsc_parse_document_media(P1(CDSC *dsc));
+dsc_private int dsc_parse_viewing_orientation(P2(CDSC *dsc, CDSCCTM **pctm));
+dsc_private int dsc_parse_page(P1(CDSC *dsc));
+dsc_private void dsc_save_line(P1(CDSC *dsc));
+dsc_private int dsc_scan_type(P1(CDSC *dsc));
+dsc_private int dsc_scan_comments(P1(CDSC *dsc));
+dsc_private int dsc_scan_preview(P1(CDSC *dsc));
+dsc_private int dsc_scan_defaults(P1(CDSC *dsc));
+dsc_private int dsc_scan_prolog(P1(CDSC *dsc));
+dsc_private int dsc_scan_setup(P1(CDSC *dsc));
+dsc_private int dsc_scan_page(P1(CDSC *dsc));
+dsc_private int dsc_scan_trailer(P1(CDSC *dsc));
+dsc_private int dsc_error(P4(CDSC *dsc, unsigned int explanation, 
+    char *line, unsigned int line_len));
+
+/* DSC error reporting */
+dsc_private const int dsc_severity[] = {
+    CDSC_ERROR_WARN,   /* CDSC_MESSAGE_BBOX */
+    CDSC_ERROR_WARN,   /* CDSC_MESSAGE_EARLY_TRAILER */
+    CDSC_ERROR_WARN,   /* CDSC_MESSAGE_EARLY_EOF */
+    CDSC_ERROR_ERROR,  /* CDSC_MESSAGE_PAGE_IN_TRAILER */
+    CDSC_ERROR_ERROR,  /* CDSC_MESSAGE_PAGE_ORDINAL */
+    CDSC_ERROR_ERROR,  /* CDSC_MESSAGE_PAGES_WRONG */
+    CDSC_ERROR_ERROR,  /* CDSC_MESSAGE_EPS_NO_BBOX */
+    CDSC_ERROR_ERROR,  /* CDSC_MESSAGE_EPS_PAGES */
+    CDSC_ERROR_WARN,   /* CDSC_MESSAGE_NO_MEDIA */
+    CDSC_ERROR_WARN,   /* CDSC_MESSAGE_ATEND */
+    CDSC_ERROR_INFORM,         /* CDSC_MESSAGE_DUP_COMMENT */
+    CDSC_ERROR_INFORM,         /* CDSC_MESSAGE_DUP_TRAILER */
+    CDSC_ERROR_WARN,   /* CDSC_MESSAGE_BEGIN_END */
+    CDSC_ERROR_INFORM,         /* CDSC_MESSAGE_BAD_SECTION */
+    CDSC_ERROR_INFORM,  /* CDSC_MESSAGE_LONG_LINE */
+    CDSC_ERROR_WARN,   /* CDSC_MESSAGE_INCORRECT_USAGE */
+    0
+};
+
+#define DSC_MAX_ERROR ((sizeof(dsc_severity) / sizeof(int))-2)
+
+const CDSCMEDIA dsc_known_media[CDSC_KNOWN_MEDIA] = {
+    /* These sizes taken from Ghostscript gs_statd.ps */
+    {"11x17", 792, 1224, 0, NULL, NULL, NULL},
+    {"A0", 2380, 3368, 0, NULL, NULL, NULL},
+    {"A1", 1684, 2380, 0, NULL, NULL, NULL}, 
+    {"A2", 1190, 1684, 0, NULL, NULL, NULL}, 
+    {"A3", 842, 1190, 0, NULL, NULL, NULL},
+    {"A4", 595, 842, 0, NULL, NULL, NULL},
+    {"A5", 421, 595, 0, NULL, NULL, NULL},
+    {"A6", 297, 421, 0, NULL, NULL, NULL}, 
+    {"A7", 210, 297, 0, NULL, NULL, NULL}, 
+    {"A8", 148, 210, 0, NULL, NULL, NULL}, 
+    {"A9", 105, 148, 0, NULL, NULL, NULL}, 
+    {"A10", 74, 105, 0, NULL, NULL, NULL}, 
+    {"B0", 2836, 4008, 0, NULL, NULL, NULL}, 
+    {"B1", 2004, 2836, 0, NULL, NULL, NULL}, 
+    {"B2", 1418, 2004, 0, NULL, NULL, NULL}, 
+    {"B3", 1002, 1418, 0, NULL, NULL, NULL}, 
+    {"B4", 709, 1002, 0, NULL, NULL, NULL}, /* ISO, but not Adobe standard */
+    {"B5", 501, 709, 0, NULL, NULL, NULL},  /* ISO, but not Adobe standard */
+    {"B6", 354, 501, 0, NULL, NULL, NULL}, 
+    {"C0", 2600, 3677, 0, NULL, NULL, NULL}, 
+    {"C1", 1837, 2600, 0, NULL, NULL, NULL},  
+    {"C2", 1298, 1837, 0, NULL, NULL, NULL}, 
+    {"C3", 918, 1298, 0, NULL, NULL, NULL}, 
+    {"C4", 649, 918, 0, NULL, NULL, NULL}, 
+    {"C5", 459, 649, 0, NULL, NULL, NULL}, 
+    {"C6", 323, 459, 0, NULL, NULL, NULL}, 
+    {"Ledger", 1224, 792, 0, NULL, NULL, NULL},
+    {"Legal", 612, 1008, 0, NULL, NULL, NULL},
+    {"Letter", 612, 792, 0, NULL, NULL, NULL},
+    {"Note", 612, 792, 0, NULL, NULL, NULL},
+// ISO and JIS B sizes are different....
+    {"jisb0", 2916, 4128, 0, NULL, NULL, NULL},
+    {"jisb1", 2064, 2916, 0, NULL, NULL, NULL}, 
+    {"jisb2", 1458, 2064, 0, NULL, NULL, NULL}, 
+    {"jisb3", 1032, 1458, 0, NULL, NULL, NULL}, 
+    {"jisb4", 729, 1032, 0, NULL, NULL, NULL}, 
+    {"jisb5", 516, 729, 0, NULL, NULL, NULL}, 
+    {"jisb6", 363, 516, 0, NULL, NULL, NULL}, 
+// U.S. CAD standard paper sizes
+    {"archE", 2592, 3456, 0, NULL, NULL, NULL}, 
+    {"archD", 1728, 2592, 0, NULL, NULL, NULL}, 
+    {"archC", 1296, 1728, 0, NULL, NULL, NULL}, 
+    {"archB", 864, 1296, 0, NULL, NULL, NULL}, 
+    {"archA", 648, 864, 0, NULL, NULL, NULL}, 
+// Other paper sizes
+    {"flsa", 612, 936, 0, NULL, NULL, NULL}, /* U.S. foolscap */
+    {"flse", 612, 936, 0, NULL, NULL, NULL}, /* European foolscap */
+    {"halfletter", 396, 612, 0, NULL, NULL, NULL}, 
+    {NULL, 0, 0, 0, NULL, NULL, NULL}
+};
+
+/* parser state */
+enum CDSC_SCAN_SECTION {
+    scan_none = 0,
+    scan_comments = 1,
+    scan_pre_preview = 2,
+    scan_preview = 3,
+    scan_pre_defaults = 4,
+    scan_defaults = 5,
+    scan_pre_prolog = 6,
+    scan_prolog = 7,
+    scan_pre_setup = 8,
+    scan_setup = 9,
+    scan_pre_pages = 10,
+    scan_pages = 11,
+    scan_pre_trailer = 12,
+    scan_trailer = 13,
+    scan_eof = 14
+};
+
+static const char * const dsc_scan_section_name[15] = {
+ "Type", "Comments", 
+ "pre-Preview", "Preview",
+ "pre-Defaults", "Defaults",
+ "pre-Prolog", "Prolog",
+ "pre-Setup", "Setup",
+ "pre-Page", "Page",
+ "pre-Trailer", "Trailer",
+ "EOF"
+};
+
+/******************************************************************/
+/* Public functions                                               */
+/******************************************************************/
+
+/* constructor */
+CDSC *
+dsc_init(void *caller_data)
+{
+    CDSC *dsc = (CDSC *)malloc(sizeof(CDSC));
+    if (dsc == NULL)
+       return NULL;
+    memset(dsc, 0, sizeof(CDSC));
+    dsc->caller_data = caller_data;
+
+    return dsc_init2(dsc);
+}
+
+/* constructor, with caller supplied memalloc */
+CDSC *
+dsc_init_with_alloc(
+    void *caller_data,
+    void *(*memalloc)(size_t size, void *closure_data),
+    void (*memfree)(void *ptr, void *closure_data),
+    void *closure_data)
+{
+    CDSC *dsc = (CDSC *)memalloc(sizeof(CDSC), closure_data);
+    if (dsc == NULL)
+       return NULL;
+    memset(dsc, 0, sizeof(CDSC));
+    dsc->caller_data = caller_data;
+
+    dsc->memalloc = memalloc;
+    dsc->memfree = memfree;
+    dsc->mem_closure_data = closure_data;
+    
+    return dsc_init2(dsc);
+}
+
+
+
+/* destructor */
+void 
+dsc_free(CDSC *dsc)
+{
+    if (dsc == NULL)
+       return;
+    dsc_reset(dsc);
+    dsc_memfree(dsc, dsc);
+}
+
+
+/* Tell DSC parser how long document will be, to allow ignoring
+ * of early %%Trailer and %%EOF.  This is optional.
+ */
+void 
+dsc_set_length(CDSC *dsc, unsigned long len)
+{
+    dsc->file_length = len;
+}
+
+/* Process a buffer containing DSC comments and PostScript */
+/* Return value is < 0 for error, >=0 for OK.
+ *  CDSC_ERROR
+ *  CDSC_OK
+ *  CDSC_NOTDSC (DSC will be ignored)
+ *  other values indicate the last DSC comment read
+ */ 
+int
+dsc_scan_data(CDSC *dsc, const char *data, int length)
+{
+    int bytes_read;
+    int code = 0;
+
+    if (dsc == NULL)
+       return CDSC_ERROR;
+
+    if (dsc->id == CDSC_NOTDSC)
+       return CDSC_NOTDSC;
+    dsc->id = CDSC_OK;
+    if (dsc->eof)
+       return CDSC_OK; /* ignore */
+
+    if (length == 0) {
+       /* EOF, so process what remains */
+       dsc->eof = TRUE;
+    }
+
+    do {
+       if (dsc->id == CDSC_NOTDSC)
+           break;
+
+       if (length != 0) {
+           /* move existing data if needed */
+           if (dsc->data_length > CDSC_DATA_LENGTH/2) {
+               memmove(dsc->data, dsc->data + dsc->data_index,
+                   dsc->data_length - dsc->data_index);
+               dsc->data_offset += dsc->data_index;
+               dsc->data_length -= dsc->data_index;
+               dsc->data_index = 0;
+           }
+           /* append to buffer */
+           bytes_read = min(length, (int)(CDSC_DATA_LENGTH - dsc->data_length));
+           memcpy(dsc->data + dsc->data_length, data, bytes_read);
+           dsc->data_length += bytes_read;
+           data += bytes_read;
+           length -= bytes_read;
+       }
+       if (dsc->scan_section == scan_none) {
+           code = dsc_scan_type(dsc);
+           if (code == CDSC_NEEDMORE) {
+               /* need more characters before we can identify type */
+               code = CDSC_OK;
+               break;
+           }
+           dsc->id = code;
+       }
+
+        if (code == CDSC_NOTDSC) {
+           dsc->id = CDSC_NOTDSC;
+           break;
+       }
+
+       while ((code = dsc_read_line(dsc)) > 0) {
+           if (dsc->id == CDSC_NOTDSC)
+               break;
+           if (dsc->doseps_end && 
+               (dsc->data_offset + dsc->data_index > dsc->doseps_end)) {
+               /* have read past end of DOS EPS PostScript section */
+               return CDSC_OK; /* ignore */
+           }
+           if (dsc->eof)
+               return CDSC_OK;
+           if (dsc->skip_document)
+               continue;       /* embedded document */
+           if (dsc->skip_lines)
+               continue;       /* embedded lines */
+           if (IS_DSC(dsc->line, "%%BeginData:"))
+               continue;
+           if (IS_DSC(dsc->line, "%%BeginBinary:"))
+               continue;
+           if (IS_DSC(dsc->line, "%%EndDocument"))
+               continue;
+           if (IS_DSC(dsc->line, "%%EndData"))
+               continue;
+           if (IS_DSC(dsc->line, "%%EndBinary"))
+               continue;
+
+           do {
+               switch (dsc->scan_section) {
+                   case scan_comments:
+                       code = dsc_scan_comments(dsc);
+                       break;
+                   case scan_pre_preview:
+                   case scan_preview:
+                       code = dsc_scan_preview(dsc);
+                       break;
+                   case scan_pre_defaults:
+                   case scan_defaults:
+                       code = dsc_scan_defaults(dsc);
+                       break;
+                   case scan_pre_prolog:
+                   case scan_prolog:
+                       code = dsc_scan_prolog(dsc);
+                       break;
+                   case scan_pre_setup:
+                   case scan_setup:
+                       code = dsc_scan_setup(dsc);
+                       break;
+                   case scan_pre_pages:
+                   case scan_pages:
+                       code = dsc_scan_page(dsc);
+                       break;
+                   case scan_pre_trailer:
+                   case scan_trailer:
+                       code = dsc_scan_trailer(dsc);
+                       break;
+                   case scan_eof:
+                       code = CDSC_OK;
+                       break;
+                   default:
+                       /* invalid state */
+                       code = CDSC_ERROR;
+               }
+               /* repeat if line is start of next section */
+           } while (code == CDSC_PROPAGATE);
+
+           /* if DOS EPS header not complete, ask for more */
+           if (code == CDSC_NEEDMORE) {
+               code = CDSC_OK;
+               break;
+           }
+           if (code == CDSC_NOTDSC) {
+               dsc->id = CDSC_NOTDSC;
+               break;
+           }
+       }
+    } while (length != 0);
+
+    return (code < 0) ? code : dsc->id;
+}
+
+/* Tidy up from incorrect DSC comments */
+int 
+dsc_fixup(CDSC *dsc)
+{
+    unsigned int i;
+    char buf[32];
+    unsigned long *last;
+
+    if (dsc->id == CDSC_NOTDSC)
+       return 0;
+
+    /* flush last partial line */
+    dsc_scan_data(dsc, NULL, 0);
+
+    /* Fix DSC error: code between %%EndSetup and %%Page */
+    if (dsc->page_count && (dsc->page[0].begin != dsc->endsetup)
+               && (dsc->endsetup != dsc->beginsetup)) {
+       dsc->endsetup = dsc->page[0].begin;
+       dsc_debug_print(dsc, "Warning: code included between setup and first page\n");
+    }
+
+    /* Last page contained a false trailer, */
+    /* so extend last page to start of trailer */
+    if (dsc->page_count && (dsc->begintrailer != 0) &&
+       (dsc->page[dsc->page_count-1].end != dsc->begintrailer)) {
+       dsc_debug_print(dsc, "Ignoring earlier misplaced trailer\n");
+       dsc_debug_print(dsc, "and extending last page to start of trailer\n"); 
+       dsc->page[dsc->page_count-1].end = dsc->begintrailer;
+    }
+
+    /* 
+     * Join up all sections.
+     * There might be extra code between them, or we might have
+     * missed including the \n which followed \r.
+     */
+    last = &dsc->endcomments;
+    dsc_section_join(dsc->beginpreview, &dsc->endpreview, &last);
+    dsc_section_join(dsc->begindefaults, &dsc->enddefaults, &last);
+    dsc_section_join(dsc->beginprolog, &dsc->endprolog, &last);
+    dsc_section_join(dsc->beginsetup, &dsc->endsetup, &last);
+    for (i=0; i<dsc->page_count; i++)
+       dsc_section_join(dsc->page[i].begin, &dsc->page[i].end, &last);
+    if (dsc->begintrailer)
+       *last = dsc->begintrailer;
+       
+    if ((dsc->page_pages == 0) && (dsc->page_count == 1)) {
+       /* don't flag an error if %%Pages absent but one %%Page found */
+       /* adjust incorrect page count */
+       dsc->page_pages = dsc->page_count;
+    }
+
+    /* Warnings and Errors that we can now identify */
+    if ((dsc->page_count != dsc->page_pages)) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_PAGES_WRONG, NULL, 0);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+               /* adjust incorrect page count */
+               dsc->page_pages = dsc->page_count;
+               break;
+           case CDSC_RESPONSE_CANCEL:
+               break;;
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+
+    if (dsc->epsf && (dsc->bbox == (CDSCBBOX *)NULL)) {
+       /* EPS files MUST include a BoundingBox */
+       int rc = dsc_error(dsc, CDSC_MESSAGE_EPS_NO_BBOX, NULL, 0);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+               /* Assume that it is EPS */
+               break;
+           case CDSC_RESPONSE_CANCEL:
+               /* Is NOT an EPS file */
+               dsc->epsf = FALSE;
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+
+    if (dsc->epsf && ((dsc->page_count > 1) || (dsc->page_pages > 1))) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_EPS_PAGES, NULL, 0);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+               /* Is an EPS file */
+               break;
+           case CDSC_RESPONSE_CANCEL:
+               /* Is NOT an EPS file */
+               dsc->epsf = FALSE;
+               break;
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+
+    if ((dsc->media_count == 1) && (dsc->page_media == NULL)) {
+       /* if one only media was specified, and default page media */
+       /* was not specified, assume that default is the only media. */
+       dsc->page_media = dsc->media[0];
+    }
+
+    if ((dsc->media_count != 0) && (dsc->page_media == NULL)) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_NO_MEDIA, NULL, 0);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+               /* default media is first listed */
+               dsc->page_media = dsc->media[0];
+               break;
+           case CDSC_RESPONSE_CANCEL:
+               /* No default media */
+               break;
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+
+    /* make sure all pages have a label */
+    for (i=0; i<dsc->page_count; i++) {
+       if (strlen(dsc->page[i].label) == 0) {
+           sprintf(buf, "%d", i+1);
+           if ((dsc->page[i].label = dsc_alloc_string(dsc, buf, strlen(buf))) 
+               == (char *)NULL)
+               return CDSC_ERROR;      /* no memory */
+       }
+    }
+    return CDSC_OK;
+}
+
+/* Install a function to be used for displaying messages about 
+ * DSC errors and warnings, and to request advice from user.
+ * Installing an error function is optional.
+ */
+void 
+dsc_set_error_function(CDSC *dsc, 
+       int (*fn)(P5(void *caller_data, CDSC *dsc, 
+       unsigned int explanation, const char *line, unsigned int line_len)))
+{
+    dsc->dsc_error_fn = fn;
+}
+
+
+/* Install a function for printing debug messages */
+/* This is optional */
+void 
+dsc_set_debug_function(CDSC *dsc, 
+       void (*debug_fn)(P2(void *caller_data, const char *str)))
+{
+    dsc->debug_print_fn = debug_fn;
+}
+
+/* Doesn't need to be public for PostScript documents */
+/* Made public so GSview can add pages when processing PDF files */
+int 
+dsc_add_page(CDSC *dsc, int ordinal, char *label)
+{
+    dsc->page[dsc->page_count].ordinal = ordinal;
+    dsc->page[dsc->page_count].label = 
+       dsc_alloc_string(dsc, label, strlen(label)+1);
+    dsc->page[dsc->page_count].begin = 0;
+    dsc->page[dsc->page_count].end = 0;
+    dsc->page[dsc->page_count].orientation = CDSC_ORIENT_UNKNOWN;
+    dsc->page[dsc->page_count].media = NULL;
+    dsc->page[dsc->page_count].bbox = NULL;
+    dsc->page[dsc->page_count].viewing_orientation = NULL;
+
+    dsc->page_count++;
+    if (dsc->page_count >= dsc->page_chunk_length) {
+       CDSCPAGE *new_page = (CDSCPAGE *)dsc_memalloc(dsc, 
+           (CDSC_PAGE_CHUNK+dsc->page_count) * sizeof(CDSCPAGE));
+       if (new_page == NULL)
+           return CDSC_ERROR;  /* out of memory */
+       memcpy(new_page, dsc->page, 
+           dsc->page_count * sizeof(CDSCPAGE));
+       dsc_memfree(dsc, dsc->page);
+       dsc->page= new_page;
+       dsc->page_chunk_length = CDSC_PAGE_CHUNK+dsc->page_count;
+    }
+    return CDSC_OK;
+}
+
+/* Doesn't need to be public for PostScript documents */
+/* Made public so GSview can store PDF MediaBox */
+int
+dsc_add_media(CDSC *dsc, CDSCMEDIA *media)
+{
+    CDSCMEDIA **newmedia_array;
+    CDSCMEDIA *newmedia;
+
+    /* extend media array  */
+    newmedia_array = (CDSCMEDIA **)dsc_memalloc(dsc, 
+       (dsc->media_count + 1) * sizeof(CDSCMEDIA *));
+    if (newmedia_array == NULL)
+       return CDSC_ERROR;      /* out of memory */
+    if (dsc->media != NULL) {
+       memcpy(newmedia_array, dsc->media, 
+           dsc->media_count * sizeof(CDSCMEDIA *));
+       dsc_memfree(dsc, dsc->media);
+    }
+    dsc->media = newmedia_array;
+
+    /* allocate new media */
+    newmedia = dsc->media[dsc->media_count] =
+       (CDSCMEDIA *)dsc_memalloc(dsc, sizeof(CDSCMEDIA));
+    if (newmedia == NULL)
+       return CDSC_ERROR;      /* out of memory */
+    newmedia->name = NULL;
+    newmedia->width = 595.0;
+    newmedia->height = 842.0;
+    newmedia->weight = 80.0;
+    newmedia->colour = NULL;
+    newmedia->type = NULL;
+    newmedia->mediabox = NULL;
+
+    dsc->media_count++;
+
+    if (media->name) {
+       newmedia->name = dsc_alloc_string(dsc, media->name,
+           strlen(media->name));
+       if (newmedia->name == NULL)
+           return CDSC_ERROR;  /* no memory */
+    }
+    newmedia->width = media->width;
+    newmedia->height = media->height;
+    newmedia->weight = media->weight;
+    if (media->colour) {
+       newmedia->colour = dsc_alloc_string(dsc, media->colour, 
+           strlen(media->colour));
+        if (newmedia->colour == NULL)
+           return CDSC_ERROR;  /* no memory */
+    }
+    if (media->type) {
+       newmedia->type = dsc_alloc_string(dsc, media->type, 
+           strlen(media->type));
+       if (newmedia->type == NULL)
+           return CDSC_ERROR;  /* no memory */
+    }
+    newmedia->mediabox = NULL;
+
+    if (media->mediabox) {
+       newmedia->mediabox = (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX));
+       if (newmedia->mediabox == NULL)
+           return CDSC_ERROR;  /* no memory */
+       *newmedia->mediabox = *media->mediabox;
+    }
+    return CDSC_OK;
+}
+
+/* Doesn't need to be public for PostScript documents */
+/* Made public so GSview can store PDF CropBox */
+int
+dsc_set_page_bbox(CDSC *dsc, unsigned int page_number, 
+    int llx, int lly, int urx, int ury)
+{
+    CDSCBBOX *bbox;
+    if (page_number >= dsc->page_count)
+       return CDSC_ERROR;
+    bbox = dsc->page[page_number].bbox;
+    if (bbox == NULL)
+       dsc->page[page_number].bbox = bbox = 
+           (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX));
+    if (bbox == NULL)
+       return CDSC_ERROR;
+    bbox->llx = llx;
+    bbox->lly = lly;
+    bbox->urx = urx;
+    bbox->ury = ury;
+    return CDSC_OK;
+}
+
+
+/******************************************************************/
+/* Private functions below here.                                  */
+/******************************************************************/
+
+dsc_private void *
+dsc_memalloc(CDSC *dsc, size_t size)
+{
+    if (dsc->memalloc)
+       return dsc->memalloc(size, dsc->mem_closure_data);
+    return malloc(size);
+}
+
+dsc_private void
+dsc_memfree(CDSC*dsc, void *ptr)
+{
+    if (dsc->memfree) 
+       dsc->memfree(ptr, dsc->mem_closure_data);
+    else
+       free(ptr);
+}
+
+/* private constructor */
+dsc_private CDSC *
+dsc_init2(CDSC *dsc)
+{
+    dsc_reset(dsc);
+
+    dsc->string_head = (CDSCSTRING *)dsc_memalloc(dsc, sizeof(CDSCSTRING));
+    if (dsc->string_head == NULL) {
+       dsc_free(dsc);
+       return NULL;    /* no memory */
+    }
+    dsc->string = dsc->string_head;
+    dsc->string->next = NULL;
+    dsc->string->data = (char *)dsc_memalloc(dsc, CDSC_STRING_CHUNK);
+    if (dsc->string->data == NULL) {
+       dsc_free(dsc);
+       return NULL;    /* no memory */
+    }
+    dsc->string->index = 0;
+    dsc->string->length = CDSC_STRING_CHUNK;
+       
+    dsc->page = (CDSCPAGE *)dsc_memalloc(dsc, CDSC_PAGE_CHUNK * sizeof(CDSCPAGE));
+    if (dsc->page == NULL) {
+       dsc_free(dsc);
+       return NULL;    /* no memory */
+    }
+    dsc->page_chunk_length = CDSC_PAGE_CHUNK;
+    dsc->page_count = 0;
+       
+    dsc->line = NULL;
+    dsc->data_length = 0;
+    dsc->data_index = dsc->data_length;
+
+    return dsc;
+}
+
+
+dsc_private void 
+dsc_reset(CDSC *dsc)
+{
+    unsigned int i;
+    /* Clear public members */
+    dsc->dsc = FALSE;
+    dsc->ctrld = FALSE;
+    dsc->pjl = FALSE;
+    dsc->epsf = FALSE;
+    dsc->pdf = FALSE;
+    dsc->epsf = FALSE;
+    dsc->preview = CDSC_NOPREVIEW;
+    dsc->dsc_version = NULL;   /* stored in dsc->string */
+    dsc->language_level = 0;
+    dsc->document_data = CDSC_DATA_UNKNOWN;
+    dsc->begincomments = 0;
+    dsc->endcomments = 0;
+    dsc->beginpreview = 0;
+    dsc->endpreview = 0;
+    dsc->begindefaults = 0;
+    dsc->enddefaults = 0;
+    dsc->beginprolog = 0;
+    dsc->endprolog = 0;
+    dsc->beginsetup = 0;
+    dsc->endsetup = 0;
+    dsc->begintrailer = 0;
+    dsc->endtrailer = 0;
+       
+    for (i=0; i<dsc->page_count; i++) {
+       /* page media is pointer to an element of media or dsc_known_media */
+       /* do not free it. */
+
+       if (dsc->page[i].bbox)
+           dsc_memfree(dsc, dsc->page[i].bbox);
+       if (dsc->page[i].viewing_orientation)
+           dsc_memfree(dsc, dsc->page[i].viewing_orientation);
+    }
+    if (dsc->page)
+       dsc_memfree(dsc, dsc->page);
+    dsc->page = NULL;
+       
+    dsc->page_count = 0;
+    dsc->page_pages = 0;
+    dsc->page_order = CDSC_ORDER_UNKNOWN;
+    dsc->page_orientation = CDSC_ORIENT_UNKNOWN;
+    if (dsc->viewing_orientation)
+       dsc_memfree(dsc, dsc->viewing_orientation);
+    dsc->viewing_orientation = NULL;
+       
+    if (dsc->media) {
+       for (i=0; i<dsc->media_count; i++) {
+           if (dsc->media[i]) {
+               if (dsc->media[i]->mediabox)
+                   dsc_memfree(dsc, dsc->media[i]->mediabox);
+               dsc_memfree(dsc, dsc->media[i]);
+           }
+       }
+       dsc_memfree(dsc, dsc->media);
+    }
+    dsc->media_count = 0;
+    dsc->media = NULL;
+
+    /* page_media is pointer to an element of media or dsc_known_media */
+    /* do not free it. */
+    dsc->page_media = NULL;
+
+    if (dsc->bbox)
+       dsc_memfree(dsc, dsc->bbox);
+    dsc->bbox = NULL;
+    if (dsc->page_bbox)
+       dsc_memfree(dsc, dsc->page_bbox);
+    dsc->page_bbox = NULL;
+    if (dsc->doseps)
+       dsc_memfree(dsc, dsc->doseps);
+    dsc->doseps = NULL;
+       
+    dsc->dsc_title = NULL;
+    dsc->dsc_creator = NULL;
+    dsc->dsc_date = NULL;
+    dsc->dsc_for = NULL;
+       
+
+    dsc->max_error = DSC_MAX_ERROR;
+    dsc->severity = dsc_severity;
+
+    /* Clear private members */
+    /* Don't touch dsc->caller_data */
+    dsc->id = CDSC_OK;
+    dsc->scan_section = scan_none;
+    dsc->doseps_end = 0;
+    dsc->page_chunk_length = 0;
+    dsc->file_length = 0;
+    dsc->skip_document = 0;
+    dsc->skip_bytes = 0;
+    dsc->skip_lines = 0;
+    dsc->skip_pjl = 0;
+    dsc->begin_font_count = 0;
+    dsc->begin_feature_count = 0;
+    dsc->begin_resource_count = 0;
+    dsc->begin_procset_count = 0;
+
+    dsc->data_length = 0;
+    dsc->data_index = 0;
+    dsc->data_offset = 0;
+
+    dsc->eof = 0;
+       
+    dsc->line = 0;
+    dsc->line_length = 0;
+    dsc->eol = 0;
+    dsc->last_cr = FALSE;
+    dsc->line_count = 1;
+    dsc->long_line = FALSE;
+    memset(dsc->last_line, 0, sizeof(dsc->last_line));
+
+    dsc->string = dsc->string_head;
+    while (dsc->string != (CDSCSTRING *)NULL) {
+       if (dsc->string->data)
+           dsc_memfree(dsc, dsc->string->data);
+       dsc->string_head = dsc->string;
+       dsc->string = dsc->string->next;
+       dsc_memfree(dsc, dsc->string_head);
+    }
+    dsc->string_head = NULL;
+    dsc->string = NULL;
+
+    /* don't touch caller functions */
+
+    /* public data */
+    if (dsc->hires_bbox)
+       dsc_memfree(dsc, dsc->hires_bbox);
+    dsc->hires_bbox = NULL;
+    if (dsc->crop_box)
+       dsc_memfree(dsc, dsc->crop_box);
+    dsc->crop_box = NULL;
+}
+
+/* 
+* Join up all sections.
+* There might be extra code between them, or we might have
+* missed including the \n which followed \r.
+* begin is the start of this section
+* pend is a pointer to the end of this section
+* pplast is a pointer to a pointer of the end of the previous section
+*/
+dsc_private void 
+dsc_section_join(unsigned long begin, unsigned long *pend, unsigned long **pplast)
+{
+    if (begin)
+       **pplast = begin;
+    if (*pend > begin)
+       *pplast = pend;
+}
+
+
+/* return value is 0 if no line available, or length of line */
+dsc_private int
+dsc_read_line(CDSC *dsc)
+{
+    char *p, *last;
+    dsc->line = NULL;
+
+    if (dsc->eof) {
+       /* return all that remains, even if line incomplete */
+       dsc->line = dsc->data + dsc->data_index;
+       dsc->line_length = dsc->data_length - dsc->data_index;
+       dsc->data_index = dsc->data_length;
+       return dsc->line_length;
+    }
+
+    /* ignore embedded bytes */
+    if (dsc->skip_bytes) {
+       int cnt = min(dsc->skip_bytes,
+                    (int)(dsc->data_length - dsc->data_index));
+       dsc->skip_bytes -= cnt;
+       dsc->data_index += cnt;
+       if (dsc->skip_bytes != 0)
+           return 0;
+    }
+
+    do {
+       dsc->line = dsc->data + dsc->data_index;
+       last = dsc->data + dsc->data_length;
+       if (dsc->data_index == dsc->data_length) {
+           dsc->line_length = 0;
+           return 0;
+       }
+       if (dsc->eol) {
+           /* if previous line was complete, increment line count */
+           dsc->line_count++;
+           if (dsc->skip_lines)
+               dsc->skip_lines--;
+       }
+           
+       /* skip over \n which followed \r */
+       if (dsc->last_cr && dsc->line[0] == '\n') {
+           dsc->data_index++;
+           dsc->line++;
+       }
+       dsc->last_cr = FALSE;
+
+       /* look for EOL */
+       dsc->eol = FALSE;
+       for (p = dsc->line; p < last; p++) {
+           if (*p == '\r') {
+               p++;
+               if ((p<last) && (*p == '\n'))
+                   p++;        /* include line feed also */
+               else
+                   dsc->last_cr = TRUE; /* we might need to skip \n */
+               dsc->eol = TRUE;        /* dsc->line is a complete line */
+               break;
+           }
+           if (*p == '\n') {
+               p++;
+               dsc->eol = TRUE;        /* dsc->line is a complete line */
+               break;
+           }
+           if (*p == '\032') {         /* MS-DOS Ctrl+Z */
+               dsc->eol = TRUE;
+           }
+       }
+       if (dsc->eol == FALSE) {
+           /* we haven't got a complete line yet */
+           if (dsc->data_length - dsc->data_index < sizeof(dsc->data)/2) {
+               /* buffer is less than half full, ask for some more */
+               dsc->line_length = 0;
+               return 0;
+           }
+       }
+       dsc->data_index += dsc->line_length = (p - dsc->line);
+    } while (dsc->skip_lines && dsc->line_length);
+
+    if (dsc->line_length == 0)
+       return 0;
+       
+    if ((dsc->line[0]=='%') && (dsc->line[1]=='%'))  {
+       /* handle recursive %%BeginDocument */
+       if ((dsc->skip_document) && dsc->line_length &&
+               COMPARE(dsc->line, "%%EndDocument")) {
+           dsc->skip_document--;
+       }
+
+       /* handle embedded lines or binary data */
+       if (COMPARE(dsc->line, "%%BeginData:")) {
+           /* %%BeginData: <numberof>[ <type> [ <bytesorlines> ] ] 
+            * <numberof> ::= <uint> (Lines or physical bytes) 
+            * <type> ::= Hex | Binary | ASCII (Type of data) 
+            * <bytesorlines> ::= Bytes | Lines (Read in bytes or lines) 
+            */
+           char begindata[MAXSTR+1];
+           int cnt;
+            unsigned int num;
+           const char *numberof, *bytesorlines;
+            if ((num = dsc->line_length) >= sizeof(begindata)-1)
+                num = sizeof(begindata)-1;
+            memcpy(begindata, dsc->line, num);
+            begindata[num] = '\0';
+           numberof = strtok(begindata+12, " \r\n");
+           strtok(NULL, " \r\n");      /* dump type */
+           bytesorlines = strtok(NULL, " \r\n");
+           if (bytesorlines == NULL)
+               bytesorlines = "Bytes";
+          
+           if ( (numberof == NULL) || (bytesorlines == NULL) ) {
+               /* invalid usage of %%BeginData */
+               /* ignore that we ever saw it */
+               int rc = dsc_error(dsc, CDSC_MESSAGE_INCORRECT_USAGE, 
+                           dsc->line, dsc->line_length);
+               switch (rc) {
+                   case CDSC_RESPONSE_OK:
+                   case CDSC_RESPONSE_CANCEL:
+                       break;
+                   case CDSC_RESPONSE_IGNORE_ALL:
+                       return 0;
+               }
+           }
+           else {
+               cnt = atoi(numberof);
+               if (cnt) {
+                   if (bytesorlines && (dsc_stricmp(bytesorlines, "Lines")==0)) {
+                       /* skip cnt lines */
+                       if (dsc->skip_lines == 0) {
+                           /* we are not already skipping lines */
+                           dsc->skip_lines = cnt+1;
+                       }
+                   }
+                   else {
+                       /* byte count doesn't includes \n or \r\n  */
+                       /* or \r of %%BeginData: */
+                       /* skip cnt bytes */
+                       if (dsc->skip_bytes == 0) {
+                           /* we are not already skipping lines */
+                           dsc->skip_bytes = cnt;
+                       }
+
+                   }
+               }
+           }
+       }
+       else if (COMPARE(dsc->line, "%%BeginBinary:")) {
+           /* byte count doesn't includes \n or \r\n or \r of %%BeginBinary:*/
+           unsigned long cnt = atoi(dsc->line + 14);
+           if (dsc->skip_bytes == 0) {
+               /* we are not already skipping lines */
+               dsc->skip_bytes = cnt;
+           }
+       }
+    }
+       
+    if ((dsc->line[0]=='%') && (dsc->line[1]=='%') &&
+       COMPARE(dsc->line, "%%BeginDocument:") ) {
+       /* Skip over embedded document, recursively */
+       dsc->skip_document++;
+    }
+
+    if (!dsc->long_line && (dsc->line_length > DSC_LINE_LENGTH)) {
+       dsc_error(dsc, CDSC_MESSAGE_LONG_LINE, dsc->line, dsc->line_length);
+        dsc->long_line = TRUE;
+    }
+       
+    return dsc->line_length;
+}
+
+
+/* Save last DSC line, for use with %%+ */
+dsc_private void 
+dsc_save_line(CDSC *dsc)
+{
+    int len = min(sizeof(dsc->last_line), dsc->line_length);
+    memcpy(dsc->last_line, dsc->line, len);
+}
+
+/* display unknown DSC line */
+dsc_private void 
+dsc_unknown(CDSC *dsc)
+{
+    if (dsc->debug_print_fn) {
+       char line[DSC_LINE_LENGTH];
+       unsigned int length = min(DSC_LINE_LENGTH-1, dsc->line_length);
+       sprintf(line, "Unknown in %s section at line %d:\n  ", 
+           dsc_scan_section_name[dsc->scan_section], dsc->line_count);
+       dsc_debug_print(dsc, line);
+       strncpy(line, dsc->line, length);
+       line[length] = '\0';
+       dsc_debug_print(dsc, line);
+    }
+}
+
+
+dsc_private GSBOOL
+dsc_is_section(char *line)
+{
+    if ( !((line[0]=='%') && (line[1]=='%')) )
+       return FALSE;
+    if (IS_DSC(line, "%%BeginPreview"))
+       return TRUE;
+    if (IS_DSC(line, "%%BeginDefaults"))
+       return TRUE;
+    if (IS_DSC(line, "%%BeginProlog"))
+       return TRUE;
+    if (IS_DSC(line, "%%BeginSetup"))
+       return TRUE;
+    if (IS_DSC(line, "%%Page:"))
+       return TRUE;
+    if (IS_DSC(line, "%%Trailer"))
+       return TRUE;
+    if (IS_DSC(line, "%%EOF"))
+       return TRUE;
+    return FALSE;
+}
+
+
+dsc_private GSDWORD
+dsc_get_dword(const unsigned char *buf)
+{
+    GSDWORD dw;
+    dw = (GSDWORD)buf[0];
+    dw += ((GSDWORD)buf[1])<<8;
+    dw += ((GSDWORD)buf[2])<<16;
+    dw += ((GSDWORD)buf[3])<<24;
+    return dw;
+}
+
+dsc_private GSWORD
+dsc_get_word(const unsigned char *buf)
+{
+    GSWORD w;
+    w = (GSWORD)buf[0];
+    w |= (GSWORD)(buf[1]<<8);
+    return w;
+}
+
+dsc_private int
+dsc_read_doseps(CDSC *dsc)
+{
+    unsigned char *line = (unsigned char *)dsc->line;
+    if ((dsc->doseps = (CDSCDOSEPS *)dsc_memalloc(dsc, sizeof(CDSCDOSEPS))) == NULL)
+       return CDSC_ERROR;      /* no memory */
+       
+    dsc->doseps->ps_begin = dsc_get_dword(line+4);
+    dsc->doseps->ps_length = dsc_get_dword(line+8);
+    dsc->doseps->wmf_begin = dsc_get_dword(line+12);
+    dsc->doseps->wmf_length = dsc_get_dword(line+16);
+    dsc->doseps->tiff_begin = dsc_get_dword(line+20);
+    dsc->doseps->tiff_length = dsc_get_dword(line+24);
+    dsc->doseps->checksum = dsc_get_word(line+28);
+       
+    dsc->doseps_end = dsc->doseps->ps_begin + dsc->doseps->ps_length;
+
+    /* move data_index backwards to byte after doseps header */
+    dsc->data_index -= dsc->line_length - 30;
+    /* we haven't read a line of PostScript code yet */
+    dsc->line_count = 0;
+    /* skip from current position to start of PostScript section */
+    dsc->skip_bytes = dsc->doseps->ps_begin - 30;
+
+    if (dsc->doseps->tiff_begin)
+       dsc->preview = CDSC_TIFF;
+    if (dsc->doseps->wmf_begin)
+       dsc->preview = CDSC_WMF;
+
+    return CDSC_OK;
+}
+
+
+
+dsc_private int 
+dsc_parse_pages(CDSC *dsc)
+{
+    int ip, io; 
+    unsigned int i;
+    char *p;
+    int n;
+    if ((dsc->page_pages != 0) && (dsc->scan_section == scan_comments)) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, 
+               dsc->line_length);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+           case CDSC_RESPONSE_CANCEL:
+               return CDSC_OK; /* ignore duplicate comments in header */
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+    if ((dsc->page_pages != 0) && (dsc->scan_section == scan_trailer)) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, 
+               dsc->line_length);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+           case CDSC_RESPONSE_CANCEL:
+               break;          /* use duplicate comments in header */
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+
+    n = IS_DSC(dsc->line, "%%+") ? 3 : 8;
+    while (IS_WHITE(dsc->line[n]))
+       n++;
+    p = dsc->line + n;
+    if (COMPARE(p, "atend")) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, dsc->line_length);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+               /* assume (atend) */
+               /* we should mark it as deferred */
+               break;
+           case CDSC_RESPONSE_CANCEL:
+               /* ignore it */
+               break;
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+    else if (COMPARE(p, "(atend)")) {
+       /* do nothing */
+       /* we should mark it as deferred */
+    }
+    else {
+       ip = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
+        if (i) {
+           n+=i;
+           dsc->page_pages = ip;
+           io = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
+           if (i) {
+               /* DSC 2 uses extra integer to indicate page order */
+               /* DSC 3 uses %%PageOrder: */
+               if (dsc->page_order == CDSC_ORDER_UNKNOWN)
+                   switch (io) {
+                       case -1:
+                           dsc->page_order = CDSC_DESCEND;
+                           break;
+                       case 0:
+                           dsc->page_order = CDSC_SPECIAL;
+                           break;
+                       case 1:
+                           dsc->page_order = CDSC_ASCEND;
+                           break;
+                   }
+           }
+       }
+       else {
+           int rc = dsc_error(dsc, CDSC_MESSAGE_INCORRECT_USAGE, dsc->line, 
+               dsc->line_length);
+           switch (rc) {
+               case CDSC_RESPONSE_OK:
+               case CDSC_RESPONSE_CANCEL:
+                   /* ignore it */
+                   break;
+               case CDSC_RESPONSE_IGNORE_ALL:
+                   return CDSC_NOTDSC;
+           }
+       }
+    }
+    return CDSC_OK;
+}
+
+dsc_private int 
+dsc_parse_bounding_box(CDSC *dsc, CDSCBBOX** pbbox, int offset)
+{
+    unsigned int i, n;
+    int llx, lly, urx, ury;
+    float fllx, flly, furx, fury;
+    char *p;
+    /* Process first %%BoundingBox: in comments, and last in trailer */
+    if ((*pbbox != NULL) && (dsc->scan_section == scan_comments)) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, 
+               dsc->line_length);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+           case CDSC_RESPONSE_CANCEL:
+               return CDSC_OK; /* ignore duplicate comments in header */
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+    if ((*pbbox != NULL) && (dsc->scan_section == scan_pages)) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, 
+               dsc->line_length);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+           case CDSC_RESPONSE_CANCEL:
+               return CDSC_OK; /* ignore duplicate comments in header */
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+    if ((*pbbox != NULL) && (dsc->scan_section == scan_trailer)) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, 
+               dsc->line_length);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+           case CDSC_RESPONSE_CANCEL:
+               break;          /* use duplicate comments in trailer */
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+    if (*pbbox != NULL) {
+       dsc_memfree(dsc, *pbbox);
+       *pbbox = NULL;
+    }
+
+    /* should only process first %%BoundingBox: */
+
+    while (IS_WHITE(dsc->line[offset]))
+       offset++;
+    p = dsc->line + offset;
+    
+    if (COMPARE(p, "atend")) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, 
+               dsc->line_length);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+               /* assume (atend) */
+               /* we should mark it as deferred */
+               break;
+           case CDSC_RESPONSE_CANCEL:
+               /* ignore it */
+               break;
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+    else if (COMPARE(p, "(atend)")) {
+       /* do nothing */
+       /* we should mark it as deferred */
+    }
+    else {
+        /* llx = */ lly = urx = ury = 0;
+       n = offset;
+       llx = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
+       n += i;
+       if (i)
+           lly = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
+       n += i;
+       if (i)
+           urx = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
+       n += i;
+       if (i)
+           ury = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
+       if (i) {
+           *pbbox = (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX));
+           if (*pbbox == NULL)
+               return CDSC_ERROR;      /* no memory */
+           (*pbbox)->llx = llx;
+           (*pbbox)->lly = lly;
+           (*pbbox)->urx = urx;
+           (*pbbox)->ury = ury;
+       }
+       else {
+           int rc = dsc_error(dsc, CDSC_MESSAGE_BBOX, dsc->line, 
+               dsc->line_length);
+           switch (rc) {
+             case CDSC_RESPONSE_OK:
+               /* fllx = */ flly = furx = fury = 0.0;
+               n = offset;
+               n += i;
+               fllx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+               n += i;
+               if (i)
+                   flly = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+               n += i;
+               if (i)
+                   furx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+               n += i;
+               if (i)
+                   fury = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+               if (i) {
+                   *pbbox = (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX));
+                   if (*pbbox == NULL)
+                       return CDSC_ERROR;      /* no memory */
+                       (*pbbox)->llx = (int)fllx;
+                       (*pbbox)->lly = (int)flly;
+                       (*pbbox)->urx = (int)(furx+0.999);
+                       (*pbbox)->ury = (int)(fury+0.999);
+               }
+               return CDSC_OK;
+           case CDSC_RESPONSE_CANCEL:
+               return CDSC_OK;
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+         }
+       }
+    }
+    return CDSC_OK;
+}
+
+dsc_private int 
+dsc_parse_float_bounding_box(CDSC *dsc, CDSCFBBOX** pbbox, int offset)
+{
+    unsigned int i, n;
+    float fllx, flly, furx, fury;
+    char *p;
+    /* Process first %%HiResBoundingBox: or %%CropBox: in comments, 
+     * and last in trailer.
+     */
+    if ((*pbbox != NULL) && (dsc->scan_section == scan_comments)) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, 
+               dsc->line_length);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+           case CDSC_RESPONSE_CANCEL:
+               return CDSC_OK; /* ignore duplicate comments in header */
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+    if ((*pbbox != NULL) && (dsc->scan_section == scan_pages)) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, 
+               dsc->line_length);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+           case CDSC_RESPONSE_CANCEL:
+               return CDSC_OK; /* ignore duplicate comments in header */
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+    if ((*pbbox != NULL) && (dsc->scan_section == scan_trailer)) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, 
+               dsc->line_length);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+           case CDSC_RESPONSE_CANCEL:
+               break;          /* use duplicate comments in trailer */
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+    if (*pbbox != NULL) {
+       dsc_memfree(dsc, *pbbox);
+       *pbbox = NULL;
+    }
+
+    /* should only process first %%BoundingBox: */
+
+    while (IS_WHITE(dsc->line[offset]))
+       offset++;
+    p = dsc->line + offset;
+    
+    if (COMPARE(p, "atend")) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, 
+               dsc->line_length);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+               /* assume (atend) */
+               /* we should mark it as deferred */
+               break;
+           case CDSC_RESPONSE_CANCEL:
+               /* ignore it */
+               break;
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+    else if (COMPARE(p, "(atend)")) {
+       /* do nothing */
+       /* we should mark it as deferred */
+    }
+    else {
+       /* fllx = */ flly = furx = fury = 0.0;
+       n = offset;
+       fllx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+       n += i;
+       if (i)
+           flly = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+       n += i;
+       if (i)
+           furx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+       n += i;
+       if (i)
+           fury = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+       if (i) {
+           *pbbox = (CDSCFBBOX *)dsc_memalloc(dsc, sizeof(CDSCFBBOX));
+           if (*pbbox == NULL)
+               return CDSC_ERROR;      /* no memory */
+           (*pbbox)->fllx = fllx;
+           (*pbbox)->flly = flly;
+           (*pbbox)->furx = furx;
+           (*pbbox)->fury = fury;
+       }
+    }
+    return CDSC_OK;
+}
+
+dsc_private int 
+dsc_parse_orientation(CDSC *dsc, unsigned int *porientation, int offset)
+{
+    char *p;
+    if ((dsc->page_orientation != CDSC_ORIENT_UNKNOWN) && 
+       (dsc->scan_section == scan_comments)) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, 
+               dsc->line_length);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+           case CDSC_RESPONSE_CANCEL:
+               return CDSC_OK; /* ignore duplicate comments in header */
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+    if ((dsc->page_orientation != CDSC_ORIENT_UNKNOWN) && 
+       (dsc->scan_section == scan_trailer)) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, 
+               dsc->line_length);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+           case CDSC_RESPONSE_CANCEL:
+               break;          /* use duplicate comments in header; */
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+    p = dsc->line + offset;
+    while (IS_WHITE(*p))
+       p++;
+    if (COMPARE(p, "atend")) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, dsc->line_length);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+               /* assume (atend) */
+               /* we should mark it as deferred */
+               break;
+           case CDSC_RESPONSE_CANCEL:
+               /* ignore it */
+               break;
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+    else if (COMPARE(p, "(atend)")) {
+       /* do nothing */
+       /* we should mark it as deferred */
+    }
+    else if (COMPARE(p, "Portrait")) {
+       *porientation = CDSC_PORTRAIT;
+    }
+    else if (COMPARE(p, "Landscape")) {
+       *porientation = CDSC_LANDSCAPE;
+    }
+    else {
+       dsc_unknown(dsc);
+    }
+    return CDSC_OK;
+}
+
+dsc_private int 
+dsc_parse_order(CDSC *dsc)
+{
+    char *p;
+    if ((dsc->page_order != CDSC_ORDER_UNKNOWN) && 
+       (dsc->scan_section == scan_comments)) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, 
+               dsc->line_length);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+           case CDSC_RESPONSE_CANCEL:
+               return CDSC_OK; /* ignore duplicate comments in header */
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+    if ((dsc->page_order != CDSC_ORDER_UNKNOWN) && 
+       (dsc->scan_section == scan_trailer)) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, 
+               dsc->line_length);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+           case CDSC_RESPONSE_CANCEL:
+               break;          /* use duplicate comments in trailer */
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+
+    p = dsc->line + (IS_DSC(dsc->line, "%%+") ? 3 : 13);
+    while (IS_WHITE(*p))
+       p++;
+    if (COMPARE(p, "atend")) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, 
+               dsc->line_length);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+               /* assume (atend) */
+               /* we should mark it as deferred */
+               break;
+           case CDSC_RESPONSE_CANCEL:
+               /* ignore it */
+               break;
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+    else if (COMPARE(p, "(atend)")) {
+       /* do nothing */
+       /* we should mark it as deferred */
+    }
+    else if (COMPARE(p, "Ascend")) {
+       dsc->page_order = CDSC_ASCEND;
+    }
+    else if (COMPARE(p, "Descend")) {
+       dsc->page_order = CDSC_DESCEND;
+    }
+    else if (COMPARE(p, "Special")) {
+       dsc->page_order = CDSC_SPECIAL;
+    }
+    else {
+       dsc_unknown(dsc);
+    }
+    return CDSC_OK;
+}
+
+
+dsc_private int 
+dsc_parse_media(CDSC *dsc, const CDSCMEDIA **page_media)
+{
+    char media_name[MAXSTR];
+    int n = IS_DSC(dsc->line, "%%+") ? 3 : 12; /* %%PageMedia: */
+    unsigned int i;
+
+    if (dsc_copy_string(media_name, sizeof(media_name)-1,
+       dsc->line+n, dsc->line_length-n, NULL)) {
+       for (i=0; i<dsc->media_count; i++) {
+           if (dsc->media[i]->name && 
+               (dsc_stricmp(media_name, dsc->media[i]->name) == 0)) {
+               *page_media = dsc->media[i];
+               return CDSC_OK;
+           }
+       }
+    }
+    dsc_unknown(dsc);
+    
+    return CDSC_OK;
+}
+
+
+dsc_private int 
+dsc_parse_document_media(CDSC *dsc)
+{
+    unsigned int i, n;
+    CDSCMEDIA lmedia;
+    GSBOOL blank_line;
+
+    if (IS_DSC(dsc->line, "%%DocumentMedia:"))
+       n = 16;
+    else if (IS_DSC(dsc->line, "%%+"))
+       n = 3;
+    else
+       return CDSC_ERROR;      /* error */
+
+    /* check for blank remainder of line */
+    blank_line = TRUE;
+    for (i=n; i<dsc->line_length; i++) {
+       if (!IS_WHITE_OR_EOL(dsc->line[i])) {
+           blank_line = FALSE;
+           break;
+       }
+    }
+
+    if (!blank_line) {
+       char name[MAXSTR];
+       char colour[MAXSTR];
+       char type[MAXSTR];
+       lmedia.name = lmedia.colour = lmedia.type = (char *)NULL;
+       lmedia.width = lmedia.height = lmedia.weight = 0;
+       lmedia.mediabox = (CDSCBBOX *)NULL;
+       lmedia.name = dsc_copy_string(name, sizeof(name)-1,
+               dsc->line+n, dsc->line_length-n, &i);
+       n+=i;
+       if (i)
+           lmedia.width = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+       n+=i;
+       if (i)
+           lmedia.height = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+       n+=i;
+       if (i)
+           lmedia.weight = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+       n+=i;
+       if (i)
+           lmedia.colour = dsc_copy_string(colour, sizeof(colour)-1,
+               dsc->line+n, dsc->line_length-n, &i);
+       n+=i;
+       if (i)
+           lmedia.type = dsc_copy_string(type, sizeof(type)-1,
+               dsc->line+n, dsc->line_length-n, &i);
+
+       if (i==0)
+           dsc_unknown(dsc); /* we didn't get all fields */
+       else {
+           if (dsc_add_media(dsc, &lmedia))
+               return CDSC_ERROR;      /* out of memory */
+       }
+    }
+    return CDSC_OK;
+}
+
+/* viewing orientation is believed to be the first four elements of
+ * a CTM matrix
+ */
+dsc_private int 
+dsc_parse_viewing_orientation(CDSC *dsc, CDSCCTM **pctm)
+{
+    CDSCCTM ctm;
+    unsigned int i, n;
+
+    if (*pctm != NULL) {
+       dsc_memfree(dsc, *pctm);
+       *pctm = NULL;
+    }
+
+    n = IS_DSC(dsc->line, "%%+") ? 3 : 21;  /* %%ViewingOrientation: */
+    while (IS_WHITE(dsc->line[n]))
+       n++;
+
+    /* ctm.xx = */ ctm.xy = ctm.yx = ctm.yy = 0.0;
+    ctm.xx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+    n += i;
+    if (i)
+        ctm.xy = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+    n += i;
+    if (i)
+        ctm.yx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+    n += i;
+    if (i)
+        ctm.yy = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+    if (i==0) {
+       dsc_unknown(dsc); /* we didn't get all fields */
+    }
+    else {
+       *pctm = (CDSCCTM *)dsc_memalloc(dsc, sizeof(CDSCCTM));
+       if (*pctm == NULL)
+           return CDSC_ERROR;  /* no memory */
+       **pctm = ctm;
+    }
+    return CDSC_OK;
+}
+   
+
+/* This is called before dsc_read_line(), since we may
+ * need to skip a binary header which contains a new line
+ * character
+ */
+dsc_private int 
+dsc_scan_type(CDSC *dsc)
+{
+    unsigned char *p;
+    unsigned char *line = (unsigned char *)(dsc->data + dsc->data_index);
+    int length = dsc->data_length - dsc->data_index;
+
+    /* Types that should be known:
+     *   DSC
+     *   EPSF
+     *   PJL + any of above
+     *   ^D + any of above
+     *   DOS EPS
+     *   PDF
+     *   non-DSC
+     */
+
+    /* First process any non PostScript headers */
+    /* At this stage we do not have a complete line */
+
+    if (length == 0)
+       return CDSC_NEEDMORE;
+
+    if (dsc->skip_pjl) {
+       /* skip until first PostScript comment */
+       while (length >= 2) {
+           while (length && !IS_EOL(line[0])) {
+               /* skip until EOL character */
+               line++;
+               dsc->data_index++;
+               length--;
+           }
+           while ((length >= 2) && IS_EOL(line[0]) && IS_EOL(line[1])) {
+               /* skip until EOL followed by non-EOL */
+               line++;
+               dsc->data_index++;
+               length--;
+           }
+           if (length < 2)
+               return CDSC_NEEDMORE;
+
+           if (IS_EOL(line[0]) && line[1]=='%') {
+               line++;
+               dsc->data_index++;
+               length--;
+               dsc->skip_pjl = FALSE;
+               break;
+           }
+           else {
+               /* line++; */
+               dsc->data_index++;
+               /* length--; */
+               return CDSC_NEEDMORE;
+           }
+       }
+       if (dsc->skip_pjl)
+           return CDSC_NEEDMORE;
+    }
+
+    if (length == 0)
+       return CDSC_NEEDMORE;
+
+    if (line[0] == '\004') {
+       line++;
+       dsc->data_index++;
+       length--;
+       dsc->ctrld = TRUE;
+    }
+
+    if (line[0] == '\033') {
+       /* possibly PJL */
+       if (length < 9)
+           return CDSC_NEEDMORE;
+       if (COMPARE(line, "\033%-12345X")) {
+           dsc->skip_pjl = TRUE;  /* skip until first PostScript comment */
+           dsc->pjl = TRUE;
+           dsc->data_index += 9;
+           return dsc_scan_type(dsc);
+       }
+    }
+
+    if ((line[0]==0xc5) && (length < 4))
+       return CDSC_NEEDMORE;
+    if ((line[0]==0xc5) && (line[1]==0xd0) && 
+        (line[2]==0xd3) && (line[3]==0xc6) ) {
+       /* id is "EPSF" with bit 7 set */
+       /* read DOS EPS header, then ignore all bytes until the PS section */
+       if (length < 30)
+           return CDSC_NEEDMORE;
+       dsc->line = (char *)line;
+       if (dsc_read_doseps(dsc))
+           return CDSC_ERROR;
+    }
+    else {
+       if (length < 2)
+           return CDSC_NEEDMORE;
+       if ((line[0] == '%') && (line[1] == 'P')) {
+           if (length < 5)
+               return CDSC_NEEDMORE;
+           if (COMPARE(line, "%PDF-")) {
+               dsc->pdf = TRUE;
+               dsc->scan_section = scan_comments;
+               return CDSC_OK;
+           }
+       }
+    }
+
+    /* Finally process PostScript headers */
+
+    if (dsc_read_line(dsc) <= 0)
+       return CDSC_NEEDMORE;
+       
+    dsc->dsc_version = dsc_add_line(dsc, dsc->line, dsc->line_length);
+    if (COMPARE(dsc->line, "%!PS-Adobe")) {
+       dsc->dsc = TRUE;
+       dsc->begincomments = DSC_START(dsc);
+       if (dsc->dsc_version == NULL)
+           return CDSC_ERROR;  /* no memory */
+       p = (unsigned char *)dsc->line + 14;
+       while (IS_WHITE(*p))
+           p++;
+       if (COMPARE(p, "EPSF-"))
+           dsc->epsf = TRUE;
+       dsc->scan_section = scan_comments;
+       return CDSC_PSADOBE;
+    }
+    if (COMPARE(dsc->line, "%!")) {
+       dsc->scan_section = scan_comments;
+       return CDSC_NOTDSC;
+    }
+
+    dsc->scan_section = scan_comments;
+    return CDSC_NOTDSC;        /* unrecognised */
+}
+
+
+
+dsc_private int 
+dsc_scan_comments(CDSC *dsc)
+{
+    /* Comments section ends at */
+    /*  %%EndComments */
+    /*  another section */
+    /*  line that does not start with %% */
+    /* Save a few important lines */
+
+    char *line = dsc->line;
+    GSBOOL continued = FALSE;
+    dsc->id = CDSC_OK;
+    if (IS_DSC(line, "%%EndComments")) {
+       dsc->id = CDSC_ENDCOMMENTS;
+       dsc->endcomments = DSC_END(dsc);
+       dsc->scan_section = scan_pre_preview;
+       return CDSC_OK;
+    }
+    else if (IS_DSC(line, "%%BeginComments")) {
+       /* ignore because we are in this section */
+       dsc->id = CDSC_BEGINCOMMENTS;
+    }
+    else if (dsc_is_section(line)) {
+       dsc->endcomments = DSC_START(dsc);
+       dsc->scan_section = scan_pre_preview;
+       return CDSC_PROPAGATE;
+    }
+    else if (line[0] == '%' && IS_WHITE_OR_EOL(line[1])) {
+       dsc->endcomments = DSC_START(dsc);
+       dsc->scan_section = scan_pre_preview;
+       return CDSC_PROPAGATE;
+    }
+    else if (line[0] != '%') {
+       dsc->id = CDSC_OK;
+       dsc->endcomments = DSC_START(dsc);
+       dsc->scan_section = scan_pre_preview;
+       return CDSC_PROPAGATE;
+    }
+    else if (IS_DSC(line, "%%Begin")) {
+       dsc->endcomments = DSC_START(dsc);
+       dsc->scan_section = scan_pre_preview;
+       return CDSC_PROPAGATE;
+    }
+
+    /* Handle continuation lines.
+     * To simply processing, we assume that contination lines 
+     * will only occur if repeat parameters are allowed and that 
+     * a complete set of these parameters appears on each line.  
+     * This is more restrictive than the DSC specification, but
+     * is valid for the DSC comments understood by this parser
+     * for all documents that we have seen.
+     */
+    if (IS_DSC(line, "%%+")) {
+       line = dsc->last_line;
+       continued = TRUE;
+    }
+    else
+       dsc_save_line(dsc);
+
+    if (IS_DSC(line, "%%Pages:")) {
+       dsc->id = CDSC_PAGES;
+       if (dsc_parse_pages(dsc) != 0)
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%Creator:")) {
+       dsc->id = CDSC_CREATOR;
+       dsc->dsc_creator = dsc_add_line(dsc, dsc->line+10, dsc->line_length-10);
+       if (dsc->dsc_creator==NULL)
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%CreationDate:")) {
+       dsc->id = CDSC_CREATIONDATE;
+       dsc->dsc_date = dsc_add_line(dsc, dsc->line+15, dsc->line_length-15);
+       if (dsc->dsc_date==NULL)
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%Title:")) {
+       dsc->id = CDSC_TITLE;
+       dsc->dsc_title = dsc_add_line(dsc, dsc->line+8, dsc->line_length-8);
+       if (dsc->dsc_title==NULL)
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%For:")) {
+       dsc->id = CDSC_FOR;
+       dsc->dsc_for = dsc_add_line(dsc, dsc->line+6, dsc->line_length-6);
+       if (dsc->dsc_for==NULL)
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%LanguageLevel:")) {
+       unsigned int n = continued ? 3 : 16;
+       unsigned int i;
+       int ll;
+       dsc->id = CDSC_LANGUAGELEVEL;
+       ll = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
+       if (i) {
+           if ( (ll==1) || (ll==2) || (ll==3) )
+               dsc->language_level = ll;
+           else {
+               dsc_unknown(dsc);
+           }
+       }
+       else 
+           dsc_unknown(dsc);
+    }
+    else if (IS_DSC(line, "%%BoundingBox:")) {
+       dsc->id = CDSC_BOUNDINGBOX;
+       if (dsc_parse_bounding_box(dsc, &(dsc->bbox), continued ? 3 : 14))
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%HiResBoundingBox:")) {
+       dsc->id = CDSC_HIRESBOUNDINGBOX;
+       if (dsc_parse_float_bounding_box(dsc, &(dsc->hires_bbox), 
+           continued ? 3 : 19))
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%CropBox:")) {
+       dsc->id = CDSC_CROPBOX;
+       if (dsc_parse_float_bounding_box(dsc, &(dsc->crop_box), 
+           continued ? 3 : 10))
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%Orientation:")) {
+       dsc->id = CDSC_ORIENTATION;
+       if (dsc_parse_orientation(dsc, &(dsc->page_orientation), 
+               continued ? 3 : 14))
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%PageOrder:")) {
+       dsc->id = CDSC_PAGEORDER;
+       if (dsc_parse_order(dsc))
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%DocumentMedia:")) {
+       dsc->id = CDSC_DOCUMENTMEDIA;
+       if (dsc_parse_document_media(dsc))
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%DocumentPaperSizes:")) {
+       /* DSC 2.1 */
+       unsigned int n = continued ? 3 : 21;
+       unsigned int count = 0;
+       unsigned int i = 1;
+       char name[MAXSTR];
+       char *p;
+       dsc->id = CDSC_DOCUMENTPAPERSIZES;
+       while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) {
+           p = dsc_copy_string(name, sizeof(name)-1,
+                   dsc->line+n, dsc->line_length-n, &i);
+           if (i && p) {
+               const CDSCMEDIA *m = dsc_known_media;
+               if (count >= dsc->media_count) {
+                   /* set some default values */
+                   CDSCMEDIA lmedia;
+                   lmedia.name = p;
+                   lmedia.width = 595.0;
+                   lmedia.height = 842.0;
+                   lmedia.weight = 80.0;
+                   lmedia.colour = NULL;
+                   lmedia.type = NULL;
+                   lmedia.mediabox = NULL;
+                   if (dsc_add_media(dsc, &lmedia))
+                       return CDSC_ERROR;
+               }
+               else
+                   dsc->media[count]->name = 
+                       dsc_alloc_string(dsc, p, strlen(p));
+               /* find in list of known media */
+               while (m && m->name) {
+                   if (dsc_stricmp(p, m->name)==0) {
+                       dsc->media[count]->width = m->width;
+                       dsc->media[count]->height = m->height;
+                       break;
+                   }
+                   m++;
+               }
+           }
+           n+=i;
+           count++;
+       }
+    }
+    else if (IS_DSC(line, "%%DocumentPaperForms:")) {
+       /* DSC 2.1 */
+       unsigned int n = continued ? 3 : 21;
+       unsigned int count = 0;
+       unsigned int i = 1;
+       char type[MAXSTR];
+       char *p;
+       dsc->id = CDSC_DOCUMENTPAPERFORMS;
+       while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) {
+           p = dsc_copy_string(type, sizeof(type)-1,
+                   dsc->line+n, dsc->line_length-n, &i);
+           if (i && p) {
+               if (count >= dsc->media_count) {
+                   /* set some default values */
+                   CDSCMEDIA lmedia;
+                   lmedia.name = NULL;
+                   lmedia.width = 595.0;
+                   lmedia.height = 842.0;
+                   lmedia.weight = 80.0;
+                   lmedia.colour = NULL;
+                   lmedia.type = p;
+                   lmedia.mediabox = NULL;
+                   if (dsc_add_media(dsc, &lmedia))
+                       return CDSC_ERROR;
+               }
+               else
+                   dsc->media[count]->type = 
+                       dsc_alloc_string(dsc, p, strlen(p));
+           }
+           n+=i;
+           count++;
+       }
+    }
+    else if (IS_DSC(line, "%%DocumentPaperColors:")) {
+       /* DSC 2.1 */
+       unsigned int n = continued ? 3 : 22;
+       unsigned int count = 0;
+       unsigned int i = 1;
+       char colour[MAXSTR];
+       char *p;
+       dsc->id = CDSC_DOCUMENTPAPERCOLORS;
+       while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) {
+           p = dsc_copy_string(colour, sizeof(colour)-1, 
+                   dsc->line+n, dsc->line_length-n, &i);
+           if (i && p) {
+               if (count >= dsc->media_count) {
+                   /* set some default values */
+                   CDSCMEDIA lmedia;
+                   lmedia.name = NULL;
+                   lmedia.width = 595.0;
+                   lmedia.height = 842.0;
+                   lmedia.weight = 80.0;
+                   lmedia.colour = p;
+                   lmedia.type = NULL;
+                   lmedia.mediabox = NULL;
+                   if (dsc_add_media(dsc, &lmedia))
+                       return CDSC_ERROR;
+               }
+               else
+                   dsc->media[count]->colour = 
+                       dsc_alloc_string(dsc, p, strlen(p));
+           }
+           n+=i;
+           count++;
+       }
+    }
+    else if (IS_DSC(line, "%%DocumentPaperWeights:")) {
+       /* DSC 2.1 */
+       unsigned int n = continued ? 3 : 23;
+       unsigned int count = 0;
+       unsigned int i = 1;
+       float w;
+       dsc->id = CDSC_DOCUMENTPAPERWEIGHTS;
+       while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) {
+           w = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+           if (i) {
+               if (count >= dsc->media_count) {
+                   /* set some default values */
+                   CDSCMEDIA lmedia;
+                   lmedia.name = NULL;
+                   lmedia.width = 595.0;
+                   lmedia.height = 842.0;
+                   lmedia.weight = w;
+                   lmedia.colour = NULL;
+                   lmedia.type = NULL;
+                   lmedia.mediabox = NULL;
+                   if (dsc_add_media(dsc, &lmedia))
+                       return CDSC_ERROR;
+               }
+               else
+                   dsc->media[count]->weight = w;
+           }
+           n+=i;
+           count++;
+       }
+    }
+    else if (IS_DSC(line, "%%DocumentData:")) {
+       unsigned int n = continued ? 3 : 15;
+       char *p = dsc->line + n;
+        while (IS_WHITE(*p))
+           p++;
+       dsc->id = CDSC_DOCUMENTDATA;
+       if (COMPARE(p, "Clean7Bit"))
+           dsc->document_data = CDSC_CLEAN7BIT;
+       else if (COMPARE(p, "Clean8Bit"))
+           dsc->document_data = CDSC_CLEAN8BIT;
+       else if (COMPARE(p, "Binary"))
+           dsc->document_data = CDSC_BINARY;
+       else
+           dsc_unknown(dsc);
+    }
+    else if (IS_DSC(line, "%%Requirements:")) {
+       dsc->id = CDSC_REQUIREMENTS;
+       /* ignore */
+    }
+    else if (IS_DSC(line, "%%DocumentNeededFonts:")) {
+       dsc->id = CDSC_DOCUMENTNEEDEDFONTS;
+       /* ignore */
+    }
+    else if (IS_DSC(line, "%%DocumentSuppliedFonts:")) {
+       dsc->id = CDSC_DOCUMENTSUPPLIEDFONTS;
+       /* ignore */
+    }
+    else if (dsc->line[0] == '%' && IS_WHITE_OR_EOL(dsc->line[1])) {
+       dsc->id = CDSC_OK;
+       /* ignore */
+    }
+    else {
+       dsc->id = CDSC_UNKNOWNDSC;
+       dsc_unknown(dsc);
+    }
+
+    dsc->endcomments = DSC_END(dsc);
+    return CDSC_OK;
+}
+
+
+dsc_private int 
+dsc_scan_preview(CDSC *dsc)
+{
+    /* Preview section ends at */
+    /*  %%EndPreview */
+    /*  another section */
+    /* Preview section must start with %%BeginPreview */
+    char *line = dsc->line;
+    dsc->id = CDSC_OK;
+
+    if (dsc->scan_section == scan_pre_preview) {
+       if (IS_BLANK(line))
+           return CDSC_OK;     /* ignore blank lines before preview */
+       else if (IS_DSC(line, "%%BeginPreview")) {
+           dsc->id = CDSC_BEGINPREVIEW;
+           dsc->beginpreview = DSC_START(dsc);
+           dsc->endpreview = DSC_END(dsc);
+           dsc->scan_section = scan_preview;
+           /* Don't mark the preview as EPSI if a DOS EPS header is present */
+           if (dsc->preview == CDSC_NOPREVIEW)
+               dsc->preview = CDSC_EPSI;
+           return CDSC_OK;
+       }
+       else {
+           dsc->scan_section = scan_pre_defaults;
+           return CDSC_PROPAGATE;
+       }
+    }
+
+    if (IS_DSC(line, "%%BeginPreview")) {
+       /* ignore because we are in this section */
+    }
+    else if (dsc_is_section(line)) {
+       dsc->endpreview = DSC_START(dsc);
+       dsc->scan_section = scan_pre_defaults;
+       return CDSC_PROPAGATE;
+    }
+    else if (IS_DSC(line, "%%EndPreview")) {
+       dsc->id = CDSC_ENDPREVIEW;
+       dsc->endpreview = DSC_END(dsc);
+       dsc->scan_section = scan_pre_defaults;
+       return CDSC_OK;
+    }
+    else if (line[0] == '%' && line[1] != '%') {
+       /* Ordinary comments are OK */
+    }
+    else {
+       dsc->id = CDSC_UNKNOWNDSC;
+       /* DSC comments should not occur in preview */
+       dsc_unknown(dsc);
+    }
+
+    dsc->endpreview = DSC_END(dsc);
+    return CDSC_OK;
+}
+
+dsc_private int
+dsc_scan_defaults(CDSC *dsc)
+{
+    /* Defaults section ends at */
+    /*  %%EndDefaults */
+    /*  another section */
+    /* Defaults section must start with %%BeginDefaults */
+    char *line = dsc->line;
+    dsc->id = CDSC_OK;
+
+    if (dsc->scan_section == scan_pre_defaults) {
+       if (IS_BLANK(line))
+           return CDSC_OK;     /* ignore blank lines before defaults */
+       else if (IS_DSC(line, "%%BeginDefaults")) {
+           dsc->id = CDSC_BEGINDEFAULTS;
+           dsc->begindefaults = DSC_START(dsc);
+           dsc->enddefaults = DSC_END(dsc);
+           dsc->scan_section = scan_defaults;
+           return CDSC_OK;
+       }
+       else {
+           dsc->scan_section = scan_pre_prolog;
+           return CDSC_PROPAGATE;
+       }
+    }
+
+    if (NOT_DSC_LINE(line)) {
+       /* ignore */
+    }
+    else if (IS_DSC(line, "%%BeginPreview")) {
+       /* ignore because we have already processed this section */
+    }
+    else if (IS_DSC(line, "%%BeginDefaults")) {
+       /* ignore because we are in this section */
+    }
+    else if (dsc_is_section(line)) {
+       dsc->enddefaults = DSC_START(dsc);
+       dsc->scan_section = scan_pre_prolog;
+       return CDSC_PROPAGATE;
+    }
+    else if (IS_DSC(line, "%%EndDefaults")) {
+       dsc->id = CDSC_ENDDEFAULTS;
+       dsc->enddefaults = DSC_END(dsc);
+       dsc->scan_section = scan_pre_prolog;
+       return CDSC_OK;
+    }
+    else if (IS_DSC(line, "%%PageMedia:")) {
+       dsc->id = CDSC_PAGEMEDIA;
+       dsc_parse_media(dsc, &dsc->page_media);
+    }
+    else if (IS_DSC(line, "%%PageOrientation:")) {
+       dsc->id = CDSC_PAGEORIENTATION;
+       /* This can override %%Orientation:  */
+       if (dsc_parse_orientation(dsc, &(dsc->page_orientation), 18))
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%PageBoundingBox:")) {
+       dsc->id = CDSC_PAGEBOUNDINGBOX;
+       if (dsc_parse_bounding_box(dsc, &(dsc->page_bbox), 18))
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%ViewingOrientation:")) {
+       dsc->id = CDSC_VIEWINGORIENTATION;
+       if (dsc_parse_viewing_orientation(dsc, &dsc->viewing_orientation))
+           return CDSC_ERROR;
+    }
+    else {
+       dsc->id = CDSC_UNKNOWNDSC;
+       /* All other DSC comments are unknown, but not an error */
+       dsc_unknown(dsc);
+    }
+    dsc->enddefaults = DSC_END(dsc);
+    return CDSC_OK;
+}
+
+/* CDSC_RESPONSE_OK and CDSC_RESPONSE_CANCEL mean ignore the 
+ * mismatch (default) */
+dsc_private int
+dsc_check_match_prompt(CDSC *dsc, const char *str, int count)
+{
+    if (count != 0) {
+       char buf[MAXSTR+MAXSTR] = "";
+       if (dsc->line_length < (unsigned int)(sizeof(buf)/2-1))  {
+           strncpy(buf, dsc->line, dsc->line_length);
+           buf[dsc->line_length] = '\0';
+       }
+       sprintf(buf+strlen(buf), "\n%%%%Begin%.40s: / %%%%End%.40s\n", str, str);
+       return dsc_error(dsc, CDSC_MESSAGE_BEGIN_END, buf, strlen(buf));
+    }
+    return CDSC_RESPONSE_CANCEL;
+}
+
+dsc_private int
+dsc_check_match_type(CDSC *dsc, const char *str, int count)
+{
+    if (dsc_check_match_prompt(dsc, str, count) == CDSC_RESPONSE_IGNORE_ALL)
+       return CDSC_NOTDSC;
+    return CDSC_OK;
+}
+
+/* complain if Begin/End blocks didn't match */
+/* return non-zero if we should ignore all DSC */
+dsc_private int
+dsc_check_match(CDSC *dsc)
+{
+    int rc = 0;
+    const char *font = "Font";
+    const char *feature = "Feature";
+    const char *resource = "Resource";
+    const char *procset = "ProcSet";
+
+    if (!rc)
+       rc = dsc_check_match_type(dsc, font, dsc->begin_font_count);
+    if (!rc)
+       rc = dsc_check_match_type(dsc, feature, dsc->begin_feature_count);
+    if (!rc)
+       rc = dsc_check_match_type(dsc, resource, dsc->begin_resource_count);
+    if (!rc)
+       rc = dsc_check_match_type(dsc, procset, dsc->begin_procset_count);
+
+    dsc->begin_font_count = 0;
+    dsc->begin_feature_count = 0;
+    dsc->begin_resource_count = 0;
+    dsc->begin_procset_count = 0;
+    return rc;
+}
+
+
+dsc_private int 
+dsc_scan_prolog(CDSC *dsc)
+{
+    /* Prolog section ends at */
+    /*  %%EndProlog */
+    /*  another section */
+    /* Prolog section may start with %%BeginProlog or non-dsc line */
+    char *line = dsc->line;
+    dsc->id = CDSC_OK;
+
+    if (dsc->scan_section == scan_pre_prolog) {
+        if (dsc_is_section(line) && (!IS_DSC(line, "%%BeginProlog"))) {
+           dsc->scan_section = scan_pre_setup;
+           return CDSC_PROPAGATE;
+       }
+       dsc->id = CDSC_BEGINPROLOG;
+       dsc->beginprolog = DSC_START(dsc);
+       dsc->endprolog = DSC_END(dsc);
+       dsc->scan_section = scan_prolog;
+       if (IS_DSC(line, "%%BeginProlog"))
+           return CDSC_OK;
+    }
+   
+    if (NOT_DSC_LINE(line)) {
+       /* ignore */
+    }
+    else if (IS_DSC(line, "%%BeginPreview")) {
+       /* ignore because we have already processed this section */
+    }
+    else if (IS_DSC(line, "%%BeginDefaults")) {
+       /* ignore because we have already processed this section */
+    }
+    else if (IS_DSC(line, "%%BeginProlog")) {
+       /* ignore because we are in this section */
+    }
+    else if (dsc_is_section(line)) {
+       dsc->endprolog = DSC_START(dsc);
+       dsc->scan_section = scan_pre_setup;
+       if (dsc_check_match(dsc))
+           return CDSC_NOTDSC;
+       return CDSC_PROPAGATE;
+    }
+    else if (IS_DSC(line, "%%EndProlog")) {
+       dsc->id = CDSC_ENDPROLOG;
+       dsc->endprolog = DSC_END(dsc);
+       dsc->scan_section = scan_pre_setup;
+       if (dsc_check_match(dsc))
+           return CDSC_NOTDSC;
+       return CDSC_OK;
+    }
+    else if (IS_DSC(line, "%%BeginFont:")) {
+       dsc->id = CDSC_BEGINFONT;
+       /* ignore Begin/EndFont, apart form making sure */
+       /* that they are matched. */
+       dsc->begin_font_count++;
+    }
+    else if (IS_DSC(line, "%%EndFont")) {
+       dsc->id = CDSC_ENDFONT;
+       dsc->begin_font_count--;
+    }
+    else if (IS_DSC(line, "%%BeginFeature:")) {
+       dsc->id = CDSC_BEGINFEATURE;
+       /* ignore Begin/EndFeature, apart form making sure */
+       /* that they are matched. */
+       dsc->begin_feature_count++;
+    }
+    else if (IS_DSC(line, "%%EndFeature")) {
+       dsc->id = CDSC_ENDFEATURE;
+       dsc->begin_feature_count--;
+    }
+    else if (IS_DSC(line, "%%BeginResource:")) {
+       dsc->id = CDSC_BEGINRESOURCE;
+       /* ignore Begin/EndResource, apart form making sure */
+       /* that they are matched. */
+       dsc->begin_resource_count++;
+    }
+    else if (IS_DSC(line, "%%EndResource")) {
+       dsc->id = CDSC_ENDRESOURCE;
+       dsc->begin_resource_count--;
+    }
+    else if (IS_DSC(line, "%%BeginProcSet:")) {
+       dsc->id = CDSC_BEGINPROCSET;
+       /* ignore Begin/EndProcSet, apart form making sure */
+       /* that they are matched. */
+       dsc->begin_procset_count++;
+    }
+    else if (IS_DSC(line, "%%EndProcSet")) {
+       dsc->id = CDSC_ENDPROCSET;
+       dsc->begin_procset_count--;
+    }
+    else {
+       /* All other DSC comments are unknown, but not an error */
+       dsc->id = CDSC_UNKNOWNDSC;
+       dsc_unknown(dsc);
+    }
+
+    dsc->endprolog = DSC_END(dsc);
+    return CDSC_OK;
+}
+
+dsc_private int
+dsc_scan_setup(CDSC *dsc)
+{
+    /* Setup section ends at */
+    /*  %%EndSetup */
+    /*  another section */
+    /* Setup section must start with %%BeginSetup */
+
+    char *line = dsc->line;
+    dsc->id = CDSC_OK;
+
+    if (dsc->scan_section == scan_pre_setup) {
+       if (IS_BLANK(line))
+           return CDSC_OK;     /* ignore blank lines before setup */
+       else if (IS_DSC(line, "%%BeginSetup")) {
+           dsc->id = CDSC_BEGINSETUP;
+           dsc->beginsetup = DSC_START(dsc);
+           dsc->endsetup = DSC_END(dsc);
+           dsc->scan_section = scan_setup;
+           return CDSC_OK;
+       }
+       else {
+           dsc->scan_section = scan_pre_pages;
+           return CDSC_PROPAGATE;
+       }
+    }
+
+    if (NOT_DSC_LINE(line)) {
+       /* ignore */
+    }
+    else if (IS_DSC(line, "%%BeginPreview")) {
+       /* ignore because we have already processed this section */
+    }
+    else if (IS_DSC(line, "%%BeginDefaults")) {
+       /* ignore because we have already processed this section */
+    }
+    else if (IS_DSC(line, "%%BeginProlog")) {
+       /* ignore because we have already processed this section */
+    }
+    else if (IS_DSC(line, "%%BeginSetup")) {
+       /* ignore because we are in this section */
+    }
+    else if (dsc_is_section(line)) {
+       dsc->endsetup = DSC_START(dsc);
+       dsc->scan_section = scan_pre_pages;
+       if (dsc_check_match(dsc))
+           return CDSC_NOTDSC;
+       return CDSC_PROPAGATE;
+    }
+    else if (IS_DSC(line, "%%EndSetup")) {
+       dsc->id = CDSC_ENDSETUP;
+       dsc->endsetup = DSC_END(dsc);
+       dsc->scan_section = scan_pre_pages;
+       if (dsc_check_match(dsc))
+           return CDSC_NOTDSC;
+       return CDSC_OK;
+    }
+    else if (IS_DSC(line, "%%BeginFeature:")) {
+       dsc->id = CDSC_BEGINFEATURE;
+       /* ignore Begin/EndFeature, apart form making sure */
+       /* that they are matched. */
+       dsc->begin_feature_count++;
+    }
+    else if (IS_DSC(line, "%%EndFeature")) {
+       dsc->id = CDSC_ENDFEATURE;
+       dsc->begin_feature_count--;
+    }
+    else if (IS_DSC(line, "%%Feature:")) {
+       dsc->id = CDSC_FEATURE;
+       /* ignore */
+    }
+    else if (IS_DSC(line, "%%BeginResource:")) {
+       dsc->id = CDSC_BEGINRESOURCE;
+       /* ignore Begin/EndResource, apart form making sure */
+       /* that they are matched. */
+       dsc->begin_resource_count++;
+    }
+    else if (IS_DSC(line, "%%EndResource")) {
+       dsc->id = CDSC_ENDRESOURCE;
+       dsc->begin_resource_count--;
+    }
+    else if (IS_DSC(line, "%%PaperColor:")) {
+       dsc->id = CDSC_PAPERCOLOR;
+       /* ignore */
+    }
+    else if (IS_DSC(line, "%%PaperForm:")) {
+       dsc->id = CDSC_PAPERFORM;
+       /* ignore */
+    }
+    else if (IS_DSC(line, "%%PaperWeight:")) {
+       dsc->id = CDSC_PAPERWEIGHT;
+       /* ignore */
+    }
+    else if (IS_DSC(line, "%%PaperSize:")) {
+       /* DSC 2.1 */
+        GSBOOL found_media = FALSE;
+       int i;
+       int n = 12;
+       char buf[MAXSTR];
+       buf[0] = '\0';
+       dsc->id = CDSC_PAPERSIZE;
+       dsc_copy_string(buf, sizeof(buf)-1, dsc->line+n, dsc->line_length-n, 
+               NULL);
+       for (i=0; i<(int)dsc->media_count; i++) {
+           if (dsc->media[i] && dsc->media[i]->name && 
+               (dsc_stricmp(buf, dsc->media[i]->name)==0)) {
+               dsc->page_media = dsc->media[i];
+               found_media = TRUE;
+               break;
+           }
+       }
+       if (!found_media) {
+           /* It didn't match %%DocumentPaperSizes: */
+           /* Try our known media */
+           const CDSCMEDIA *m = dsc_known_media;
+           while (m->name) {
+               if (dsc_stricmp(buf, m->name)==0) {
+                   dsc->page_media = m;
+                   break;
+               }
+               m++;
+           }
+           if (m->name == NULL)
+               dsc_unknown(dsc);
+       }
+    }
+    else {
+       /* All other DSC comments are unknown, but not an error */
+       dsc->id = CDSC_UNKNOWNDSC;
+       dsc_unknown(dsc);
+    }
+
+    dsc->endsetup = DSC_END(dsc);
+    return CDSC_OK;
+}
+
+dsc_private int 
+dsc_scan_page(CDSC *dsc)
+{
+    /* Page section ends at */
+    /*  %%Page */
+    /*  %%Trailer */
+    /*  %%EOF */
+    char *line = dsc->line;
+    dsc->id = CDSC_OK;
+
+    if (dsc->scan_section == scan_pre_pages) {
+       if (IS_DSC(line, "%%Page:")) {
+           dsc->scan_section = scan_pages;
+           /* fall through */
+       }
+       else  {
+           /* %%Page: didn't follow %%EndSetup
+            * Keep reading until reach %%Page or %%Trailer
+            * and add it to previous section.
+            */
+           unsigned long *last;
+           if (dsc->endsetup != 0)
+               last = &dsc->endsetup;
+           else if (dsc->endprolog != 0)
+               last = &dsc->endprolog;
+           else if (dsc->enddefaults != 0)
+               last = &dsc->enddefaults;
+           else if (dsc->endpreview != 0)
+               last = &dsc->endpreview;
+           else if (dsc->endcomments != 0)
+               last = &dsc->endcomments;
+           else
+               last = &dsc->begincomments;
+           *last = DSC_START(dsc);
+           if (IS_DSC(line, "%%Trailer") || IS_DSC(line, "%%EOF")) {
+               dsc->scan_section = scan_pre_trailer;
+               return CDSC_PROPAGATE;
+           }
+           return CDSC_OK;
+       }
+    }
+
+    if (NOT_DSC_LINE(line)) {
+       /* ignore */
+    }
+    else if (IS_DSC(line, "%%Page:")) {
+       dsc->id = CDSC_PAGE;
+       if (dsc->page_count) {
+           dsc->page[dsc->page_count-1].end = DSC_START(dsc);
+           if (dsc_check_match(dsc))
+               return CDSC_NOTDSC;
+       }
+
+       if (dsc_parse_page(dsc) != 0)
+           return CDSC_ERROR;
+
+       return CDSC_OK;
+    }
+    else if (IS_DSC(line, "%%BeginPreview")) {
+       /* ignore because we have already processed this section */
+    }
+    else if (IS_DSC(line, "%%BeginDefaults")) {
+       /* ignore because we have already processed this section */
+    }
+    else if (IS_DSC(line, "%%BeginProlog")) {
+       /* ignore because we have already processed this section */
+    }
+    else if (IS_DSC(line, "%%BeginSetup")) {
+       /* ignore because we have already processed this section */
+    }
+    else if (dsc_is_section(line)) {
+       if (IS_DSC(line, "%%Trailer")) {
+           dsc->page[dsc->page_count-1].end = DSC_START(dsc);
+           if (dsc->file_length) {
+               if ((!dsc->doseps && 
+                       ((DSC_END(dsc) + 32768) < dsc->file_length)) ||
+                    ((dsc->doseps) && 
+                       ((DSC_END(dsc) + 32768) < dsc->doseps_end))) {
+                   int rc = dsc_error(dsc, CDSC_MESSAGE_EARLY_TRAILER, 
+                       dsc->line, dsc->line_length);
+                   switch (rc) {
+                       case CDSC_RESPONSE_OK:
+                           /* ignore early trailer */
+                           break;
+                       case CDSC_RESPONSE_CANCEL:
+                           /* this is the trailer */
+                           dsc->scan_section = scan_pre_trailer;
+                           if (dsc_check_match(dsc))
+                               return CDSC_NOTDSC;
+                           return CDSC_PROPAGATE;
+                       case CDSC_RESPONSE_IGNORE_ALL:
+                           return CDSC_NOTDSC;
+                   }
+               }
+               else {
+                   dsc->scan_section = scan_pre_trailer;
+                   if (dsc_check_match(dsc))
+                       return CDSC_NOTDSC;
+                   return CDSC_PROPAGATE;
+               }
+           }
+           else {
+               dsc->scan_section = scan_pre_trailer;
+               if (dsc_check_match(dsc))
+                   return CDSC_NOTDSC;
+               return CDSC_PROPAGATE;
+           }
+       }
+       else if (IS_DSC(line, "%%EOF")) {
+           dsc->page[dsc->page_count-1].end = DSC_START(dsc);
+           if (dsc->file_length) {
+               if ((DSC_END(dsc)+100 < dsc->file_length) ||
+                   (dsc->doseps && (DSC_END(dsc) + 100 < dsc->doseps_end))) {
+                   int rc = dsc_error(dsc, CDSC_MESSAGE_EARLY_EOF, 
+                       dsc->line, dsc->line_length);
+                   switch (rc) {
+                       case CDSC_RESPONSE_OK:
+                           /* %%EOF is wrong, ignore it */
+                           break;
+                       case CDSC_RESPONSE_CANCEL:
+                           /* %%EOF is correct */
+                           dsc->scan_section = scan_eof;
+                           dsc->eof = TRUE;
+                           if (dsc_check_match(dsc))
+                               return CDSC_NOTDSC;
+                           return CDSC_PROPAGATE;
+                       case CDSC_RESPONSE_IGNORE_ALL:
+                           return CDSC_NOTDSC;
+                   }
+               }
+           }
+           else {
+               /* ignore it */
+               if (dsc_check_match(dsc))
+                   return CDSC_NOTDSC;
+               return CDSC_OK;
+           }
+       }
+       else {
+           /* Section comment, probably from a badly */
+           /* encapsulated EPS file. */
+           int rc = dsc_error(dsc, CDSC_MESSAGE_BAD_SECTION, 
+                   dsc->line, dsc->line_length);
+           if (rc == CDSC_RESPONSE_IGNORE_ALL)
+               return CDSC_NOTDSC;
+       }
+    }
+    else if (IS_DSC(line, "%%PageTrailer")) {
+       dsc->id = CDSC_PAGETRAILER;
+       /* ignore */
+    }
+    else if (IS_DSC(line, "%%BeginPageSetup")) {
+       dsc->id = CDSC_BEGINPAGESETUP;
+       /* ignore */
+    }
+    else if (IS_DSC(line, "%%EndPageSetup")) {
+       dsc->id = CDSC_ENDPAGESETUP;
+       /* ignore */
+    }
+    else if (IS_DSC(line, "%%PageMedia:")) {
+       dsc->id = CDSC_PAGEMEDIA;
+       dsc_parse_media(dsc, &(dsc->page[dsc->page_count-1].media));
+    }
+    else if (IS_DSC(line, "%%PaperColor:")) {
+       dsc->id = CDSC_PAPERCOLOR;
+       /* ignore */
+    }
+    else if (IS_DSC(line, "%%PaperForm:")) {
+       dsc->id = CDSC_PAPERFORM;
+       /* ignore */
+    }
+    else if (IS_DSC(line, "%%PaperWeight:")) {
+       dsc->id = CDSC_PAPERWEIGHT;
+       /* ignore */
+    }
+    else if (IS_DSC(line, "%%PaperSize:")) {
+       /* DSC 2.1 */
+        GSBOOL found_media = FALSE;
+       int i;
+       int n = 12;
+       char buf[MAXSTR];
+       buf[0] = '\0';
+       dsc_copy_string(buf, sizeof(buf)-1, dsc->line+n, 
+           dsc->line_length-n, NULL);
+       for (i=0; i<(int)dsc->media_count; i++) {
+           if (dsc->media[i] && dsc->media[i]->name && 
+               (dsc_stricmp(buf, dsc->media[i]->name)==0)) {
+               dsc->page_media = dsc->media[i];
+               found_media = TRUE;
+               break;
+           }
+       }
+       if (!found_media) {
+           /* It didn't match %%DocumentPaperSizes: */
+           /* Try our known media */
+           const CDSCMEDIA *m = dsc_known_media;
+           while (m->name) {
+               if (dsc_stricmp(buf, m->name)==0) {
+                   dsc->page[dsc->page_count-1].media = m;
+                   break;
+               }
+               m++;
+           }
+           if (m->name == NULL)
+               dsc_unknown(dsc);
+       }
+    }
+    else if (IS_DSC(line, "%%PageOrientation:")) {
+       dsc->id = CDSC_PAGEORIENTATION;
+       if (dsc_parse_orientation(dsc, 
+               &(dsc->page[dsc->page_count-1].orientation) ,18))
+           return CDSC_NOTDSC;
+    }
+    else if (IS_DSC(line, "%%PageBoundingBox:")) {
+       dsc->id = CDSC_PAGEBOUNDINGBOX;
+       if (dsc_parse_bounding_box(dsc, &dsc->page[dsc->page_count-1].bbox, 18))
+           return CDSC_NOTDSC;
+    }
+    else if (IS_DSC(line, "%%ViewingOrientation:")) {
+       dsc->id = CDSC_VIEWINGORIENTATION;
+       if (dsc_parse_viewing_orientation(dsc, 
+           &dsc->page[dsc->page_count-1].viewing_orientation))
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%BeginFont:")) {
+       dsc->id = CDSC_BEGINFONT;
+       /* ignore Begin/EndFont, apart form making sure */
+       /* that they are matched. */
+       dsc->begin_font_count++;
+    }
+    else if (IS_DSC(line, "%%EndFont")) {
+       dsc->id = CDSC_BEGINFONT;
+       dsc->begin_font_count--;
+    }
+    else if (IS_DSC(line, "%%BeginFeature:")) {
+       dsc->id = CDSC_BEGINFEATURE;
+       /* ignore Begin/EndFeature, apart form making sure */
+       /* that they are matched. */
+       dsc->begin_feature_count++;
+    }
+    else if (IS_DSC(line, "%%EndFeature")) {
+       dsc->id = CDSC_ENDFEATURE;
+       dsc->begin_feature_count--;
+    }
+    else if (IS_DSC(line, "%%BeginResource:")) {
+       dsc->id = CDSC_BEGINRESOURCE;
+       /* ignore Begin/EndResource, apart form making sure */
+       /* that they are matched. */
+       dsc->begin_resource_count++;
+    }
+    else if (IS_DSC(line, "%%EndResource")) {
+       dsc->id = CDSC_ENDRESOURCE;
+       dsc->begin_resource_count--;
+    }
+    else if (IS_DSC(line, "%%BeginProcSet:")) {
+       dsc->id = CDSC_BEGINPROCSET;
+       /* ignore Begin/EndProcSet, apart form making sure */
+       /* that they are matched. */
+       dsc->begin_procset_count++;
+    }
+    else if (IS_DSC(line, "%%EndProcSet")) {
+       dsc->id = CDSC_ENDPROCSET;
+       dsc->begin_procset_count--;
+    }
+    else if (IS_DSC(line, "%%IncludeFont:")) {
+       dsc->id = CDSC_INCLUDEFONT;
+       /* ignore */
+    }
+    else {
+       /* All other DSC comments are unknown, but not an error */
+       dsc->id = CDSC_UNKNOWNDSC;
+       dsc_unknown(dsc);
+    }
+
+    dsc->page[dsc->page_count-1].end = DSC_END(dsc);
+    return CDSC_OK;
+}
+
+/* Valid Trailer comments are
+ * %%Trailer
+ * %%EOF
+ * or the following deferred with (atend)
+ * %%BoundingBox:
+ * %%DocumentCustomColors:
+ * %%DocumentFiles:
+ * %%DocumentFonts:
+ * %%DocumentNeededFiles:
+ * %%DocumentNeededFonts:
+ * %%DocumentNeededProcSets:
+ * %%DocumentNeededResources:
+ * %%DocumentProcSets:
+ * %%DocumentProcessColors:
+ * %%DocumentSuppliedFiles:
+ * %%DocumentSuppliedFonts:
+ * %%DocumentSuppliedProcSets: 
+ * %%DocumentSuppliedResources: 
+ * %%Orientation: 
+ * %%Pages: 
+ * %%PageOrder: 
+ *
+ * Our supported subset is
+ * %%Trailer
+ * %%EOF
+ * %%BoundingBox:
+ * %%Orientation: 
+ * %%Pages: 
+ * %%PageOrder: 
+ * In addition to these, we support
+ * %%DocumentMedia:
+ * 
+ * A %%PageTrailer can have the following:
+ * %%PageBoundingBox: 
+ * %%PageCustomColors: 
+ * %%PageFiles: 
+ * %%PageFonts: 
+ * %%PageOrientation: 
+ * %%PageProcessColors: 
+ * %%PageResources: 
+ */
+
+dsc_private int
+dsc_scan_trailer(CDSC *dsc)
+{
+    /* Trailer section start at */
+    /*  %%Trailer */
+    /* and ends at */
+    /*  %%EOF */
+    char *line = dsc->line;
+    GSBOOL continued = FALSE;
+    dsc->id = CDSC_OK;
+
+    if (dsc->scan_section == scan_pre_trailer) {
+       if (IS_DSC(line, "%%Trailer")) {
+           dsc->id = CDSC_TRAILER;
+           dsc->begintrailer = DSC_START(dsc);
+           dsc->endtrailer = DSC_END(dsc);
+           dsc->scan_section = scan_trailer;
+           return CDSC_OK;
+       }
+       else if (IS_DSC(line, "%%EOF")) {
+           dsc->id = CDSC_EOF;
+           dsc->begintrailer = DSC_START(dsc);
+           dsc->endtrailer = DSC_END(dsc);
+           dsc->scan_section = scan_trailer;
+           /* Continue, in case we found %%EOF in an embedded document */
+           return CDSC_OK;
+       }
+       else {
+           /* %%Page: didn't follow %%EndSetup
+            * Keep reading until reach %%Page or %%Trailer
+            * and add it to setup section
+            */
+           /* append to previous section */
+           if (dsc->beginsetup)
+               dsc->endsetup = DSC_END(dsc);
+           else if (dsc->beginprolog)
+               dsc->endprolog = DSC_END(dsc);
+           else {
+               /* horribly confused */
+           }
+           return CDSC_OK;
+       }
+    }
+
+    /* Handle continuation lines.
+     * See comment above about our restrictive processing of 
+     * continuation lines
+     */
+    if (IS_DSC(line, "%%+")) {
+       line = dsc->last_line;
+       continued = TRUE;
+    }
+    else
+       dsc_save_line(dsc);
+
+    if (NOT_DSC_LINE(line)) {
+       /* ignore */
+    }
+    else if (IS_DSC(dsc->line, "%%EOF")) {
+       /* Keep scanning, in case we have a false trailer */
+       dsc->id = CDSC_EOF;
+    }
+    else if (IS_DSC(dsc->line, "%%Trailer")) {
+       /* Cope with no pages with code after setup and before trailer. */
+       /* Last trailer is the correct one. */
+       dsc->id = CDSC_TRAILER;
+       dsc->begintrailer = DSC_START(dsc);
+    }
+    else if (IS_DSC(line, "%%Pages:")) {
+       dsc->id = CDSC_PAGES;
+       if (dsc_parse_pages(dsc) != 0)
+              return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%BoundingBox:")) {
+       dsc->id = CDSC_BOUNDINGBOX;
+       if (dsc_parse_bounding_box(dsc, &(dsc->bbox), continued ? 3 : 14))
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%HiResBoundingBox:")) {
+       dsc->id = CDSC_HIRESBOUNDINGBOX;
+       if (dsc_parse_float_bounding_box(dsc, &(dsc->hires_bbox), 
+           continued ? 3 : 19))
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%CropBox:")) {
+       dsc->id = CDSC_CROPBOX;
+       if (dsc_parse_float_bounding_box(dsc, &(dsc->crop_box), 
+           continued ? 3 : 10))
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%Orientation:")) {
+       dsc->id = CDSC_ORIENTATION;
+       if (dsc_parse_orientation(dsc, &(dsc->page_orientation), continued ? 3 : 14))
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%PageOrder:")) {
+       dsc->id = CDSC_PAGEORDER;
+       if (dsc_parse_order(dsc))
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(line, "%%DocumentMedia:")) {
+       dsc->id = CDSC_DOCUMENTMEDIA;
+       if (dsc_parse_document_media(dsc))
+           return CDSC_ERROR;
+    }
+    else if (IS_DSC(dsc->line, "%%Page:")) {
+       /* This should not occur in the trailer, but we might see 
+        * this if a document has been incorrectly embedded.
+        */
+       int rc = dsc_error(dsc, CDSC_MESSAGE_PAGE_IN_TRAILER, 
+               dsc->line, dsc->line_length);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+               /* Assume that we are really in the previous */
+               /* page, not the trailer */
+               dsc->scan_section = scan_pre_pages;
+               if (dsc->page_count)
+                   dsc->page[dsc->page_count-1].end = DSC_START(dsc);
+               return CDSC_PROPAGATE;  /* try again */
+           case CDSC_RESPONSE_CANCEL:
+               /* ignore pages in trailer */
+               break;
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+    else if (IS_DSC(line, "%%DocumentNeededFonts:")) {
+       dsc->id = CDSC_DOCUMENTNEEDEDFONTS;
+       /* ignore */
+    }
+    else if (IS_DSC(line, "%%DocumentSuppliedFonts:")) {
+       dsc->id = CDSC_DOCUMENTSUPPLIEDFONTS;
+       /* ignore */
+    }
+    else {
+       /* All other DSC comments are unknown, but not an error */
+       dsc->id = CDSC_UNKNOWNDSC;
+       dsc_unknown(dsc);
+    }
+
+    dsc->endtrailer = DSC_END(dsc);
+    return CDSC_OK;
+}
+
+
+dsc_private char *
+dsc_alloc_string(CDSC *dsc, const char *str, int len)
+{
+    char *p;
+    if (dsc->string_head == NULL) {
+       dsc->string_head = (CDSCSTRING *)dsc_memalloc(dsc, sizeof(CDSCSTRING));
+       if (dsc->string_head == NULL)
+           return NULL;        /* no memory */
+       dsc->string = dsc->string_head;
+       dsc->string->next = NULL;
+       dsc->string->data = (char *)dsc_memalloc(dsc, CDSC_STRING_CHUNK);
+       if (dsc->string->data == NULL) {
+           dsc_reset(dsc);
+           return NULL;        /* no memory */
+       }
+       dsc->string->index = 0;
+       dsc->string->length = CDSC_STRING_CHUNK;
+    }
+    if ( dsc->string->index + len + 1 > dsc->string->length) {
+       /* allocate another string block */
+       CDSCSTRING *newstring = (CDSCSTRING *)dsc_memalloc(dsc, sizeof(CDSCSTRING));
+       if (newstring == NULL) {
+           dsc_debug_print(dsc, "Out of memory\n");
+           return NULL;
+       }
+        newstring->next = NULL;
+       newstring->length = 0;
+       newstring->index = 0;
+       newstring->data = (char *)dsc_memalloc(dsc, CDSC_STRING_CHUNK);
+       if (newstring->data == NULL) {
+           dsc_memfree(dsc, newstring);
+           dsc_debug_print(dsc, "Out of memory\n");
+           return NULL;        /* no memory */
+       }
+       newstring->length = CDSC_STRING_CHUNK;
+       dsc->string->next = newstring;
+       dsc->string = newstring;
+    }
+    if ( dsc->string->index + len + 1 > dsc->string->length)
+       return NULL;    /* failed */
+    p = dsc->string->data + dsc->string->index;
+    memcpy(p, str, len);
+    *(p+len) = '\0';
+    dsc->string->index += len + 1;
+    return p;
+}
+
+/* store line, ignoring leading spaces */
+dsc_private char *
+dsc_add_line(CDSC *dsc, const char *line, unsigned int len)
+{
+    char *newline;
+    unsigned int i;
+    while (len && (IS_WHITE(*line))) {
+       len--;
+       line++;
+    }
+    newline = dsc_alloc_string(dsc, line, len);
+    if (newline == NULL)
+       return NULL;
+
+    for (i=0; i<len; i++) {
+       if (newline[i] == '\r') {
+           newline[i]='\0';
+           break;
+       }
+       if (newline[i] == '\n') {
+           newline[i]='\0';
+           break;
+       }
+    }
+    return newline;
+}
+
+
+/* Copy string on line to new allocated string str */
+/* String is always null terminated */
+/* String is no longer than len */
+/* Return pointer to string  */
+/* Store number of used characters from line */
+/* Don't copy enclosing () */
+dsc_private char *
+dsc_copy_string(char *str, unsigned int slen, char *line, 
+       unsigned int len, unsigned int *offset)
+{
+    int quoted = FALSE;
+    int instring=0;
+    unsigned int newlength = 0;
+    unsigned int i = 0;
+    unsigned char ch;
+    if (len > slen)
+       len = slen-1;
+    while ( (i<len) && IS_WHITE(line[i]))
+       i++;    /* skip leading spaces */
+    if (line[i]=='(') {
+       quoted = TRUE;
+       instring++;
+       i++; /* don't copy outside () */
+    }
+    while (i < len) {
+       str[newlength] = ch = line[i];
+       i++;
+       if (quoted) {
+           if (ch == '(')
+                   instring++;
+           if (ch == ')')
+                   instring--;
+           if (instring==0)
+                   break;
+       }
+       else if (ch == ' ')
+           break;
+
+       if (ch == '\r')
+           break;
+       if (ch == '\n')
+           break;
+       else if ( (ch == '\\') && (i+1 < len) ) {
+           ch = line[i];
+           if ((ch >= '0') && (ch <= '9')) {
+               /* octal coded character */
+               int j = 3;
+               ch = 0;
+               while (j && (i < len) && line[i]>='0' && line[i]<='7') {
+                   ch = (unsigned char)((ch<<3) + (line[i]-'0'));
+                   i++;
+                   j--;
+               }
+               str[newlength] = ch;
+           }
+           else if (ch == '(') {
+               str[newlength] = ch;
+               i++;
+           }
+           else if (ch == ')') {
+               str[newlength] = ch;
+               i++;
+           }
+           else if (ch == 'b') {
+               str[newlength] = '\b';
+               i++;
+           }
+           else if (ch == 'f') {
+               str[newlength] = '\b';
+               i++;
+           }
+           else if (ch == 'n') {
+               str[newlength] = '\n';
+               i++;
+           }
+           else if (ch == 'r') {
+               str[newlength] = '\r';
+               i++;
+           }
+           else if (ch == 't') {
+               str[newlength] = '\t';
+               i++;
+           }
+           else if (ch == '\\') {
+               str[newlength] = '\\';
+               i++;
+           }
+       }
+       newlength++;
+    }
+    str[newlength] = '\0';
+    if (offset != (unsigned int *)NULL)
+        *offset = i;
+    return str;
+}
+
+dsc_private int 
+dsc_get_int(const char *line, unsigned int len, unsigned int *offset)
+{
+    char newline[MAXSTR];
+    int newlength = 0;
+    unsigned int i = 0;
+    unsigned char ch;
+
+    len = min(len, sizeof(newline)-1);
+    while ((i<len) && IS_WHITE(line[i]))
+       i++;    /* skip leading spaces */
+    while (i < len) {
+       newline[newlength] = ch = line[i];
+       if (!(isdigit(ch) || (ch=='-') || (ch=='+')))
+           break;  /* not part of an integer number */
+       i++;
+       newlength++;
+    }
+    while ((i<len) && IS_WHITE(line[i]))
+       i++;    /* skip trailing spaces */
+    newline[newlength] = '\0';
+    if (offset != (unsigned int *)NULL)
+        *offset = i;
+    return atoi(newline);
+}
+
+dsc_private float 
+dsc_get_real(const char *line, unsigned int len, unsigned int *offset)
+{
+    char newline[MAXSTR];
+    int newlength = 0;
+    unsigned int i = 0;
+    unsigned char ch;
+
+    len = min(len, sizeof(newline)-1);
+    while ((i<len) && IS_WHITE(line[i]))
+       i++;    /* skip leading spaces */
+    while (i < len) {
+       newline[newlength] = ch = line[i];
+       if (!(isdigit(ch) || (ch=='.') || (ch=='-') || (ch=='+') 
+           || (ch=='e') || (ch=='E')))
+           break;  /* not part of a real number */
+       i++;
+       newlength++;
+    }
+    while ((i<len) && IS_WHITE(line[i]))
+       i++;    /* skip trailing spaces */
+
+    newline[newlength] = '\0';
+
+    if (offset != (unsigned int *)NULL)
+        *offset = i;
+    return (float)atof(newline);
+}
+
+dsc_private int
+dsc_stricmp(const char *s, const char *t)
+{
+    while (toupper(*s) == toupper(*t)) {
+       if (*s == '\0')
+           return 0;
+       s++;
+       t++; 
+    }
+    return (toupper(*s) - toupper(*t));
+}
+
+
+dsc_private int
+dsc_parse_page(CDSC *dsc)
+{
+    char *p;
+    unsigned int i;
+    char page_label[MAXSTR];
+    char *pl;
+    int page_ordinal;
+    int page_number;
+
+    p = dsc->line + 7;
+    pl = dsc_copy_string(page_label, sizeof(page_label)-1, p, dsc->line_length-7, &i);
+    if (pl == NULL)
+       return CDSC_ERROR;
+    p += i;
+    page_ordinal = atoi(p);
+
+    if ( (page_ordinal == 0) || (strlen(page_label) == 0) ||
+       (dsc->page_count && 
+           (page_ordinal != dsc->page[dsc->page_count-1].ordinal+1)) ) {
+       int rc = dsc_error(dsc, CDSC_MESSAGE_PAGE_ORDINAL, dsc->line, 
+               dsc->line_length);
+       switch (rc) {
+           case CDSC_RESPONSE_OK:
+               /* ignore this page */
+               return CDSC_OK;
+           case CDSC_RESPONSE_CANCEL:
+               /* accept the page */
+               break;
+           case CDSC_RESPONSE_IGNORE_ALL:
+               return CDSC_NOTDSC;
+       }
+    }
+
+    page_number = dsc->page_count;
+    dsc_add_page(dsc, page_ordinal, page_label);
+    dsc->page[page_number].begin = DSC_START(dsc);
+    dsc->page[page_number].end = DSC_START(dsc);
+
+    if (dsc->page[page_number].label == NULL)
+       return CDSC_ERROR;      /* no memory */
+       
+    return CDSC_OK;
+}
+
+
+
+/* DSC error reporting */
+
+void 
+dsc_debug_print(CDSC *dsc, const char *str)
+{
+    if (dsc->debug_print_fn)
+       dsc->debug_print_fn(dsc->caller_data, str);
+}
+
+
+/* Display a message about a problem with the DSC comments.
+ * 
+ * explanation = an index to to a multiline explanation in dsc_message[]
+ * line = pointer to the offending DSC line (if any)
+ * return code = 
+ *   CDSC_RESPONSE_OK         DSC was wrong, make a guess about what 
+ *                             was really meant.
+ *   CDSC_RESPONSE_CANCEL      Assume DSC was correct, ignore if it 
+ *                             is misplaced.
+ *   CDSC_RESPONSE_IGNORE_ALL  Ignore all DSC.
+ */
+/* Silent operation.  Don't display errors. */
+dsc_private int 
+dsc_error(CDSC *dsc, unsigned int explanation, 
+       char *line, unsigned int line_len)
+{
+    /* if error function provided, use it */
+    if (dsc->dsc_error_fn)
+       return dsc->dsc_error_fn(dsc->caller_data, dsc, 
+           explanation, line, line_len);
+
+    /* treat DSC as being correct */
+    return CDSC_RESPONSE_CANCEL;
+}
+
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/thumbnailers/ps/dscparse.h b/thumbnailers/ps/dscparse.h
new file mode 100644 (file)
index 0000000..4463058
--- /dev/null
@@ -0,0 +1,477 @@
+/* Copyright (C) 2000-2001, Ghostgum Software Pty Ltd.  All rights reserved.
+    
+  This file is part of GSview.
+   
+  This file is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
+  to anyone for the consequences of using it or for whether it serves any
+  particular purpose or works at all, unless he says so in writing.  Refer
+  to the GNU General Public License for full details.
+   
+  Everyone is granted permission to copy, modify and redistribute this
+  file, but only under the conditions described in the GNU General
+  Public License.  A copy of this license is supposed to have been given
+  to you along with this file so you can know your rights and
+  responsibilities.  It should be in a file named COPYING.  Among other
+  things, the copyright notice and this notice must be preserved on all
+  copies.
+*/
+
+/* $Id$ */
+
+/* dscparse.h */
+/* Interface for the DSC parser. */
+
+#ifndef _DSCPARSE_H_
+#define _DSCPARSE_H_
+
+/* Some local types that may need modification */
+typedef bool GSBOOL;
+typedef unsigned long GSDWORD; /* must be at least 32 bits */
+typedef unsigned int GSWORD;   /* must be at least 16 bits */
+
+#ifndef FALSE
+# define FALSE ((GSBOOL)0)
+# define TRUE ((GSBOOL)(!FALSE))
+#endif
+
+#ifndef dsc_private
+# ifdef private
+#  define dsc_private private
+# else
+#  define dsc_private static
+# endif
+#endif
+
+#ifndef min
+# define min(a,b)  ((a) < (b) ? (a) : (b))
+#endif
+
+/* macros to allow conversion of function declarations to K&R */
+#ifndef P0
+#define P0() void
+#define P1(t1) t1
+#define P2(t1,t2) t1,t2
+#define P3(t1,t2,t3) t1,t2,t3
+#define P4(t1,t2,t3,t4) t1,t2,t3,t4
+#define P5(t1,t2,t3,t4,t5) t1,t2,t3,t4,t5
+#define P6(t1,t2,t3,t4,t5,t6) t1,t2,t3,t4,t5,t6
+#endif
+
+/* maximum legal length of lines in a DSC compliant file */
+#define DSC_LINE_LENGTH 255
+
+/* memory for strings is allocated in chunks of this length */
+#define CDSC_STRING_CHUNK 4096
+
+/* page array is allocated in chunks of this many pages */
+#define CDSC_PAGE_CHUNK 128    
+
+/* buffer length for storing lines passed to dsc_scan_data() */
+/* must be at least 2 * DSC_LINE_LENGTH */
+/* We choose 8192 as twice the length passed to us by GSview */
+#define CDSC_DATA_LENGTH 8192
+
+/* Return codes from dsc_scan_data()
+ *  < 0     = error
+ *  >=0     = OK
+ *
+ *  -1      = error, usually insufficient memory.
+ *  0-9     = normal
+ *  10-99   = internal codes, should not be seen.
+ *  100-999 = identifier of last DSC comment processed.
+ */
+
+typedef enum {
+  CDSC_ERROR           = -1,   /* Fatal error, usually insufficient memory */
+
+  CDSC_OK              = 0,    /* OK, no DSC comment found */
+  CDSC_NOTDSC          = 1,    /* Not DSC, or DSC is being ignored */
+
+/* Any section */
+  CDSC_UNKNOWNDSC      = 100,  /* DSC comment not recognised */
+
+/* Header section */
+  CDSC_PSADOBE         = 200,  /* %!PS-Adobe- */
+  CDSC_BEGINCOMMENTS   = 201,  /* %%BeginComments */
+  CDSC_ENDCOMMENTS     = 202,  /* %%EndComments */
+  CDSC_PAGES           = 203,  /* %%Pages: */
+  CDSC_CREATOR         = 204,  /* %%Creator: */
+  CDSC_CREATIONDATE    = 205,  /* %%CreationDate: */
+  CDSC_TITLE           = 206,  /* %%Title: */
+  CDSC_FOR             = 207,  /* %%For: */
+  CDSC_LANGUAGELEVEL   = 208,  /* %%LanguageLevel: */
+  CDSC_BOUNDINGBOX     = 209,  /* %%BoundingBox: */
+  CDSC_ORIENTATION     = 210,  /* %%Orientation: */
+  CDSC_PAGEORDER       = 211,  /* %%PageOrder: */
+  CDSC_DOCUMENTMEDIA   = 212,  /* %%DocumentMedia: */
+  CDSC_DOCUMENTPAPERSIZES    = 213,    /* %%DocumentPaperSizes: */
+  CDSC_DOCUMENTPAPERFORMS    = 214,    /* %%DocumentPaperForms: */
+  CDSC_DOCUMENTPAPERCOLORS   = 215,    /* %%DocumentPaperColors: */
+  CDSC_DOCUMENTPAPERWEIGHTS  = 216,    /* %%DocumentPaperWeights: */
+  CDSC_DOCUMENTDATA         = 217,     /* %%DocumentData: */
+  CDSC_REQUIREMENTS         = 218,     /* IGNORED %%Requirements: */
+  CDSC_DOCUMENTNEEDEDFONTS   = 219,    /* IGNORED %%DocumentNeededFonts: */
+  CDSC_DOCUMENTSUPPLIEDFONTS = 220,    /* IGNORED %%DocumentSuppliedFonts: */
+  CDSC_HIRESBOUNDINGBOX             = 221,     /* %%HiResBoundingBox: */
+  CDSC_CROPBOX              = 222,     /* %%CropBox: */
+
+/* Preview section */
+  CDSC_BEGINPREVIEW    = 301,  /* %%BeginPreview */
+  CDSC_ENDPREVIEW      = 302,  /* %%EndPreview */
+
+/* Defaults section */
+  CDSC_BEGINDEFAULTS   = 401,  /* %%BeginDefaults */
+  CDSC_ENDDEFAULTS     = 402,  /* %%EndDefaults */
+/* also %%PageMedia, %%PageOrientation, %%PageBoundingBox */
+
+/* Prolog section */
+  CDSC_BEGINPROLOG     = 501,  /* %%BeginProlog */
+  CDSC_ENDPROLOG       = 502,  /* %%EndProlog */
+  CDSC_BEGINFONT       = 503,  /* IGNORED %%BeginFont */
+  CDSC_ENDFONT         = 504,  /* IGNORED %%EndFont */
+  CDSC_BEGINFEATURE    = 505,  /* IGNORED %%BeginFeature */
+  CDSC_ENDFEATURE      = 506,  /* IGNORED %%EndFeature */
+  CDSC_BEGINRESOURCE   = 507,  /* IGNORED %%BeginResource */
+  CDSC_ENDRESOURCE     = 508,  /* IGNORED %%EndResource */
+  CDSC_BEGINPROCSET    = 509,  /* IGNORED %%BeginProcSet */
+  CDSC_ENDPROCSET      = 510,  /* IGNORED %%EndProcSet */
+
+/* Setup section */
+  CDSC_BEGINSETUP      = 601,  /* %%BeginSetup */
+  CDSC_ENDSETUP                = 602,  /* %%EndSetup */
+  CDSC_FEATURE         = 603,  /* IGNORED %%Feature: */
+  CDSC_PAPERCOLOR      = 604,  /* IGNORED %%PaperColor: */
+  CDSC_PAPERFORM       = 605,  /* IGNORED %%PaperForm: */
+  CDSC_PAPERWEIGHT     = 606,  /* IGNORED %%PaperWeight: */
+  CDSC_PAPERSIZE       = 607,  /* %%PaperSize: */
+/* also %%Begin/EndFeature, %%Begin/EndResource */
+
+/* Page section */
+  CDSC_PAGE            = 700,  /* %%Page: */
+  CDSC_PAGETRAILER     = 701,  /* IGNORED %%PageTrailer */
+  CDSC_BEGINPAGESETUP  = 702,  /* IGNORED %%BeginPageSetup */
+  CDSC_ENDPAGESETUP    = 703,  /* IGNORED %%EndPageSetup */
+  CDSC_PAGEMEDIA       = 704,  /* %%PageMedia: */
+/* also %%PaperColor, %%PaperForm, %%PaperWeight, %%PaperSize */
+  CDSC_PAGEORIENTATION = 705,  /* %%PageOrientation: */
+  CDSC_PAGEBOUNDINGBOX = 706,  /* %%PageBoundingBox: */
+/* also %%Begin/EndFont, %%Begin/EndFeature */
+/* also %%Begin/EndResource, %%Begin/EndProcSet */
+  CDSC_INCLUDEFONT     = 707,  /* IGNORED %%IncludeFont: */
+  CDSC_VIEWINGORIENTATION = 708, /* %%ViewingOrientation: */
+
+/* Trailer section */
+  CDSC_TRAILER         = 800,  /* %%Trailer */
+/* also %%Pages, %%BoundingBox, %%Orientation, %%PageOrder, %%DocumentMedia */ 
+/* %%Page is recognised as an error */
+/* also %%DocumentNeededFonts, %%DocumentSuppliedFonts */
+
+/* End of File */
+  CDSC_EOF             = 900   /* %%EOF */
+} CDSC_RETURN_CODE;
+
+
+/* stored in dsc->preview */ 
+typedef enum {
+    CDSC_NOPREVIEW = 0,
+    CDSC_EPSI = 1,
+    CDSC_TIFF = 2,
+    CDSC_WMF = 3,
+    CDSC_PICT = 4
+} CDSC_PREVIEW_TYPE;
+
+/* stored in dsc->page_order */ 
+typedef enum {
+    CDSC_ORDER_UNKNOWN = 0,
+    CDSC_ASCEND = 1,
+    CDSC_DESCEND = 2,
+    CDSC_SPECIAL = 3
+} CDSC_PAGE_ORDER;
+
+/* stored in dsc->page_orientation and dsc->page[pagenum-1].orientation */ 
+typedef enum {
+    CDSC_ORIENT_UNKNOWN = 0,
+    CDSC_PORTRAIT = 1,
+    CDSC_LANDSCAPE = 2,
+    CDSC_UPSIDEDOWN = 3,
+    CDSC_SEASCAPE = 4
+} CDSC_ORIENTATION_ENUM;
+
+/* stored in dsc->document_data */
+typedef enum {
+    CDSC_DATA_UNKNOWN = 0,
+    CDSC_CLEAN7BIT = 1,
+    CDSC_CLEAN8BIT = 2,
+    CDSC_BINARY = 3
+} CDSC_DOCUMENT_DATA ;
+
+typedef struct CDSCBBOX_S {
+    int llx;
+    int lly;
+    int urx;
+    int ury;
+} CDSCBBOX;
+
+typedef struct CDSCFBBOX_S {
+    float fllx;
+    float flly;
+    float furx;
+    float fury;
+} CDSCFBBOX;
+
+typedef struct CDSCMEDIA_S {
+    const char *name;
+    float width;       /* PostScript points */
+    float height;
+    float weight;      /* GSM */
+    const char *colour;
+    const char *type;
+    CDSCBBOX *mediabox;        /* Used by GSview for PDF MediaBox */
+} CDSCMEDIA;
+
+#define CDSC_KNOWN_MEDIA 46
+extern const CDSCMEDIA dsc_known_media[CDSC_KNOWN_MEDIA];
+
+typedef struct CDSCCTM_S { /* used for %%ViewingOrientation */
+    float xx;
+    float xy;
+    float yx;
+    float yy;
+    /* float ty; */
+    /* float ty; */
+} CDSCCTM;
+
+typedef struct CDSCPAGE_S {
+    int ordinal;
+    const char *label;
+    unsigned long begin;
+    unsigned long end;
+    unsigned int orientation;
+    const CDSCMEDIA *media;
+    CDSCBBOX *bbox;  /* PageBoundingBox, also used by GSview for PDF CropBox */
+    CDSCCTM *viewing_orientation;
+} CDSCPAGE;
+
+/* binary DOS EPS header */
+typedef struct CDSCDOSEPS_S {
+    GSDWORD ps_begin;
+    GSDWORD ps_length;
+    GSDWORD wmf_begin;
+    GSDWORD wmf_length;
+    GSDWORD tiff_begin;
+    GSDWORD tiff_length;
+    GSWORD checksum;
+} CDSCDOSEPS;
+
+/* rather than allocated every string with malloc, we allocate
+ * chunks of 4k and place the (usually) short strings in these
+ * chunks.
+ */
+typedef struct CDSCSTRING_S CDSCSTRING;
+struct CDSCSTRING_S {
+    unsigned int index;
+    unsigned int length;
+    char *data;
+    CDSCSTRING *next;
+};
+
+
+/* DSC error reporting */
+
+typedef enum {
+  CDSC_MESSAGE_BBOX = 0,
+  CDSC_MESSAGE_EARLY_TRAILER = 1,
+  CDSC_MESSAGE_EARLY_EOF = 2,
+  CDSC_MESSAGE_PAGE_IN_TRAILER = 3,
+  CDSC_MESSAGE_PAGE_ORDINAL = 4,
+  CDSC_MESSAGE_PAGES_WRONG = 5,
+  CDSC_MESSAGE_EPS_NO_BBOX = 6,
+  CDSC_MESSAGE_EPS_PAGES = 7,
+  CDSC_MESSAGE_NO_MEDIA = 8,
+  CDSC_MESSAGE_ATEND = 9,
+  CDSC_MESSAGE_DUP_COMMENT = 10,
+  CDSC_MESSAGE_DUP_TRAILER = 11,
+  CDSC_MESSAGE_BEGIN_END = 12,
+  CDSC_MESSAGE_BAD_SECTION = 13,
+  CDSC_MESSAGE_LONG_LINE = 14,
+  CDSC_MESSAGE_INCORRECT_USAGE = 15
+} CDSC_MESSAGE_ERROR;
+
+/* severity */
+typedef enum {
+  CDSC_ERROR_INFORM    = 0,    /* Not an error */
+  CDSC_ERROR_WARN      = 1,    /* Not a DSC error itself,  */
+  CDSC_ERROR_ERROR     = 2     /* DSC error */
+} CDSC_MESSAGE_SEVERITY;
+
+/* response */
+typedef enum {
+  CDSC_RESPONSE_OK     = 0,
+  CDSC_RESPONSE_CANCEL = 1,
+  CDSC_RESPONSE_IGNORE_ALL = 2
+} CDSC_RESPONSE;
+
+extern const char * const dsc_message[];
+
+typedef struct CDSC_S CDSC;
+struct CDSC_S {
+    /* public data */
+    GSBOOL dsc;                        /* TRUE if DSC comments found */
+    GSBOOL ctrld;              /* TRUE if has CTRLD at start of stream */
+    GSBOOL pjl;                        /* TRUE if has HP PJL at start of stream */
+    GSBOOL epsf;               /* TRUE if EPSF */
+    GSBOOL pdf;                        /* TRUE if Portable Document Format */
+    unsigned int preview;      /* enum CDSC_PREVIEW_TYPE */
+    char *dsc_version; /* first line of file */
+    unsigned int language_level;
+    unsigned int document_data;        /* Clean7Bit, Clean8Bit, Binary */
+                               /* enum CDSC_DOCUMENT_DATA */
+    /* DSC sections */
+    unsigned long begincomments;
+    unsigned long endcomments;
+    unsigned long beginpreview;
+    unsigned long endpreview;
+    unsigned long begindefaults;
+    unsigned long enddefaults;
+    unsigned long beginprolog;
+    unsigned long endprolog;
+    unsigned long beginsetup;
+    unsigned long endsetup;
+    unsigned long begintrailer;
+    unsigned long endtrailer;
+    CDSCPAGE *page;
+    unsigned int page_count;   /* number of %%Page: pages in document */
+    unsigned int page_pages;   /* number of pages in document from %%Pages: */
+    unsigned int page_order;   /* enum CDSC_PAGE_ORDER */
+    unsigned int page_orientation;  /* the default page orientation */
+                               /* enum CDSC_ORIENTATION */
+    CDSCCTM *viewing_orientation;
+    unsigned int media_count;  /* number of media items */
+    CDSCMEDIA **media;         /* the array of media */
+    const CDSCMEDIA *page_media;/* the default page media */
+    CDSCBBOX *bbox;            /* the document bounding box */
+    CDSCBBOX *page_bbox;       /* the default page bounding box */
+    CDSCDOSEPS *doseps;                /* DOS binary header */
+    char *dsc_title;
+    char *dsc_creator;
+    char *dsc_date;
+    char *dsc_for;
+
+    unsigned int max_error;    /* highest error number that will be reported */
+    const int *severity;       /* array of severity values, one per error */
+
+
+    /* private data */
+    void *caller_data;         /* pointer to be provided when calling */
+                               /* error and debug callbacks */
+    int id;                    /* last DSC comment found */
+    int scan_section;          /* section currently being scanned */
+                               /* enum CDSC_SECTION */
+
+    unsigned long doseps_end;  /* ps_begin+ps_length, otherwise 0 */
+    unsigned int page_chunk_length; /* number of pages allocated */
+    unsigned long file_length; /* length of document */
+               /* If provided we try to recognise %%Trailer and %%EOF */
+               /* incorrectly embedded inside document. */
+               /* Can be left set to default value of 0 */
+    int skip_document;         /* recursion level of %%BeginDocument: */
+    int skip_bytes;            /* #bytes to ignore from BeginData: */
+                               /* or DOSEPS preview section */
+    int skip_lines;            /* #lines to ignore from BeginData: */
+    GSBOOL skip_pjl;           /* TRUE if skip PJL until first PS comment */ 
+    int begin_font_count;      /* recursion level of %%BeginFont */
+    int begin_feature_count;   /* recursion level of %%BeginFeature */
+    int begin_resource_count;  /* recursion level of %%BeginResource */
+    int begin_procset_count;   /* recursion level of %%BeginProcSet */
+
+    /* buffer for input */
+    char data[CDSC_DATA_LENGTH];/* start of buffer */
+    unsigned int data_length;  /* length of data in buffer */
+    unsigned int data_index;   /* offset to next char in buffer */
+    unsigned long data_offset; /* offset from start of document */
+                               /* to byte in data[0] */
+    GSBOOL eof;                        /* TRUE if there is no more data */
+
+    /* information about DSC line */
+    char *line;                        /* pointer to last read DSC line */
+                               /* not null terminated */
+    unsigned int line_length;  /* number of characters in line */
+    GSBOOL eol;                        /* TRUE if dsc_line contains EOL */
+    GSBOOL last_cr;            /* TRUE if last line ended in \r */
+                               /* check next time for \n */
+    unsigned int line_count;   /* line number */
+    GSBOOL long_line;          /* TRUE if found a line longer than 255 characters */
+    char last_line[256];       /* previous DSC line, used for %%+ */
+
+    /* more efficient string storage (for short strings) than malloc */
+    CDSCSTRING *string_head;   /* linked list head */
+    CDSCSTRING *string;                /* current list item */
+
+    /* memory allocation routines */
+    void *(*memalloc)(P2(size_t size, void *closure_data));
+    void (*memfree)(P2(void *ptr, void *closure_data));
+    void *mem_closure_data;
+
+    /* function for printing debug messages */
+    void (*debug_print_fn)(P2(void *caller_data, const char *str));
+
+    /* function for reporting errors in DSC comments */
+    int (*dsc_error_fn)(P5(void *caller_data, CDSC *dsc, 
+       unsigned int explanation, const char *line, unsigned int line_len));
+
+    /* public data */
+    /* Added 2001-10-01 */
+    CDSCFBBOX *hires_bbox;     /* the hires document bounding box */
+    CDSCFBBOX *crop_box;       /* the size of the trimmed page */
+};
+
+
+/* Public functions */
+
+/* Create and initialise DSC parser */
+CDSC *dsc_init(P1(void *caller_data));
+
+CDSC *dsc_init_with_alloc(P4(
+    void *caller_data,
+    void *(*memalloc)(size_t size, void *closure_data),
+    void (*memfree)(void *ptr, void *closure_data),
+    void *closure_data));
+
+/* Free the DSC parser */
+void dsc_free(P1(CDSC *dsc));
+
+/* Tell DSC parser how long document will be, to allow ignoring
+ * of early %%Trailer and %%EOF.  This is optional.
+ */
+void dsc_set_length(P2(CDSC *dsc, unsigned long len));
+
+/* Process a buffer containing DSC comments and PostScript */
+int dsc_scan_data(P3(CDSC *dsc, const char *data, int len));
+
+/* All data has been processed, fixup any DSC errors */
+int dsc_fixup(P1(CDSC *dsc));
+
+/* Install error query function */
+void dsc_set_error_function(P2(CDSC *dsc, 
+    int (*dsc_error_fn)(P5(void *caller_data, CDSC *dsc, 
+       unsigned int explanation, const char *line, unsigned int line_len))));
+
+/* Install print function for debug messages */
+void dsc_set_debug_function(P2(CDSC *dsc, 
+       void (*debug_fn)(P2(void *caller_data, const char *str))));
+
+/* Print a message to debug output, if provided */
+void dsc_debug_print(P2(CDSC *dsc, const char *str));
+
+/* should be internal only functions, but made available to 
+ * GSview for handling PDF
+ */
+int dsc_add_page(P3(CDSC *dsc, int ordinal, char *label));
+int dsc_add_media(P2(CDSC *dsc, CDSCMEDIA *media));
+int dsc_set_page_bbox(P6(CDSC *dsc, unsigned int page_number, 
+    int llx, int lly, int urx, int ury));
+
+#endif
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/thumbnailers/ps/dscparse_adapter.cpp b/thumbnailers/ps/dscparse_adapter.cpp
new file mode 100644 (file)
index 0000000..aa91b81
--- /dev/null
@@ -0,0 +1,420 @@
+/** 
+ * Copyright (C) 2001 the KGhostView authors. See file AUTHORS.
+ *     
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include "dscparse_adapter.h"
+
+using namespace std;
+
+/*-- KDSCBBOX implementation -----------------------------------------------*/
+
+KDSCBBOX::KDSCBBOX() :
+    _llx( 0 ), _lly( 0 ),
+    _urx( 0 ), _ury( 0 )
+{}
+
+KDSCBBOX::KDSCBBOX( const KDSCBBOX& b ) :
+    _llx( b._llx ), _lly( b._lly ),
+    _urx( b._urx ), _ury( b._ury )
+{}
+
+KDSCBBOX::KDSCBBOX( int llx, int lly, int urx, int ury ) :
+    _llx( llx ), _lly( lly ), 
+    _urx( urx ), _ury( ury ) 
+{}
+
+KDSCBBOX::KDSCBBOX( const CDSCBBOX& bbox ) :
+    _llx( bbox.llx ), _lly( bbox.lly ), 
+    _urx( bbox.urx ), _ury( bbox.ury ) 
+{}
+
+KDSCBBOX& KDSCBBOX::operator = ( const KDSCBBOX& b ) 
+{ 
+    _llx = b._llx; _lly = b._lly; _urx = b._urx; _ury = b._ury;
+    return *this; 
+}
+
+bool KDSCBBOX::operator == ( const KDSCBBOX& b ) 
+{ 
+    return ( _llx == b._llx && _lly == b._lly 
+         && _urx == b._urx && _ury == b._ury ); 
+}
+
+bool KDSCBBOX::operator != ( const KDSCBBOX& b ) 
+{ 
+    return !( *this == b ); 
+}
+
+int KDSCBBOX::llx() const { return _llx; }
+int KDSCBBOX::lly() const { return _lly; }
+int KDSCBBOX::urx() const { return _urx; }
+int KDSCBBOX::ury() const { return _ury; }
+
+int KDSCBBOX::width()  const { return _urx - _llx; }
+int KDSCBBOX::height() const { return _ury - _lly; }
+
+QSize KDSCBBOX::size() const { return QSize( width(), height() ); }
+
+ostream& operator << ( ostream& os, const KDSCBBOX& source )
+{
+    os << "{ llx: "<< source.llx() << ", lly: " << source.lly()
+       <<  " urx: "<< source.urx() << ", ury: " << source.ury() << " }";
+    return os;
+}
+
+/*-- KDSCError implementation ----------------------------------------------*/
+
+KDSCError::KDSCError( Type type, Severity severity, const QByteArray& line,
+                     unsigned int lineNumber ) :
+    _type( type ),
+    _severity( severity ),
+    _line( line ),
+    _lineNumber( lineNumber )
+{}
+
+KDSCError::Type KDSCError::type() const
+{
+    return _type;
+}
+
+KDSCError::Severity KDSCError::severity() const
+{
+    return _severity; 
+}
+
+QByteArray KDSCError::line() const
+{
+    return _line; 
+}
+
+unsigned int KDSCError::lineNumber() const
+{
+    return _lineNumber; 
+}
+
+/*-- KDSCOkErrorHandler implementation -------------------------------------*/
+
+KDSCErrorHandler::Response KDSCOkErrorHandler::error( const KDSCError& err ) 
+{
+    cout << "KDSC: error in line " << err.lineNumber() << endl;
+    //cout << err.line() << endl;
+    return Ok;
+}
+
+/*-- KDSC implementation ---------------------------------------------------*/
+
+KDSC::KDSC() :
+    _errorHandler( 0 ),
+    _commentHandler( 0 )
+{
+    _cdsc = dsc_init( this );
+    Q_ASSERT( _cdsc != 0 );
+    _scanHandler = new KDSCScanHandler( _cdsc );
+}
+
+KDSC::~KDSC()
+{
+    dsc_free( _cdsc );
+    delete _scanHandler;
+}
+
+QString KDSC::dsc_version() const
+{
+    return QString( _cdsc->dsc_version );   
+}
+
+bool KDSC::dsc() const
+{
+    return ( _cdsc->dsc == TRUE );
+}
+
+bool KDSC::ctrld() const
+{
+    return ( _cdsc->ctrld == TRUE );
+}
+
+bool KDSC::pjl() const
+{
+    return ( _cdsc->pjl == TRUE );
+}
+
+bool KDSC::epsf() const
+{
+    return ( _cdsc->epsf == TRUE );
+}
+
+bool KDSC::pdf() const
+{
+    return ( _cdsc->pdf == TRUE );
+}
+
+unsigned int KDSC::preview() const
+{
+    return _cdsc->preview;
+}
+
+unsigned int KDSC::language_level() const
+{
+    return _cdsc->language_level;
+}
+
+unsigned int KDSC::document_data() const
+{
+    return _cdsc->document_data;
+}
+
+unsigned long KDSC::begincomments() const
+{
+    return _cdsc->begincomments;
+}
+
+unsigned long KDSC::endcomments() const
+{
+    return _cdsc->endcomments;
+}
+
+unsigned long KDSC::beginpreview() const
+{
+    return _cdsc->beginpreview;
+}
+
+unsigned long KDSC::endpreview() const
+{
+    return _cdsc->endpreview;
+}
+
+unsigned long KDSC::begindefaults() const
+{
+    return _cdsc->begindefaults;
+}
+
+unsigned long KDSC::enddefaults() const
+{
+    return _cdsc->enddefaults;
+}
+
+unsigned long KDSC::beginprolog() const
+{
+    return _cdsc->beginprolog;
+}
+
+unsigned long KDSC::endprolog() const
+{
+    return _cdsc->endprolog;
+}
+
+unsigned long KDSC::beginsetup() const
+{
+    return _cdsc->beginsetup;
+}
+
+unsigned long KDSC::endsetup() const
+{
+    return _cdsc->endsetup;
+}
+
+unsigned long KDSC::begintrailer() const
+{
+    return _cdsc->begintrailer;
+}
+
+unsigned long KDSC::endtrailer() const
+{
+    return _cdsc->endtrailer;
+}
+
+CDSCPAGE* KDSC::page() const
+{
+    return _cdsc->page;
+}
+
+unsigned int KDSC::page_count() const
+{
+    return _cdsc->page_count;
+}
+
+unsigned int KDSC::page_pages() const
+{
+    return _cdsc->page_pages;
+}
+
+unsigned int KDSC::page_order() const
+{
+    return _cdsc->page_order;
+}
+
+unsigned int KDSC::page_orientation() const
+{
+    return _cdsc->page_orientation;
+}
+
+CDSCCTM* KDSC::viewing_orientation() const
+{
+    return _cdsc->viewing_orientation;
+}
+
+unsigned int KDSC::media_count() const
+{
+    return _cdsc->media_count;
+}
+
+CDSCMEDIA** KDSC::media() const
+{
+    return _cdsc->media;
+}
+
+const CDSCMEDIA* KDSC::page_media() const
+{
+    return _cdsc->page_media;
+}
+
+auto_ptr<KDSCBBOX> KDSC::bbox() const
+{
+    if( _cdsc->bbox == 0 )
+       return auto_ptr<KDSCBBOX>( 0 );
+    else
+       return auto_ptr<KDSCBBOX>( new KDSCBBOX( *_cdsc->bbox ) );
+}
+
+auto_ptr<KDSCBBOX> KDSC::page_bbox() const
+{
+    if( _cdsc->page_bbox == 0 )
+       return auto_ptr<KDSCBBOX>( 0 );
+    else
+       return auto_ptr<KDSCBBOX>( new KDSCBBOX( *_cdsc->page_bbox ) );
+}
+
+QString KDSC::dsc_title() const
+{
+    return QString( _cdsc->dsc_title );
+}
+
+QString KDSC::dsc_creator() const
+{
+    return QString( _cdsc->dsc_creator );
+}
+
+QString KDSC::dsc_date() const
+{
+    return QString( _cdsc->dsc_date );
+}
+
+QString KDSC::dsc_for() const
+{
+    return QString( _cdsc->dsc_for );
+}
+
+bool KDSC::scanData( char* buffer, unsigned int count )
+{
+    return _scanHandler->scanData( buffer, count );
+}
+
+int KDSC::fixup()
+{
+    return dsc_fixup( _cdsc );
+}
+
+KDSCErrorHandler* KDSC::errorHandler() const
+{
+    return _errorHandler;
+}
+
+void KDSC::setErrorHandler( KDSCErrorHandler* errorHandler )
+{
+    _errorHandler = errorHandler;
+    if( errorHandler == 0 )
+       dsc_set_error_function( _cdsc, 0 );
+    else
+       dsc_set_error_function( _cdsc, &errorFunction );
+}
+
+KDSCCommentHandler* KDSC::commentHandler() const
+{
+    return _commentHandler;
+}
+
+void KDSC::setCommentHandler( KDSCCommentHandler* commentHandler )
+{
+    if( _commentHandler != 0 && commentHandler == 0 )
+    {
+       delete _scanHandler;
+       _scanHandler = new KDSCScanHandler( _cdsc );
+    }
+    else if( _commentHandler == 0 && commentHandler != 0 )
+    {
+       delete _scanHandler;
+       _scanHandler = new KDSCScanHandlerByLine( _cdsc, commentHandler );
+    }
+    _commentHandler = commentHandler;
+}
+
+bool KDSC::isStructured() const 
+{
+    return epsf() ? ( page_count() > 1 ) : ( page_count() > 0 );
+}
+
+CDSC* KDSC::cdsc() const
+{
+    return _cdsc;
+}
+
+int KDSC::errorFunction( void* caller_data, CDSC* dsc,
+       unsigned int explanation, const char* line, unsigned int line_len )
+{
+    KDSCError error( 
+           static_cast< KDSCError::Type >( explanation ), 
+           static_cast< KDSCError::Severity >( dsc->severity[explanation] ),
+           QByteArray( line, line_len + 1 ),
+           dsc->line_count
+    );
+    
+    KDSC* kdsc = static_cast< KDSC* >( caller_data );
+    Q_ASSERT( kdsc );
+    
+    return kdsc->errorHandler()->error( error );
+}
+
+bool KDSCScanHandlerByLine::scanData( char* buf, unsigned int count )
+{
+    char* lineStart = buf;
+    char* it = buf;
+    while( it < buf + count )
+    {
+       if( *it++ == '\n' )
+       {
+           int retval = dsc_scan_data( _cdsc, lineStart, it - lineStart );
+           if( retval < 0 ) 
+               return false;
+           else if( retval > 0 )
+           {
+               _commentHandler->comment( 
+                       static_cast<KDSCCommentHandler::Name>( retval ) );
+           }
+           lineStart = it;
+       }
+    }
+  
+    if( it != lineStart )
+    {
+       // Scan the remaining part of the string.
+       return ( dsc_scan_data( _cdsc, lineStart, it - lineStart ) < 0 );
+    }
+    else
+       return true;
+}
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/thumbnailers/ps/dscparse_adapter.h b/thumbnailers/ps/dscparse_adapter.h
new file mode 100644 (file)
index 0000000..1e35380
--- /dev/null
@@ -0,0 +1,391 @@
+/** 
+ * Copyright (C) 2001 the KGhostView authors. See file AUTHORS.
+ *     
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef DSCPARSE_ADAPTER_H
+#define DSCPARSE_ADAPTER_H
+
+#include <iostream>
+#include <map>
+#include <memory>
+
+#include <qsize.h>
+#include <qstring.h>
+
+#include "dscparse.h"
+
+#ifndef KDE_USE_FINAL
+#undef min
+#undef max
+#endif
+
+#if defined(__GNUC__)
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 93)
+/*
+ * We add a quick 'n' dirty inline implementation of auto_ptr for older
+ * releases of GCC, which don't include an auto_ptr implementation in
+ * <memory>.
+ */
+
+template <class T> class auto_ptr {
+private:
+       T* _ptr;
+
+public:
+       typedef T element_type;
+       explicit auto_ptr(T* p = 0) : _ptr(p) {}
+       auto_ptr(auto_ptr& a) : _ptr(a.release()) {}
+       template <class T1> auto_ptr(auto_ptr<T1>& a) : _ptr(a.release()) {}
+       auto_ptr& operator=(auto_ptr& a) {
+               if (&a != this) {
+                       delete _ptr;
+                       _ptr = a.release();
+               }
+               return *this;
+       }
+       template <class T1>
+       auto_ptr& operator=(auto_ptr<T1>& a) {
+               if (a.get() != this->get()) {
+                       delete _ptr;
+                       _ptr = a.release();
+               }
+               return *this;
+       }
+       ~auto_ptr() { delete _ptr; }
+
+       T& operator*() const { return *_ptr; }
+       T* operator->() const { return _ptr; }
+       T* get() const { return _ptr; }
+       T* release() { T* tmp = _ptr; _ptr = 0; return tmp; }
+       void reset(T* p = 0) { delete _ptr; _ptr = p; }
+};
+
+#endif
+#endif
+
+
+class KDSCBBOX
+{
+public:
+    KDSCBBOX(); 
+    KDSCBBOX( const KDSCBBOX& b );
+    KDSCBBOX( int llx, int lly, int urx, int ury ); 
+    KDSCBBOX( const CDSCBBOX& bbox ); 
+
+    KDSCBBOX& operator = ( const KDSCBBOX& b );  
+    
+    bool operator == ( const KDSCBBOX& b ); 
+    bool operator != ( const KDSCBBOX& b );
+    
+    int llx() const;
+    int lly() const;
+    int urx() const;
+    int ury() const;
+
+    int width()  const;
+    int height() const;
+
+    QSize size() const;
+
+private:
+    int _llx, _lly, _urx, _ury;
+};
+
+std::ostream& operator << ( std::ostream&, const KDSCBBOX& );
+
+
+class KDSCError
+{
+public:
+    enum Type
+    {
+       BBox             = CDSC_MESSAGE_BBOX,
+       EarlyTrailer     = CDSC_MESSAGE_EARLY_TRAILER,
+       EarlyEOF         = CDSC_MESSAGE_EARLY_EOF,
+       PageInTrailer    = CDSC_MESSAGE_PAGE_IN_TRAILER,
+       PageOrdinal      = CDSC_MESSAGE_PAGE_ORDINAL,
+       PagesWrong       = CDSC_MESSAGE_PAGES_WRONG,
+       EPSNoBBox        = CDSC_MESSAGE_EPS_NO_BBOX,
+       EPSPages         = CDSC_MESSAGE_EPS_PAGES,
+       NoMedia          = CDSC_MESSAGE_NO_MEDIA,
+       AtEnd            = CDSC_MESSAGE_ATEND,
+       DuplicateComment = CDSC_MESSAGE_DUP_COMMENT,
+       DuplicateTrailer = CDSC_MESSAGE_DUP_TRAILER,
+       BeginEnd         = CDSC_MESSAGE_BEGIN_END,
+       BadSection       = CDSC_MESSAGE_BAD_SECTION,
+       LongLine         = CDSC_MESSAGE_LONG_LINE,
+       IncorrectUsage   = CDSC_MESSAGE_INCORRECT_USAGE
+    };
+
+    enum Severity
+    {
+       Information = CDSC_ERROR_INFORM,
+       Warning     = CDSC_ERROR_WARN,
+       Error       = CDSC_ERROR_ERROR
+    };
+
+    KDSCError( Type, Severity, const QByteArray& line, 
+              unsigned int lineNumber );
+    
+    Type         type()       const;
+    Severity     severity()   const;
+    QByteArray     line()       const;
+    unsigned int lineNumber() const;
+    
+private:
+    Type         _type;
+    Severity     _severity;
+    QByteArray     _line;
+    unsigned int _lineNumber;
+};
+
+
+class KDSCErrorHandler
+{
+public:
+    virtual ~KDSCErrorHandler() {}
+    enum Response 
+    { 
+       Ok        = CDSC_RESPONSE_OK, 
+       Cancel    = CDSC_RESPONSE_CANCEL,
+       IgnoreAll = CDSC_RESPONSE_IGNORE_ALL
+    };
+    
+    virtual Response error( const KDSCError& ) = 0;
+};
+
+class KDSCOkErrorHandler : public KDSCErrorHandler
+{
+    Response error( const KDSCError& );
+};
+
+class KDSCCommentHandler
+{
+public:
+    virtual ~KDSCCommentHandler() {}
+    enum Name
+    {
+       // Header section
+       PSAdobe               = CDSC_PSADOBE,
+       BeginComments         = CDSC_BEGINCOMMENTS,
+       EndComments           = CDSC_ENDCOMMENTS,
+       Pages                 = CDSC_PAGES,
+       Creator               = CDSC_CREATOR,
+       CreationDate          = CDSC_CREATIONDATE,
+       Title                 = CDSC_TITLE,
+       For                   = CDSC_FOR,
+       LanguageLevel         = CDSC_LANGUAGELEVEL,
+       BoundingBox           = CDSC_BOUNDINGBOX,
+       Orientation           = CDSC_ORIENTATION,
+       PageOrder             = CDSC_PAGEORDER,
+       DocumentMedia         = CDSC_DOCUMENTMEDIA,
+       DocumentPaperSizes    = CDSC_DOCUMENTPAPERSIZES,
+       DocumentPaperForms    = CDSC_DOCUMENTPAPERFORMS,
+       DocumentPaperColors   = CDSC_DOCUMENTPAPERCOLORS,
+       DocumentPaperWeights  = CDSC_DOCUMENTPAPERWEIGHTS,
+       DocumentData          = CDSC_DOCUMENTDATA,
+       Requirements          = CDSC_REQUIREMENTS,
+       DocumentNeededFonts   = CDSC_DOCUMENTNEEDEDFONTS,
+       DocumentSuppliedFonts = CDSC_DOCUMENTSUPPLIEDFONTS,
+       HiResBoundingBox      = CDSC_HIRESBOUNDINGBOX,
+       CropBox               = CDSC_CROPBOX,
+       
+       // Preview section
+       BeginPreview          = CDSC_BEGINPREVIEW,
+       EndPreview            = CDSC_ENDPREVIEW,
+
+       // Defaults section
+       BeginDefaults         = CDSC_BEGINDEFAULTS,
+       EndDefaults           = CDSC_ENDDEFAULTS,
+       // also %%PageMedia, %%PageOrientation, %%PageBoundingBox
+
+       // Prolog section 
+       BeginProlog           = CDSC_BEGINPROLOG,
+       EndProlog             = CDSC_ENDPROLOG,
+       BeginFont             = CDSC_BEGINFONT,
+       EndFont               = CDSC_ENDFONT,
+       BeginFeature          = CDSC_BEGINFEATURE,
+       EndFeature            = CDSC_ENDFEATURE,
+       BeginResource         = CDSC_BEGINRESOURCE,
+       EndResource           = CDSC_ENDRESOURCE,
+       BeginProcset          = CDSC_BEGINPROCSET,
+       EndProcset            = CDSC_ENDPROCSET,
+
+       // Setup section
+       BeginSetup            = CDSC_BEGINSETUP,
+       EndSetup              = CDSC_ENDSETUP,
+       Feature               = CDSC_FEATURE,
+       PaperColor            = CDSC_PAPERCOLOR,
+       PaperForm             = CDSC_PAPERFORM,
+       PaperWeight           = CDSC_PAPERWEIGHT,
+       PaperSize             = CDSC_PAPERSIZE,
+       // also %%Begin/EndFeature, %%Begin/EndResource
+
+       // Page section
+       Page                  = CDSC_PAGE,
+       PageTrailer           = CDSC_PAGETRAILER,
+       BeginPageSetup        = CDSC_BEGINPAGESETUP,
+       EndPageSetup          = CDSC_ENDPAGESETUP,
+       PageMedia             = CDSC_PAGEMEDIA,
+       // also %%PaperColor, %%PaperForm, %%PaperWeight, %%PaperSize
+       PageOrientation       = CDSC_PAGEORIENTATION,
+       PageBoundingBox       = CDSC_PAGEBOUNDINGBOX,
+       // also %%Begin/EndFont, %%Begin/EndFeature 
+       // also %%Begin/EndResource, %%Begin/EndProcSet 
+       IncludeFont           = CDSC_INCLUDEFONT,
+       ViewingOrientation    = CDSC_VIEWINGORIENTATION,
+
+       // Trailer section
+       Trailer               = CDSC_TRAILER,
+       // also %%Pages, %%BoundingBox, %%Orientation, %%PageOrder, 
+       // %%DocumentMedia
+       // %%Page is recognised as an error
+       // also %%DocumentNeededFonts, %%DocumentSuppliedFonts
+
+       // End of File */
+       Eof                    = CDSC_EOF
+    };
+       
+    virtual void comment( Name name ) { std::cout << name << std::endl; }
+};
+
+class KDSCScanHandler;
+class KDSC
+{
+public:
+    KDSC();
+    ~KDSC();
+
+    /*--- Adapter for CDSC ------------------------------------------------*/
+    QString dsc_version() const;
+    
+    bool dsc()   const;
+    bool ctrld() const;
+    bool pjl()   const;
+    bool epsf()  const;
+    bool pdf()   const;
+    
+    unsigned int preview()        const;
+    unsigned int language_level() const;
+    unsigned int document_data()  const;
+
+    unsigned long begincomments() const;
+    unsigned long endcomments()   const;
+    unsigned long beginpreview()  const;
+    unsigned long endpreview()    const;
+    unsigned long begindefaults() const;
+    unsigned long enddefaults()   const;
+    unsigned long beginprolog()   const;
+    unsigned long endprolog()     const;
+    unsigned long beginsetup()    const;
+    unsigned long endsetup()      const;
+    unsigned long begintrailer()  const;
+    unsigned long endtrailer()    const;
+
+    CDSCPAGE* page() const;
+
+    unsigned int page_count()       const;
+    unsigned int page_pages()       const;
+    unsigned int page_order()       const;
+    unsigned int page_orientation() const;
+
+    CDSCCTM* viewing_orientation() const;
+    
+    unsigned int media_count()    const;
+    CDSCMEDIA** media()           const;
+    const CDSCMEDIA* page_media() const;
+
+#if defined(__GNUC__) && (__GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 93))
+    auto_ptr<KDSCBBOX> bbox()      const;
+    auto_ptr<KDSCBBOX> page_bbox() const;
+#else
+    std::auto_ptr<KDSCBBOX> bbox()      const;
+    std::auto_ptr<KDSCBBOX> page_bbox() const;
+#endif
+
+    // CDSCDOSEPS *doseps;
+
+    QString dsc_title()   const;
+    QString dsc_creator() const;
+    QString dsc_date()    const;
+    QString dsc_for()     const;
+
+    // unsigned int max_error
+   
+    bool scanData( char*, unsigned int );
+
+    /**
+     * Tidy up from incorrect DSC comments.
+     */
+    int fixup();
+    
+    KDSCErrorHandler* errorHandler() const;
+    void setErrorHandler( KDSCErrorHandler* );
+    
+    KDSCCommentHandler* commentHandler() const;
+    void setCommentHandler( KDSCCommentHandler* );
+    
+    /*--- Extra methods for convenience -----------------------------------*/
+    bool isStructured() const;
+
+    /*--- Temporary -------------------------------------------------------*/
+    CDSC* cdsc() const;
+
+protected:
+    static int errorFunction( void* caller_data, CDSC* dsc, 
+                              unsigned int explanation, 
+                              const char* line, unsigned int line_len );
+    
+private:
+    CDSC*               _cdsc;
+    KDSCErrorHandler*   _errorHandler;
+    KDSCCommentHandler* _commentHandler;
+    KDSCScanHandler*    _scanHandler;
+};
+
+class KDSCScanHandler
+{
+public:
+    virtual ~KDSCScanHandler() {}
+    KDSCScanHandler( CDSC* cdsc ) : _cdsc( cdsc ) {}
+    
+    virtual bool scanData( char* buf, unsigned int count )
+    {
+       return ( dsc_scan_data( _cdsc, buf, count ) >= 0 );
+    }
+    
+protected:
+    CDSC* _cdsc;
+};
+
+class KDSCScanHandlerByLine : public KDSCScanHandler
+{
+public:
+    KDSCScanHandlerByLine( CDSC* cdsc, KDSCCommentHandler* commentHandler ) : 
+       KDSCScanHandler( cdsc ),
+       _commentHandler( commentHandler ) 
+    {}
+    
+    virtual bool scanData( char* buf, unsigned int count );
+
+protected:
+    KDSCCommentHandler* _commentHandler;
+};
+
+#endif
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/thumbnailers/ps/gscreator.cpp b/thumbnailers/ps/gscreator.cpp
new file mode 100644 (file)
index 0000000..2650e30
--- /dev/null
@@ -0,0 +1,624 @@
+/*  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 <QVector>
+
+
+#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, '\0');
+
+  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.indexOf(QRegExp("\\.epsi?$", Qt::CaseInsensitive)) > 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
+    QByteArray 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;
+    int ret;
+    do {
+      ret = waitpid(pid, &status, 0);
+    } while (ret == -1 && errno == EINTR);
+    if (ret != 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(QIODevice::ReadOnly))
+    return false;
+
+  unsigned char test[4];
+  if ( f.read( (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.seek( n-4 );
+
+  unsigned char trailer[4] = { 0xdf,0xdf,0xdf,0xdf };
+
+  if ( f.read( (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, QImage::Format_Indexed8);
+  img.setColorCount(colors);
+
+  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;
+  QVector<unsigned char> bindata(bindatabytes);
+
+  for (unsigned int i = 0; i < bindatabytes; i++) {
+    if (offset >= previewsize)
+      return false;
+
+    while (!isxdigit(previewstr[offset].toLatin1()) &&
+          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.convertToFormat(QImage::Format_RGB32).scaled(imgwidth, imgheight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+
+  return true;
+}
diff --git a/thumbnailers/ps/gscreator.h b/thumbnailers/ps/gscreator.h
new file mode 100644 (file)
index 0000000..cb9fb6f
--- /dev/null
@@ -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/thumbnailers/ps/gsthumbnail.desktop b/thumbnailers/ps/gsthumbnail.desktop
new file mode 100644 (file)
index 0000000..22111dd
--- /dev/null
@@ -0,0 +1,79 @@
+[Desktop Entry]
+Type=Service
+Name=PostScript, PDF and DVI Files
+Name[ar]=ملفات PostScript, PDF و DVI
+Name[ast]=Ficheros PostScript, PDF y DVI
+Name[bg]=Файлове PostScript, PDF и DVI
+Name[br]=Restroù PostScript, PDF ha DVI
+Name[bs]=Postskript, PDF i DVI datoteke
+Name[ca]=Fitxers PostScript, PDF i DVI
+Name[ca@valencia]=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[en_GB]=PostScript, PDF and DVI Files
+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[hi]=पोस्ट-स्क्रिप्ट, पीडीएफ तथा डीवीआई फ़ाइलें
+Name[hne]=पोस्ट-स्क्रिप्ट, पीडीएफ अउ डीवीआई फाइल मन ल
+Name[hr]=Datoteke oblika PostScript, PDF i DVI
+Name[hu]=PostScript-, PDF- és DVI-fájlok
+Name[ia]=Files PostScript, PDF e DVI
+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[ko]=포스트크스립트, PDF, DVI 파일
+Name[ku]=Pelên PostScript, PDF û DVI
+Name[lt]=Postscript, PDF ir DVI failai
+Name[lv]=Postscript, PDF un DVI faili
+Name[mr]=पोस्टस्क्रिप्ट, PDF व DVI फाईल्स
+Name[ms]=PostScript, PDF dan Fail DVI
+Name[nb]=PostScript, PDF og DVI filer
+Name[nds]=PostScript-, PDF- un DVI-Dateien
+Name[ne]=पोष्टस्क्रिप्ट, पीडीएफ र डीभीआई फाइल
+Name[nl]=PostScript-, DVI- en PDF-bestanden
+Name[nn]=PostScript-, PDF- og DVI-filer
+Name[pa]=ਪੋਸਟ-ਸਕ੍ਰਿਪਟ, PDF ਅਤੇ DVI ਫਾਇਲਾਂ
+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[si]=PostScript, PDF සහ DVI ගොනු
+Name[sk]=PostScript, PDF a DVI súbory
+Name[sl]=Datoteke PostScript, PDF in DVI
+Name[sr]=Постскрипт, ПДФ и ДВИ фајлови
+Name[sr@ijekavian]=Постскрипт, ПДФ и ДВИ фајлови
+Name[sr@ijekavianlatin]=PostScript, PDF i DVI fajlovi
+Name[sr@latin]=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[ug]=PostScript، PDF ۋە DVI ھۆججەتلىرى
+Name[uk]=Файли PostScript, PDF та DVI
+Name[uz]=PostScript, PDF va DVI fayllari
+Name[uz@cyrillic]=PostScript, PDF ва DVI файллари
+Name[vi]=Các tập tin PostScript, PDF và DVI
+Name[x-test]=xxPostScript, PDF and DVI Filesxx
+Name[zh_CN]=PostScript、PDF 和 DVI 文件
+Name[zh_HK]=PostScript 、PDF 及 DVI 檔案
+Name[zh_TW]=PostScript,PDF 與 DVI 檔 
+X-KDE-ServiceTypes=ThumbCreator
+MimeType=application/x-dvi;application/postscript;application/pdf;image/x-eps;
+X-KDE-Library=gsthumbnail
+CacheThumbnail=true
diff --git a/thumbnailers/raw/CMakeLists.txt b/thumbnailers/raw/CMakeLists.txt
new file mode 100644 (file)
index 0000000..adce793
--- /dev/null
@@ -0,0 +1,19 @@
+project(rawthumbnail)
+
+## includes and linking
+include_directories(${KEXIV2_INCLUDE_DIR} ${KDCRAW_INCLUDE_DIR})
+
+
+#sources
+set(rawthumbnail_SRCS rawcreator.cpp)
+kde4_add_plugin(rawthumbnail ${rawthumbnail_SRCS})
+
+
+## includes and linking
+target_link_libraries(rawthumbnail ${KDE4_KIO_LIBS} ${KDCRAW_LIBRARIES} ${KEXIV2_LIBRARIES} ${QT_QTGUI_LIBRARY} ${KDE4_KDECORE_LIBS})
+
+## install the plugin
+install(TARGETS rawthumbnail DESTINATION ${PLUGIN_INSTALL_DIR})
+install(FILES rawthumbnail.desktop DESTINATION ${SERVICES_INSTALL_DIR})
+
+
diff --git a/thumbnailers/raw/rawcreator.cpp b/thumbnailers/raw/rawcreator.cpp
new file mode 100644 (file)
index 0000000..48d2749
--- /dev/null
@@ -0,0 +1,109 @@
+/**
+ Copyright (C) 2008  Unai Garro <ugarro@gmail.com>
+
+ 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; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ USA
+**/
+
+#include "rawcreator.h"
+
+#include <QImage>
+
+#include <libkdcraw/kdcraw.h>
+#include <libkexiv2/kexiv2.h>
+
+extern "C"
+{
+    KDE_EXPORT ThumbCreator *new_creator()
+    {
+        return new RAWCreator;
+    }
+}
+
+RAWCreator::RAWCreator()
+{
+}
+
+RAWCreator::~RAWCreator()
+{
+}
+
+bool RAWCreator::create(const QString &path, int width, int height, QImage &img)
+{
+    //load the image into the QByteArray
+    QByteArray data;
+    bool loaded=KDcrawIface::KDcraw::loadEmbeddedPreview(data,path);
+
+    if (loaded)
+    {
+
+        //Load the image into a QImage
+        QImage preview;
+        if (!preview.loadFromData(data) || preview.isNull())
+           return false;
+
+        //And its EXIF info
+        KExiv2Iface::KExiv2 exiv;
+        if (exiv.loadFromData(data))
+        {
+            //We managed reading the EXIF info, rotate the image
+            //according to the EXIF orientation flag
+            KExiv2Iface::KExiv2::ImageOrientation orient=exiv.getImageOrientation();
+
+            //Rotate according to the EXIF orientation flag
+            switch(orient)
+            {
+                case KExiv2Iface::KExiv2::ORIENTATION_UNSPECIFIED:
+                case KExiv2Iface::KExiv2::ORIENTATION_NORMAL:
+                    break; //we do nothing
+                case KExiv2Iface::KExiv2::ORIENTATION_HFLIP:
+                    preview = preview.mirrored(true,false);
+                    break;
+                case KExiv2Iface::KExiv2::ORIENTATION_ROT_180:
+                    preview = preview.transformed(QMatrix().rotate(180));
+                    break;
+                case KExiv2Iface::KExiv2::ORIENTATION_VFLIP:
+                    preview = preview.mirrored(false,true);
+                    break;
+                case KExiv2Iface::KExiv2::ORIENTATION_ROT_90_HFLIP:
+                    preview = preview.mirrored(true,false);
+                    preview = preview.transformed(QMatrix().rotate(90));
+                    break;
+                case KExiv2Iface::KExiv2::ORIENTATION_ROT_90:
+                    preview = preview.transformed(QMatrix().rotate(90));
+                    break;
+                case KExiv2Iface::KExiv2::ORIENTATION_ROT_90_VFLIP:
+                    preview = preview.mirrored(false,true);
+                    preview = preview.transformed(QMatrix().rotate(90));
+                    break;
+                case KExiv2Iface::KExiv2::ORIENTATION_ROT_270:
+                    preview = preview.transformed(QMatrix().rotate(270));
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        //Scale the image as requested by the thumbnailer
+        img=preview.scaled(width,height,Qt::KeepAspectRatio);
+
+    }
+    return loaded;
+}
+
+ThumbCreator::Flags RAWCreator::flags() const
+{
+    return (Flags)(0);
+}
diff --git a/thumbnailers/raw/rawcreator.h b/thumbnailers/raw/rawcreator.h
new file mode 100644 (file)
index 0000000..f01532a
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ Copyright (C) 2008  Unai Garro <ugarro@gmail.com>
+
+ 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; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+ USA
+**/
+
+#ifndef RAWCREATOR_H
+#define RAWCREATOR_H
+
+#include <kio/thumbcreator.h>
+
+class RAWCreator : public ThumbCreator
+{
+public:
+    RAWCreator();
+    virtual ~RAWCreator();
+    virtual bool create(const QString &path, int width, int height, QImage &img);
+    virtual Flags flags() const;
+};
+
+#endif
diff --git a/thumbnailers/raw/rawthumbnail.desktop b/thumbnailers/raw/rawthumbnail.desktop
new file mode 100644 (file)
index 0000000..7049808
--- /dev/null
@@ -0,0 +1,60 @@
+[Desktop Entry]
+Type=Service
+Name=RAW Photo Camera Files
+Name[ar]=ملفات الخامة RAW لآلة التصوير
+Name[bg]=Снимки RAW от фотоапарат
+Name[bs]=Sirove datoteke s kamere
+Name[ca]=Fitxers RAW de càmera de fotos
+Name[ca@valencia]=Fitxers RAW de càmera de fotos
+Name[cs]=RAW soubory z fotoaparátu
+Name[da]=Kamera-filer i RAW-foto
+Name[de]=RAW-Fotokamera-Dateien
+Name[el]=RAW αρχεία φωτογραφιών
+Name[en_GB]=RAW Photo Camera Files
+Name[es]=Archivos RAW de cámara fotográfica
+Name[et]=Kaamera toorfailid
+Name[eu]=RAW argazki kamera-fitxategiak
+Name[fi]=RAW-kuvakameratiedostot
+Name[fr]=Fichiers « RAW » d'appareil photo numérique
+Name[ga]=Comhaid Cheamara RAW
+Name[gl]=Ficheiros RAW de cámara de fotos
+Name[hr]=Fotografske datoteke RAW
+Name[hu]=RAW-fájlok
+Name[ia]=Files de photo camera RAW
+Name[is]=RAW myndavélaskrár
+Name[it]=File grezzi fotocamera
+Name[ja]=カメラの RAW ファイル
+Name[kk]=Камераның RAW ('шикі') файлдары
+Name[km]=ឯកសារ​រូបថត​របស់​ម៉ាស៊ីន​ថត​ដើម
+Name[ko]=RAW 사진 카메라 파일
+Name[lt]=Fotoaparato RAW failai
+Name[lv]=RAW fotogrāfiju faili
+Name[mr]=RAW फोटो कॅमेरा फाईल्स
+Name[nb]=RAW foto kamerafiler
+Name[nds]=RAW-Fotokamera-Dateien
+Name[nl]=Bestanden met RAW-camera-afbeelding
+Name[pa]=RAW ਫੋਟੋ ਕੈਮਰਾ ਫਾਇਲਾਂ
+Name[pl]=Pliki RAW z aparatów cyfrowych
+Name[pt]=Ficheiros de Máquinas Fotográficas RAW
+Name[pt_BR]=Arquivos RAW de câmeras fotográficas
+Name[ro]=Fișiere fotografice brute
+Name[ru]=Цифровые негативы (RAW)
+Name[si]=RAW පිංතූර කැමරා ගොනු
+Name[sk]=RAW súbory z digitálneho fotoaparátu
+Name[sl]=Surove datoteke s fotoaparata
+Name[sr]=Сирови фајлови с фотоапарата
+Name[sr@ijekavian]=Сирови фајлови с фотоапарата
+Name[sr@ijekavianlatin]=Sirovi fajlovi s fotoaparata
+Name[sr@latin]=Sirovi fajlovi s fotoaparata
+Name[sv]=Obehandlade kamerafiler
+Name[tr]=RAW Fotoğraf Makinesi Dosyaları
+Name[ug]=RAW سۈرەت كامېرا ھۆججىتى
+Name[uk]=Файли цифрових негативів
+Name[x-test]=xxRAW Photo Camera Filesxx
+Name[zh_CN]=RAW 照片相机文件
+Name[zh_TW]=原始相機檔
+X-KDE-ServiceTypes=ThumbCreator
+# image/x-dcraw is the subclass for all "raw" image formats, so no need to list them all
+MimeType=image/x-dcraw;
+X-KDE-Library=rawthumbnail
+CacheThumbnail=true