diff --git a/CMakeLists.txt b/CMakeLists.txt index d1c9512f..56ca299d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 index 00000000..8e9dcc26 --- /dev/null +++ b/svgpart/CMakeLists.txt @@ -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 index 00000000..d511905c --- /dev/null +++ b/svgpart/COPYING @@ -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. + + + Copyright (C) + + 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. + + , 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 index 00000000..afee0945 --- /dev/null +++ b/svgpart/Messages.sh @@ -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 index 00000000..0edbec32 --- /dev/null +++ b/svgpart/svgpart.cpp @@ -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 +#include +#include +#include + +// KDE +#include +#include +#include +#include + +// 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 ")); + 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 index 00000000..249387ca --- /dev/null +++ b/svgpart/svgpart.desktop @@ -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 index 00000000..cb2a1e21 --- /dev/null +++ b/svgpart/svgpart.h @@ -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 + + +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 index 00000000..bd858c45 --- /dev/null +++ b/svgpart/svgpart.rc @@ -0,0 +1,22 @@ + + + + &View + + + + + + +Main Toolbar + + + + + + + diff --git a/thumbnailers/CMakeLists.txt b/thumbnailers/CMakeLists.txt new file mode 100644 index 00000000..47bd2fb0 --- /dev/null +++ b/thumbnailers/CMakeLists.txt @@ -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 index 00000000..d511905c --- /dev/null +++ b/thumbnailers/COPYING @@ -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. + + + Copyright (C) + + 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. + + , 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 index 00000000..2676d08a --- /dev/null +++ b/thumbnailers/COPYING.LIB @@ -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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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. + + , 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 index 00000000..b6643a3a --- /dev/null +++ b/thumbnailers/ps/CMakeLists.txt @@ -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 index 00000000..1eaefe0a --- /dev/null +++ b/thumbnailers/ps/Messages.sh @@ -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 index 00000000..c1f68bd8 --- /dev/null +++ b/thumbnailers/ps/dscparse.cpp @@ -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 /* for sprintf(), not file I/O */ +#include +#include +#include + +#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; ipage_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; ipage_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; ipage_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; imedia_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 ((plast_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: [ [ ] ] + * ::= (Lines or physical bytes) + * ::= Hex | Binary | ASCII (Type of data) + * ::= 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; imedia_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; iline_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 slen) + len = slen-1; + while ( (i= '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 ((iline + 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 index 00000000..4463058c --- /dev/null +++ b/thumbnailers/ps/dscparse.h @@ -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 index 00000000..aa91b81e --- /dev/null +++ b/thumbnailers/ps/dscparse_adapter.cpp @@ -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 KDSC::bbox() const +{ + if( _cdsc->bbox == 0 ) + return auto_ptr( 0 ); + else + return auto_ptr( new KDSCBBOX( *_cdsc->bbox ) ); +} + +auto_ptr KDSC::page_bbox() const +{ + if( _cdsc->page_bbox == 0 ) + return auto_ptr( 0 ); + else + return auto_ptr( 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( 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 index 00000000..1e353801 --- /dev/null +++ b/thumbnailers/ps/dscparse_adapter.h @@ -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 +#include +#include + +#include +#include + +#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 + * . + */ + +template 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 auto_ptr(auto_ptr& a) : _ptr(a.release()) {} + auto_ptr& operator=(auto_ptr& a) { + if (&a != this) { + delete _ptr; + _ptr = a.release(); + } + return *this; + } + template + auto_ptr& operator=(auto_ptr& 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 bbox() const; + auto_ptr page_bbox() const; +#else + std::auto_ptr bbox() const; + std::auto_ptr 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 index 00000000..2650e306 --- /dev/null +++ b/thumbnailers/ps/gscreator.cpp @@ -0,0 +1,624 @@ +/* This file is part of the KDE libraries + Copyright (C) 2001 Malte Starostik + + Handling of EPS previews Copyright (C) 2003 Philipp Hullmann + + 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 +#endif + + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_SELECT_H +#include +#endif +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#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 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(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(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(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(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(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(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 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 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(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(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 index 00000000..cb9fb6fb --- /dev/null +++ b/thumbnailers/ps/gscreator.h @@ -0,0 +1,42 @@ +/* This file is part of the KDE libraries + Copyright (C) 2000 Malte Starostik + + 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 +#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 index 00000000..22111dd1 --- /dev/null +++ b/thumbnailers/ps/gsthumbnail.desktop @@ -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 index 00000000..adce793f --- /dev/null +++ b/thumbnailers/raw/CMakeLists.txt @@ -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 index 00000000..48d27492 --- /dev/null +++ b/thumbnailers/raw/rawcreator.cpp @@ -0,0 +1,109 @@ +/** + Copyright (C) 2008 Unai Garro + + 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 + +#include +#include + +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 index 00000000..f01532ab --- /dev/null +++ b/thumbnailers/raw/rawcreator.h @@ -0,0 +1,34 @@ +/** + Copyright (C) 2008 Unai Garro + + 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 + +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 index 00000000..7049808f --- /dev/null +++ b/thumbnailers/raw/rawthumbnail.desktop @@ -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