libextractor

GNU libextractor
Log | Files | Refs | Submodules | README | LICENSE

commit a0655d656c37edd602dc0fd40bbb53071cbfb85b
parent b058a6839623b32fb5fbadb0aec586887bd12237
Author: Christian Grothoff <christian@grothoff.org>
Date:   Tue, 15 Dec 2009 16:40:48 +0000

pdf

Diffstat:
Mconfigure.ac | 38++++++++++++--------------------------
Msrc/include/extractor.h | 4++++
Msrc/main/extractor_metatypes.c | 7+++++--
Msrc/plugins/Makefile.am | 36++++++++++++++++++------------------
Msrc/plugins/dvi_extractor.c | 2+-
Dsrc/plugins/pdf/Array.cc | 73-------------------------------------------------------------------------
Dsrc/plugins/pdf/Array.h | 58----------------------------------------------------------
Dsrc/plugins/pdf/COPYING | 339-------------------------------------------------------------------------------
Dsrc/plugins/pdf/Catalog.cc | 360-------------------------------------------------------------------------------
Dsrc/plugins/pdf/Catalog.h | 89-------------------------------------------------------------------------------
Dsrc/plugins/pdf/CompactFontInfo.h | 464-------------------------------------------------------------------------------
Dsrc/plugins/pdf/Decrypt.cc | 399-------------------------------------------------------------------------------
Dsrc/plugins/pdf/Decrypt.h | 61-------------------------------------------------------------
Dsrc/plugins/pdf/Dict.cc | 95-------------------------------------------------------------------------------
Dsrc/plugins/pdf/Dict.h | 77-----------------------------------------------------------------------------
Dsrc/plugins/pdf/Error.cc | 21---------------------
Dsrc/plugins/pdf/Error.h | 23-----------------------
Dsrc/plugins/pdf/ErrorCodes.h | 36------------------------------------
Dsrc/plugins/pdf/FontEncoding.cc | 143-------------------------------------------------------------------------------
Dsrc/plugins/pdf/FontEncoding.h | 64----------------------------------------------------------------
Dsrc/plugins/pdf/FontFile.cc | 2530-------------------------------------------------------------------------------
Dsrc/plugins/pdf/FontFile.h | 170-------------------------------------------------------------------------------
Dsrc/plugins/pdf/Function.cc | 1520-------------------------------------------------------------------------------
Dsrc/plugins/pdf/Function.h | 183-------------------------------------------------------------------------------
Dsrc/plugins/pdf/GString.cc | 232-------------------------------------------------------------------------------
Dsrc/plugins/pdf/GString.h | 102-------------------------------------------------------------------------------
Dsrc/plugins/pdf/INFO | 21---------------------
Dsrc/plugins/pdf/Lexer.cc | 474-------------------------------------------------------------------------------
Dsrc/plugins/pdf/Lexer.h | 77-----------------------------------------------------------------------------
Dsrc/plugins/pdf/Link.cc | 849-------------------------------------------------------------------------------
Dsrc/plugins/pdf/Link.h | 409-------------------------------------------------------------------------------
Dsrc/plugins/pdf/Makefile.am | 44--------------------------------------------
Dsrc/plugins/pdf/Object.cc | 164-------------------------------------------------------------------------------
Dsrc/plugins/pdf/Object.h | 303-------------------------------------------------------------------------------
Dsrc/plugins/pdf/PDFDoc.cc | 296-------------------------------------------------------------------------------
Dsrc/plugins/pdf/PDFDoc.h | 173-------------------------------------------------------------------------------
Dsrc/plugins/pdf/Page.cc | 349-------------------------------------------------------------------------------
Dsrc/plugins/pdf/Page.h | 168-------------------------------------------------------------------------------
Dsrc/plugins/pdf/Params.cc | 88-------------------------------------------------------------------------------
Dsrc/plugins/pdf/Params.h | 40----------------------------------------
Dsrc/plugins/pdf/Parser.cc | 231-------------------------------------------------------------------------------
Dsrc/plugins/pdf/Parser.h | 60------------------------------------------------------------
Dsrc/plugins/pdf/StdFontInfo.h | 546-------------------------------------------------------------------------------
Dsrc/plugins/pdf/Stream-CCITT.h | 459-------------------------------------------------------------------------------
Dsrc/plugins/pdf/Stream.cc | 4656------------------------------------------------------------------------------
Dsrc/plugins/pdf/Stream.h | 848-------------------------------------------------------------------------------
Dsrc/plugins/pdf/XRef.cc | 965-------------------------------------------------------------------------------
Dsrc/plugins/pdf/XRef.h | 135-------------------------------------------------------------------------------
Dsrc/plugins/pdf/aconf.h | 92-------------------------------------------------------------------------------
Dsrc/plugins/pdf/aconf2.h | 38--------------------------------------
Dsrc/plugins/pdf/gfile.cc | 387-------------------------------------------------------------------------------
Dsrc/plugins/pdf/gfile.h | 104-------------------------------------------------------------------------------
Dsrc/plugins/pdf/gmem.cc | 204-------------------------------------------------------------------------------
Dsrc/plugins/pdf/gmem.h | 53-----------------------------------------------------
Dsrc/plugins/pdf/gmempp.cc | 31-------------------------------
Dsrc/plugins/pdf/gtypes.h | 29-----------------------------
Dsrc/plugins/pdf/parseargs.cc | 190-------------------------------------------------------------------------------
Dsrc/plugins/pdf/parseargs.h | 71-----------------------------------------------------------------------
Dsrc/plugins/pdf/pdfextractor.cc | 306-------------------------------------------------------------------------------
Asrc/plugins/pdf_extractor.cc | 216+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
60 files changed, 256 insertions(+), 19946 deletions(-)

diff --git a/configure.ac b/configure.ac @@ -217,6 +217,13 @@ AC_CHECK_LIB(mpeg2, mpeg2_init, AM_CONDITIONAL(HAVE_MPEG2, false))], AM_CONDITIONAL(HAVE_MPEG2, false)) +AC_CHECK_LIB(poppler, _ZTI9MemStream, + [AC_CHECK_HEADERS([poppler/goo/gmem.h], + AM_CONDITIONAL(HAVE_POPPLER, true) + AC_DEFINE(HAVE_POPPLER,1,[Have libpoppler]), + AM_CONDITIONAL(HAVE_POPPLER, false))], + AM_CONDITIONAL(HAVE_POPPLER, false)) + # restore LIBS LIBS=$LIBSOLD @@ -309,7 +316,6 @@ else fi # check for all C++ dependencies... -xpdf=0 exiv2=0 qt=0 qt4=0 @@ -398,21 +404,6 @@ AC_ARG_WITH(qt, EXT_LIB_PATH="-L$with_qt/lib $EXT_LIB_PATH" qt_svg=1)))]) -AC_MSG_CHECKING([whether to enable xpdf-based extractor]) -AC_ARG_ENABLE(xpdf, - [AC_HELP_STRING([--enable-xpdf],[Enable xpdf-based extractor]) - AC_HELP_STRING([--disable-xpdf],[Disable xpdf-based extractor])], - [case "$enableval" in - no) AC_MSG_RESULT(no) - xpdf=0 - ;; - *) AC_MSG_RESULT(yes) - xpdf=1 - ;; - esac], - [ AC_MSG_RESULT(no) - xpdf=0]) - exiv2=1 AC_MSG_CHECKING([whether to enable exiv2 extractor]) AC_ARG_ENABLE(exiv2, @@ -455,8 +446,6 @@ fi AM_CONDITIONAL(HAVE_QT_SVG, test x$qt_svg != x0) AM_CONDITIONAL(HAVE_QT_SVG4, test x$qt_svg4 != x0) -AM_CONDITIONAL(HAVE_XPDF, test x$xpdf != x0) - AM_CONDITIONAL(HAVE_EXIV2, test x$exiv2 != x0) AC_DEFINE_UNQUOTED([HAVE_EXIV2], $exiv2, [We use EXIV2]) @@ -569,7 +558,6 @@ src/main/Makefile src/plugins/Makefile src/plugins/ole2/Makefile src/plugins/oo/Makefile -src/plugins/pdf/Makefile src/plugins/printable/Makefile src/plugins/hash/Makefile src/plugins/thumbnail/Makefile @@ -627,13 +615,6 @@ fi AC_OUTPUT -if test "x$xpdf" = "x1" -then - AC_MSG_NOTICE([NOTICE: xpdf enabled (xpdf has a bad security record)]) -else - AC_MSG_NOTICE([NOTICE: xpdf disabled (result: limited PDF support)]) -fi - if test "x$exiv2" = "x0" then AC_MSG_NOTICE([NOTICE: exiv2 disabled]) @@ -679,6 +660,11 @@ then AC_MSG_NOTICE([NOTICE: libmpeg2 not found (will not compile mpeg2 plugin)]) fi +if test "x$HAVE_POPPLER_TRUE" = "x#" +then + AC_MSG_NOTICE([NOTICE: libpoppler not found (will not compile pdf plugin)]) +fi + if test "x$HAVE_CXX" != "xyes" then AC_MSG_NOTICE([NOTICE: no C++ compiler found (not compiling plugins that require C++)]) diff --git a/src/include/extractor.h b/src/include/extractor.h @@ -237,6 +237,10 @@ enum EXTRACTOR_MetaType /* image specifics */ EXTRACTOR_METATYPE_IMAGE_DIMENSIONS = 112, + + + EXTRACTOR_METATYPE_PRODUCED_BY_SOFTWARE = 113, + /* fixme: used up to here! */ EXTRACTOR_METATYPE_THUMBNAIL_DATA = 70, diff --git a/src/main/extractor_metatypes.c b/src/main/extractor_metatypes.c @@ -282,8 +282,11 @@ static const struct MetaTypeDescription meta_type_descriptions[] = { gettext_noop ("") }, { gettext_noop ("image dimensions"), gettext_noop ("") }, - { gettext_noop (""), - gettext_noop ("") }, + { gettext_noop ("produced by software"), + gettext_noop ("") }, /* what is the exact difference between the software + creator and the software producer? PDF and DVI + both have this distinction (i.e., Writer vs. + OpenOffice) */ { gettext_noop (""), gettext_noop ("") }, #if 0 diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am @@ -46,22 +46,19 @@ if HAVE_CXX if HAVE_EXIV2 exiv2=libextractor_exiv2.la endif +if HAVE_POPPLER + pdf=libextractor_pdf.la endif - - -if HAVE_XPDF - xpdfdir=pdf -else - pdfplugin=libextractor_pdf.la endif + if HAVE_MPEG2 extrampeg = libextractor_mpeg.la endif # toggle for development SUBDIRS = . -# SUBDIRS = . $(thumbgtk) $(thumbffmpeg) $(oodir) $(printdir) hash $(oledir) $(xpdfdir) +# SUBDIRS = . $(thumbgtk) $(thumbffmpeg) $(oodir) $(printdir) hash $(oledir) if HAVE_VORBISFILE @@ -95,6 +92,7 @@ plugin_LTLIBRARIES = \ libextractor_html.la \ libextractor_it.la \ libextractor_mime.la \ + $(pdf) \ $(rpm) libextractor_applefile_la_SOURCES = \ @@ -148,6 +146,19 @@ libextractor_it_la_SOURCES = \ libextractor_it_la_LDFLAGS = \ $(PLUGINFLAGS) +libextractor_mime_la_SOURCES = \ + mime_extractor.c +libextractor_mime_la_LDFLAGS = \ + $(PLUGINFLAGS) + +libextractor_pdf_la_SOURCES = \ + pdf_extractor.cc +libextractor_pdf_la_LDFLAGS = \ + $(XTRA_CPPLIBS) $(PLUGINFLAGS) +libextractor_pdf_la_LIBADD = \ + $(top_builddir)/src/common/libextractor_common.la \ + -lpoppler + libextractor_rpm_la_SOURCES = \ rpm_extractor.c libextractor_rpm_la_LDFLAGS = \ @@ -155,10 +166,6 @@ libextractor_rpm_la_LDFLAGS = \ libextractor_rpm_la_LIBADD = \ -lrpm -libextractor_mime_la_SOURCES = \ - mime_extractor.c -libextractor_mime_la_LDFLAGS = \ - $(PLUGINFLAGS) @@ -236,13 +243,6 @@ libextractor_wav_la_LDFLAGS = \ libextractor_wav_la_LIBADD = \ $(LE_LIBINTL) -libextractor_pdf_la_SOURCES = \ - pdfextractor.c -libextractor_pdf_la_LDFLAGS = \ - $(PLUGINFLAGS) -libextractor_pdf_la_LIBADD = \ - $(top_builddir)/src/common/libextractor_common.la - libextractor_mp3_la_SOURCES = \ mp3extractor.c libextractor_mp3_la_LDFLAGS = \ diff --git a/src/plugins/dvi_extractor.c b/src/plugins/dvi_extractor.c @@ -33,7 +33,7 @@ static Matches tmap[] = { {"/Author (", EXTRACTOR_METATYPE_AUTHOR_NAME}, {"/Keywords (", EXTRACTOR_METATYPE_KEYWORDS}, {"/Creator (", EXTRACTOR_METATYPE_CREATED_BY_SOFTWARE }, - {"/Producer (", EXTRACTOR_METATYPE_CREATED_BY_SOFTWARE}, + {"/Producer (", EXTRACTOR_METATYPE_PRODUCED_BY_SOFTWARE}, {NULL, 0}, }; diff --git a/src/plugins/pdf/Array.cc b/src/plugins/pdf/Array.cc @@ -1,73 +0,0 @@ -//======================================================================== -// -// Array.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include <stdlib.h> -#include <stddef.h> -#include "gmem.h" -#include "Object.h" -#include "Array.h" - -//------------------------------------------------------------------------ -// Array -//------------------------------------------------------------------------ - -Array::Array(XRef *xrefA) { - xref = xrefA; - elems = NULL; - size = length = 0; - ref = 1; -} - -Array::~Array() { - int i; - - for (i = 0; i < length; ++i) - elems[i].free(); - gfree(elems); -} - -void Array::add(Object *elem) { - if (length == size) { - if (length == 0) { - size = 8; - } else { - size *= 2; - } - elems = (Object *)grealloc(elems, size * sizeof(Object)); - } - elems[length] = *elem; - ++length; -} - -Object *Array::get(int i, Object *obj) { - if (i < 0 || i >= length) { -#ifdef DEBUG_MEM - abort(); -#else - return obj->initNull(); -#endif - } - return elems[i].fetch(xref, obj); -} - -Object *Array::getNF(int i, Object *obj) { - if (i < 0 || i >= length) { -#ifdef DEBUG_MEM - abort(); -#else - return obj->initNull(); -#endif - } - return elems[i].copy(obj); -} diff --git a/src/plugins/pdf/Array.h b/src/plugins/pdf/Array.h @@ -1,58 +0,0 @@ -//======================================================================== -// -// Array.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef ARRAY_H -#define ARRAY_H - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "Object.h" - -class XRef; - -//------------------------------------------------------------------------ -// Array -//------------------------------------------------------------------------ - -class Array { -public: - - // Constructor. - Array(XRef *xrefA); - - // Destructor. - ~Array(); - - // Reference counting. - int incRef() { return ++ref; } - int decRef() { return --ref; } - - // Get number of elements. - int getLength() { return length; } - - // Add an element. - void add(Object *elem); - - // Accessors. - Object *get(int i, Object *obj); - Object *getNF(int i, Object *obj); - -private: - - XRef *xref; // the xref table for this PDF file - Object *elems; // array of elements - int size; // size of <elems> array - int length; // number of elements in array - int ref; // reference count -}; - -#endif diff --git a/src/plugins/pdf/COPYING b/src/plugins/pdf/COPYING @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, 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 Library 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 - - Appendix: How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) 19yy <name of author> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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) 19yy name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/src/plugins/pdf/Catalog.cc b/src/plugins/pdf/Catalog.cc @@ -1,360 +0,0 @@ -//======================================================================== -// -// Catalog.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include <stddef.h> -#include "gmem.h" -#include "Object.h" -#include "XRef.h" -#include "Array.h" -#include "Dict.h" -#include "Page.h" -#include "Error.h" -#include "Link.h" -#include "Catalog.h" - -// This define is used to limit the depth of recursive readPageTree calls -// This is needed because the page tree nodes can reference their parents -// leaving us in an infinite loop -// Most sane pdf documents don't have a call depth higher than 10 -#define MAX_CALL_DEPTH 1000 - -//------------------------------------------------------------------------ -// Catalog -//------------------------------------------------------------------------ - -Catalog::Catalog(XRef *xrefA) { - Object catDict, pagesDict; - Object obj, obj2; - int numPages0; - int i; - - ok = gTrue; - xref = xrefA; - pages = NULL; - pageRefs = NULL; - numPages = pagesSize = 0; - baseURI = NULL; - - xref->getCatalog(&catDict); - if (!catDict.isDict()) { - error(-1, "Catalog object is wrong type (%s)", catDict.getTypeName()); - goto err1; - } - - // read page tree - catDict.dictLookup("Pages", &pagesDict); - // This should really be isDict("Pages"), but I've seen at least one - // PDF file where the /Type entry is missing. - if (!pagesDict.isDict()) { - error(-1, "Top-level pages object is wrong type (%s)", - pagesDict.getTypeName()); - goto err2; - } - pagesDict.dictLookup("Count", &obj); - // some PDF files actually use real numbers here ("/Count 9.0") - if (!obj.isNum()) { - error(-1, "Page count in top-level pages object is wrong type (%s)", - obj.getTypeName()); - goto err3; - } - pagesSize = numPages0 = (int)obj.getNum(); - obj.free(); - pages = (Page **)gmalloc(pagesSize * sizeof(Page *)); - pageRefs = (Ref *)gmalloc(pagesSize * sizeof(Ref)); - for (i = 0; i < pagesSize; ++i) { - pages[i] = NULL; - pageRefs[i].num = -1; - pageRefs[i].gen = -1; - } - numPages = readPageTree(pagesDict.getDict(), NULL, 0, 0); - if (numPages != numPages0) { - error(-1, "Page count in top-level pages object is incorrect"); - } - pagesDict.free(); - - // read named destination dictionary - catDict.dictLookup("Dests", &dests); - - // read root of named destination tree - if (catDict.dictLookup("Names", &obj)->isDict()) - obj.dictLookup("Dests", &nameTree); - else - nameTree.initNull(); - obj.free(); - - // read base URI - if (catDict.dictLookup("URI", &obj)->isDict()) { - if (obj.dictLookup("Base", &obj2)->isString()) { - baseURI = obj2.getString()->copy(); - } - obj2.free(); - } - obj.free(); - - // get the metadata stream - catDict.dictLookup("Metadata", &metadata); - - // get the structure tree root - catDict.dictLookup("StructTreeRoot", &structTreeRoot); - - // get the outline dictionary - catDict.dictLookup("Outlines", &outline); - - catDict.free(); - return; - - err3: - obj.free(); - err2: - pagesDict.free(); - err1: - catDict.free(); - dests.initNull(); - nameTree.initNull(); - ok = gFalse; -} - -Catalog::~Catalog() { - int i; - - if (pages) { - for (i = 0; i < pagesSize; ++i) { - if (pages[i]) { - delete pages[i]; - } - } - gfree(pages); - gfree(pageRefs); - } - dests.free(); - nameTree.free(); - if (baseURI) { - delete baseURI; - } - metadata.free(); - structTreeRoot.free(); - outline.free(); -} - -GString *Catalog::readMetadata() { - GString *s; - Dict *dict; - Object obj; - int c; - - if (!metadata.isStream()) { - return NULL; - } - dict = metadata.streamGetDict(); - if (!dict->lookup("Subtype", &obj)->isName("XML")) { - error(-1, "Unknown Metadata type: '%s'", - obj.isName() ? obj.getName() : "???"); - } - obj.free(); - s = new GString(); - metadata.streamReset(); - while ((c = metadata.streamGetChar()) != EOF) { - s->append(c); - } - metadata.streamClose(); - return s; -} - -int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start, int callDepth) { - Object kids; - Object kid; - Object kidRef; - PageAttrs *attrs1, *attrs2; - Page *page; - int i, j; - - attrs1 = new PageAttrs(attrs, pagesDict); - pagesDict->lookup("Kids", &kids); - if (!kids.isArray()) { - error(-1, "Kids object (page %d) is wrong type (%s)", - start+1, kids.getTypeName()); - goto err1; - } - for (i = 0; i < kids.arrayGetLength(); ++i) { - kids.arrayGet(i, &kid); - if (kid.isDict("Page")) { - attrs2 = new PageAttrs(attrs1, kid.getDict()); - page = new Page(xref, start+1, kid.getDict(), attrs2); - if (!page->isOk()) { - ++start; - goto err3; - } - if (start >= pagesSize) { - pagesSize += 32; - pages = (Page **)grealloc(pages, pagesSize * sizeof(Page *)); - pageRefs = (Ref *)grealloc(pageRefs, pagesSize * sizeof(Ref)); - for (j = pagesSize - 32; j < pagesSize; ++j) { - pages[j] = NULL; - pageRefs[j].num = -1; - pageRefs[j].gen = -1; - } - } - pages[start] = page; - kids.arrayGetNF(i, &kidRef); - if (kidRef.isRef()) { - pageRefs[start].num = kidRef.getRefNum(); - pageRefs[start].gen = kidRef.getRefGen(); - } - kidRef.free(); - ++start; - // This should really be isDict("Pages"), but I've seen at least one - // PDF file where the /Type entry is missing. - } else if (kid.isDict()) { - if (callDepth > MAX_CALL_DEPTH) { - error(-1, "Limit of %d recursive calls reached while reading the page tree. If your document is correct and not a test to try to force a crash, please report a bug.", MAX_CALL_DEPTH); - } else { - if ((start = readPageTree(kid.getDict(), attrs1, start, callDepth + 1)) - < 0) - goto err2; - } - } else { - error(-1, "Kid object (page %d) is wrong type (%s)", - start+1, kid.getTypeName()); - goto err2; - } - kid.free(); - } - delete attrs1; - kids.free(); - return start; - - err3: - delete page; - err2: - kid.free(); - err1: - kids.free(); - delete attrs1; - ok = gFalse; - return -1; -} - -int Catalog::findPage(int num, int gen) { - int i; - - for (i = 0; i < numPages; ++i) { - if (pageRefs[i].num == num && pageRefs[i].gen == gen) - return i + 1; - } - return 0; -} - -LinkDest *Catalog::findDest(GString *name) { - LinkDest *dest; - Object obj1, obj2; - GBool found; - - // try named destination dictionary then name tree - found = gFalse; - if (dests.isDict()) { - if (!dests.dictLookup(name->getCString(), &obj1)->isNull()) - found = gTrue; - else - obj1.free(); - } - if (!found && nameTree.isDict()) { - if (!findDestInTree(&nameTree, name, &obj1)->isNull()) - found = gTrue; - else - obj1.free(); - } - if (!found) - return NULL; - - // construct LinkDest - dest = NULL; - if (obj1.isArray()) { - dest = new LinkDest(obj1.getArray()); - } else if (obj1.isDict()) { - if (obj1.dictLookup("D", &obj2)->isArray()) - dest = new LinkDest(obj2.getArray()); - else - error(-1, "Bad named destination value"); - obj2.free(); - } else { - error(-1, "Bad named destination value"); - } - obj1.free(); - if (dest && !dest->isOk()) { - delete dest; - dest = NULL; - } - - return dest; -} - -Object *Catalog::findDestInTree(Object *tree, GString *name, Object *obj) { - Object names, name1; - Object kids, kid, limits, low, high; - GBool done, found; - int cmp, i; - - // leaf node - if (tree->dictLookup("Names", &names)->isArray()) { - done = found = gFalse; - for (i = 0; !done && i < names.arrayGetLength(); i += 2) { - if (names.arrayGet(i, &name1)->isString()) { - cmp = name->cmp(name1.getString()); - if (cmp == 0) { - names.arrayGet(i+1, obj); - found = gTrue; - done = gTrue; - } else if (cmp < 0) { - done = gTrue; - } - } - name1.free(); - } - names.free(); - if (!found) - obj->initNull(); - return obj; - } - names.free(); - - // root or intermediate node - done = gFalse; - if (tree->dictLookup("Kids", &kids)->isArray()) { - for (i = 0; !done && i < kids.arrayGetLength(); ++i) { - if (kids.arrayGet(i, &kid)->isDict()) { - if (kid.dictLookup("Limits", &limits)->isArray()) { - if (limits.arrayGet(0, &low)->isString() && - name->cmp(low.getString()) >= 0) { - if (limits.arrayGet(1, &high)->isString() && - name->cmp(high.getString()) <= 0) { - findDestInTree(&kid, name, obj); - done = gTrue; - } - high.free(); - } - low.free(); - } - limits.free(); - } - kid.free(); - } - } - kids.free(); - - // name was outside of ranges of all kids - if (!done) - obj->initNull(); - - return obj; -} diff --git a/src/plugins/pdf/Catalog.h b/src/plugins/pdf/Catalog.h @@ -1,89 +0,0 @@ -//======================================================================== -// -// Catalog.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef CATALOG_H -#define CATALOG_H - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -class XRef; -class Object; -class Page; -class PageAttrs; -struct Ref; -class LinkDest; - -//------------------------------------------------------------------------ -// Catalog -//------------------------------------------------------------------------ - -class Catalog { -public: - - // Constructor. - Catalog(XRef *xrefA); - - // Destructor. - ~Catalog(); - - // Is catalog valid? - GBool isOk() { return ok; } - - // Get number of pages. - int getNumPages() { return numPages; } - - // Get a page. - Page *getPage(int i) { return pages[i-1]; } - - // Get the reference for a page object. - Ref *getPageRef(int i) { return &pageRefs[i-1]; } - - // Return base URI, or NULL if none. - GString *getBaseURI() { return baseURI; } - - // Return the contents of the metadata stream, or NULL if there is - // no metadata. - GString *readMetadata(); - - // Return the structure tree root object. - Object *getStructTreeRoot() { return &structTreeRoot; } - - // Find a page, given its object ID. Returns page number, or 0 if - // not found. - int findPage(int num, int gen); - - // Find a named destination. Returns the link destination, or - // NULL if <name> is not a destination. - LinkDest *findDest(GString *name); - - Object *getOutline() { return &outline; } - -private: - - XRef *xref; // the xref table for this PDF file - Page **pages; // array of pages - Ref *pageRefs; // object ID for each page - int numPages; // number of pages - int pagesSize; // size of pages array - Object dests; // named destination dictionary - Object nameTree; // name tree - GString *baseURI; // base URI for URI-type links - Object metadata; // metadata stream - Object structTreeRoot; // structure tree root dictionary - Object outline; // outline dictionary - GBool ok; // true if catalog is valid - - int readPageTree(Dict *pages, PageAttrs *attrs, int start, int callDepth); - Object *findDestInTree(Object *tree, GString *name, Object *obj); -}; - -#endif diff --git a/src/plugins/pdf/CompactFontInfo.h b/src/plugins/pdf/CompactFontInfo.h @@ -1,464 +0,0 @@ -//======================================================================== -// -// CompactFontInfo.h -// -// Copyright 1999 Derek B. Noonburg -// -//======================================================================== - -#ifndef COMPACTFONTINFO_H -#define COMPACTFONTINFO_H - -static char *type1CStdStrings[391] = { - ".notdef", - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quoteright", - "parenleft", - "parenright", - "asterisk", - "plus", - "comma", - "hyphen", - "period", - "slash", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "colon", - "semicolon", - "less", - "equal", - "greater", - "question", - "at", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "bracketleft", - "backslash", - "bracketright", - "asciicircum", - "underscore", - "quoteleft", - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "braceleft", - "bar", - "braceright", - "asciitilde", - "exclamdown", - "cent", - "sterling", - "fraction", - "yen", - "florin", - "section", - "currency", - "quotesingle", - "quotedblleft", - "guillemotleft", - "guilsinglleft", - "guilsinglright", - "fi", - "fl", - "endash", - "dagger", - "daggerdbl", - "periodcentered", - "paragraph", - "bullet", - "quotesinglbase", - "quotedblbase", - "quotedblright", - "guillemotright", - "ellipsis", - "perthousand", - "questiondown", - "grave", - "acute", - "circumflex", - "tilde", - "macron", - "breve", - "dotaccent", - "dieresis", - "ring", - "cedilla", - "hungarumlaut", - "ogonek", - "caron", - "emdash", - "AE", - "ordfeminine", - "Lslash", - "Oslash", - "OE", - "ordmasculine", - "ae", - "dotlessi", - "lslash", - "oslash", - "oe", - "germandbls", - "onesuperior", - "logicalnot", - "mu", - "trademark", - "Eth", - "onehalf", - "plusminus", - "Thorn", - "onequarter", - "divide", - "brokenbar", - "degree", - "thorn", - "threequarters", - "twosuperior", - "registered", - "minus", - "eth", - "multiply", - "threesuperior", - "copyright", - "Aacute", - "Acircumflex", - "Adieresis", - "Agrave", - "Aring", - "Atilde", - "Ccedilla", - "Eacute", - "Ecircumflex", - "Edieresis", - "Egrave", - "Iacute", - "Icircumflex", - "Idieresis", - "Igrave", - "Ntilde", - "Oacute", - "Ocircumflex", - "Odieresis", - "Ograve", - "Otilde", - "Scaron", - "Uacute", - "Ucircumflex", - "Udieresis", - "Ugrave", - "Yacute", - "Ydieresis", - "Zcaron", - "aacute", - "acircumflex", - "adieresis", - "agrave", - "aring", - "atilde", - "ccedilla", - "eacute", - "ecircumflex", - "edieresis", - "egrave", - "iacute", - "icircumflex", - "idieresis", - "igrave", - "ntilde", - "oacute", - "ocircumflex", - "odieresis", - "ograve", - "otilde", - "scaron", - "uacute", - "ucircumflex", - "udieresis", - "ugrave", - "yacute", - "ydieresis", - "zcaron", - "exclamsmall", - "Hungarumlautsmall", - "dollaroldstyle", - "dollarsuperior", - "ampersandsmall", - "Acutesmall", - "parenleftsuperior", - "parenrightsuperior", - "twodotenleader", - "onedotenleader", - "zerooldstyle", - "oneoldstyle", - "twooldstyle", - "threeoldstyle", - "fouroldstyle", - "fiveoldstyle", - "sixoldstyle", - "sevenoldstyle", - "eightoldstyle", - "nineoldstyle", - "commasuperior", - "threequartersemdash", - "periodsuperior", - "questionsmall", - "asuperior", - "bsuperior", - "centsuperior", - "dsuperior", - "esuperior", - "isuperior", - "lsuperior", - "msuperior", - "nsuperior", - "osuperior", - "rsuperior", - "ssuperior", - "tsuperior", - "ff", - "ffi", - "ffl", - "parenleftinferior", - "parenrightinferior", - "Circumflexsmall", - "hyphensuperior", - "Gravesmall", - "Asmall", - "Bsmall", - "Csmall", - "Dsmall", - "Esmall", - "Fsmall", - "Gsmall", - "Hsmall", - "Ismall", - "Jsmall", - "Ksmall", - "Lsmall", - "Msmall", - "Nsmall", - "Osmall", - "Psmall", - "Qsmall", - "Rsmall", - "Ssmall", - "Tsmall", - "Usmall", - "Vsmall", - "Wsmall", - "Xsmall", - "Ysmall", - "Zsmall", - "colonmonetary", - "onefitted", - "rupiah", - "Tildesmall", - "exclamdownsmall", - "centoldstyle", - "Lslashsmall", - "Scaronsmall", - "Zcaronsmall", - "Dieresissmall", - "Brevesmall", - "Caronsmall", - "Dotaccentsmall", - "Macronsmall", - "figuredash", - "hypheninferior", - "Ogoneksmall", - "Ringsmall", - "Cedillasmall", - "questiondownsmall", - "oneeighth", - "threeeighths", - "fiveeighths", - "seveneighths", - "onethird", - "twothirds", - "zerosuperior", - "foursuperior", - "fivesuperior", - "sixsuperior", - "sevensuperior", - "eightsuperior", - "ninesuperior", - "zeroinferior", - "oneinferior", - "twoinferior", - "threeinferior", - "fourinferior", - "fiveinferior", - "sixinferior", - "seveninferior", - "eightinferior", - "nineinferior", - "centinferior", - "dollarinferior", - "periodinferior", - "commainferior", - "Agravesmall", - "Aacutesmall", - "Acircumflexsmall", - "Atildesmall", - "Adieresissmall", - "Aringsmall", - "AEsmall", - "Ccedillasmall", - "Egravesmall", - "Eacutesmall", - "Ecircumflexsmall", - "Edieresissmall", - "Igravesmall", - "Iacutesmall", - "Icircumflexsmall", - "Idieresissmall", - "Ethsmall", - "Ntildesmall", - "Ogravesmall", - "Oacutesmall", - "Ocircumflexsmall", - "Otildesmall", - "Odieresissmall", - "OEsmall", - "Oslashsmall", - "Ugravesmall", - "Uacutesmall", - "Ucircumflexsmall", - "Udieresissmall", - "Yacutesmall", - "Thornsmall", - "Ydieresissmall", - "001.000", - "001.001", - "001.002", - "001.003", - "Black", - "Bold", - "Book", - "Light", - "Medium", - "Regular", - "Roman", - "Semibold" -}; - -static Gushort type1CISOAdobeCharset[229] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228 -}; - -static Gushort type1CExpertCharset[166] = { - 0, 1, 229, 230, 231, 232, 233, 234, 235, 236, - 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, - 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, - 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, 266, 109, 110, 267, 268, - 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, - 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, - 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, - 158, 155, 163, 319, 320, 321, 322, 323, 324, 325, - 326, 150, 164, 169, 327, 328, 329, 330, 331, 332, - 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, - 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, - 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, - 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, - 373, 374, 375, 376, 377, 378 -}; - -static Gushort type1CExpertSubsetCharset[87] = { - 0, 1, 231, 232, 235, 236, 237, 238, 13, 14, - 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, - 247, 248, 27, 28, 249, 250, 251, 253, 254, 255, - 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, - 266, 109, 110, 267, 268, 269, 270, 272, 300, 301, - 302, 305, 314, 315, 158, 155, 163, 320, 321, 322, - 323, 324, 325, 326, 150, 164, 169, 327, 328, 329, - 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, - 340, 341, 342, 343, 344, 345, 346 -}; - -#endif diff --git a/src/plugins/pdf/Decrypt.cc b/src/plugins/pdf/Decrypt.cc @@ -1,399 +0,0 @@ -//======================================================================== -// -// Decrypt.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include "gmem.h" -#include "Decrypt.h" - -static void rc4InitKey(Guchar *key, int keyLen, Guchar *state); -static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c); -static void md5(Guchar *msg, int msgLen, Guchar *digest); - -static Guchar passwordPad[32] = { - 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, - 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08, - 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, - 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a -}; - -//------------------------------------------------------------------------ -// Decrypt -//------------------------------------------------------------------------ - -Decrypt::Decrypt(Guchar *fileKey, int keyLength, int objNum, int objGen) { - int i; - - // construct object key - for (i = 0; i < keyLength; ++i) { - objKey[i] = fileKey[i]; - } - objKey[keyLength] = objNum & 0xff; - objKey[keyLength + 1] = (objNum >> 8) & 0xff; - objKey[keyLength + 2] = (objNum >> 16) & 0xff; - objKey[keyLength + 3] = objGen & 0xff; - objKey[keyLength + 4] = (objGen >> 8) & 0xff; - md5(objKey, keyLength + 5, objKey); - - // set up for decryption - x = y = 0; - if ((objKeyLength = keyLength + 5) > 16) { - objKeyLength = 16; - } - rc4InitKey(objKey, objKeyLength, state); -} - -void Decrypt::reset() { - x = y = 0; - rc4InitKey(objKey, objKeyLength, state); -} - -Guchar Decrypt::decryptByte(Guchar c) { - return rc4DecryptByte(state, &x, &y, c); -} - -GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength, - GString *ownerKey, GString *userKey, - int permissions, GString *fileID, - GString *ownerPassword, GString *userPassword, - Guchar *fileKey, GBool *ownerPasswordOk) { - Guchar test[32], test2[32]; - GString *userPassword2; - Guchar fState[256]; - Guchar tmpKey[16]; - Guchar fx, fy; - int len, i, j; - - // try using the supplied owner password to generate the user password - *ownerPasswordOk = gFalse; - if (ownerPassword) { - len = ownerPassword->getLength(); - if (len < 32) { - memcpy(test, ownerPassword->getCString(), len); - memcpy(test + len, passwordPad, 32 - len); - } else { - memcpy(test, ownerPassword->getCString(), 32); - } - md5(test, 32, test); - if (encRevision == 3) { - for (i = 0; i < 50; ++i) { - md5(test, 16, test); - } - } - if (encRevision == 2) { - rc4InitKey(test, keyLength, fState); - fx = fy = 0; - for (i = 0; i < 32; ++i) { - test2[i] = rc4DecryptByte(fState, &fx, &fy, ownerKey->getChar(i)); - } - } else { - memcpy(test2, ownerKey->getCString(), 32); - for (i = 19; i >= 0; --i) { - for (j = 0; j < keyLength; ++j) { - tmpKey[j] = test[j] ^ i; - } - rc4InitKey(tmpKey, keyLength, fState); - fx = fy = 0; - for (j = 0; j < 32; ++j) { - test2[j] = rc4DecryptByte(fState, &fx, &fy, test2[j]); - } - } - } - userPassword2 = new GString((char *)test2, 32); - if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, - permissions, fileID, userPassword2, fileKey)) { - *ownerPasswordOk = gTrue; - delete userPassword2; - return gTrue; - } - delete userPassword2; - } - - // try using the supplied user password - return makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, - permissions, fileID, userPassword, fileKey); -} - -GBool Decrypt::makeFileKey2(int encVersion, int encRevision, int keyLength, - GString *ownerKey, GString *userKey, - int permissions, GString *fileID, - GString *userPassword, Guchar *fileKey) { - Guchar *buf; - Guchar test[32]; - Guchar fState[256]; - Guchar tmpKey[16]; - Guchar fx, fy; - int len, i, j; - GBool ok; - - // generate file key - buf = (Guchar *)gmalloc(68 + fileID->getLength()); - if (userPassword) { - len = userPassword->getLength(); - if (len < 32) { - memcpy(buf, userPassword->getCString(), len); - memcpy(buf + len, passwordPad, 32 - len); - } else { - memcpy(buf, userPassword->getCString(), 32); - } - } else { - memcpy(buf, passwordPad, 32); - } - memcpy(buf + 32, ownerKey->getCString(), 32); - buf[64] = permissions & 0xff; - buf[65] = (permissions >> 8) & 0xff; - buf[66] = (permissions >> 16) & 0xff; - buf[67] = (permissions >> 24) & 0xff; - memcpy(buf + 68, fileID->getCString(), fileID->getLength()); - md5(buf, 68 + fileID->getLength(), fileKey); - if (encRevision == 3) { - for (i = 0; i < 50; ++i) { - md5(fileKey, keyLength, fileKey); - } - } - - // test user password - if (encRevision == 2) { - rc4InitKey(fileKey, keyLength, fState); - fx = fy = 0; - for (i = 0; i < 32; ++i) { - test[i] = rc4DecryptByte(fState, &fx, &fy, userKey->getChar(i)); - } - ok = memcmp(test, passwordPad, 32) == 0; - } else if (encRevision == 3) { - memcpy(test, userKey->getCString(), 32); - for (i = 19; i >= 0; --i) { - for (j = 0; j < keyLength; ++j) { - tmpKey[j] = fileKey[j] ^ i; - } - rc4InitKey(tmpKey, keyLength, fState); - fx = fy = 0; - for (j = 0; j < 32; ++j) { - test[j] = rc4DecryptByte(fState, &fx, &fy, test[j]); - } - } - memcpy(buf, passwordPad, 32); - memcpy(buf + 32, fileID->getCString(), fileID->getLength()); - md5(buf, 32 + fileID->getLength(), buf); - ok = memcmp(test, buf, 16) == 0; - } else { - ok = gFalse; - } - - gfree(buf); - return ok; -} - -//------------------------------------------------------------------------ -// RC4-compatible decryption -//------------------------------------------------------------------------ - -static void rc4InitKey(Guchar *key, int keyLen, Guchar *state) { - Guchar index1, index2; - Guchar t; - int i; - - for (i = 0; i < 256; ++i) - state[i] = i; - index1 = index2 = 0; - for (i = 0; i < 256; ++i) { - index2 = (key[index1] + state[i] + index2) % 256; - t = state[i]; - state[i] = state[index2]; - state[index2] = t; - index1 = (index1 + 1) % keyLen; - } -} - -static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c) { - Guchar x1, y1, tx, ty; - - x1 = *x = (*x + 1) % 256; - y1 = *y = (state[*x] + *y) % 256; - tx = state[x1]; - ty = state[y1]; - state[x1] = ty; - state[y1] = tx; - return c ^ state[(tx + ty) % 256]; -} - -//------------------------------------------------------------------------ -// MD5 message digest -//------------------------------------------------------------------------ - -// this works around a bug in older Sun compilers -static inline Gulong rotateLeft(Gulong x, int r) { - x &= 0xffffffff; - return ((x << r) | (x >> (32 - r))) & 0xffffffff; -} - -static inline Gulong md5Round1(Gulong a, Gulong b, Gulong c, Gulong d, - Gulong Xk, Gulong s, Gulong Ti) { - return b + rotateLeft((a + ((b & c) | (~b & d)) + Xk + Ti), s); -} - -static inline Gulong md5Round2(Gulong a, Gulong b, Gulong c, Gulong d, - Gulong Xk, Gulong s, Gulong Ti) { - return b + rotateLeft((a + ((b & d) | (c & ~d)) + Xk + Ti), s); -} - -static inline Gulong md5Round3(Gulong a, Gulong b, Gulong c, Gulong d, - Gulong Xk, Gulong s, Gulong Ti) { - return b + rotateLeft((a + (b ^ c ^ d) + Xk + Ti), s); -} - -static inline Gulong md5Round4(Gulong a, Gulong b, Gulong c, Gulong d, - Gulong Xk, Gulong s, Gulong Ti) { - return b + rotateLeft((a + (c ^ (b | ~d)) + Xk + Ti), s); -} - -static void md5(Guchar *msg, int msgLen, Guchar *digest) { - Gulong x[16]; - Gulong a, b, c, d, aa, bb, cc, dd; - int n64; - int i, j, k; - - // compute number of 64-byte blocks - // (length + pad byte (0x80) + 8 bytes for length) - n64 = (msgLen + 1 + 8 + 63) / 64; - - // initialize a, b, c, d - a = 0x67452301; - b = 0xefcdab89; - c = 0x98badcfe; - d = 0x10325476; - - // loop through blocks - k = 0; - for (i = 0; i < n64; ++i) { - - // grab a 64-byte block - for (j = 0; j < 16 && k < msgLen - 3; ++j, k += 4) - x[j] = (((((msg[k+3] << 8) + msg[k+2]) << 8) + msg[k+1]) << 8) + msg[k]; - if (i == n64 - 1) { - if (k == msgLen - 3) - x[j] = 0x80000000 + (((msg[k+2] << 8) + msg[k+1]) << 8) + msg[k]; - else if (k == msgLen - 2) - x[j] = 0x800000 + (msg[k+1] << 8) + msg[k]; - else if (k == msgLen - 1) - x[j] = 0x8000 + msg[k]; - else - x[j] = 0x80; - ++j; - while (j < 16) - x[j++] = 0; - x[14] = msgLen << 3; - } - - // save a, b, c, d - aa = a; - bb = b; - cc = c; - dd = d; - - // round 1 - a = md5Round1(a, b, c, d, x[0], 7, 0xd76aa478); - d = md5Round1(d, a, b, c, x[1], 12, 0xe8c7b756); - c = md5Round1(c, d, a, b, x[2], 17, 0x242070db); - b = md5Round1(b, c, d, a, x[3], 22, 0xc1bdceee); - a = md5Round1(a, b, c, d, x[4], 7, 0xf57c0faf); - d = md5Round1(d, a, b, c, x[5], 12, 0x4787c62a); - c = md5Round1(c, d, a, b, x[6], 17, 0xa8304613); - b = md5Round1(b, c, d, a, x[7], 22, 0xfd469501); - a = md5Round1(a, b, c, d, x[8], 7, 0x698098d8); - d = md5Round1(d, a, b, c, x[9], 12, 0x8b44f7af); - c = md5Round1(c, d, a, b, x[10], 17, 0xffff5bb1); - b = md5Round1(b, c, d, a, x[11], 22, 0x895cd7be); - a = md5Round1(a, b, c, d, x[12], 7, 0x6b901122); - d = md5Round1(d, a, b, c, x[13], 12, 0xfd987193); - c = md5Round1(c, d, a, b, x[14], 17, 0xa679438e); - b = md5Round1(b, c, d, a, x[15], 22, 0x49b40821); - - // round 2 - a = md5Round2(a, b, c, d, x[1], 5, 0xf61e2562); - d = md5Round2(d, a, b, c, x[6], 9, 0xc040b340); - c = md5Round2(c, d, a, b, x[11], 14, 0x265e5a51); - b = md5Round2(b, c, d, a, x[0], 20, 0xe9b6c7aa); - a = md5Round2(a, b, c, d, x[5], 5, 0xd62f105d); - d = md5Round2(d, a, b, c, x[10], 9, 0x02441453); - c = md5Round2(c, d, a, b, x[15], 14, 0xd8a1e681); - b = md5Round2(b, c, d, a, x[4], 20, 0xe7d3fbc8); - a = md5Round2(a, b, c, d, x[9], 5, 0x21e1cde6); - d = md5Round2(d, a, b, c, x[14], 9, 0xc33707d6); - c = md5Round2(c, d, a, b, x[3], 14, 0xf4d50d87); - b = md5Round2(b, c, d, a, x[8], 20, 0x455a14ed); - a = md5Round2(a, b, c, d, x[13], 5, 0xa9e3e905); - d = md5Round2(d, a, b, c, x[2], 9, 0xfcefa3f8); - c = md5Round2(c, d, a, b, x[7], 14, 0x676f02d9); - b = md5Round2(b, c, d, a, x[12], 20, 0x8d2a4c8a); - - // round 3 - a = md5Round3(a, b, c, d, x[5], 4, 0xfffa3942); - d = md5Round3(d, a, b, c, x[8], 11, 0x8771f681); - c = md5Round3(c, d, a, b, x[11], 16, 0x6d9d6122); - b = md5Round3(b, c, d, a, x[14], 23, 0xfde5380c); - a = md5Round3(a, b, c, d, x[1], 4, 0xa4beea44); - d = md5Round3(d, a, b, c, x[4], 11, 0x4bdecfa9); - c = md5Round3(c, d, a, b, x[7], 16, 0xf6bb4b60); - b = md5Round3(b, c, d, a, x[10], 23, 0xbebfbc70); - a = md5Round3(a, b, c, d, x[13], 4, 0x289b7ec6); - d = md5Round3(d, a, b, c, x[0], 11, 0xeaa127fa); - c = md5Round3(c, d, a, b, x[3], 16, 0xd4ef3085); - b = md5Round3(b, c, d, a, x[6], 23, 0x04881d05); - a = md5Round3(a, b, c, d, x[9], 4, 0xd9d4d039); - d = md5Round3(d, a, b, c, x[12], 11, 0xe6db99e5); - c = md5Round3(c, d, a, b, x[15], 16, 0x1fa27cf8); - b = md5Round3(b, c, d, a, x[2], 23, 0xc4ac5665); - - // round 4 - a = md5Round4(a, b, c, d, x[0], 6, 0xf4292244); - d = md5Round4(d, a, b, c, x[7], 10, 0x432aff97); - c = md5Round4(c, d, a, b, x[14], 15, 0xab9423a7); - b = md5Round4(b, c, d, a, x[5], 21, 0xfc93a039); - a = md5Round4(a, b, c, d, x[12], 6, 0x655b59c3); - d = md5Round4(d, a, b, c, x[3], 10, 0x8f0ccc92); - c = md5Round4(c, d, a, b, x[10], 15, 0xffeff47d); - b = md5Round4(b, c, d, a, x[1], 21, 0x85845dd1); - a = md5Round4(a, b, c, d, x[8], 6, 0x6fa87e4f); - d = md5Round4(d, a, b, c, x[15], 10, 0xfe2ce6e0); - c = md5Round4(c, d, a, b, x[6], 15, 0xa3014314); - b = md5Round4(b, c, d, a, x[13], 21, 0x4e0811a1); - a = md5Round4(a, b, c, d, x[4], 6, 0xf7537e82); - d = md5Round4(d, a, b, c, x[11], 10, 0xbd3af235); - c = md5Round4(c, d, a, b, x[2], 15, 0x2ad7d2bb); - b = md5Round4(b, c, d, a, x[9], 21, 0xeb86d391); - - // increment a, b, c, d - a += aa; - b += bb; - c += cc; - d += dd; - } - - // break digest into bytes - digest[0] = (Guchar)(a & 0xff); - digest[1] = (Guchar)((a >>= 8) & 0xff); - digest[2] = (Guchar)((a >>= 8) & 0xff); - digest[3] = (Guchar)((a >>= 8) & 0xff); - digest[4] = (Guchar)(b & 0xff); - digest[5] = (Guchar)((b >>= 8) & 0xff); - digest[6] = (Guchar)((b >>= 8) & 0xff); - digest[7] = (Guchar)((b >>= 8) & 0xff); - digest[8] = (Guchar)(c & 0xff); - digest[9] = (Guchar)((c >>= 8) & 0xff); - digest[10] = (Guchar)((c >>= 8) & 0xff); - digest[11] = (Guchar)((c >>= 8) & 0xff); - digest[12] = (Guchar)(d & 0xff); - digest[13] = (Guchar)((d >>= 8) & 0xff); - digest[14] = (Guchar)((d >>= 8) & 0xff); - digest[15] = (Guchar)((d >>= 8) & 0xff); -} diff --git a/src/plugins/pdf/Decrypt.h b/src/plugins/pdf/Decrypt.h @@ -1,61 +0,0 @@ -//======================================================================== -// -// Decrypt.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef DECRYPT_H -#define DECRYPT_H - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "GString.h" - -//------------------------------------------------------------------------ -// Decrypt -//------------------------------------------------------------------------ - -class Decrypt { -public: - - // Initialize the decryptor object. - Decrypt(Guchar *fileKey, int keyLength, int objNum, int objGen); - - // Reset decryption. - void reset(); - - // Decrypt one byte. - Guchar decryptByte(Guchar c); - - // Generate a file key. The <fileKey> buffer must have space for at - // least 16 bytes. Checks <ownerPassword> and then <userPassword> - // and returns true if either is correct. Sets <ownerPasswordOk> if - // the owner password was correct. Either or both of the passwords - // may be NULL, which is treated as an empty string. - static GBool makeFileKey(int encVersion, int encRevision, int keyLength, - GString *ownerKey, GString *userKey, - int permissions, GString *fileID, - GString *ownerPassword, GString *userPassword, - Guchar *fileKey, GBool *ownerPasswordOk); - -private: - - static GBool makeFileKey2(int encVersion, int encRevision, int keyLength, - GString *ownerKey, GString *userKey, - int permissions, GString *fileID, - GString *userPassword, Guchar *fileKey); - - int objKeyLength; - Guchar objKey[21]; - Guchar state[256]; - Guchar x, y; -}; - -#endif diff --git a/src/plugins/pdf/Dict.cc b/src/plugins/pdf/Dict.cc @@ -1,95 +0,0 @@ -//======================================================================== -// -// Dict.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include <stddef.h> -#include <string.h> -#include "gmem.h" -#include "Object.h" -#include "XRef.h" -#include "Dict.h" - -//------------------------------------------------------------------------ -// Dict -//------------------------------------------------------------------------ - -Dict::Dict(XRef *xrefA) { - xref = xrefA; - entries = NULL; - size = length = 0; - ref = 1; -} - -Dict::~Dict() { - int i; - - for (i = 0; i < length; ++i) { - gfree(entries[i].key); - entries[i].val.free(); - } - gfree(entries); -} - -void Dict::add(char *key, Object *val) { - if (length == size) { - if (length == 0) { - size = 8; - } else { - size *= 2; - } - entries = (DictEntry *)grealloc(entries, size * sizeof(DictEntry)); - } - entries[length].key = key; - entries[length].val = *val; - ++length; -} - -inline DictEntry *Dict::find(const char *key) { - int i; - - for (i = 0; i < length; ++i) { - if (!strcmp(key, entries[i].key)) - return &entries[i]; - } - return NULL; -} - -GBool Dict::is(const char *type) { - DictEntry *e; - - return (e = find("Type")) && e->val.isName(type); -} - -Object *Dict::lookup(const char *key, Object *obj) { - DictEntry *e; - - return (e = find(key)) ? e->val.fetch(xref, obj) : obj->initNull(); -} - -Object *Dict::lookupNF(const char *key, Object *obj) { - DictEntry *e; - - return (e = find(key)) ? e->val.copy(obj) : obj->initNull(); -} - -char *Dict::getKey(int i) { - return entries[i].key; -} - -Object *Dict::getVal(int i, Object *obj) { - return entries[i].val.fetch(xref, obj); -} - -Object *Dict::getValNF(int i, Object *obj) { - return entries[i].val.copy(obj); -} diff --git a/src/plugins/pdf/Dict.h b/src/plugins/pdf/Dict.h @@ -1,77 +0,0 @@ -//======================================================================== -// -// Dict.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef DICT_H -#define DICT_H - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "Object.h" - -//------------------------------------------------------------------------ -// Dict -//------------------------------------------------------------------------ - -struct DictEntry { - char *key; - Object val; -}; - -class Dict { -public: - - // Constructor. - Dict(XRef *xrefA); - - // Destructor. - ~Dict(); - - // Reference counting. - int incRef() { return ++ref; } - int decRef() { return --ref; } - - // Get number of entries. - int getLength() { return length; } - - // Add an entry. NB: does not copy key. - void add(char *key, Object *val); - - // Check if dictionary is of specified type. - GBool is(const char *type); - - // Look up an entry and return the value. Returns a null object - // if <key> is not in the dictionary. - Object *lookup(const char *key, Object *obj); - Object *lookupNF(const char *key, Object *obj); - - // Iterative accessors. - char *getKey(int i); - Object *getVal(int i, Object *obj); - Object *getValNF(int i, Object *obj); - - // Set the xref pointer. This is only used in one special case: the - // trailer dictionary, which is read before the xref table is - // parsed. - void setXRef(XRef *xrefA) { xref = xrefA; } - -private: - - XRef *xref; // the xref table for this PDF file - DictEntry *entries; // array of entries - int size; // size of <entries> array - int length; // number of entries in dictionary - int ref; // reference count - - DictEntry *find(const char *key); -}; - -#endif diff --git a/src/plugins/pdf/Error.cc b/src/plugins/pdf/Error.cc @@ -1,21 +0,0 @@ -//======================================================================== -// -// Error.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include <stdio.h> -#include <stddef.h> -#include <stdarg.h> -#include "Error.h" - -void error(int pos, const char *msg, ...) { -} diff --git a/src/plugins/pdf/Error.h b/src/plugins/pdf/Error.h @@ -1,23 +0,0 @@ -//======================================================================== -// -// Error.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef ERROR_H -#define ERROR_H - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include <stdio.h> -#include "config.h" - -extern void error(int pos, const char *msg, ...); - -#endif diff --git a/src/plugins/pdf/ErrorCodes.h b/src/plugins/pdf/ErrorCodes.h @@ -1,36 +0,0 @@ -//======================================================================== -// -// ErrorCodes.h -// -// Copyright 2002-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef ERRORCODES_H -#define ERRORCODES_H - -#define errNone 0 // no error - -#define errOpenFile 1 // couldn't open the PDF file - -#define errBadCatalog 2 // couldn't read the page catalog - -#define errDamaged 3 // PDF file was damaged and couldn't be - // repaired - -#define errEncrypted 4 // file was encrypted and password was - // incorrect or not supplied - -#define errHighlightFile 5 // nonexistent or invalid highlight file - -#define errBadPrinter 6 // invalid printer - -#define errPrinting 7 // error during printing - -#define errPermission 8 // PDF file doesn't allow that operation - -#define errBadPageNum 9 // invalid page number - -#define errFileIO 10 // file I/O error - -#endif diff --git a/src/plugins/pdf/FontEncoding.cc b/src/plugins/pdf/FontEncoding.cc @@ -1,143 +0,0 @@ -//======================================================================== -// -// FontEncoding.cc -// -// Copyright 1999 Derek B. Noonburg -// -//======================================================================== - -#ifdef __GNUC__ -#pragma implementation -#endif - -#include <stdlib.h> -#include <stddef.h> -#include <stdio.h> -#include <string.h> -#include "gmem.h" -#include "FontEncoding.h" - -//------------------------------------------------------------------------ -// FontEncoding -//------------------------------------------------------------------------ - -inline int FontEncoding::hash(char *name) { - Guint h; - - h = (Guint)name[0] & 0xff; - if (h && name[1]) - h = h * 61 + ((Guint)name[1] & 0xff); - return (int)(h % (Guint)fontEncHashSize); -} - -FontEncoding::FontEncoding() { - int i; - - encoding = (char **)gmalloc(256 * sizeof(char *)); - size = 256; - freeEnc = gTrue; - for (i = 0; i < 256; ++i) - encoding[i] = NULL; - for (i = 0; i < fontEncHashSize; ++i) - hashTab[i] = -1; -} - -FontEncoding::FontEncoding(char **encodingA, int sizeA) { - int i; - - encoding = encodingA; - size = sizeA; - freeEnc = gFalse; - for (i = 0; i < fontEncHashSize; ++i) - hashTab[i] = -1; - for (i = 0; i < size; ++i) { - if (encoding[i]) - addChar1(i, encoding[i]); - } -} - -FontEncoding::FontEncoding(FontEncoding *fontEnc) { - int i; - - encoding = (char **)gmalloc(fontEnc->size * sizeof(char *)); - size = fontEnc->size; - freeEnc = gTrue; - for (i = 0; i < size; ++i) { - encoding[i] = - fontEnc->encoding[i] ? copyString(fontEnc->encoding[i]) : (char *)NULL; - } - memcpy(hashTab, fontEnc->hashTab, fontEncHashSize * sizeof(short)); -} - -void FontEncoding::addChar(int code, char *name) { - int h, i; - - // replace character associated with code - if (encoding[code]) { - h = hash(encoding[code]); - for (i = 0; i < fontEncHashSize; ++i) { - if (hashTab[h] == code) { - hashTab[h] = -2; - break; - } - if (++h == fontEncHashSize) - h = 0; - } - gfree(encoding[code]); - } - - // associate name with code - encoding[code] = name; - - // insert name in hash table - addChar1(code, name); -} - -void FontEncoding::addChar1(int code, char *name) { - int h, i, code2; - - // insert name in hash table - h = hash(name); - for (i = 0; i < fontEncHashSize; ++i) { - code2 = hashTab[h]; - if (code2 < 0) { - hashTab[h] = code; - break; - } else if (encoding[code2] && !strcmp(encoding[code2], name)) { - // keep the highest code for each char -- this is needed because - // X won't display chars with codes < 32 - if (code > code2) - hashTab[h] = code; - break; - } - if (++h == fontEncHashSize) - h = 0; - } -} - -FontEncoding::~FontEncoding() { - int i; - - if (freeEnc) { - for (i = 0; i < size; ++i) { - if (encoding[i]) - gfree(encoding[i]); - } - gfree(encoding); - } -} - -int FontEncoding::getCharCode(char *name) { - int h, i, code; - - h = hash(name); - for (i = 0; i < fontEncHashSize; ++i) { - code = hashTab[h]; - if (code == -1 || - (code >= 0 && encoding[code] && !strcmp(encoding[code], name))) - return code; - if (++h >= fontEncHashSize) - h = 0; - } - return -1; -} diff --git a/src/plugins/pdf/FontEncoding.h b/src/plugins/pdf/FontEncoding.h @@ -1,64 +0,0 @@ -//======================================================================== -// -// FontEncoding.h -// -// Copyright 1999 Derek B. Noonburg -// -//======================================================================== - -#ifndef FONTENCODING_H -#define FONTENCODING_H - -#ifdef __GNUC__ -#pragma interface -#endif - -#include "gtypes.h" - -//------------------------------------------------------------------------ -// FontEncoding -//------------------------------------------------------------------------ - -#define fontEncHashSize 419 - -class FontEncoding { -public: - - // Construct an empty encoding. - FontEncoding(); - - // Construct an encoding from an array of char names. - FontEncoding(char **encodingA, int sizeA); - - // Destructor. - ~FontEncoding(); - - // Create a copy of the encoding. - FontEncoding *copy() { return new FontEncoding(this); } - - // Return number of codes in encoding, i.e., max code + 1. - int getSize() { return size; } - - // Add a char to the encoding. - void addChar(int code, char *name); - - // Return the character name associated with <code>. - char *getCharName(int code) { return encoding[code]; } - - // Return the code associated with <name>. - int getCharCode(char *name); - -private: - - FontEncoding(FontEncoding *fontEnc); - int hash(char *name); - void addChar1(int code, char *name); - - char **encoding; // code --> name mapping - int size; // number of codes - GBool freeEnc; // should we free the encoding array? - short // name --> code hash table - hashTab[fontEncHashSize]; -}; - -#endif diff --git a/src/plugins/pdf/FontFile.cc b/src/plugins/pdf/FontFile.cc @@ -1,2530 +0,0 @@ -//======================================================================== -// -// FontFile.cc -// -// Copyright 1999 Derek B. Noonburg -// -//======================================================================== - -#ifdef __GNUC__ -#pragma implementation -#endif - -#include <math.h> -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <ctype.h> -#include "gmem.h" -#include "Error.h" -#include "FontFile.h" - -#include "StdFontInfo.h" -#include "CompactFontInfo.h" - -//------------------------------------------------------------------------ - -static Guint getWord(Guchar *ptr, int size); -static double getNum(Guchar **ptr, GBool *fp); -static char *getString(int sid, Guchar *stringIdxPtr, - Guchar *stringStartPtr, int stringOffSize, - char *buf); - -//------------------------------------------------------------------------ - -static inline char *nextLine(char *line, char *end) { - while (line < end && *line != '\n' && *line != '\r') - ++line; - while (line < end && *line == '\n' || *line == '\r') - ++line; - return line; -} - -static char hexChars[17] = "0123456789ABCDEF"; - -//------------------------------------------------------------------------ -// FontFile -//------------------------------------------------------------------------ - -FontFile::FontFile() { -} - -FontFile::~FontFile() { -} - -//------------------------------------------------------------------------ -// Type1FontFile -//------------------------------------------------------------------------ - -Type1FontFile::Type1FontFile(char *file, int len) { - char *line, *line1, *p, *p2; - char buf[256]; - char c; - int n, code, i; - - name = NULL; - encoding = NULL; - freeEnc = gTrue; - - for (i = 1, line = file; i <= 100 && line < file + len && !encoding; ++i) { - - // get font name - if (!strncmp(line, "/FontName", 9)) { - strncpy(buf, line, 255); - buf[255] = '\0'; - if ((p = strchr(buf+9, '/')) && - (p = strtok(p+1, " \t\n\r"))) - name = copyString(p); - line = nextLine(line, file + len); - - // get encoding - } else if (!strncmp(line, "/Encoding StandardEncoding def", 30)) { - encoding = type1StdEncoding.copy(); - } else if (!strncmp(line, "/Encoding 256 array", 19)) { - encoding = new FontEncoding(); - for (i = 0; i < 300; ++i) { - line1 = nextLine(line, file + len); - if ((n = line1 - line) > 255) - n = 255; - strncpy(buf, line, n); - buf[n] = '\0'; - for (p = buf; *p == ' ' || *p == '\t'; ++p) ; - if (!strncmp(p, "dup", 3)) { - for (p += 3; *p == ' ' || *p == '\t'; ++p) ; - for (p2 = p; *p2 >= '0' && *p2 <= '9'; ++p2) ; - if (*p2) { - c = *p2; - *p2 = '\0'; - if ((code = atoi(p)) < 256) { - *p2 = c; - for (p = p2; *p == ' ' || *p == '\t'; ++p) ; - if (*p == '/') { - ++p; - for (p2 = p; *p2 && *p2 != ' ' && *p2 != '\t'; ++p2) ; - *p2 = '\0'; - encoding->addChar(code, copyString(p)); - } - } - } - } else { - if (strtok(buf, " \t") && - (p = strtok(NULL, " \t\n\r")) && !strcmp(p, "def")) { - break; - } - } - line = line1; - } - //~ check for getinterval/putinterval junk - - } else { - line = nextLine(line, file + len); - } - } -} - -Type1FontFile::~Type1FontFile() { - if (name) - gfree(name); - if (encoding && freeEnc) - delete encoding; -} - -FontEncoding *Type1FontFile::getEncoding(GBool taken) { - if (taken) - freeEnc = gFalse; - return encoding; -} - -//------------------------------------------------------------------------ -// Type1CFontFile -//------------------------------------------------------------------------ - -Type1CFontFile::Type1CFontFile(char *file, int len) { - char buf[256]; - Guchar *topPtr, *idxStartPtr, *idxPtr0, *idxPtr1; - Guchar *stringIdxPtr, *stringStartPtr; - int topOffSize, idxOffSize, stringOffSize; - int nFonts, nStrings, nGlyphs; - int nCodes, nRanges, nLeft, nSups; - Gushort *glyphNames; - int charset, enc, charstrings; - int charsetFormat, encFormat; - int c, sid; - double op[48]; - double x; - GBool isFP; - int key; - int i, j, n; - - name = NULL; - encoding = NULL; - freeEnc = gTrue; - - // read header - topPtr = (Guchar *)file + (file[2] & 0xff); - topOffSize = file[3] & 0xff; - - // read name index (first font only) - nFonts = getWord(topPtr, 2); - idxOffSize = topPtr[2]; - topPtr += 3; - idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1; - idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize); - idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize); - if ((n = idxPtr1 - idxPtr0) > 255) - n = 255; - strncpy(buf, (char *)idxPtr0, n); - buf[n] = '\0'; - name = copyString(buf); - topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize); - - // read top dict index (first font only) - nFonts = getWord(topPtr, 2); - idxOffSize = topPtr[2]; - topPtr += 3; - idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1; - idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize); - idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize); - charset = 0; - enc = 0; - charstrings = 0; - i = 0; - while (idxPtr0 < idxPtr1) { - if (*idxPtr0 <= 27 || *idxPtr0 == 31) { - key = *idxPtr0++; - if (key == 0x0c) - key = (key << 8) | *idxPtr0++; - if (key == 0x0f) { // charset - charset = (int)op[0]; - } else if (key == 0x10) { // encoding - enc = (int)op[0]; - } else if (key == 0x11) { // charstrings - charstrings = (int)op[0]; - } - i = 0; - } else { - x = getNum(&idxPtr0, &isFP); - if (i < 48) - op[i++] = x; - } - } - topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize); - - // read string index - nStrings = getWord(topPtr, 2); - stringOffSize = topPtr[2]; - topPtr += 3; - stringIdxPtr = topPtr; - stringStartPtr = topPtr + (nStrings + 1) * stringOffSize - 1; - topPtr = stringStartPtr + getWord(topPtr + nStrings * stringOffSize, - stringOffSize); - - // get number of glyphs from charstrings index - topPtr = (Guchar *)file + charstrings; - nGlyphs = getWord(topPtr, 2); - - // read charset - if (charset == 0) { - glyphNames = type1CISOAdobeCharset; - } else if (charset == 1) { - glyphNames = type1CExpertCharset; - } else if (charset == 2) { - glyphNames = type1CExpertSubsetCharset; - } else { - glyphNames = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort)); - glyphNames[0] = 0; - topPtr = (Guchar *)file + charset; - charsetFormat = *topPtr++; - if (charsetFormat == 0) { - for (i = 1; i < nGlyphs; ++i) { - glyphNames[i] = getWord(topPtr, 2); - topPtr += 2; - } - } else if (charsetFormat == 1) { - i = 1; - while (i < nGlyphs) { - c = getWord(topPtr, 2); - topPtr += 2; - nLeft = *topPtr++; - for (j = 0; j <= nLeft; ++j) - glyphNames[i++] = c++; - } - } else if (charsetFormat == 2) { - i = 1; - while (i < nGlyphs) { - c = getWord(topPtr, 2); - topPtr += 2; - nLeft = getWord(topPtr, 2); - topPtr += 2; - for (j = 0; j <= nLeft; ++j) - glyphNames[i++] = c++; - } - } - } - - // read encoding (glyph -> code mapping) - if (enc == 0) { - encoding = type1StdEncoding.copy(); - } else if (enc == 1) { - encoding = type1ExpertEncoding.copy(); - } else { - encoding = new FontEncoding(); - topPtr = (Guchar *)file + enc; - encFormat = *topPtr++; - if ((encFormat & 0x7f) == 0) { - nCodes = 1 + *topPtr++; - if (nCodes > nGlyphs) { - nCodes = nGlyphs; - } - for (i = 1; i < nCodes; ++i) { - c = *topPtr++; - getString(glyphNames[i], stringIdxPtr, stringStartPtr, - stringOffSize, buf); - encoding->addChar(c, copyString(buf)); - } - } else if ((encFormat & 0x7f) == 1) { - nRanges = *topPtr++; - nCodes = 1; - for (i = 0; i < nRanges; ++i) { - c = *topPtr++; - nLeft = *topPtr++; - for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) { - getString(glyphNames[nCodes], stringIdxPtr, stringStartPtr, - stringOffSize, buf); - encoding->addChar(c, copyString(buf)); - ++nCodes; - ++c; - } - } - } - if (encFormat & 0x80) { - nSups = *topPtr++; - for (i = 0; i < nSups; ++i) { - c = *topPtr++; - sid = getWord(topPtr, 2); - topPtr += 2; - getString(sid, stringIdxPtr, stringStartPtr, - stringOffSize, buf); - encoding->addChar(c, copyString(buf)); - } - } - } - - if (charset > 2) - gfree(glyphNames); -} - -Type1CFontFile::~Type1CFontFile() { - if (name) - gfree(name); - if (encoding && freeEnc) - delete encoding; -} - -FontEncoding *Type1CFontFile::getEncoding(GBool taken) { - if (taken) - freeEnc = gFalse; - return encoding; -} - -static Guint getWord(Guchar *ptr, int size) { - Guint x; - int i; - - x = 0; - for (i = 0; i < size; ++i) - x = (x << 8) + *ptr++; - return x; -} - -static double getNum(Guchar **ptr, GBool *fp) { - static char nybChars[16] = "0123456789.ee -"; - int b0, b, nyb0, nyb1; - double x; - char buf[65]; - int i; - - x = 0; - *fp = gFalse; - b0 = (*ptr)[0]; - if (b0 < 28) { - x = 0; - } else if (b0 == 28) { - x = ((*ptr)[1] << 8) + (*ptr)[2]; - *ptr += 3; - } else if (b0 == 29) { - x = ((*ptr)[1] << 24) + ((*ptr)[2] << 16) + ((*ptr)[3] << 8) + (*ptr)[4]; - *ptr += 5; - } else if (b0 == 30) { - *ptr += 1; - i = 0; - do { - b = *(*ptr)++; - nyb0 = b >> 4; - nyb1 = b & 0x0f; - if (nyb0 == 0xf) - break; - buf[i++] = nybChars[nyb0]; - if (i == 64) - break; - if (nyb0 == 0xc) - buf[i++] = '-'; - if (i == 64) - break; - if (nyb1 == 0xf) - break; - buf[i++] = nybChars[nyb1]; - if (i == 64) - break; - if (nyb1 == 0xc) - buf[i++] = '-'; - } while (i < 64); - buf[i] = '\0'; - x = atof(buf); - *fp = gTrue; - } else if (b0 == 31) { - x = 0; - } else if (b0 < 247) { - x = b0 - 139; - *ptr += 1; - } else if (b0 < 251) { - x = ((b0 - 247) << 8) + (*ptr)[1] + 108; - *ptr += 2; - } else { - x = -((b0 - 251) << 8) - (*ptr)[1] - 108; - *ptr += 2; - } - return x; -} - -static char *getString(int sid, Guchar *stringIdxPtr, - Guchar *stringStartPtr, int stringOffSize, - char *buf) { - Guchar *idxPtr0, *idxPtr1; - int len; - - if (sid < 391) { - strcpy(buf, type1CStdStrings[sid]); - } else { - sid -= 391; - idxPtr0 = stringStartPtr + getWord(stringIdxPtr + sid * stringOffSize, - stringOffSize); - idxPtr1 = stringStartPtr + getWord(stringIdxPtr + (sid+1) * stringOffSize, - stringOffSize); - if ((len = idxPtr1 - idxPtr0) > 255) - len = 255; - strncpy(buf, (char *)idxPtr0, len); - buf[len] = '\0'; - } - return buf; -} - -//------------------------------------------------------------------------ -// Type1CFontConverter -//------------------------------------------------------------------------ - -Type1CFontConverter::Type1CFontConverter(char *fileA, int lenA, FILE *outA) { - file = fileA; - len = lenA; - out = outA; - r1 = 55665; - line = 0; -} - -Type1CFontConverter::~Type1CFontConverter() { -} - -void Type1CFontConverter::convert() { - char *fontName; - struct { - int version; - int notice; - int copyright; - int fullName; - int familyName; - int weight; - int isFixedPitch; - double italicAngle; - double underlinePosition; - double underlineThickness; - int paintType; - int charstringType; //~ ??? - double fontMatrix[6]; - int uniqueID; - double fontBBox[4]; - double strokeWidth; //~ ??? - int charset; - int encoding; - int charStrings; - int privateSize; - int privateOffset; - } dict; - char buf[256], eBuf[256]; - Guchar *topPtr, *idxStartPtr, *idxPtr0, *idxPtr1; - Guchar *stringIdxPtr, *stringStartPtr; - int topOffSize, idxOffSize, stringOffSize; - int nFonts, nStrings, nGlyphs; - int nCodes, nRanges, nLeft, nSups; - Gushort *glyphNames; - int charsetFormat, encFormat; - int subrsOffset, nSubrs; - int nCharStrings; - int c, sid; - double x; - GBool isFP; - int key; - int i, j, n; - - // read header - topPtr = (Guchar *)file + (file[2] & 0xff); - topOffSize = file[3] & 0xff; - - // read name (first font only) - nFonts = getWord(topPtr, 2); - idxOffSize = topPtr[2]; - topPtr += 3; - idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1; - idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize); - idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize); - if ((n = idxPtr1 - idxPtr0) > 255) - n = 255; - strncpy(buf, (char *)idxPtr0, n); - buf[n] = '\0'; - fontName = copyString(buf); - topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize); - - // read top dict (first font only) - nFonts = getWord(topPtr, 2); - idxOffSize = topPtr[2]; - topPtr += 3; - idxStartPtr = topPtr + (nFonts + 1) * idxOffSize - 1; - idxPtr0 = idxStartPtr + getWord(topPtr, idxOffSize); - idxPtr1 = idxStartPtr + getWord(topPtr + idxOffSize, idxOffSize); - dict.version = 0; - dict.notice = 0; - dict.copyright = 0; - dict.fullName = 0; - dict.familyName = 0; - dict.weight = 0; - dict.isFixedPitch = 0; - dict.italicAngle = 0; - dict.underlinePosition = -100; - dict.underlineThickness = 50; - dict.paintType = 0; - dict.charstringType = 2; - dict.fontMatrix[0] = 0.001; - dict.fontMatrix[1] = 0; - dict.fontMatrix[2] = 0; - dict.fontMatrix[3] = 0.001; - dict.fontMatrix[4] = 0; - dict.fontMatrix[5] = 0; - dict.uniqueID = 0; - dict.fontBBox[0] = 0; - dict.fontBBox[1] = 0; - dict.fontBBox[2] = 0; - dict.fontBBox[3] = 0; - dict.strokeWidth = 0; - dict.charset = 0; - dict.encoding = 0; - dict.charStrings = 0; - dict.privateSize = 0; - dict.privateOffset = 0; - i = 0; - while (idxPtr0 < idxPtr1) { - if (*idxPtr0 <= 27 || *idxPtr0 == 31) { - key = *idxPtr0++; - if (key == 0x0c) - key = (key << 8) | *idxPtr0++; - switch (key) { - case 0x0000: dict.version = (int)op[0]; break; - case 0x0001: dict.notice = (int)op[0]; break; - case 0x0c00: dict.copyright = (int)op[0]; break; - case 0x0002: dict.fullName = (int)op[0]; break; - case 0x0003: dict.familyName = (int)op[0]; break; - case 0x0004: dict.weight = (int)op[0]; break; - case 0x0c01: dict.isFixedPitch = (int)op[0]; break; - case 0x0c02: dict.italicAngle = op[0]; break; - case 0x0c03: dict.underlinePosition = op[0]; break; - case 0x0c04: dict.underlineThickness = op[0]; break; - case 0x0c05: dict.paintType = (int)op[0]; break; - case 0x0c06: dict.charstringType = (int)op[0]; break; - case 0x0c07: dict.fontMatrix[0] = op[0]; - dict.fontMatrix[1] = op[1]; - dict.fontMatrix[2] = op[2]; - dict.fontMatrix[3] = op[3]; - dict.fontMatrix[4] = op[4]; - dict.fontMatrix[5] = op[5]; break; - case 0x000d: dict.uniqueID = (int)op[0]; break; - case 0x0005: dict.fontBBox[0] = op[0]; - dict.fontBBox[1] = op[1]; - dict.fontBBox[2] = op[2]; - dict.fontBBox[3] = op[3]; break; - case 0x0c08: dict.strokeWidth = op[0]; break; - case 0x000f: dict.charset = (int)op[0]; break; - case 0x0010: dict.encoding = (int)op[0]; break; - case 0x0011: dict.charStrings = (int)op[0]; break; - case 0x0012: dict.privateSize = (int)op[0]; - dict.privateOffset = (int)op[1]; break; - } - i = 0; - } else { - x = getNum(&idxPtr0, &isFP); - if (i < 48) { - op[i] = x; - fp[i++] = isFP; - } - } - } - topPtr = idxStartPtr + getWord(topPtr + nFonts * idxOffSize, idxOffSize); - - // read string index - nStrings = getWord(topPtr, 2); - stringOffSize = topPtr[2]; - topPtr += 3; - stringIdxPtr = topPtr; - stringStartPtr = topPtr + (nStrings + 1) * stringOffSize - 1; - topPtr = stringStartPtr + getWord(topPtr + nStrings * stringOffSize, - stringOffSize); - -#if 1 //~ - // get global subrs - int nGSubrs; - int gSubrOffSize; - - nGSubrs = getWord(topPtr, 2); - gSubrOffSize = topPtr[2]; - topPtr += 3; -#endif - - // write header and font dictionary, up to encoding - fprintf(out, "%%!FontType1-1.0: %s", fontName); - if (dict.version != 0) { - fprintf(out, "%s", - getString(dict.version, stringIdxPtr, stringStartPtr, - stringOffSize, buf)); - } - fprintf(out, "\n"); - fprintf(out, "11 dict begin\n"); - fprintf(out, "/FontInfo 10 dict dup begin\n"); - if (dict.version != 0) { - fprintf(out, "/version (%s) readonly def\n", - getString(dict.version, stringIdxPtr, stringStartPtr, - stringOffSize, buf)); - } - if (dict.notice != 0) { - fprintf(out, "/Notice (%s) readonly def\n", - getString(dict.notice, stringIdxPtr, stringStartPtr, - stringOffSize, buf)); - } - if (dict.copyright != 0) { - fprintf(out, "/Copyright (%s) readonly def\n", - getString(dict.copyright, stringIdxPtr, stringStartPtr, - stringOffSize, buf)); - } - if (dict.fullName != 0) { - fprintf(out, "/FullName (%s) readonly def\n", - getString(dict.fullName, stringIdxPtr, stringStartPtr, - stringOffSize, buf)); - } - if (dict.familyName != 0) { - fprintf(out, "/FamilyName (%s) readonly def\n", - getString(dict.familyName, stringIdxPtr, stringStartPtr, - stringOffSize, buf)); - } - if (dict.weight != 0) { - fprintf(out, "/Weight (%s) readonly def\n", - getString(dict.weight, stringIdxPtr, stringStartPtr, - stringOffSize, buf)); - } - fprintf(out, "/isFixedPitch %s def\n", dict.isFixedPitch ? "true" : "false"); - fprintf(out, "/ItalicAngle %g def\n", dict.italicAngle); - fprintf(out, "/UnderlinePosition %g def\n", dict.underlinePosition); - fprintf(out, "/UnderlineThickness %g def\n", dict.underlineThickness); - fprintf(out, "end readonly def\n"); - fprintf(out, "/FontName /%s def\n", fontName); - fprintf(out, "/PaintType %d def\n", dict.paintType); - fprintf(out, "/FontType 1 def\n"); - fprintf(out, "/FontMatrix [%g %g %g %g %g %g] readonly def\n", - dict.fontMatrix[0], dict.fontMatrix[1], dict.fontMatrix[2], - dict.fontMatrix[3], dict.fontMatrix[4], dict.fontMatrix[5]); - fprintf(out, "/FontBBox [%g %g %g %g] readonly def\n", - dict.fontBBox[0], dict.fontBBox[1], - dict.fontBBox[2], dict.fontBBox[3]); - if (dict.uniqueID != 0) { - fprintf(out, "/UniqueID %d def\n", dict.uniqueID); - } - - // get number of glyphs from charstrings index - topPtr = (Guchar *)file + dict.charStrings; - nGlyphs = getWord(topPtr, 2); - - // read charset - if (dict.charset == 0) { - glyphNames = type1CISOAdobeCharset; - } else if (dict.charset == 1) { - glyphNames = type1CExpertCharset; - } else if (dict.charset == 2) { - glyphNames = type1CExpertSubsetCharset; - } else { - glyphNames = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort)); - glyphNames[0] = 0; - topPtr = (Guchar *)file + dict.charset; - charsetFormat = *topPtr++; - if (charsetFormat == 0) { - for (i = 1; i < nGlyphs; ++i) { - glyphNames[i] = getWord(topPtr, 2); - topPtr += 2; - } - } else if (charsetFormat == 1) { - i = 1; - while (i < nGlyphs) { - c = getWord(topPtr, 2); - topPtr += 2; - nLeft = *topPtr++; - for (j = 0; j <= nLeft; ++j) - glyphNames[i++] = c++; - } - } else if (charsetFormat == 2) { - i = 1; - while (i < nGlyphs) { - c = getWord(topPtr, 2); - topPtr += 2; - nLeft = getWord(topPtr, 2); - topPtr += 2; - for (j = 0; j <= nLeft; ++j) - glyphNames[i++] = c++; - } - } - } - - // read encoding (glyph -> code mapping), write Type 1 encoding - fprintf(out, "/Encoding "); - if (dict.encoding == 0) { - fprintf(out, "StandardEncoding def\n"); - } else { - fprintf(out, "256 array\n"); - fprintf(out, "0 1 255 {1 index exch /.notdef put} for\n"); - if (dict.encoding == 1) { - for (i = 0; i < 256; ++i) { - if (type1ExpertEncodingNames[i]) - fprintf(out, "dup %d /%s put\n", i, type1ExpertEncodingNames[i]); - } - } else { - topPtr = (Guchar *)file + dict.encoding; - encFormat = *topPtr++; - if ((encFormat & 0x7f) == 0) { - nCodes = 1 + *topPtr++; - if (nCodes > nGlyphs) { - nCodes = nGlyphs; - } - for (i = 1; i < nCodes; ++i) { - c = *topPtr++; - fprintf(out, "dup %d /%s put\n", c, - getString(glyphNames[i], stringIdxPtr, stringStartPtr, - stringOffSize, buf)); - } - } else if ((encFormat & 0x7f) == 1) { - nRanges = *topPtr++; - nCodes = 1; - for (i = 0; i < nRanges; ++i) { - c = *topPtr++; - nLeft = *topPtr++; - for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) { - fprintf(out, "dup %d /%s put\n", c, - getString(glyphNames[nCodes], stringIdxPtr, stringStartPtr, - stringOffSize, buf)); - ++nCodes; - ++c; - } - } - } - if (encFormat & 0x80) { - nSups = *topPtr++; - for (i = 0; i < nSups; ++i) { - c = *topPtr++; - sid = getWord(topPtr, 2); - topPtr += 2; - fprintf(out, "dup %d /%s put\n", c, - getString(sid, stringIdxPtr, stringStartPtr, - stringOffSize, buf)); - } - } - } - fprintf(out, "readonly def\n"); - } - fprintf(out, "currentdict end\n"); - fprintf(out, "currentfile eexec\n"); - - // get private dictionary - eexecWrite("\x83\xca\x73\xd5"); - eexecWrite("dup /Private 32 dict dup begin\n"); - eexecWrite("/RD {string currentfile exch readstring pop} executeonly def\n"); - eexecWrite("/ND {noaccess def} executeonly def\n"); - eexecWrite("/NP {noaccess put} executeonly def\n"); - eexecWrite("/MinFeature {16 16} ND\n"); - eexecWrite("/password 5839 def\n"); - subrsOffset = 0; - defaultWidthX = 0; - nominalWidthX = 0; - topPtr = (Guchar *)file + dict.privateOffset; - idxPtr0 = topPtr; - idxPtr1 = idxPtr0 + dict.privateSize; - i = 0; - while (idxPtr0 < idxPtr1) { - if (*idxPtr0 <= 27 || *idxPtr0 == 31) { - key = *idxPtr0++; - if (key == 0x0c) - key = (key << 8) | *idxPtr0++; - switch (key) { - case 0x0006: - getDeltaInt(eBuf, "BlueValues", op, i); - eexecWrite(eBuf); - break; - case 0x0007: - getDeltaInt(eBuf, "OtherBlues", op, i); - eexecWrite(eBuf); - break; - case 0x0008: - getDeltaInt(eBuf, "FamilyBlues", op, i); - eexecWrite(eBuf); - break; - case 0x0009: - getDeltaInt(eBuf, "FamilyOtherBlues", op, i); - eexecWrite(eBuf); - break; - case 0x0c09: - sprintf(eBuf, "/BlueScale %g def\n", op[0]); - eexecWrite(eBuf); - break; - case 0x0c0a: - sprintf(eBuf, "/BlueShift %d def\n", (int)op[0]); - eexecWrite(eBuf); - break; - case 0x0c0b: - sprintf(eBuf, "/BlueFuzz %d def\n", (int)op[0]); - eexecWrite(eBuf); - break; - case 0x000a: - sprintf(eBuf, "/StdHW [%g] def\n", op[0]); - eexecWrite(eBuf); - break; - case 0x000b: - sprintf(eBuf, "/StdVW [%g] def\n", op[0]); - eexecWrite(eBuf); - break; - case 0x0c0c: - getDeltaReal(eBuf, "StemSnapH", op, i); - eexecWrite(eBuf); - break; - case 0x0c0d: - getDeltaReal(eBuf, "StemSnapV", op, i); - eexecWrite(eBuf); - break; - case 0x0c0e: - sprintf(eBuf, "/ForceBold %s def\n", op[0] ? "true" : "false"); - eexecWrite(eBuf); - break; - case 0x0c0f: - sprintf(eBuf, "/ForceBoldThreshold %g def\n", op[0]); - eexecWrite(eBuf); - break; - case 0x0c11: - sprintf(eBuf, "/LanguageGroup %d def\n", (int)op[0]); - eexecWrite(eBuf); - break; - case 0x0c12: - sprintf(eBuf, "/ExpansionFactor %g def\n", op[0]); - eexecWrite(eBuf); - break; - case 0x0c13: - error(-1, "Got Type 1C InitialRandomSeed"); - break; - case 0x0013: - subrsOffset = (int)op[0]; - break; - case 0x0014: - defaultWidthX = op[0]; - defaultWidthXFP = fp[0]; - break; - case 0x0015: - nominalWidthX = op[0]; - nominalWidthXFP = fp[0]; - break; - default: - error(-1, "Unknown Type 1C private dict entry %04x", key); - break; - } - i = 0; - } else { - x = getNum(&idxPtr0, &isFP); - if (i < 48) { - op[i] = x; - fp[i++] = isFP; - } - } - } - - // get subrs - if (subrsOffset != 0) { - topPtr += subrsOffset; - nSubrs = getWord(topPtr, 2); - idxOffSize = topPtr[2]; - topPtr += 3; - sprintf(eBuf, "/Subrs %d array\n", nSubrs); - eexecWrite(eBuf); - idxStartPtr = topPtr + (nSubrs + 1) * idxOffSize - 1; - idxPtr1 = idxStartPtr + getWord(topPtr, idxOffSize); - for (i = 0; i < nSubrs; ++i) { - idxPtr0 = idxPtr1; - idxPtr1 = idxStartPtr + getWord(topPtr + (i+1)*idxOffSize, idxOffSize); - n = idxPtr1 - idxPtr0; -#if 1 //~ - error(-1, "Unimplemented Type 2 subrs"); -#else - sprintf(eBuf, "dup %d %d RD ", i, n); - eexecWrite(eBuf); - cvtGlyph(idxPtr0, n); - eexecWrite(" NP\n"); -#endif - } - eexecWrite("ND\n"); - } - - // get CharStrings - topPtr = (Guchar *)file + dict.charStrings; - nCharStrings = getWord(topPtr, 2); - idxOffSize = topPtr[2]; - topPtr += 3; - sprintf(eBuf, "2 index /CharStrings %d dict dup begin\n", nCharStrings); - eexecWrite(eBuf); - idxStartPtr = topPtr + (nCharStrings + 1) * idxOffSize - 1; - idxPtr1 = idxStartPtr + getWord(topPtr, idxOffSize); - for (i = 0; i < nCharStrings; ++i) { - idxPtr0 = idxPtr1; - idxPtr1 = idxStartPtr + getWord(topPtr + (i+1)*idxOffSize, idxOffSize); - n = idxPtr1 - idxPtr0; - cvtGlyph(getString(glyphNames[i], stringIdxPtr, stringStartPtr, - stringOffSize, buf), - idxPtr0, n); - } - eexecWrite("end\n"); - eexecWrite("end\n"); - eexecWrite("readonly put\n"); - eexecWrite("noaccess put\n"); - eexecWrite("dup /FontName get exch definefont pop\n"); - eexecWrite("mark currentfile closefile\n"); - - // trailer - if (line > 0) - fputc('\n', out); - for (i = 0; i < 8; ++i) { - fprintf(out, "0000000000000000000000000000000000000000000000000000000000000000\n"); - } - fprintf(out, "cleartomark\n"); - - // clean up - if (dict.charset > 2) - gfree(glyphNames); - gfree(fontName); -} - -void Type1CFontConverter::eexecWrite(char *s) { - Guchar *p; - Guchar x; - - for (p = (Guchar *)s; *p; ++p) { - x = *p ^ (r1 >> 8); - r1 = (x + r1) * 52845 + 22719; - fputc(hexChars[x >> 4], out); - fputc(hexChars[x & 0x0f], out); - line += 2; - if (line == 64) { - fputc('\n', out); - line = 0; - } - } -} - -void Type1CFontConverter::cvtGlyph(char *name, Guchar *s, int n) { - int nHints; - int x; - GBool first = gTrue; - char eBuf[256]; - double d, dx, dy; - GBool dFP; - int i, k; - - charBuf = new GString(); - charBuf->append((char)73); - charBuf->append((char)58); - charBuf->append((char)147); - charBuf->append((char)134); - - i = 0; - nOps = 0; - nHints = 0; - while (i < n) { - if (s[i] == 12) { - switch (s[i+1]) { - case 0: // dotsection (should be Type 1 only?) - //~ ignored - break; - case 34: // hflex - if (nOps != 7) { - error(-1, "Wrong number of args (%d) to Type 2 hflex", nOps); - } - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpNum(0, gFalse); - eexecDumpOp1(8); - eexecDumpNum(op[4], fp[4]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[5], fp[5]); - eexecDumpNum(-op[2], fp[2]); - eexecDumpNum(op[6], fp[6]); - eexecDumpNum(0, gFalse); - eexecDumpOp1(8); - break; - case 35: // flex - if (nOps != 13) { - error(-1, "Wrong number of args (%d) to Type 2 flex", nOps); - } - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpNum(op[4], fp[4]); - eexecDumpNum(op[5], fp[5]); - eexecDumpOp1(8); - eexecDumpNum(op[6], fp[6]); - eexecDumpNum(op[7], fp[7]); - eexecDumpNum(op[8], fp[8]); - eexecDumpNum(op[9], fp[9]); - eexecDumpNum(op[10], fp[10]); - eexecDumpNum(op[11], fp[11]); - eexecDumpOp1(8); - break; - case 36: // hflex1 - if (nOps != 9) { - error(-1, "Wrong number of args (%d) to Type 2 hflex1", nOps); - } - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpNum(op[4], fp[4]); - eexecDumpNum(0, gFalse); - eexecDumpOp1(8); - eexecDumpNum(op[5], fp[5]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[6], fp[6]); - eexecDumpNum(op[7], fp[7]); - eexecDumpNum(op[8], fp[8]); - eexecDumpNum(-(op[1] + op[3] + op[7]), fp[1] | fp[3] | fp[7]); - eexecDumpOp1(8); - break; - case 37: // flex1 - if (nOps != 11) { - error(-1, "Wrong number of args (%d) to Type 2 flex1", nOps); - } - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpNum(op[4], fp[4]); - eexecDumpNum(op[5], fp[5]); - eexecDumpOp1(8); - eexecDumpNum(op[6], fp[6]); - eexecDumpNum(op[7], fp[7]); - eexecDumpNum(op[8], fp[8]); - eexecDumpNum(op[9], fp[9]); - dx = op[0] + op[2] + op[4] + op[6] + op[8]; - dy = op[1] + op[3] + op[5] + op[7] + op[9]; - if (fabs(dx) > fabs(dy)) { - eexecDumpNum(op[10], fp[10]); - eexecDumpNum(-dy, fp[1] | fp[3] | fp[5] | fp[7] | fp[9]); - } else { - eexecDumpNum(-dx, fp[0] | fp[2] | fp[4] | fp[6] | fp[8]); - eexecDumpNum(op[10], fp[10]); - } - eexecDumpOp1(8); - break; - case 3: // and - case 4: // or - case 5: // not - case 8: // store - case 9: // abs - case 10: // add - case 11: // sub - case 12: // div - case 13: // load - case 14: // neg - case 15: // eq - case 18: // drop - case 20: // put - case 21: // get - case 22: // ifelse - case 23: // random - case 24: // mul - case 26: // sqrt - case 27: // dup - case 28: // exch - case 29: // index - case 30: // roll - error(-1, "Unimplemented Type 2 charstring op: 12.%d", s[i+1]); - break; - default: - error(-1, "Illegal Type 2 charstring op: 12.%d", s[i+1]); - break; - } - i += 2; - nOps = 0; - } else if (s[i] == 19) { // hintmask - //~ ignored - if (first) { - cvtGlyphWidth(nOps == 1); - first = gFalse; - } - if (nOps > 0) { - if (nOps & 1) { - error(-1, "Wrong number of args (%d) to Type 2 hintmask/vstemhm", - nOps); - } - nHints += nOps / 2; - } - i += 1 + ((nHints + 7) >> 3); - nOps = 0; - } else if (s[i] == 20) { // cntrmask - //~ ignored - if (first) { - cvtGlyphWidth(nOps == 1); - first = gFalse; - } - if (nOps > 0) { - if (nOps & 1) { - error(-1, "Wrong number of args (%d) to Type 2 cntrmask/vstemhm", - nOps); - } - nHints += nOps / 2; - } - i += 1 + ((nHints + 7) >> 3); - nOps = 0; - } else if (s[i] == 28) { - x = (s[i+1] << 8) + s[i+2]; - if (x & 0x8000) - x |= -1 << 15; - if (nOps < 48) { - fp[nOps] = gFalse; - op[nOps++] = x; - } - i += 3; - } else if (s[i] <= 31) { - switch (s[i]) { - case 4: // vmoveto - if (first) { - cvtGlyphWidth(nOps == 2); - first = gFalse; - } - if (nOps != 1) - error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps); - eexecDumpNum(op[0], fp[0]); - eexecDumpOp1(4); - break; - case 5: // rlineto - if (nOps < 2 || nOps % 2 != 0) - error(-1, "Wrong number of args (%d) to Type 2 rlineto", nOps); - for (k = 0; k < nOps; k += 2) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpOp1(5); - } - break; - case 6: // hlineto - if (nOps < 1) - error(-1, "Wrong number of args (%d) to Type 2 hlineto", nOps); - for (k = 0; k < nOps; ++k) { - eexecDumpNum(op[k], fp[k]); - eexecDumpOp1((k & 1) ? 7 : 6); - } - break; - case 7: // vlineto - if (nOps < 1) - error(-1, "Wrong number of args (%d) to Type 2 vlineto", nOps); - for (k = 0; k < nOps; ++k) { - eexecDumpNum(op[k], fp[k]); - eexecDumpOp1((k & 1) ? 6 : 7); - } - break; - case 8: // rrcurveto - if (nOps < 6 || nOps % 6 != 0) - error(-1, "Wrong number of args (%d) to Type 2 rrcurveto", nOps); - for (k = 0; k < nOps; k += 6) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpNum(op[k+4], fp[k+4]); - eexecDumpNum(op[k+5], fp[k+5]); - eexecDumpOp1(8); - } - break; - case 14: // endchar / seac - if (first) { - cvtGlyphWidth(nOps == 1 || nOps == 5); - first = gFalse; - } - if (nOps == 4) { - eexecDumpNum(0, 0); - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpOp2(6); - } else if (nOps == 0) { - eexecDumpOp1(14); - } else { - error(-1, "Wrong number of args (%d) to Type 2 endchar", nOps); - } - break; - case 21: // rmoveto - if (first) { - cvtGlyphWidth(nOps == 3); - first = gFalse; - } - if (nOps != 2) - error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps); - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[1], fp[1]); - eexecDumpOp1(21); - break; - case 22: // hmoveto - if (first) { - cvtGlyphWidth(nOps == 2); - first = gFalse; - } - if (nOps != 1) - error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps); - eexecDumpNum(op[0], fp[0]); - eexecDumpOp1(22); - break; - case 24: // rcurveline - if (nOps < 8 || (nOps - 2) % 6 != 0) - error(-1, "Wrong number of args (%d) to Type 2 rcurveline", nOps); - for (k = 0; k < nOps - 2; k += 6) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpNum(op[k+4], fp[k+4]); - eexecDumpNum(op[k+5], fp[k+5]); - eexecDumpOp1(8); - } - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k]); - eexecDumpOp1(5); - break; - case 25: // rlinecurve - if (nOps < 8 || (nOps - 6) % 2 != 0) - error(-1, "Wrong number of args (%d) to Type 2 rlinecurve", nOps); - for (k = 0; k < nOps - 6; k += 2) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k]); - eexecDumpOp1(5); - } - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpNum(op[k+4], fp[k+4]); - eexecDumpNum(op[k+5], fp[k+5]); - eexecDumpOp1(8); - break; - case 26: // vvcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) - error(-1, "Wrong number of args (%d) to Type 2 vvcurveto", nOps); - if (nOps % 2 == 1) { - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[4], fp[4]); - eexecDumpOp1(8); - k = 5; - } else { - k = 0; - } - for (; k < nOps; k += 4) { - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpOp1(8); - } - break; - case 27: // hhcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) - error(-1, "Wrong number of args (%d) to Type 2 hhcurveto", nOps); - if (nOps % 2 == 1) { - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpNum(op[4], fp[4]); - eexecDumpNum(0, gFalse); - eexecDumpOp1(8); - k = 5; - } else { - k = 0; - } - for (; k < nOps; k += 4) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpNum(0, gFalse); - eexecDumpOp1(8); - } - break; - case 30: // vhcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) - error(-1, "Wrong number of args (%d) to Type 2 vhcurveto", nOps); - for (k = 0; k < nOps && k != nOps-5; k += 4) { - if (k % 8 == 0) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpOp1(30); - } else { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpOp1(31); - } - } - if (k == nOps-5) { - if (k % 8 == 0) { - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpNum(op[k+4], fp[k+4]); - } else { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+4], fp[k+4]); - eexecDumpNum(op[k+3], fp[k+3]); - } - eexecDumpOp1(8); - } - break; - case 31: // hvcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) - error(-1, "Wrong number of args (%d) to Type 2 hvcurveto", nOps); - for (k = 0; k < nOps && k != nOps-5; k += 4) { - if (k % 8 == 0) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpOp1(31); - } else { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpOp1(30); - } - } - if (k == nOps-5) { - if (k % 8 == 0) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+4], fp[k+4]); - eexecDumpNum(op[k+3], fp[k+3]); - } else { - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpNum(op[k+4], fp[k+4]); - } - eexecDumpOp1(8); - } - break; - case 1: // hstem - if (first) { - cvtGlyphWidth(nOps & 1); - first = gFalse; - } - if (nOps & 1) { - error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps); - } - d = 0; - dFP = gFalse; - for (k = 0; k < nOps; k += 2) { - if (op[k+1] < 0) { - d += op[k] + op[k+1]; - dFP |= fp[k] | fp[k+1]; - eexecDumpNum(d, dFP); - eexecDumpNum(-op[k+1], fp[k+1]); - } else { - d += op[k]; - dFP |= fp[k]; - eexecDumpNum(d, dFP); - eexecDumpNum(op[k+1], fp[k+1]); - d += op[k+1]; - dFP |= fp[k+1]; - } - eexecDumpOp1(1); - } - nHints += nOps / 2; - break; - case 3: // vstem - if (first) { - cvtGlyphWidth(nOps & 1); - first = gFalse; - } - if (nOps & 1) { - error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps); - } - d = 0; - dFP = gFalse; - for (k = 0; k < nOps; k += 2) { - if (op[k+1] < 0) { - d += op[k] + op[k+1]; - dFP |= fp[k] | fp[k+1]; - eexecDumpNum(d, dFP); - eexecDumpNum(-op[k+1], fp[k+1]); - } else { - d += op[k]; - dFP |= fp[k]; - eexecDumpNum(d, dFP); - eexecDumpNum(op[k+1], fp[k+1]); - d += op[k+1]; - dFP |= fp[k+1]; - } - eexecDumpOp1(3); - } - nHints += nOps / 2; - break; - case 18: // hstemhm - //~ ignored - if (first) { - cvtGlyphWidth(nOps & 1); - first = gFalse; - } - if (nOps & 1) { - error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps); - } - nHints += nOps / 2; - break; - case 23: // vstemhm - //~ ignored - if (first) { - cvtGlyphWidth(nOps & 1); - first = gFalse; - } - if (nOps & 1) { - error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps); - } - nHints += nOps / 2; - break; - case 10: // callsubr - case 11: // return - case 16: // blend - case 29: // callgsubr - error(-1, "Unimplemented Type 2 charstring op: %d", s[i]); - break; - default: - error(-1, "Illegal Type 2 charstring op: %d", s[i]); - break; - } - ++i; - nOps = 0; - } else if (s[i] <= 246) { - if (nOps < 48) { - fp[nOps] = gFalse; - op[nOps++] = (int)s[i] - 139; - } - ++i; - } else if (s[i] <= 250) { - if (nOps < 48) { - fp[nOps] = gFalse; - op[nOps++] = (((int)s[i] - 247) << 8) + (int)s[i+1] + 108; - } - i += 2; - } else if (s[i] <= 254) { - if (nOps < 48) { - fp[nOps] = gFalse; - op[nOps++] = -(((int)s[i] - 251) << 8) - (int)s[i+1] - 108; - } - i += 2; - } else { - x = (s[i+1] << 24) | (s[i+2] << 16) | (s[i+3] << 8) | s[i+4]; - if (x & 0x80000000) - x |= -1 << 31; - if (nOps < 48) { - fp[nOps] = gTrue; - op[nOps++] = (double)x / 65536.0; - } - i += 5; - } - } - - sprintf(eBuf, "/%s %d RD ", name, charBuf->getLength()); - eexecWrite(eBuf); - eexecWriteCharstring((Guchar *)charBuf->getCString(), charBuf->getLength()); - eexecWrite(" ND\n"); - delete charBuf; -} - -void Type1CFontConverter::cvtGlyphWidth(GBool useOp) { - double w; - GBool wFP; - int i; - - if (useOp) { - w = nominalWidthX + op[0]; - wFP = nominalWidthXFP | fp[0]; - for (i = 1; i < nOps; ++i) { - op[i-1] = op[i]; - fp[i-1] = fp[i]; - } - --nOps; - } else { - w = defaultWidthX; - wFP = defaultWidthXFP; - } - eexecDumpNum(0, gFalse); - eexecDumpNum(w, wFP); - eexecDumpOp1(13); -} - -void Type1CFontConverter::eexecDumpNum(double x, GBool fpA) { - Guchar buf[12]; - int y, n; - - n = 0; - if (fpA) { - if (x >= -32768 && x < 32768) { - y = (int)(x * 256.0); - buf[0] = 255; - buf[1] = (Guchar)(y >> 24); - buf[2] = (Guchar)(y >> 16); - buf[3] = (Guchar)(y >> 8); - buf[4] = (Guchar)y; - buf[5] = 255; - buf[6] = 0; - buf[7] = 0; - buf[8] = 1; - buf[9] = 0; - buf[10] = 12; - buf[11] = 12; - n = 12; - } else { - error(-1, "Type 2 fixed point constant out of range"); - } - } else { - y = (int)x; - if (y >= -107 && y <= 107) { - buf[0] = (Guchar)(y + 139); - n = 1; - } else if (y > 107 && y <= 1131) { - y -= 108; - buf[0] = (Guchar)((y >> 8) + 247); - buf[1] = (Guchar)(y & 0xff); - n = 2; - } else if (y < -107 && y >= -1131) { - y = -y - 108; - buf[0] = (Guchar)((y >> 8) + 251); - buf[1] = (Guchar)(y & 0xff); - n = 2; - } else { - buf[0] = 255; - buf[1] = (Guchar)(y >> 24); - buf[2] = (Guchar)(y >> 16); - buf[3] = (Guchar)(y >> 8); - buf[4] = (Guchar)y; - n = 5; - } - } - charBuf->append((char *)buf, n); -} - -void Type1CFontConverter::eexecDumpOp1(int opA) { - charBuf->append((char)opA); -} - -void Type1CFontConverter::eexecDumpOp2(int opA) { - charBuf->append((char)12); - charBuf->append((char)opA); -} - -void Type1CFontConverter::eexecWriteCharstring(Guchar *s, int n) { - Gushort r2; - Guchar x; - int i; - - r2 = 4330; - - for (i = 0; i < n; ++i) { - // charstring encryption - x = s[i]; - x ^= (r2 >> 8); - r2 = (x + r2) * 52845 + 22719; - - // eexec encryption - x ^= (r1 >> 8); - r1 = (x + r1) * 52845 + 22719; - fputc(hexChars[x >> 4], out); - fputc(hexChars[x & 0x0f], out); - line += 2; - if (line == 64) { - fputc('\n', out); - line = 0; - } - } -} - -void Type1CFontConverter::getDeltaInt(char *buf, char *name, double *opA, - int n) { - int x, i; - - sprintf(buf, "/%s [", name); - buf += strlen(buf); - x = 0; - for (i = 0; i < n; ++i) { - x += (int)opA[i]; - sprintf(buf, "%s%d", i > 0 ? " " : "", x); - buf += strlen(buf); - } - sprintf(buf, "] def\n"); -} - -void Type1CFontConverter::getDeltaReal(char *buf, char *name, double *opA, - int n) { - double x; - int i; - - sprintf(buf, "/%s [", name); - buf += strlen(buf); - x = 0; - for (i = 0; i < n; ++i) { - x += opA[i]; - sprintf(buf, "%s%g", i > 0 ? " " : "", x); - buf += strlen(buf); - } - sprintf(buf, "] def\n"); -} - -//------------------------------------------------------------------------ -// TrueTypeFontFile -//------------------------------------------------------------------------ - -// -// Terminology -// ----------- -// -// character code = number used as an element of a text string -// -// character name = glyph name = name for a particular glyph within a -// font -// -// glyph index = position (within some internal table in the font) -// where the instructions to draw a particular glyph are -// stored -// -// Type 1 fonts -// ------------ -// -// Type 1 fonts contain: -// -// Encoding: array of glyph names, maps char codes to glyph names -// -// Encoding[charCode] = charName -// -// CharStrings: dictionary of instructions, keyed by character names, -// maps character name to glyph data -// -// CharStrings[charName] = glyphData -// -// TrueType fonts -// -------------- -// -// TrueType fonts contain: -// -// 'cmap' table: mapping from character code to glyph index; there may -// be multiple cmaps in a TrueType font -// -// cmap[charCode] = glyphIdx -// -// 'post' table: mapping from glyph index to glyph name -// -// post[glyphIdx] = glyphName -// -// Type 42 fonts -// ------------- -// -// Type 42 fonts contain: -// -// Encoding: array of glyph names, maps char codes to glyph names -// -// Encoding[charCode] = charName -// -// CharStrings: dictionary of glyph indexes, keyed by character names, -// maps character name to glyph index -// -// CharStrings[charName] = glyphIdx -// - -struct TTFontTableHdr { - char tag[4]; - Guint checksum; - Guint offset; - Guint length; -}; - -// TrueType tables required by the Type 42 spec. -static char *t42ReqTables[9] = { - "head", - "hhea", - "loca", - "maxp", - "cvt ", - "prep", - "glyf", - "hmtx", - "fpgm" -}; - -// Glyph names in some arbitrary standard that Apple uses for their -// TrueType fonts. -static char *macGlyphNames[258] = { - ".notdef", - "null", - "CR", - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quotesingle", - "parenleft", - "parenright", - "asterisk", - "plus", - "comma", - "hyphen", - "period", - "slash", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "colon", - "semicolon", - "less", - "equal", - "greater", - "question", - "at", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "bracketleft", - "backslash", - "bracketright", - "asciicircum", - "underscore", - "grave", - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "braceleft", - "bar", - "braceright", - "asciitilde", - "Adieresis", - "Aring", - "Ccedilla", - "Eacute", - "Ntilde", - "Odieresis", - "Udieresis", - "aacute", - "agrave", - "acircumflex", - "adieresis", - "atilde", - "aring", - "ccedilla", - "eacute", - "egrave", - "ecircumflex", - "edieresis", - "iacute", - "igrave", - "icircumflex", - "idieresis", - "ntilde", - "oacute", - "ograve", - "ocircumflex", - "odieresis", - "otilde", - "uacute", - "ugrave", - "ucircumflex", - "udieresis", - "dagger", - "degree", - "cent", - "sterling", - "section", - "bullet", - "paragraph", - "germandbls", - "registered", - "copyright", - "trademark", - "acute", - "dieresis", - "notequal", - "AE", - "Oslash", - "infinity", - "plusminus", - "lessequal", - "greaterequal", - "yen", - "mu1", - "partialdiff", - "summation", - "product", - "pi", - "integral", - "ordfeminine", - "ordmasculine", - "Ohm", - "ae", - "oslash", - "questiondown", - "exclamdown", - "logicalnot", - "radical", - "florin", - "approxequal", - "increment", - "guillemotleft", - "guillemotright", - "ellipsis", - "nbspace", - "Agrave", - "Atilde", - "Otilde", - "OE", - "oe", - "endash", - "emdash", - "quotedblleft", - "quotedblright", - "quoteleft", - "quoteright", - "divide", - "lozenge", - "ydieresis", - "Ydieresis", - "fraction", - "currency", - "guilsinglleft", - "guilsinglright", - "fi", - "fl", - "daggerdbl", - "periodcentered", - "quotesinglbase", - "quotedblbase", - "perthousand", - "Acircumflex", - "Ecircumflex", - "Aacute", - "Edieresis", - "Egrave", - "Iacute", - "Icircumflex", - "Idieresis", - "Igrave", - "Oacute", - "Ocircumflex", - "applelogo", - "Ograve", - "Uacute", - "Ucircumflex", - "Ugrave", - "dotlessi", - "circumflex", - "tilde", - "overscore", - "breve", - "dotaccent", - "ring", - "cedilla", - "hungarumlaut", - "ogonek", - "caron", - "Lslash", - "lslash", - "Scaron", - "scaron", - "Zcaron", - "zcaron", - "brokenbar", - "Eth", - "eth", - "Yacute", - "yacute", - "Thorn", - "thorn", - "minus", - "multiply", - "onesuperior", - "twosuperior", - "threesuperior", - "onehalf", - "onequarter", - "threequarters", - "franc", - "Gbreve", - "gbreve", - "Idot", - "Scedilla", - "scedilla", - "Cacute", - "cacute", - "Ccaron", - "ccaron", - "dmacron" -}; - -TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) { - int pos, i; - - file = fileA; - len = lenA; - - encoding = NULL; - freeEnc = gTrue; - - // read table directory - nTables = getUShort(4); - tableHdrs = (TTFontTableHdr *)gmalloc(nTables * sizeof(TTFontTableHdr)); - pos = 12; - for (i = 0; i < nTables; ++i) { - tableHdrs[i].tag[0] = getByte(pos+0); - tableHdrs[i].tag[1] = getByte(pos+1); - tableHdrs[i].tag[2] = getByte(pos+2); - tableHdrs[i].tag[3] = getByte(pos+3); - tableHdrs[i].checksum = getULong(pos+4); - tableHdrs[i].offset = getULong(pos+8); - tableHdrs[i].length = getULong(pos+12); - pos += 16; - } - - // check for tables that are required by both the TrueType spec - // and the Type 42 spec - if (seekTable("head") < 0 || - seekTable("hhea") < 0 || - seekTable("loca") < 0 || - seekTable("maxp") < 0 || - seekTable("glyf") < 0 || - seekTable("hmtx") < 0) { - error(-1, "TrueType font file is missing a required table"); - return; - } - - // read the 'head' table - pos = seekTable("head"); - bbox[0] = getShort(pos + 36); - bbox[1] = getShort(pos + 38); - bbox[2] = getShort(pos + 40); - bbox[3] = getShort(pos + 42); - locaFmt = getShort(pos + 50); - - // read the 'maxp' table - pos = seekTable("maxp"); - nGlyphs = getUShort(pos + 4); -} - -TrueTypeFontFile::~TrueTypeFontFile() { - if (encoding && freeEnc) { - delete encoding; - } - gfree(tableHdrs); -} - -char *TrueTypeFontFile::getName() { - return NULL; -} - -FontEncoding *TrueTypeFontFile::getEncoding(GBool taken) { - int cmap[256]; - int nCmaps, cmapPlatform, cmapEncoding, cmapFmt, cmapLen, cmapOffset; - int segCnt, segStart, segEnd, segDelta, segOffset; - int pos, i, j, k; - Guint fmt; - GString *s; - int stringIdx, stringPos, n; - - //----- construct the (char code) -> (glyph idx) mapping - - // map everything to the missing glyph - for (i = 0; i < 256; ++i) { - cmap[i] = 0; - } - - // look for the 'cmap' table - if ((pos = seekTable("cmap")) >= 0) { - nCmaps = getUShort(pos+2); - - // if the font has a Windows-symbol cmap, use it; - // otherwise, use the first cmap in the table - for (i = 0; i < nCmaps; ++i) { - cmapPlatform = getUShort(pos + 4 + 8*i); - cmapEncoding = getUShort(pos + 4 + 8*i + 2); - if (cmapPlatform == 3 && cmapEncoding == 0) { - break; - } - } - if (i >= nCmaps) { - i = 0; - cmapPlatform = getUShort(pos + 4); - cmapEncoding = getUShort(pos + 4 + 2); - } - pos += getULong(pos + 4 + 8*i + 4); - - // read the cmap - cmapFmt = getUShort(pos); - switch (cmapFmt) { - case 0: // byte encoding table (Apple standard) - cmapLen = getUShort(pos + 2); - for (i = 0; i < cmapLen && i < 256; ++i) { - cmap[i] = getByte(pos + 6 + i); - } - break; - case 4: // segment mapping to delta values (Microsoft standard) - if (cmapPlatform == 3 && cmapEncoding == 0) { - // Windows-symbol uses char codes 0xf000 - 0xf0ff - cmapOffset = 0xf000; - } else { - cmapOffset = 0; - } - segCnt = getUShort(pos + 6) / 2; - for (i = 0; i < segCnt; ++i) { - segEnd = getUShort(pos + 14 + 2*i); - segStart = getUShort(pos + 16 + 2*segCnt + 2*i); - segDelta = getUShort(pos + 16 + 4*segCnt + 2*i); - segOffset = getUShort(pos + 16 + 6*segCnt + 2*i); - if (segStart - cmapOffset <= 0xff && - segEnd - cmapOffset >= 0) { - for (j = (segStart - cmapOffset >= 0) ? segStart : cmapOffset; - j <= segEnd && j - cmapOffset <= 0xff; - ++j) { - if (segOffset == 0) { - k = (j + segDelta) & 0xffff; - } else { - k = getUShort(pos + 16 + 6*segCnt + 2*i + - segOffset + 2 * (j - segStart)); - if (k != 0) { - k = (k + segDelta) & 0xffff; - } - } - cmap[j - cmapOffset] = k; - } - } - } - break; - default: - error(-1, "Unimplemented cmap type (%d) in TrueType font file", - cmapFmt); - break; - } - } - - //----- construct the (glyph idx) -> (glyph name) mapping - //----- and compute the (char code) -> (glyph name) mapping - - encoding = new FontEncoding(); - - if ((pos = seekTable("post")) >= 0) { - fmt = getULong(pos); - - // Apple font - if (fmt == 0x00010000) { - for (i = 0; i < 256; ++i) { - j = (cmap[i] < 258) ? cmap[i] : 0; - encoding->addChar(i, copyString(macGlyphNames[j])); - } - - // Microsoft font - } else if (fmt == 0x00020000) { - stringIdx = 0; - stringPos = pos + 34 + 2*nGlyphs; - for (i = 0; i < 256; ++i) { - if (cmap[i] < nGlyphs) { - j = getUShort(pos + 34 + 2 * cmap[i]); - if (j < 258) { - encoding->addChar(i, copyString(macGlyphNames[j])); - } else { - j -= 258; - if (j != stringIdx) { - for (stringIdx = 0, stringPos = pos + 34 + 2*nGlyphs; - stringIdx < j; - ++stringIdx, stringPos += 1 + getByte(stringPos)) ; - } - n = getByte(stringPos); - s = new GString(file + stringPos + 1, n); - encoding->addChar(i, copyString(s->getCString())); - delete s; - ++stringIdx; - stringPos += 1 + n; - } - } else { - encoding->addChar(i, copyString(macGlyphNames[0])); - } - } - - // Apple subset - } else if (fmt == 0x000280000) { - for (i = 0; i < 256; ++i) { - if (cmap[i] < nGlyphs) { - j = i + getChar(pos + 32 + cmap[i]); - } else { - j = 0; - } - encoding->addChar(i, copyString(macGlyphNames[j])); - } - - // Ugh, just assume the Apple glyph set - } else { - for (i = 0; i < 256; ++i) { - j = (cmap[i] < 258) ? cmap[i] : 0; - encoding->addChar(i, copyString(macGlyphNames[j])); - } - } - - // no "post" table: assume the Apple glyph set - } else { - for (i = 0; i < 256; ++i) { - j = (cmap[i] < 258) ? cmap[i] : 0; - encoding->addChar(i, copyString(macGlyphNames[j])); - } - } - - if (taken) { - freeEnc = gFalse; - } - return encoding; -} - -void TrueTypeFontFile::convertToType42(char *name, FontEncoding *encodingA, - FILE *out) { - // write the header - fprintf(out, "%%!PS-TrueTypeFont-%g\n", getFixed(0)); - - // begin the font dictionary - fprintf(out, "10 dict begin\n"); - fprintf(out, "/FontName /%s def\n", name); - fprintf(out, "/FontType 42 def\n"); - fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n"); - fprintf(out, "/FontBBox [%d %d %d %d] def\n", - bbox[0], bbox[1], bbox[2], bbox[3]); - fprintf(out, "/PaintType 0 def\n"); - - // write the guts of the dictionary - cvtEncoding(encodingA, out); - cvtCharStrings(encodingA, out); - cvtSfnts(out); - - // end the dictionary and define the font - fprintf(out, "FontName currentdict end definefont pop\n"); -} - -int TrueTypeFontFile::getByte(int pos) { - return file[pos] & 0xff; -} - -int TrueTypeFontFile::getChar(int pos) { - int x; - - x = file[pos] & 0xff; - if (x & 0x80) - x |= 0xffffff00; - return x; -} - -int TrueTypeFontFile::getUShort(int pos) { - int x; - - x = file[pos] & 0xff; - x = (x << 8) + (file[pos+1] & 0xff); - return x; -} - -int TrueTypeFontFile::getShort(int pos) { - int x; - - x = file[pos] & 0xff; - x = (x << 8) + (file[pos+1] & 0xff); - if (x & 0x8000) - x |= 0xffff0000; - return x; -} - -Guint TrueTypeFontFile::getULong(int pos) { - int x; - - x = file[pos] & 0xff; - x = (x << 8) + (file[pos+1] & 0xff); - x = (x << 8) + (file[pos+2] & 0xff); - x = (x << 8) + (file[pos+3] & 0xff); - return x; -} - -double TrueTypeFontFile::getFixed(int pos) { - int x, y; - - x = getShort(pos); - y = getUShort(pos+2); - return (double)x + (double)y / 65536; -} - -int TrueTypeFontFile::seekTable(char *tag) { - int i; - - for (i = 0; i < nTables; ++i) { - if (!strncmp(tableHdrs[i].tag, tag, 4)) - return tableHdrs[i].offset; - } - return -1; -} - -void TrueTypeFontFile::cvtEncoding(FontEncoding *encodingA, FILE *out) { - char *name; - int i; - - fprintf(out, "/Encoding 256 array\n"); - for (i = 0; i < 256; ++i) { - if (!(name = encodingA->getCharName(i))) { - name = ".notdef"; - } - fprintf(out, "dup %d /%s put\n", i, name); - } - fprintf(out, "readonly def\n"); -} - -void TrueTypeFontFile::cvtCharStrings(FontEncoding *encodingA, FILE *out) { - int cmap[256]; - int nCmaps, cmapPlatform, cmapEncoding, cmapFmt, cmapLen, cmapOffset; - int segCnt, segStart, segEnd, segDelta, segOffset; - char *name; - int pos, i, j, k; - - //----- read the cmap: construct the (char code) -> (glyph idx) mapping - - // map everything to the missing glyph - for (i = 0; i < 256; ++i) { - cmap[i] = 0; - } - - // look for the 'cmap' table - if ((pos = seekTable("cmap")) >= 0) { - nCmaps = getUShort(pos+2); - - // if the font has a Windows-symbol cmap, use it; - // otherwise, use the first cmap in the table - for (i = 0; i < nCmaps; ++i) { - cmapPlatform = getUShort(pos + 4 + 8*i); - cmapEncoding = getUShort(pos + 4 + 8*i + 2); - if (cmapPlatform == 3 && cmapEncoding == 0) { - break; - } - } - if (i >= nCmaps) { - i = 0; - cmapPlatform = getUShort(pos + 4); - cmapEncoding = getUShort(pos + 4 + 2); - } - pos += getULong(pos + 4 + 8*i + 4); - - // read the cmap - cmapFmt = getUShort(pos); - switch (cmapFmt) { - case 0: // byte encoding table (Apple standard) - cmapLen = getUShort(pos + 2); - for (i = 0; i < cmapLen && i < 256; ++i) { - cmap[i] = getByte(pos + 6 + i); - } - break; - case 4: // segment mapping to delta values (Microsoft standard) - if (cmapPlatform == 3 && cmapEncoding == 0) { - // Windows-symbol uses char codes 0xf000 - 0xf0ff - cmapOffset = 0xf000; - } else { - cmapOffset = 0; - } - segCnt = getUShort(pos + 6) / 2; - for (i = 0; i < segCnt; ++i) { - segEnd = getUShort(pos + 14 + 2*i); - segStart = getUShort(pos + 16 + 2*segCnt + 2*i); - segDelta = getUShort(pos + 16 + 4*segCnt + 2*i); - segOffset = getUShort(pos + 16 + 6*segCnt + 2*i); - if (segStart - cmapOffset <= 0xff && - segEnd - cmapOffset >= 0) { - for (j = (segStart - cmapOffset >= 0) ? segStart : cmapOffset; - j <= segEnd && j - cmapOffset <= 0xff; - ++j) { - if (segOffset == 0) { - k = (j + segDelta) & 0xffff; - } else { - k = getUShort(pos + 16 + 6*segCnt + 2*i + - segOffset + 2 * (j - segStart)); - if (k != 0) { - k = (k + segDelta) & 0xffff; - } - } - cmap[j - cmapOffset] = k; - } - } - } - break; - default: - error(-1, "Unimplemented cmap type (%d) in TrueType font file", - cmapFmt); - break; - } - } - - //----- map char code to glyph index - - // 1. use encoding to map name to char code - // 2. use cmap to map char code to glyph index - - fprintf(out, "/CharStrings 256 dict dup begin\n"); - fprintf(out, "/.notdef 0 def\n"); - - // kludge: this loop goes backward because the WinAnsi and MacRoman - // encodings define certain chars multiple times (space, hyphen, - // etc.), and we want the lowest-numbered definition to "stick" - // (because the higher-numbered defn(s) may not have valid cmap - // entries) - i = encodingA->getSize(); - if (i > 255) { - i = 255; - } - for (; i >= 0; --i) { - name = encodingA->getCharName(i); - if (name && strcmp(name, ".notdef")) { - fprintf(out, "/%s %d def\n", name, cmap[i]); - } - } - - fprintf(out, "end readonly def\n"); -} - -void TrueTypeFontFile::cvtSfnts(FILE *out) { - char tableDir[12 + 9*16]; - int *list; - int nTablesOut, pos, destPos, i, j, k1, k2; - - fprintf(out, "/sfnts [\n"); - - // count tables - nTablesOut = 0; - for (i = 0; i < 9; ++i) { - for (j = 0; j < nTables; ++j) { - if (!strncmp(t42ReqTables[i], tableHdrs[j].tag, 4)) { - ++nTablesOut; - break; - } - } - } - - // header - tableDir[0] = 0x00; // sfnt version - tableDir[1] = 0x01; - tableDir[2] = 0x00; - tableDir[3] = 0x00; - tableDir[4] = (nTablesOut >> 8) & 0xff; // numTables - tableDir[5] = nTablesOut & 0xff; - tableDir[6] = 0; // searchRange - tableDir[7] = 128; - tableDir[8] = 0; // entrySelector - tableDir[9] = 3; - tableDir[10] = 0; // rangeShift - tableDir[11] = 16; - - // table directory - pos = 12; - destPos = 12 + 16 * nTablesOut; - for (i = 0; i < 9; ++i) { - for (j = 0; j < nTables; ++j) { - if (!strncmp(t42ReqTables[i], tableHdrs[j].tag, 4)) { - break; - } - } - if (j < nTables) { - memcpy(&tableDir[pos], t42ReqTables[i], 4); - tableDir[pos+4] = (tableHdrs[j].checksum >> 24) & 0xff; - tableDir[pos+5] = (tableHdrs[j].checksum >> 16) & 0xff; - tableDir[pos+6] = (tableHdrs[j].checksum >> 8) & 0xff; - tableDir[pos+7] = tableHdrs[j].checksum & 0xff; - tableDir[pos+8] = (destPos >> 24) & 0xff; - tableDir[pos+9] = (destPos >> 16) & 0xff; - tableDir[pos+10] = (destPos >> 8) & 0xff; - tableDir[pos+11] = destPos & 0xff; - tableDir[pos+12] = (tableHdrs[j].length >> 24) & 0xff; - tableDir[pos+13] = (tableHdrs[j].length >> 16) & 0xff; - tableDir[pos+14] = (tableHdrs[j].length >> 8) & 0xff; - tableDir[pos+15] = tableHdrs[j].length & 0xff; - pos += 16; - destPos += tableHdrs[j].length; - if (tableHdrs[j].length & 3) { - destPos += 4 - (tableHdrs[j].length & 3); - } - } - } - - dumpString(tableDir, 12 + 16 * nTablesOut, out); - - for (i = 0; i < 9; ++i) { - for (j = 0; j < nTables; ++j) { - if (!strncmp(t42ReqTables[i], tableHdrs[j].tag, 4)) { - break; - } - } - if (j < nTables) { - if (!strcmp(t42ReqTables[i], "glyf") && tableHdrs[j].length > 65532) { - // the 'glyf' table won't fit in a single string, and we're only - // allowed to break at glyph boundaries - list = (int *)gmalloc((nGlyphs + 1) * sizeof(int)); - pos = seekTable("loca"); - for (k1 = 0; k1 <= nGlyphs; ++k1) { - if (locaFmt) { - list[k1] = getULong(pos + 4*k1); - } else { - list[k1] = 2 * getUShort(pos + 2*k1); - } - } - k1 = 0; - while (k1 < nGlyphs) { - for (k2 = k1 + 1; - k2 < nGlyphs && list[k2+1] - list[k1] <= 65532; - ++k2) ; - // ghostscript is unhappy if we break at anything other - // than a multiple of four bytes - while (((list[k2] - list[k1]) & 3) && k2 > k1 + 1) { - --k2; - } - dumpString(file + tableHdrs[j].offset + list[k1], - list[k2] - list[k1], out); - k1 = k2; - } - gfree(list); - } else { - dumpString(file + tableHdrs[j].offset, tableHdrs[j].length, out); - } - } - } - - fprintf(out, "] def\n"); -} - -void TrueTypeFontFile::dumpString(char *s, int n, FILE *out) { - int i, j; - - fprintf(out, "<"); - for (i = 0; i < n; i += 32) { - for (j = 0; j < 32 && i+j < n; ++j) { - fprintf(out, "%02X", s[i+j] & 0xff); - } - if (i+32 < n) { - fprintf(out, "\n"); - } - } - if (n & 3) { - for (i = 0; i < 4 - (n & 3); ++i) { - fprintf(out, "00"); - } - } - // append an extra mystery zero byte because the Type 42 spec says so - fprintf(out, "00>\n"); -} diff --git a/src/plugins/pdf/FontFile.h b/src/plugins/pdf/FontFile.h @@ -1,170 +0,0 @@ -//======================================================================== -// -// FontFile.h -// -// Copyright 1999 Derek B. Noonburg -// -//======================================================================== - -#ifndef FONTFILE_H -#define FONTFILE_H - -#ifdef __GNUC__ -#pragma interface -#endif - -#include <stdio.h> -#include "gtypes.h" -#include "GString.h" -#include "FontEncoding.h" - -//------------------------------------------------------------------------ -// FontFile -//------------------------------------------------------------------------ - -class FontFile { -public: - - FontFile(); - virtual ~FontFile(); - - // Returns the font name, as specified internally by the font file. - // Returns NULL if no name is available. - virtual char *getName() = 0; - - // Returns the custom font encoding, or NULL if the encoding is - // not available. If <taken> is set, the caller of this function - // will be responsible for freeing the encoding object. - virtual FontEncoding *getEncoding(GBool taken) = 0; -}; - -//------------------------------------------------------------------------ -// Type1FontFile -//------------------------------------------------------------------------ - -class Type1FontFile: public FontFile { -public: - - Type1FontFile(char *file, int len); - virtual ~Type1FontFile(); - virtual char *getName() { return name; } - virtual FontEncoding *getEncoding(GBool taken); - -private: - - char *name; - FontEncoding *encoding; - GBool freeEnc; -}; - -//------------------------------------------------------------------------ -// Type1CFontFile -//------------------------------------------------------------------------ - -class Type1CFontFile: public FontFile { -public: - - Type1CFontFile(char *file, int len); - virtual ~Type1CFontFile(); - virtual char *getName() { return name; } - virtual FontEncoding *getEncoding(GBool taken); - -private: - - char *name; - FontEncoding *encoding; - GBool freeEnc; -}; - -//------------------------------------------------------------------------ -// Type1CFontConverter -//------------------------------------------------------------------------ - -class Type1CFontConverter { -public: - - Type1CFontConverter(char *fileA, int lenA, FILE *outA); - ~Type1CFontConverter(); - void convert(); - -private: - - void eexecWrite(char *s); - void cvtGlyph(char *name, Guchar *s, int n); - void cvtGlyphWidth(GBool useOp); - void eexecDumpNum(double x, GBool fpA); - void eexecDumpOp1(int opA); - void eexecDumpOp2(int opA); - void eexecWriteCharstring(Guchar *s, int n); - void getDeltaInt(char *buf, char *name, double *opA, int n); - void getDeltaReal(char *buf, char *name, double *opA, int n); - - char *file; - int len; - FILE *out; - double op[48]; // operands - GBool fp[48]; // true if operand is fixed point - int nOps; // number of operands - double defaultWidthX; // default glyph width - double nominalWidthX; // nominal glyph width - GBool defaultWidthXFP; // true if defaultWidthX is fixed point - GBool nominalWidthXFP; // true if nominalWidthX is fixed point - Gushort r1; // eexec encryption key - GString *charBuf; // charstring output buffer - int line; // number of eexec chars on current line -}; - -//------------------------------------------------------------------------ -// TrueTypeFontFile -//------------------------------------------------------------------------ - -struct TTFontTableHdr; - -class TrueTypeFontFile: public FontFile { -public: - - TrueTypeFontFile(char *fileA, int lenA); - ~TrueTypeFontFile(); - - // This always returns NULL, since it's probably better to trust the - // font name in the PDF file rather than the one in the TrueType - // font file. - virtual char *getName(); - - virtual FontEncoding *getEncoding(GBool taken); - - // Convert to a Type 42 font, suitable for embedding in a PostScript - // file. The name will be used as the PostScript font name (so we - // don't need to depend on the 'name' table in the font). The - // encoding is needed because the PDF Font object can modify the - // encoding. - void convertToType42(char *name, FontEncoding *encodingA, FILE *out); - -private: - - char *file; - int len; - - FontEncoding *encoding; - GBool freeEnc; - - TTFontTableHdr *tableHdrs; - int nTables; - int bbox[4]; - int locaFmt; - int nGlyphs; - - int getByte(int pos); - int getChar(int pos); - int getUShort(int pos); - int getShort(int pos); - Guint getULong(int pos); - double getFixed(int pos); - int seekTable(char *tag); - void cvtEncoding(FontEncoding *encodingA, FILE *out); - void cvtCharStrings(FontEncoding *encodingA, FILE *out); - void cvtSfnts(FILE *out); - void dumpString(char *s, int n, FILE *out); -}; - -#endif diff --git a/src/plugins/pdf/Function.cc b/src/plugins/pdf/Function.cc @@ -1,1520 +0,0 @@ -//======================================================================== -// -// Function.cc -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <math.h> -#include "gmem.h" -#include "Object.h" -#include "Dict.h" -#include "Stream.h" -#include "Error.h" -#include "Function.h" - -//------------------------------------------------------------------------ -// Function -//------------------------------------------------------------------------ - -Function::Function() { -} - -Function::~Function() { -} - -Function *Function::parse(Object *funcObj) { - Function *func; - Dict *dict; - int funcType; - Object obj1; - - if (funcObj->isStream()) { - dict = funcObj->streamGetDict(); - } else if (funcObj->isDict()) { - dict = funcObj->getDict(); - } else if (funcObj->isName("Identity")) { - return new IdentityFunction(); - } else { - error(-1, "Expected function dictionary or stream"); - return NULL; - } - - if (!dict->lookup("FunctionType", &obj1)->isInt()) { - error(-1, "Function type is missing or wrong type"); - obj1.free(); - return NULL; - } - funcType = obj1.getInt(); - obj1.free(); - - if (funcType == 0) { - func = new SampledFunction(funcObj, dict); - } else if (funcType == 2) { - func = new ExponentialFunction(funcObj, dict); - } else if (funcType == 3) { - func = new StitchingFunction(funcObj, dict); - } else if (funcType == 4) { - func = new PostScriptFunction(funcObj, dict); - } else { - error(-1, "Unimplemented function type (%d)", funcType); - return NULL; - } - if (!func->isOk()) { - delete func; - return NULL; - } - - return func; -} - -GBool Function::init(Dict *dict) { - Object obj1, obj2; - int i; - - //----- Domain - if (!dict->lookup("Domain", &obj1)->isArray()) { - error(-1, "Function is missing domain"); - goto err2; - } - m = obj1.arrayGetLength() / 2; - if (m > funcMaxInputs) { - error(-1, "Functions with more than %d inputs are unsupported", - funcMaxInputs); - goto err2; - } - for (i = 0; i < m; ++i) { - obj1.arrayGet(2*i, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function domain array"); - goto err1; - } - domain[i][0] = obj2.getNum(); - obj2.free(); - obj1.arrayGet(2*i+1, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function domain array"); - goto err1; - } - domain[i][1] = obj2.getNum(); - obj2.free(); - } - obj1.free(); - - //----- Range - hasRange = gFalse; - n = 0; - if (dict->lookup("Range", &obj1)->isArray()) { - hasRange = gTrue; - n = obj1.arrayGetLength() / 2; - if (n > funcMaxOutputs) { - error(-1, "Functions with more than %d outputs are unsupported", - funcMaxOutputs); - goto err2; - } - for (i = 0; i < n; ++i) { - obj1.arrayGet(2*i, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function range array"); - goto err1; - } - range[i][0] = obj2.getNum(); - obj2.free(); - obj1.arrayGet(2*i+1, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function range array"); - goto err1; - } - range[i][1] = obj2.getNum(); - obj2.free(); - } - } - obj1.free(); - - return gTrue; - - err1: - obj2.free(); - err2: - obj1.free(); - return gFalse; -} - -//------------------------------------------------------------------------ -// IdentityFunction -//------------------------------------------------------------------------ - -IdentityFunction::IdentityFunction() { - int i; - - // fill these in with arbitrary values just in case they get used - // somewhere - m = funcMaxInputs; - n = funcMaxOutputs; - for (i = 0; i < funcMaxInputs; ++i) { - domain[i][0] = 0; - domain[i][1] = 1; - } - hasRange = gFalse; -} - -IdentityFunction::~IdentityFunction() { -} - -void IdentityFunction::transform(double *in, double *out) { - int i; - - for (i = 0; i < funcMaxOutputs; ++i) { - out[i] = in[i]; - } -} - -//------------------------------------------------------------------------ -// SampledFunction -//------------------------------------------------------------------------ - -SampledFunction::SampledFunction(Object *funcObj, Dict *dict) { - Stream *str; - int nSamples, sampleBits; - double sampleMul; - Object obj1, obj2; - Guint buf, bitMask; - int bits; - int s; - int i; - - samples = NULL; - ok = gFalse; - - //----- initialize the generic stuff - if (!init(dict)) { - goto err1; - } - if (!hasRange) { - error(-1, "Type 0 function is missing range"); - goto err1; - } - - //----- get the stream - if (!funcObj->isStream()) { - error(-1, "Type 0 function isn't a stream"); - goto err1; - } - str = funcObj->getStream(); - - //----- Size - if (!dict->lookup("Size", &obj1)->isArray() || - obj1.arrayGetLength() != m) { - error(-1, "Function has missing or invalid size array"); - goto err2; - } - for (i = 0; i < m; ++i) { - obj1.arrayGet(i, &obj2); - if (!obj2.isInt()) { - error(-1, "Illegal value in function size array"); - goto err3; - } - sampleSize[i] = obj2.getInt(); - obj2.free(); - } - obj1.free(); - - //----- BitsPerSample - if (!dict->lookup("BitsPerSample", &obj1)->isInt()) { - error(-1, "Function has missing or invalid BitsPerSample"); - goto err2; - } - sampleBits = obj1.getInt(); - sampleMul = 1.0 / (double)((1 << sampleBits) - 1); - obj1.free(); - - //----- Encode - if (dict->lookup("Encode", &obj1)->isArray() && - obj1.arrayGetLength() == 2*m) { - for (i = 0; i < m; ++i) { - obj1.arrayGet(2*i, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function encode array"); - goto err3; - } - encode[i][0] = obj2.getNum(); - obj2.free(); - obj1.arrayGet(2*i+1, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function encode array"); - goto err3; - } - encode[i][1] = obj2.getNum(); - obj2.free(); - } - } else { - for (i = 0; i < m; ++i) { - encode[i][0] = 0; - encode[i][1] = sampleSize[i] - 1; - } - } - obj1.free(); - - //----- Decode - if (dict->lookup("Decode", &obj1)->isArray() && - obj1.arrayGetLength() == 2*n) { - for (i = 0; i < n; ++i) { - obj1.arrayGet(2*i, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function decode array"); - goto err3; - } - decode[i][0] = obj2.getNum(); - obj2.free(); - obj1.arrayGet(2*i+1, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function decode array"); - goto err3; - } - decode[i][1] = obj2.getNum(); - obj2.free(); - } - } else { - for (i = 0; i < n; ++i) { - decode[i][0] = range[i][0]; - decode[i][1] = range[i][1]; - } - } - obj1.free(); - - //----- samples - nSamples = n; - for (i = 0; i < m; ++i) - nSamples *= sampleSize[i]; - samples = (double *)gmalloc(nSamples * sizeof(double)); - buf = 0; - bits = 0; - bitMask = (1 << sampleBits) - 1; - str->reset(); - for (i = 0; i < nSamples; ++i) { - if (sampleBits == 8) { - s = str->getChar(); - } else if (sampleBits == 16) { - s = str->getChar(); - s = (s << 8) + str->getChar(); - } else if (sampleBits == 32) { - s = str->getChar(); - s = (s << 8) + str->getChar(); - s = (s << 8) + str->getChar(); - s = (s << 8) + str->getChar(); - } else { - while (bits < sampleBits) { - buf = (buf << 8) | (str->getChar() & 0xff); - bits += 8; - } - s = (buf >> (bits - sampleBits)) & bitMask; - bits -= sampleBits; - } - samples[i] = (double)s * sampleMul; - } - str->close(); - - ok = gTrue; - return; - - err3: - obj2.free(); - err2: - obj1.free(); - err1: - return; -} - -SampledFunction::~SampledFunction() { - if (samples) { - gfree(samples); - } -} - -SampledFunction::SampledFunction(SampledFunction *func) { - int nSamples, i; - - memcpy(this, func, sizeof(SampledFunction)); - - nSamples = n; - for (i = 0; i < m; ++i) { - nSamples *= sampleSize[i]; - } - samples = (double *)gmalloc(nSamples * sizeof(double)); - memcpy(samples, func->samples, nSamples * sizeof(double)); -} - -void SampledFunction::transform(double *in, double *out) { - double x; - int e[2][funcMaxInputs]; - double efrac[funcMaxInputs]; - double s0[1 << funcMaxInputs], s1[1 << funcMaxInputs]; - int i, j, k, idx; - - // map input values into sample array - for (i = 0; i < m; ++i) { - x = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) * - (encode[i][1] - encode[i][0]) + encode[i][0]; - if (x < 0) { - x = 0; - } else if (x > sampleSize[i] - 1) { - x = sampleSize[i] - 1; - } - e[0][i] = (int)floor(x); - e[1][i] = (int)ceil(x); - efrac[i] = x - e[0][i]; - } - - // for each output, do m-linear interpolation - for (i = 0; i < n; ++i) { - - // pull 2^m values out of the sample array - for (j = 0; j < (1<<m); ++j) { - idx = 0; - for (k = m - 1; k >= 0; --k) { - idx = idx * sampleSize[k] + e[(j >> k) & 1][k]; - } - idx = idx * n + i; - s0[j] = samples[idx]; - } - - // do m sets of interpolations - for (j = 0; j < m; ++j) { - for (k = 0; k < (1 << (m - j)); k += 2) { - s1[k >> 1] = (1 - efrac[j]) * s0[k] + efrac[j] * s0[k+1]; - } - memcpy(s0, s1, (1 << (m - j - 1)) * sizeof(double)); - } - - // map output value to range - out[i] = s0[0] * (decode[i][1] - decode[i][0]) + decode[i][0]; - if (out[i] < range[i][0]) { - out[i] = range[i][0]; - } else if (out[i] > range[i][1]) { - out[i] = range[i][1]; - } - } -} - -//------------------------------------------------------------------------ -// ExponentialFunction -//------------------------------------------------------------------------ - -ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { - Object obj1, obj2; - int i; - - ok = gFalse; - - //----- initialize the generic stuff - if (!init(dict)) { - goto err1; - } - if (m != 1) { - error(-1, "Exponential function with more than one input"); - goto err1; - } - - //----- C0 - if (dict->lookup("C0", &obj1)->isArray()) { - if (hasRange && obj1.arrayGetLength() != n) { - error(-1, "Function's C0 array is wrong length"); - goto err2; - } - n = obj1.arrayGetLength(); - for (i = 0; i < n; ++i) { - obj1.arrayGet(i, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function C0 array"); - goto err3; - } - c0[i] = obj2.getNum(); - obj2.free(); - } - } else { - if (hasRange && n != 1) { - error(-1, "Function's C0 array is wrong length"); - goto err2; - } - n = 1; - c0[0] = 0; - } - obj1.free(); - - //----- C1 - if (dict->lookup("C1", &obj1)->isArray()) { - if (obj1.arrayGetLength() != n) { - error(-1, "Function's C1 array is wrong length"); - goto err2; - } - for (i = 0; i < n; ++i) { - obj1.arrayGet(i, &obj2); - if (!obj2.isNum()) { - error(-1, "Illegal value in function C1 array"); - goto err3; - } - c1[i] = obj2.getNum(); - obj2.free(); - } - } else { - if (n != 1) { - error(-1, "Function's C1 array is wrong length"); - goto err2; - } - c1[0] = 1; - } - obj1.free(); - - //----- N (exponent) - if (!dict->lookup("N", &obj1)->isNum()) { - error(-1, "Function has missing or invalid N"); - goto err2; - } - e = obj1.getNum(); - obj1.free(); - - ok = gTrue; - return; - - err3: - obj2.free(); - err2: - obj1.free(); - err1: - return; -} - -ExponentialFunction::~ExponentialFunction() { -} - -ExponentialFunction::ExponentialFunction(ExponentialFunction *func) { - memcpy(this, func, sizeof(ExponentialFunction)); -} - -void ExponentialFunction::transform(double *in, double *out) { - double x; - int i; - - if (in[0] < domain[0][0]) { - x = domain[0][0]; - } else if (in[0] > domain[0][1]) { - x = domain[0][1]; - } else { - x = in[0]; - } - for (i = 0; i < n; ++i) { - out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]); - if (hasRange) { - if (out[i] < range[i][0]) { - out[i] = range[i][0]; - } else if (out[i] > range[i][1]) { - out[i] = range[i][1]; - } - } - } - return; -} - -//------------------------------------------------------------------------ -// StitchingFunction -//------------------------------------------------------------------------ - -StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict) { - Object obj1, obj2; - int i; - - ok = gFalse; - funcs = NULL; - bounds = NULL; - encode = NULL; - - //----- initialize the generic stuff - if (!init(dict)) { - goto err1; - } - if (m != 1) { - error(-1, "Stitching function with more than one input"); - goto err1; - } - - //----- Functions - if (!dict->lookup("Functions", &obj1)->isArray()) { - error(-1, "Missing 'Functions' entry in stitching function"); - goto err1; - } - k = obj1.arrayGetLength(); - funcs = (Function **)gmalloc(k * sizeof(Function *)); - bounds = (double *)gmalloc((k + 1) * sizeof(double)); - encode = (double *)gmalloc(2 * k * sizeof(double)); - for (i = 0; i < k; ++i) { - funcs[i] = NULL; - } - for (i = 0; i < k; ++i) { - if (!(funcs[i] = Function::parse(obj1.arrayGet(i, &obj2)))) { - goto err2; - } - if (i > 0 && (funcs[i]->getInputSize() != 1 || - funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) { - error(-1, "Incompatible subfunctions in stitching function"); - goto err2; - } - obj2.free(); - } - obj1.free(); - - //----- Bounds - if (!dict->lookup("Bounds", &obj1)->isArray() || - obj1.arrayGetLength() != k - 1) { - error(-1, "Missing or invalid 'Bounds' entry in stitching function"); - goto err1; - } - bounds[0] = domain[0][0]; - for (i = 1; i < k; ++i) { - if (!obj1.arrayGet(i - 1, &obj2)->isNum()) { - error(-1, "Invalid type in 'Bounds' array in stitching function"); - goto err2; - } - bounds[i] = obj2.getNum(); - obj2.free(); - } - bounds[k] = domain[0][1]; - obj1.free(); - - //----- Encode - if (!dict->lookup("Encode", &obj1)->isArray() || - obj1.arrayGetLength() != 2 * k) { - error(-1, "Missing or invalid 'Encode' entry in stitching function"); - goto err1; - } - for (i = 0; i < 2 * k; ++i) { - if (!obj1.arrayGet(i, &obj2)->isNum()) { - error(-1, "Invalid type in 'Encode' array in stitching function"); - goto err2; - } - encode[i] = obj2.getNum(); - obj2.free(); - } - obj1.free(); - - ok = gTrue; - return; - - err2: - obj2.free(); - err1: - obj1.free(); -} - -StitchingFunction::StitchingFunction(StitchingFunction *func) { - int i; - - k = func->k; - funcs = (Function **)gmalloc(k * sizeof(Function *)); - for (i = 0; i < k; ++i) { - funcs[i] = func->funcs[i]->copy(); - } - bounds = (double *)gmalloc((k + 1) * sizeof(double)); - memcpy(bounds, func->bounds, (k + 1) * sizeof(double)); - encode = (double *)gmalloc(2 * k * sizeof(double)); - memcpy(encode, func->encode, 2 * k * sizeof(double)); - ok = gTrue; -} - -StitchingFunction::~StitchingFunction() { - int i; - - if (funcs) { - for (i = 0; i < k; ++i) { - if (funcs[i]) { - delete funcs[i]; - } - } - } - gfree(funcs); - gfree(bounds); - gfree(encode); -} - -void StitchingFunction::transform(double *in, double *out) { - double x; - int i; - - if (in[0] < domain[0][0]) { - x = domain[0][0]; - } else if (in[0] > domain[0][1]) { - x = domain[0][1]; - } else { - x = in[0]; - } - for (i = 0; i < k - 1; ++i) { - if (x < bounds[i+1]) { - break; - } - } - x = encode[2*i] + ((x - bounds[i]) / (bounds[i+1] - bounds[i])) * - (encode[2*i+1] - encode[2*i]); - funcs[i]->transform(&x, out); -} - -//------------------------------------------------------------------------ -// PostScriptFunction -//------------------------------------------------------------------------ - -enum PSOp { - psOpAbs, - psOpAdd, - psOpAnd, - psOpAtan, - psOpBitshift, - psOpCeiling, - psOpCopy, - psOpCos, - psOpCvi, - psOpCvr, - psOpDiv, - psOpDup, - psOpEq, - psOpExch, - psOpExp, - psOpFalse, - psOpFloor, - psOpGe, - psOpGt, - psOpIdiv, - psOpIndex, - psOpLe, - psOpLn, - psOpLog, - psOpLt, - psOpMod, - psOpMul, - psOpNe, - psOpNeg, - psOpNot, - psOpOr, - psOpPop, - psOpRoll, - psOpRound, - psOpSin, - psOpSqrt, - psOpSub, - psOpTrue, - psOpTruncate, - psOpXor, - psOpIf, - psOpIfelse, - psOpReturn -}; - -// Note: 'if' and 'ifelse' are parsed separately. -// The rest are listed here in alphabetical order. -// The index in this table is equivalent to the entry in PSOp. -const char *psOpNames[] = { - "abs", - "add", - "and", - "atan", - "bitshift", - "ceiling", - "copy", - "cos", - "cvi", - "cvr", - "div", - "dup", - "eq", - "exch", - "exp", - "false", - "floor", - "ge", - "gt", - "idiv", - "index", - "le", - "ln", - "log", - "lt", - "mod", - "mul", - "ne", - "neg", - "not", - "or", - "pop", - "roll", - "round", - "sin", - "sqrt", - "sub", - "true", - "truncate", - "xor" -}; - -#define nPSOps (sizeof(psOpNames) / sizeof(char *)) - -enum PSObjectType { - psBool, - psInt, - psReal, - psOperator, - psBlock -}; - -// In the code array, 'if'/'ifelse' operators take up three slots -// plus space for the code in the subclause(s). -// -// +---------------------------------+ -// | psOperator: psOpIf / psOpIfelse | -// +---------------------------------+ -// | psBlock: ptr=<A> | -// +---------------------------------+ -// | psBlock: ptr=<B> | -// +---------------------------------+ -// | if clause | -// | ... | -// | psOperator: psOpReturn | -// +---------------------------------+ -// <A> | else clause | -// | ... | -// | psOperator: psOpReturn | -// +---------------------------------+ -// <B> | ... | -// -// For 'if', pointer <A> is present in the code stream but unused. - -struct PSObject { - PSObjectType type; - union { - GBool booln; // boolean (stack only) - int intg; // integer (stack and code) - double real; // real (stack and code) - PSOp op; // operator (code only) - int blk; // if/ifelse block pointer (code only) - }; -}; - -#define psStackSize 100 - -class PSStack { -public: - - PSStack() { sp = psStackSize; } - void pushBool(GBool booln); - void pushInt(int intg); - void pushReal(double real); - GBool popBool(); - int popInt(); - double popNum(); - GBool empty() { return sp == psStackSize; } - GBool topIsInt() { return sp < psStackSize && stack[sp].type == psInt; } - GBool topTwoAreInts() - { return sp < psStackSize - 1 && - stack[sp].type == psInt && - stack[sp+1].type == psInt; } - GBool topIsReal() { return sp < psStackSize && stack[sp].type == psReal; } - GBool topTwoAreNums() - { return sp < psStackSize - 1 && - (stack[sp].type == psInt || stack[sp].type == psReal) && - (stack[sp+1].type == psInt || stack[sp+1].type == psReal); } - void copy(int n); - void roll(int n, int j); - void idx(int i); - void pop(); - -private: - - GBool checkOverflow(int n = 1); - GBool checkUnderflow(); - GBool checkType(PSObjectType t1, PSObjectType t2); - - PSObject stack[psStackSize]; - int sp; -}; - -GBool PSStack::checkOverflow(int n) { - if (sp - n < 0) { - error(-1, "Stack overflow in PostScript function"); - return gFalse; - } - return gTrue; -} - -GBool PSStack::checkUnderflow() { - if (sp == psStackSize) { - error(-1, "Stack underflow in PostScript function"); - return gFalse; - } - return gTrue; -} - -GBool PSStack::checkType(PSObjectType t1, PSObjectType t2) { - if (stack[sp].type != t1 && stack[sp].type != t2) { - error(-1, "Type mismatch in PostScript function"); - return gFalse; - } - return gTrue; -} - -void PSStack::pushBool(GBool booln) { - if (checkOverflow()) { - stack[--sp].type = psBool; - stack[sp].booln = booln; - } -} - -void PSStack::pushInt(int intg) { - if (checkOverflow()) { - stack[--sp].type = psInt; - stack[sp].intg = intg; - } -} - -void PSStack::pushReal(double real) { - if (checkOverflow()) { - stack[--sp].type = psReal; - stack[sp].real = real; - } -} - -GBool PSStack::popBool() { - if (checkUnderflow() && checkType(psBool, psBool)) { - return stack[sp++].booln; - } - return gFalse; -} - -int PSStack::popInt() { - if (checkUnderflow() && checkType(psInt, psInt)) { - return stack[sp++].intg; - } - return 0; -} - -double PSStack::popNum() { - double ret; - - if (checkUnderflow() && checkType(psInt, psReal)) { - ret = (stack[sp].type == psInt) ? (double)stack[sp].intg : stack[sp].real; - ++sp; - return ret; - } - return 0; -} - -void PSStack::copy(int n) { - int i; - - if (!checkOverflow(n)) { - return; - } - for (i = sp + n - 1; i <= sp; ++i) { - stack[i - n] = stack[i]; - } - sp -= n; -} - -void PSStack::roll(int n, int j) { - PSObject obj; - int i, k; - - if (j >= 0) { - j %= n; - } else { - j = -j % n; - if (j != 0) { - j = n - j; - } - } - if (n <= 0 || j == 0) { - return; - } - for (i = 0; i < j; ++i) { - obj = stack[sp]; - for (k = sp; k < sp + n - 1; ++k) { - stack[k] = stack[k+1]; - } - stack[sp + n - 1] = obj; - } -} - -void PSStack::idx(int i) { - if (!checkOverflow()) { - return; - } - --sp; - stack[sp] = stack[sp + 1 + i]; -} - -void PSStack::pop() { - if (!checkUnderflow()) { - return; - } - ++sp; -} - -PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) { - Stream *str; - int codePtr; - GString *tok; - - code = NULL; - codeSize = 0; - ok = gFalse; - - //----- initialize the generic stuff - if (!init(dict)) { - goto err1; - } - if (!hasRange) { - error(-1, "Type 4 function is missing range"); - goto err1; - } - - //----- get the stream - if (!funcObj->isStream()) { - error(-1, "Type 4 function isn't a stream"); - goto err1; - } - str = funcObj->getStream(); - - //----- parse the function - str->reset(); - if (!(tok = getToken(str)) || tok->cmp("{")) { - error(-1, "Expected '{' at start of PostScript function"); - if (tok) { - delete tok; - } - goto err1; - } - delete tok; - codePtr = 0; - if (!parseCode(str, &codePtr)) { - goto err2; - } - str->close(); - - ok = gTrue; - - err2: - str->close(); - err1: - return; -} - -PostScriptFunction::PostScriptFunction(PostScriptFunction *func) { - memcpy(this, func, sizeof(PostScriptFunction)); - code = (PSObject *)gmalloc(codeSize * sizeof(PSObject)); - memcpy(code, func->code, codeSize * sizeof(PSObject)); -} - -PostScriptFunction::~PostScriptFunction() { - gfree(code); -} - -void PostScriptFunction::transform(double *in, double *out) { - PSStack *stack; - int i; - - stack = new PSStack(); - for (i = 0; i < m; ++i) { - //~ may need to check for integers here - stack->pushReal(in[i]); - } - exec(stack, 0); - for (i = n - 1; i >= 0; --i) { - out[i] = stack->popNum(); - if (out[i] < range[i][0]) { - out[i] = range[i][0]; - } else if (out[i] > range[i][1]) { - out[i] = range[i][1]; - } - } - // if (!stack->empty()) { - // error(-1, "Extra values on stack at end of PostScript function"); - // } - delete stack; -} - -GBool PostScriptFunction::parseCode(Stream *str, int *codePtr) { - GString *tok; - char *p; - GBool isReal; - int opPtr, elsePtr; - int a, b, mid, cmp; - - while (1) { - if (!(tok = getToken(str))) { - error(-1, "Unexpected end of PostScript function stream"); - return gFalse; - } - p = tok->getCString(); - if (isdigit(*p) || *p == '.' || *p == '-') { - isReal = gFalse; - for (++p; *p; ++p) { - if (*p == '.') { - isReal = gTrue; - break; - } - } - resizeCode(*codePtr); - if (isReal) { - code[*codePtr].type = psReal; - code[*codePtr].real = atof(tok->getCString()); - } else { - code[*codePtr].type = psInt; - code[*codePtr].intg = atoi(tok->getCString()); - } - ++*codePtr; - delete tok; - } else if (!tok->cmp("{")) { - delete tok; - opPtr = *codePtr; - *codePtr += 3; - resizeCode(opPtr + 2); - if (!parseCode(str, codePtr)) { - return gFalse; - } - if (!(tok = getToken(str))) { - error(-1, "Unexpected end of PostScript function stream"); - return gFalse; - } - if (!tok->cmp("{")) { - elsePtr = *codePtr; - if (!parseCode(str, codePtr)) { - return gFalse; - } - delete tok; - if (!(tok = getToken(str))) { - error(-1, "Unexpected end of PostScript function stream"); - return gFalse; - } - } else { - elsePtr = -1; - } - if (!tok->cmp("if")) { - if (elsePtr >= 0) { - error(-1, "Got 'if' operator with two blocks in PostScript function"); - return gFalse; - } - code[opPtr].type = psOperator; - code[opPtr].op = psOpIf; - code[opPtr+2].type = psBlock; - code[opPtr+2].blk = *codePtr; - } else if (!tok->cmp("ifelse")) { - if (elsePtr < 0) { - error(-1, "Got 'ifelse' operator with one blocks in PostScript function"); - return gFalse; - } - code[opPtr].type = psOperator; - code[opPtr].op = psOpIfelse; - code[opPtr+1].type = psBlock; - code[opPtr+1].blk = elsePtr; - code[opPtr+2].type = psBlock; - code[opPtr+2].blk = *codePtr; - } else { - error(-1, "Expected if/ifelse operator in PostScript function"); - delete tok; - return gFalse; - } - delete tok; - } else if (!tok->cmp("}")) { - delete tok; - resizeCode(*codePtr); - code[*codePtr].type = psOperator; - code[*codePtr].op = psOpReturn; - ++*codePtr; - break; - } else { - a = -1; - b = nPSOps; - // invariant: psOpNames[a] < tok < psOpNames[b] - while (b - a > 1) { - mid = (a + b) / 2; - cmp = tok->cmp(psOpNames[mid]); - if (cmp > 0) { - a = mid; - } else if (cmp < 0) { - b = mid; - } else { - a = b = mid; - } - } - if (cmp != 0) { - error(-1, "Unknown operator '%s' in PostScript function", - tok->getCString()); - delete tok; - return gFalse; - } - delete tok; - resizeCode(*codePtr); - code[*codePtr].type = psOperator; - code[*codePtr].op = (PSOp)a; - ++*codePtr; - } - } - return gTrue; -} - -GString *PostScriptFunction::getToken(Stream *str) { - GString *s; - int c; - - s = new GString(); - do { - c = str->getChar(); - } while (c != EOF && isspace(c)); - if (c == '{' || c == '}') { - s->append((char)c); - } else if (isdigit(c) || c == '.' || c == '-') { - while (1) { - s->append((char)c); - c = str->lookChar(); - if (c == EOF || !(isdigit(c) || c == '.' || c == '-')) { - break; - } - str->getChar(); - } - } else { - while (1) { - s->append((char)c); - c = str->lookChar(); - if (c == EOF || !isalnum(c)) { - break; - } - str->getChar(); - } - } - return s; -} - -void PostScriptFunction::resizeCode(int newSize) { - if (newSize >= codeSize) { - codeSize += 64; - code = (PSObject *)grealloc(code, codeSize * sizeof(PSObject)); - } -} - -void PostScriptFunction::exec(PSStack *stack, int codePtr) { - int i1, i2; - double r1, r2; - GBool b1, b2; - - while (1) { - switch (code[codePtr].type) { - case psInt: - stack->pushInt(code[codePtr++].intg); - break; - case psReal: - stack->pushReal(code[codePtr++].real); - break; - case psOperator: - switch (code[codePtr++].op) { - case psOpAbs: - if (stack->topIsInt()) { - stack->pushInt(abs(stack->popInt())); - } else { - stack->pushReal(fabs(stack->popNum())); - } - break; - case psOpAdd: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushInt(i1 + i2); - } else { - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushReal(r1 + r2); - } - break; - case psOpAnd: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushInt(i1 & i2); - } else { - b2 = stack->popBool(); - b1 = stack->popBool(); - stack->pushBool(b1 && b2); - } - break; - case psOpAtan: - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushReal(atan2(r1, r2)); - break; - case psOpBitshift: - i2 = stack->popInt(); - i1 = stack->popInt(); - if (i2 > 0) { - stack->pushInt(i1 << i2); - } else if (i2 < 0) { - stack->pushInt((int)((Guint)i1 >> i2)); - } else { - stack->pushInt(i1); - } - break; - case psOpCeiling: - if (!stack->topIsInt()) { - stack->pushReal(ceil(stack->popNum())); - } - break; - case psOpCopy: - stack->copy(stack->popInt()); - break; - case psOpCos: - stack->pushReal(cos(stack->popNum())); - break; - case psOpCvi: - if (!stack->topIsInt()) { - stack->pushInt((int)stack->popNum()); - } - break; - case psOpCvr: - if (!stack->topIsReal()) { - stack->pushReal(stack->popNum()); - } - break; - case psOpDiv: - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushReal(r1 / r2); - break; - case psOpDup: - stack->copy(1); - break; - case psOpEq: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushBool(i1 == i2); - } else if (stack->topTwoAreNums()) { - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushBool(r1 == r2); - } else { - b2 = stack->popBool(); - b1 = stack->popBool(); - stack->pushBool(b1 == b2); - } - break; - case psOpExch: - stack->roll(2, 1); - break; - case psOpExp: - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushReal(pow(r1, r2)); - break; - case psOpFalse: - stack->pushBool(gFalse); - break; - case psOpFloor: - if (!stack->topIsInt()) { - stack->pushReal(floor(stack->popNum())); - } - break; - case psOpGe: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushBool(i1 >= i2); - } else { - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushBool(r1 >= r2); - } - break; - case psOpGt: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushBool(i1 > i2); - } else { - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushBool(r1 > r2); - } - break; - case psOpIdiv: - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushInt(i1 / i2); - break; - case psOpIndex: - stack->idx(stack->popInt()); - break; - case psOpLe: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushBool(i1 <= i2); - } else { - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushBool(r1 <= r2); - } - break; - case psOpLn: - stack->pushReal(log(stack->popNum())); - break; - case psOpLog: - stack->pushReal(log10(stack->popNum())); - break; - case psOpLt: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushBool(i1 < i2); - } else { - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushBool(r1 < r2); - } - break; - case psOpMod: - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushInt(i1 % i2); - break; - case psOpMul: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - //~ should check for out-of-range, and push a real instead - stack->pushInt(i1 * i2); - } else { - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushReal(r1 * r2); - } - break; - case psOpNe: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushBool(i1 != i2); - } else if (stack->topTwoAreNums()) { - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushBool(r1 != r2); - } else { - b2 = stack->popBool(); - b1 = stack->popBool(); - stack->pushBool(b1 != b2); - } - break; - case psOpNeg: - if (stack->topIsInt()) { - stack->pushInt(-stack->popInt()); - } else { - stack->pushReal(-stack->popNum()); - } - break; - case psOpNot: - if (stack->topIsInt()) { - stack->pushInt(~stack->popInt()); - } else { - stack->pushBool(!stack->popBool()); - } - break; - case psOpOr: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushInt(i1 | i2); - } else { - b2 = stack->popBool(); - b1 = stack->popBool(); - stack->pushBool(b1 || b2); - } - break; - case psOpPop: - stack->pop(); - break; - case psOpRoll: - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->roll(i1, i2); - break; - case psOpRound: - if (!stack->topIsInt()) { - r1 = stack->popNum(); - stack->pushReal((r1 >= 0) ? floor(r1 + 0.5) : ceil(r1 - 0.5)); - } - break; - case psOpSin: - stack->pushReal(sin(stack->popNum())); - break; - case psOpSqrt: - stack->pushReal(sqrt(stack->popNum())); - break; - case psOpSub: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushInt(i1 - i2); - } else { - r2 = stack->popNum(); - r1 = stack->popNum(); - stack->pushReal(r1 - r2); - } - break; - case psOpTrue: - stack->pushBool(gTrue); - break; - case psOpTruncate: - if (!stack->topIsInt()) { - r1 = stack->popNum(); - stack->pushReal((r1 >= 0) ? floor(r1) : ceil(r1)); - } - break; - case psOpXor: - if (stack->topTwoAreInts()) { - i2 = stack->popInt(); - i1 = stack->popInt(); - stack->pushInt(i1 ^ i2); - } else { - b2 = stack->popBool(); - b1 = stack->popBool(); - stack->pushBool(b1 ^ b2); - } - break; - case psOpIf: - b1 = stack->popBool(); - if (b1) { - exec(stack, codePtr + 2); - } - codePtr = code[codePtr + 1].blk; - break; - case psOpIfelse: - b1 = stack->popBool(); - if (b1) { - exec(stack, codePtr + 2); - } else { - exec(stack, code[codePtr].blk); - } - codePtr = code[codePtr + 1].blk; - break; - case psOpReturn: - return; - } - break; - default: - error(-1, "Internal: bad object in PostScript function code"); - break; - } - } -} diff --git a/src/plugins/pdf/Function.h b/src/plugins/pdf/Function.h @@ -1,183 +0,0 @@ -//======================================================================== -// -// Function.h -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef FUNCTION_H -#define FUNCTION_H - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "Object.h" - -class Dict; -class Stream; -struct PSObject; -class PSStack; - -//------------------------------------------------------------------------ -// Function -//------------------------------------------------------------------------ - -#define funcMaxInputs 8 -#define funcMaxOutputs 32 - -class Function { -public: - - Function(); - - virtual ~Function(); - - // Construct a function. Returns NULL if unsuccessful. - static Function *parse(Object *funcObj); - - // Initialize the entries common to all function types. - GBool init(Dict *dict); - - virtual Function *copy() = 0; - - // Return size of input and output tuples. - int getInputSize() { return m; } - int getOutputSize() { return n; } - - // Transform an input tuple into an output tuple. - virtual void transform(double *in, double *out) = 0; - - virtual GBool isOk() = 0; - -protected: - - int m, n; // size of input and output tuples - double // min and max values for function domain - domain[funcMaxInputs][2]; - double // min and max values for function range - range[funcMaxOutputs][2]; - GBool hasRange; // set if range is defined -}; - -//------------------------------------------------------------------------ -// IdentityFunction -//------------------------------------------------------------------------ - -class IdentityFunction: public Function { -public: - - IdentityFunction(); - virtual ~IdentityFunction(); - virtual Function *copy() { return new IdentityFunction(); } - virtual void transform(double *in, double *out); - virtual GBool isOk() { return gTrue; } - -private: -}; - -//------------------------------------------------------------------------ -// SampledFunction -//------------------------------------------------------------------------ - -class SampledFunction: public Function { -public: - - SampledFunction(Object *funcObj, Dict *dict); - virtual ~SampledFunction(); - virtual Function *copy() { return new SampledFunction(this); } - virtual void transform(double *in, double *out); - virtual GBool isOk() { return ok; } - -private: - - SampledFunction(SampledFunction *func); - - int // number of samples for each domain element - sampleSize[funcMaxInputs]; - double // min and max values for domain encoder - encode[funcMaxInputs][2]; - double // min and max values for range decoder - decode[funcMaxOutputs][2]; - double *samples; // the samples - GBool ok; -}; - -//------------------------------------------------------------------------ -// ExponentialFunction -//------------------------------------------------------------------------ - -class ExponentialFunction: public Function { -public: - - ExponentialFunction(Object *funcObj, Dict *dict); - virtual ~ExponentialFunction(); - virtual Function *copy() { return new ExponentialFunction(this); } - virtual void transform(double *in, double *out); - virtual GBool isOk() { return ok; } - -private: - - ExponentialFunction(ExponentialFunction *func); - - double c0[funcMaxOutputs]; - double c1[funcMaxOutputs]; - double e; - GBool ok; -}; - -//------------------------------------------------------------------------ -// StitchingFunction -//------------------------------------------------------------------------ - -class StitchingFunction: public Function { -public: - - StitchingFunction(Object *funcObj, Dict *dict); - virtual ~StitchingFunction(); - virtual Function *copy() { return new StitchingFunction(this); } - virtual void transform(double *in, double *out); - virtual GBool isOk() { return ok; } - -private: - - StitchingFunction(StitchingFunction *func); - - int k; - Function **funcs; - double *bounds; - double *encode; - GBool ok; -}; - -//------------------------------------------------------------------------ -// PostScriptFunction -//------------------------------------------------------------------------ - -class PostScriptFunction: public Function { -public: - - PostScriptFunction(Object *funcObj, Dict *dict); - virtual ~PostScriptFunction(); - virtual Function *copy() { return new PostScriptFunction(this); } - virtual void transform(double *in, double *out); - virtual GBool isOk() { return ok; } - -private: - - PostScriptFunction(PostScriptFunction *func); - GBool parseCode(Stream *str, int *codePtr); - GString *getToken(Stream *str); - void resizeCode(int newSize); - void exec(PSStack *stack, int codePtr); - - PSObject *code; - int codeSize; - GBool ok; -}; - -#endif diff --git a/src/plugins/pdf/GString.cc b/src/plugins/pdf/GString.cc @@ -1,232 +0,0 @@ -//======================================================================== -// -// GString.cc -// -// Simple variable-length string type. -// -// Copyright 1996 Derek B. Noonburg -// -//======================================================================== - -#ifdef __GNUC__ -#pragma implementation -#endif - -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <ctype.h> -#include "gtypes.h" -#include "GString.h" - -static inline int size(int len) { - int delta; - - - - delta = len < 256 ? 7 : 255; - return ((len + 1) + delta) & ~delta; -} - -inline void GString::resize(int length1) { - char *s1; - - if (!s) { - s = new char[size(length1)]; - } else if (size(length1) != size(length)) { - s1 = new char[size(length1)]; - memcpy(s1, s, length + 1); - delete[] s; - s = s1; - } -} - -GString::GString() { - s = NULL; - resize(length = 0); - s[0] = '\0'; -} - -GString::GString(const char *sA) { - int n = strlen(sA); - - s = NULL; - resize(length = n); - memcpy(s, sA, n + 1); -} - -GString::GString(const char *sA, int lengthA) { - s = NULL; - resize(length = lengthA); - memcpy(s, sA, length * sizeof(char)); - s[length] = '\0'; -} - -GString::GString(GString *str, int idx, int lengthA) { - s = NULL; - resize(length = lengthA); - memcpy(s, str->getCString() + idx, length); - s[length] = '\0'; -} - -GString::GString(GString *str) { - s = NULL; - resize(length = str->getLength()); - memcpy(s, str->getCString(), length + 1); -} - -GString::GString(GString *str1, GString *str2) { - int n1 = str1->getLength(); - int n2 = str2->getLength(); - - s = NULL; - resize(length = n1 + n2); - memcpy(s, str1->getCString(), n1); - memcpy(s + n1, str2->getCString(), n2 + 1); -} - -GString *GString::fromInt(int x) { - char buf[24]; // enough space for 64-bit ints plus a little extra - GBool neg; - Guint y; - int i; - - i = 24; - if (x == 0) { - buf[--i] = '0'; - } else { - if ((neg = x < 0)) { - y = (Guint)-x; - } else { - y = (Guint)x; - } - while (i > 0 && y > 0) { - buf[--i] = '0' + y % 10; - y /= 10; - } - if (neg && i > 0) { - buf[--i] = '-'; - } - } - return new GString(buf + i, 24 - i); -} - -GString::~GString() { - delete[] s; -} - -GString *GString::clear() { - s[length = 0] = '\0'; - resize(0); - return this; -} - -GString *GString::append(char c) { - resize(length + 1); - s[length++] = c; - s[length] = '\0'; - return this; -} - -GString *GString::append(GString *str) { - int n = str->getLength(); - - resize(length + n); - memcpy(s + length, str->getCString(), n + 1); - length += n; - return this; -} - -GString *GString::append(const char *str) { - int n = strlen(str); - - resize(length + n); - memcpy(s + length, str, n + 1); - length += n; - return this; -} - -GString *GString::append(const char *str, int lengthA) { - resize(length + lengthA); - memcpy(s + length, str, lengthA); - length += lengthA; - s[length] = '\0'; - return this; -} - -GString *GString::insert(int i, char c) { - int j; - - resize(length + 1); - for (j = length + 1; j > i; --j) - s[j] = s[j-1]; - s[i] = c; - ++length; - return this; -} - -GString *GString::insert(int i, GString *str) { - int n = str->getLength(); - int j; - - resize(length + n); - for (j = length; j >= i; --j) - s[j+n] = s[j]; - memcpy(s+i, str->getCString(), n); - length += n; - return this; -} - -GString *GString::insert(int i, const char *str) { - int n = strlen(str); - int j; - - resize(length + n); - for (j = length; j >= i; --j) - s[j+n] = s[j]; - memcpy(s+i, str, n); - length += n; - return this; -} - -GString *GString::insert(int i, const char *str, int lengthA) { - int j; - - resize(length + lengthA); - for (j = length; j >= i; --j) - s[j+lengthA] = s[j]; - memcpy(s+i, str, lengthA); - length += lengthA; - return this; -} - -GString *GString::del(int i, int n) { - int j; - - if (n > 0) { - for (j = i; j <= length - n; ++j) - s[j] = s[j + n]; - resize(length -= n); - } - return this; -} - -GString *GString::upperCase() { - int i; - - for (i = 0; i < length; ++i) { - if (islower(s[i])) - s[i] = toupper(s[i]); - } - return this; -} - -GString *GString::lowerCase() { - int i; - - for (i = 0; i < length; ++i) { - if (isupper(s[i])) - s[i] = tolower(s[i]); - } - return this; -} diff --git a/src/plugins/pdf/GString.h b/src/plugins/pdf/GString.h @@ -1,102 +0,0 @@ -//======================================================================== -// -// GString.h -// -// Simple variable-length string type. -// -// Copyright 1996 Derek B. Noonburg -// -//======================================================================== - -#ifndef GSTRING_H -#define GSTRING_H - -#ifdef __GNUC__ -#pragma interface -#endif - -#include <string.h> - -#if defined(WIN32) - #include "../../include/platform.h" -#endif - -class GString { -public: - - // Create an empty string. - GString(); - - // Create a string from a C string. - GString(const char *sA); - - // Create a string from <lengthA> chars at <sA>. This string - // can contain null characters. - GString(const char *sA, int lengthA); - - // Create a string from <lengthA> chars at <idx> in <str>. - GString(GString *str, int idx, int lengthA); - - // Copy a string. - GString(GString *str); - GString *copy() { return new GString(this); } - - // Concatenate two strings. - GString(GString *str1, GString *str2); - - // Convert an integer to a string. - static GString *fromInt(int x); - - // Destructor. - ~GString(); - - // Get length. - int getLength() { return length; } - - // Get C string. - char *getCString() { return s; } - - // Get <i>th character. - char getChar(int i) { return s[i]; } - - // Change <i>th character. - void setChar(int i, char c) { s[i] = c; } - - // Clear string to zero length. - GString *clear(); - - // Append a character or string. - GString *append(char c); - GString *append(GString *str); - GString *append(const char *str); - GString *append(const char *str, int lengthA); - - // Insert a character or string. - GString *insert(int i, char c); - GString *insert(int i, GString *str); - GString *insert(int i, const char *str); - GString *insert(int i, const char *str, int lengthA); - - // Delete a character or range of characters. - GString *del(int i, int n = 1); - - // Convert string to all-upper/all-lower case. - GString *upperCase(); - GString *lowerCase(); - - // Compare two strings: -1:< 0:= +1:> - // These functions assume the strings do not contain null characters. - int cmp(GString *str) { return strcmp(s, str->getCString()); } - int cmpN(GString *str, int n) { return strncmp(s, str->getCString(), n); } - int cmp(const char *sA) { return strcmp(s, sA); } - int cmpN(const char *sA, int n) { return strncmp(s, sA, n); } - -private: - - int length; - char *s; - - void resize(int length1); -}; - -#endif diff --git a/src/plugins/pdf/INFO b/src/plugins/pdf/INFO @@ -1,21 +0,0 @@ -Except for pdfextractor.c and Makefile.am all files in this directory -are taken from the xpdf package, which is released under the GNU -PUBLIC LICENSE 2 (GPL). Version information: - -version 3.00 -2004-jan-22 - -The Xpdf software and documentation are -copyright 1996-2004 Glyph & Cog, LLC. - -Email: derekn@foolabs.com -WWW: http://www.foolabs.com/xpdf/ - -The PDF data structures, operators, and specification are -copyright 1985-2003 Adobe Systems Inc. - ----------- - -Note that some minor adaptions were made such that I could compile the -code with this crude approach to use autoconf/automake (mostly got rid -of VMS support...). diff --git a/src/plugins/pdf/Lexer.cc b/src/plugins/pdf/Lexer.cc @@ -1,474 +0,0 @@ -//======================================================================== -// -// Lexer.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <ctype.h> -#include "Lexer.h" -#include "Error.h" - -//------------------------------------------------------------------------ - -// A '1' in this array means the character is white space. A '1' or -// '2' means the character ends a name or command. -static char specialChars[256] = { - 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x - 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx -}; - -//------------------------------------------------------------------------ -// Lexer -//------------------------------------------------------------------------ - -Lexer::Lexer(XRef *xref, Stream *str) { - Object obj; - - curStr.initStream(str); - streams = new Array(xref); - streams->add(curStr.copy(&obj)); - strPtr = 0; - freeArray = gTrue; - curStr.streamReset(); -} - -Lexer::Lexer(XRef *xref, Object *obj) { - Object obj2; - - if (obj->isStream()) { - streams = new Array(xref); - freeArray = gTrue; - streams->add(obj->copy(&obj2)); - } else { - streams = obj->getArray(); - freeArray = gFalse; - } - strPtr = 0; - if (streams->getLength() > 0) { - streams->get(strPtr, &curStr); - curStr.streamReset(); - } -} - -Lexer::~Lexer() { - if (!curStr.isNone()) { - curStr.streamClose(); - curStr.free(); - } - if (freeArray) { - delete streams; - } -} - -int Lexer::getChar() { - int c; - - c = EOF; - while (!curStr.isNone() && (c = curStr.streamGetChar()) == EOF) { - curStr.streamClose(); - curStr.free(); - ++strPtr; - if (strPtr < streams->getLength()) { - streams->get(strPtr, &curStr); - curStr.streamReset(); - } - } - return c; -} - -int Lexer::lookChar() { - if (curStr.isNone()) { - return EOF; - } - return curStr.streamLookChar(); -} - -Object *Lexer::getObj(Object *obj) { - char *p; - int c, c2; - GBool comment, neg, done; - int numParen; - int xi; - double xf, scale; - GString *s; - int n, m; - - // skip whitespace and comments - comment = gFalse; - while (1) { - if ((c = getChar()) == EOF) { - return obj->initEOF(); - } - if (comment) { - if (c == '\r' || c == '\n') - comment = gFalse; - } else if (c == '%') { - comment = gTrue; - } else if (specialChars[c] != 1) { - break; - } - } - - // start reading token - switch (c) { - - // number - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case '-': case '.': - neg = gFalse; - xi = 0; - if (c == '-') { - neg = gTrue; - } else if (c == '.') { - goto doReal; - } else { - xi = c - '0'; - } - while (1) { - c = lookChar(); - if (isdigit(c)) { - getChar(); - xi = xi * 10 + (c - '0'); - } else if (c == '.') { - getChar(); - goto doReal; - } else { - break; - } - } - if (neg) - xi = -xi; - obj->initInt(xi); - break; - doReal: - xf = xi; - scale = 0.1; - while (1) { - c = lookChar(); - if (!isdigit(c)) { - break; - } - getChar(); - xf = xf + scale * (c - '0'); - scale *= 0.1; - } - if (neg) - xf = -xf; - obj->initReal(xf); - break; - - // string - case '(': - p = tokBuf; - n = 0; - numParen = 1; - done = gFalse; - s = NULL; - do { - c2 = EOF; - switch (c = getChar()) { - - case EOF: -#if 0 - // This breaks some PDF files, e.g., ones from Photoshop. - case '\r': - case '\n': -#endif - error(getPos(), "Unterminated string"); - done = gTrue; - break; - - case '(': - ++numParen; - c2 = c; - break; - - case ')': - if (--numParen == 0) { - done = gTrue; - } else { - c2 = c; - } - break; - - case '\\': - switch (c = getChar()) { - case 'n': - c2 = '\n'; - break; - case 'r': - c2 = '\r'; - break; - case 't': - c2 = '\t'; - break; - case 'b': - c2 = '\b'; - break; - case 'f': - c2 = '\f'; - break; - case '\\': - case '(': - case ')': - c2 = c; - break; - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - c2 = c - '0'; - c = lookChar(); - if (c >= '0' && c <= '7') { - getChar(); - c2 = (c2 << 3) + (c - '0'); - c = lookChar(); - if (c >= '0' && c <= '7') { - getChar(); - c2 = (c2 << 3) + (c - '0'); - } - } - break; - case '\r': - c = lookChar(); - if (c == '\n') { - getChar(); - } - break; - case '\n': - break; - case EOF: - error(getPos(), "Unterminated string"); - done = gTrue; - break; - default: - c2 = c; - break; - } - break; - - default: - c2 = c; - break; - } - - if (c2 != EOF) { - if (n == tokBufSize) { - if (!s) - s = new GString(tokBuf, tokBufSize); - else - s->append(tokBuf, tokBufSize); - p = tokBuf; - n = 0; - } - *p++ = (char)c2; - ++n; - } - } while (!done); - if (!s) - s = new GString(tokBuf, n); - else - s->append(tokBuf, n); - obj->initString(s); - break; - - // name - case '/': - p = tokBuf; - n = 0; - while ((c = lookChar()) != EOF && !specialChars[c]) { - getChar(); - if (c == '#') { - c2 = lookChar(); - if (c2 >= '0' && c2 <= '9') { - c = c2 - '0'; - } else if (c2 >= 'A' && c2 <= 'F') { - c = c2 - 'A' + 10; - } else if (c2 >= 'a' && c2 <= 'f') { - c = c2 - 'a' + 10; - } else { - goto notEscChar; - } - getChar(); - c <<= 4; - c2 = getChar(); - if (c2 >= '0' && c2 <= '9') { - c += c2 - '0'; - } else if (c2 >= 'A' && c2 <= 'F') { - c += c2 - 'A' + 10; - } else if (c2 >= 'a' && c2 <= 'f') { - c += c2 - 'a' + 10; - } else { - error(getPos(), "Illegal digit in hex char in name"); - } - } - notEscChar: - if (++n == tokBufSize) { - error(getPos(), "Name token too long"); - break; - } - *p++ = c; - } - *p = '\0'; - obj->initName(tokBuf); - break; - - // array punctuation - case '[': - case ']': - tokBuf[0] = c; - tokBuf[1] = '\0'; - obj->initCmd(tokBuf); - break; - - // hex string or dict punctuation - case '<': - c = lookChar(); - - // dict punctuation - if (c == '<') { - getChar(); - tokBuf[0] = tokBuf[1] = '<'; - tokBuf[2] = '\0'; - obj->initCmd(tokBuf); - - // hex string - } else { - p = tokBuf; - m = n = 0; - c2 = 0; - s = NULL; - while (1) { - c = getChar(); - if (c == '>') { - break; - } else if (c == EOF) { - error(getPos(), "Unterminated hex string"); - break; - } else if (specialChars[c] != 1) { - c2 = c2 << 4; - if (c >= '0' && c <= '9') - c2 += c - '0'; - else if (c >= 'A' && c <= 'F') - c2 += c - 'A' + 10; - else if (c >= 'a' && c <= 'f') - c2 += c - 'a' + 10; - else - error(getPos(), "Illegal character <%02x> in hex string", c); - if (++m == 2) { - if (n == tokBufSize) { - if (!s) - s = new GString(tokBuf, tokBufSize); - else - s->append(tokBuf, tokBufSize); - p = tokBuf; - n = 0; - } - *p++ = (char)c2; - ++n; - c2 = 0; - m = 0; - } - } - } - if (!s) - s = new GString(tokBuf, n); - else - s->append(tokBuf, n); - if (m == 1) - s->append((char)(c2 << 4)); - obj->initString(s); - } - break; - - // dict punctuation - case '>': - c = lookChar(); - if (c == '>') { - getChar(); - tokBuf[0] = tokBuf[1] = '>'; - tokBuf[2] = '\0'; - obj->initCmd(tokBuf); - } else { - error(getPos(), "Illegal character '>'"); - obj->initError(); - } - break; - - // error - case ')': - case '{': - case '}': - error(getPos(), "Illegal character '%c'", c); - obj->initError(); - break; - - // command - default: - p = tokBuf; - *p++ = c; - n = 1; - while ((c = lookChar()) != EOF && !specialChars[c]) { - getChar(); - if (++n == tokBufSize) { - error(getPos(), "Command token too long"); - break; - } - *p++ = c; - } - *p = '\0'; - if (tokBuf[0] == 't' && !strcmp(tokBuf, "true")) { - obj->initBool(gTrue); - } else if (tokBuf[0] == 'f' && !strcmp(tokBuf, "false")) { - obj->initBool(gFalse); - } else if (tokBuf[0] == 'n' && !strcmp(tokBuf, "null")) { - obj->initNull(); - } else { - obj->initCmd(tokBuf); - } - break; - } - - return obj; -} - -void Lexer::skipToNextLine() { - int c; - - while (1) { - c = getChar(); - if (c == EOF || c == '\n') { - return; - } - if (c == '\r') { - if ((c = lookChar()) == '\n') { - getChar(); - } - return; - } - } -} diff --git a/src/plugins/pdf/Lexer.h b/src/plugins/pdf/Lexer.h @@ -1,77 +0,0 @@ -//======================================================================== -// -// Lexer.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef LEXER_H -#define LEXER_H - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "Object.h" -#include "Stream.h" - -class XRef; - -#define tokBufSize 128 // size of token buffer - -//------------------------------------------------------------------------ -// Lexer -//------------------------------------------------------------------------ - -class Lexer { -public: - - // Construct a lexer for a single stream. Deletes the stream when - // lexer is deleted. - Lexer(XRef *xref, Stream *str); - - // Construct a lexer for a stream or array of streams (assumes obj - // is either a stream or array of streams). - Lexer(XRef *xref, Object *obj); - - // Destructor. - ~Lexer(); - - // Get the next object from the input stream. - Object *getObj(Object *obj); - - // Skip to the beginning of the next line in the input stream. - void skipToNextLine(); - - // Skip over one character. - void skipChar() { getChar(); } - - // Get stream. - Stream *getStream() - { return curStr.isNone() ? (Stream *)NULL : curStr.getStream(); } - - // Get current position in file. This is only used for error - // messages, so it returns an int instead of a Guint. - int getPos() - { return curStr.isNone() ? -1 : (int)curStr.streamGetPos(); } - - // Set position in file. - void setPos(Guint pos, int dir = 0) - { if (!curStr.isNone()) curStr.streamSetPos(pos, dir); } - -private: - - int getChar(); - int lookChar(); - - Array *streams; // array of input streams - int strPtr; // index of current stream - Object curStr; // current stream - GBool freeArray; // should lexer free the streams array? - char tokBuf[tokBufSize]; // temporary token buffer -}; - -#endif diff --git a/src/plugins/pdf/Link.cc b/src/plugins/pdf/Link.cc @@ -1,849 +0,0 @@ -//======================================================================== -// -// Link.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include <stddef.h> -#include <string.h> -#include "gmem.h" -#include "GString.h" -#include "Error.h" -#include "Object.h" -#include "Array.h" -#include "Dict.h" -#include "Link.h" - -//------------------------------------------------------------------------ -// LinkAction -//------------------------------------------------------------------------ - -LinkAction *LinkAction::parseDest(Object *obj) { - LinkAction *action; - - action = new LinkGoTo(obj); - if (!action->isOk()) { - delete action; - return NULL; - } - return action; -} - -LinkAction *LinkAction::parseAction(Object *obj, GString *baseURI) { - LinkAction *action; - Object obj2, obj3, obj4; - - if (!obj->isDict()) { - error(-1, "Bad annotation action"); - return NULL; - } - - obj->dictLookup("S", &obj2); - - // GoTo action - if (obj2.isName("GoTo")) { - obj->dictLookup("D", &obj3); - action = new LinkGoTo(&obj3); - obj3.free(); - - // GoToR action - } else if (obj2.isName("GoToR")) { - obj->dictLookup("F", &obj3); - obj->dictLookup("D", &obj4); - action = new LinkGoToR(&obj3, &obj4); - obj3.free(); - obj4.free(); - - // Launch action - } else if (obj2.isName("Launch")) { - action = new LinkLaunch(obj); - - // URI action - } else if (obj2.isName("URI")) { - obj->dictLookup("URI", &obj3); - action = new LinkURI(&obj3, baseURI); - obj3.free(); - - // Named action - } else if (obj2.isName("Named")) { - obj->dictLookup("N", &obj3); - action = new LinkNamed(&obj3); - obj3.free(); - - // Movie action - } else if (obj2.isName("Movie")) { - obj->dictLookupNF("Annot", &obj3); - obj->dictLookup("T", &obj4); - action = new LinkMovie(&obj3, &obj4); - obj3.free(); - obj4.free(); - - // unknown action - } else if (obj2.isName()) { - action = new LinkUnknown(obj2.getName()); - - // action is missing or wrong type - } else { - error(-1, "Bad annotation action"); - action = NULL; - } - - obj2.free(); - - if (action && !action->isOk()) { - delete action; - return NULL; - } - return action; -} - -GString *LinkAction::getFileSpecName(Object *fileSpecObj) { - GString *name; - Object obj1; - - name = NULL; - - // string - if (fileSpecObj->isString()) { - name = fileSpecObj->getString()->copy(); - - // dictionary - } else if (fileSpecObj->isDict()) { - if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) { - obj1.free(); - fileSpecObj->dictLookup("F", &obj1); - } - if (obj1.isString()) - name = obj1.getString()->copy(); - else - error(-1, "Illegal file spec in link"); - obj1.free(); - - // error - } else { - error(-1, "Illegal file spec in link"); - } - - return name; -} - -//------------------------------------------------------------------------ -// LinkDest -//------------------------------------------------------------------------ - -LinkDest::LinkDest(Array *a) { - Object obj1, obj2; - - // initialize fields - left = bottom = right = top = zoom = 0; - ok = gFalse; - - // get page - if (a->getLength() < 2) { - error(-1, "Annotation destination array is too short"); - return; - } - a->getNF(0, &obj1); - if (obj1.isInt()) { - pageNum = obj1.getInt() + 1; - pageIsRef = gFalse; - } else if (obj1.isRef()) { - pageRef.num = obj1.getRefNum(); - pageRef.gen = obj1.getRefGen(); - pageIsRef = gTrue; - } else { - error(-1, "Bad annotation destination"); - goto err2; - } - obj1.free(); - - // get destination type - a->get(1, &obj1); - - // XYZ link - if (obj1.isName("XYZ")) { - kind = destXYZ; - if (a->getLength() < 3) { - changeLeft = gFalse; - } else { - a->get(2, &obj2); - if (obj2.isNull()) { - changeLeft = gFalse; - } else if (obj2.isNum()) { - changeLeft = gTrue; - left = obj2.getNum(); - } else { - error(-1, "Bad annotation destination position"); - goto err1; - } - obj2.free(); - } - if (a->getLength() < 4) { - changeTop = gFalse; - } else { - a->get(3, &obj2); - if (obj2.isNull()) { - changeTop = gFalse; - } else if (obj2.isNum()) { - changeTop = gTrue; - top = obj2.getNum(); - } else { - error(-1, "Bad annotation destination position"); - goto err1; - } - obj2.free(); - } - if (a->getLength() < 5) { - changeZoom = gFalse; - } else { - a->get(4, &obj2); - if (obj2.isNull()) { - changeZoom = gFalse; - } else if (obj2.isNum()) { - changeZoom = gTrue; - zoom = obj2.getNum(); - } else { - error(-1, "Bad annotation destination position"); - goto err1; - } - obj2.free(); - } - - // Fit link - } else if (obj1.isName("Fit")) { - if (a->getLength() < 2) { - error(-1, "Annotation destination array is too short"); - goto err2; - } - kind = destFit; - - // FitH link - } else if (obj1.isName("FitH")) { - if (a->getLength() < 3) { - error(-1, "Annotation destination array is too short"); - goto err2; - } - kind = destFitH; - if (!a->get(2, &obj2)->isNum()) { - error(-1, "Bad annotation destination position"); - goto err1; - } - top = obj2.getNum(); - obj2.free(); - - // FitV link - } else if (obj1.isName("FitV")) { - if (a->getLength() < 3) { - error(-1, "Annotation destination array is too short"); - goto err2; - } - kind = destFitV; - if (!a->get(2, &obj2)->isNum()) { - error(-1, "Bad annotation destination position"); - goto err1; - } - left = obj2.getNum(); - obj2.free(); - - // FitR link - } else if (obj1.isName("FitR")) { - if (a->getLength() < 6) { - error(-1, "Annotation destination array is too short"); - goto err2; - } - kind = destFitR; - if (!a->get(2, &obj2)->isNum()) { - error(-1, "Bad annotation destination position"); - goto err1; - } - left = obj2.getNum(); - obj2.free(); - if (!a->get(3, &obj2)->isNum()) { - error(-1, "Bad annotation destination position"); - goto err1; - } - bottom = obj2.getNum(); - obj2.free(); - if (!a->get(4, &obj2)->isNum()) { - error(-1, "Bad annotation destination position"); - goto err1; - } - right = obj2.getNum(); - obj2.free(); - if (!a->get(5, &obj2)->isNum()) { - error(-1, "Bad annotation destination position"); - goto err1; - } - top = obj2.getNum(); - obj2.free(); - - // FitB link - } else if (obj1.isName("FitB")) { - if (a->getLength() < 2) { - error(-1, "Annotation destination array is too short"); - goto err2; - } - kind = destFitB; - - // FitBH link - } else if (obj1.isName("FitBH")) { - if (a->getLength() < 3) { - error(-1, "Annotation destination array is too short"); - goto err2; - } - kind = destFitBH; - if (!a->get(2, &obj2)->isNum()) { - error(-1, "Bad annotation destination position"); - goto err1; - } - top = obj2.getNum(); - obj2.free(); - - // FitBV link - } else if (obj1.isName("FitBV")) { - if (a->getLength() < 3) { - error(-1, "Annotation destination array is too short"); - goto err2; - } - kind = destFitBV; - if (!a->get(2, &obj2)->isNum()) { - error(-1, "Bad annotation destination position"); - goto err1; - } - left = obj2.getNum(); - obj2.free(); - - // unknown link kind - } else { - error(-1, "Unknown annotation destination type"); - goto err2; - } - - obj1.free(); - ok = gTrue; - return; - - err1: - obj2.free(); - err2: - obj1.free(); -} - -LinkDest::LinkDest(LinkDest *dest) { - kind = dest->kind; - pageIsRef = dest->pageIsRef; - if (pageIsRef) - pageRef = dest->pageRef; - else - pageNum = dest->pageNum; - left = dest->left; - bottom = dest->bottom; - right = dest->right; - top = dest->top; - zoom = dest->zoom; - changeLeft = dest->changeLeft; - changeTop = dest->changeTop; - changeZoom = dest->changeZoom; - ok = gTrue; -} - -//------------------------------------------------------------------------ -// LinkGoTo -//------------------------------------------------------------------------ - -LinkGoTo::LinkGoTo(Object *destObj) { - dest = NULL; - namedDest = NULL; - - // named destination - if (destObj->isName()) { - namedDest = new GString(destObj->getName()); - } else if (destObj->isString()) { - namedDest = destObj->getString()->copy(); - - // destination dictionary - } else if (destObj->isArray()) { - dest = new LinkDest(destObj->getArray()); - if (!dest->isOk()) { - delete dest; - dest = NULL; - } - - // error - } else { - error(-1, "Illegal annotation destination"); - } -} - -LinkGoTo::~LinkGoTo() { - if (dest) - delete dest; - if (namedDest) - delete namedDest; -} - -//------------------------------------------------------------------------ -// LinkGoToR -//------------------------------------------------------------------------ - -LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) { - dest = NULL; - namedDest = NULL; - - // get file name - fileName = getFileSpecName(fileSpecObj); - - // named destination - if (destObj->isName()) { - namedDest = new GString(destObj->getName()); - } else if (destObj->isString()) { - namedDest = destObj->getString()->copy(); - - // destination dictionary - } else if (destObj->isArray()) { - dest = new LinkDest(destObj->getArray()); - if (!dest->isOk()) { - delete dest; - dest = NULL; - } - - // error - } else { - error(-1, "Illegal annotation destination"); - } -} - -LinkGoToR::~LinkGoToR() { - if (fileName) - delete fileName; - if (dest) - delete dest; - if (namedDest) - delete namedDest; -} - - -//------------------------------------------------------------------------ -// LinkLaunch -//------------------------------------------------------------------------ - -LinkLaunch::LinkLaunch(Object *actionObj) { - Object obj1, obj2; - - fileName = NULL; - params = NULL; - - if (actionObj->isDict()) { - if (!actionObj->dictLookup("F", &obj1)->isNull()) { - fileName = getFileSpecName(&obj1); - } else { - obj1.free(); -#ifdef WIN32 - if (actionObj->dictLookup("Win", &obj1)->isDict()) { - obj1.dictLookup("F", &obj2); - fileName = getFileSpecName(&obj2); - obj2.free(); - if (obj1.dictLookup("P", &obj2)->isString()) { - params = obj2.getString()->copy(); - } - obj2.free(); - } else { - error(-1, "Bad launch-type link action"); - } -#else - //~ This hasn't been defined by Adobe yet, so assume it looks - //~ just like the Win dictionary until they say otherwise. - if (actionObj->dictLookup("Unix", &obj1)->isDict()) { - obj1.dictLookup("F", &obj2); - fileName = getFileSpecName(&obj2); - obj2.free(); - if (obj1.dictLookup("P", &obj2)->isString()) { - params = obj2.getString()->copy(); - } - obj2.free(); - } else { - error(-1, "Bad launch-type link action"); - } -#endif - } - obj1.free(); - } -} - -LinkLaunch::~LinkLaunch() { - if (fileName) - delete fileName; - if (params) - delete params; -} - -//------------------------------------------------------------------------ -// LinkURI -//------------------------------------------------------------------------ - -LinkURI::LinkURI(Object *uriObj, GString *baseURI) { - GString *uri2; - int n; - char c; - - uri = NULL; - if (uriObj->isString()) { - uri2 = uriObj->getString()->copy(); - if (baseURI) { - n = strcspn(uri2->getCString(), "/:"); - if (n == uri2->getLength() || uri2->getChar(n) == '/') { - uri = baseURI->copy(); - c = uri->getChar(uri->getLength() - 1); - if (c == '/' || c == '?') { - if (uri2->getChar(0) == '/') { - uri2->del(0); - } - } else { - if (uri2->getChar(0) != '/') { - uri->append('/'); - } - } - uri->append(uri2); - delete uri2; - } else { - uri = uri2; - } - } else { - uri = uri2; - } - } else { - error(-1, "Illegal URI-type link"); - } -} - -LinkURI::~LinkURI() { - if (uri) - delete uri; -} - -//------------------------------------------------------------------------ -// LinkNamed -//------------------------------------------------------------------------ - -LinkNamed::LinkNamed(Object *nameObj) { - name = NULL; - if (nameObj->isName()) { - name = new GString(nameObj->getName()); - } -} - -LinkNamed::~LinkNamed() { - if (name) { - delete name; - } -} - -//------------------------------------------------------------------------ -// LinkMovie -//------------------------------------------------------------------------ - -LinkMovie::LinkMovie(Object *annotObj, Object *titleObj) { - annotRef.num = -1; - title = NULL; - if (annotObj->isRef()) { - annotRef = annotObj->getRef(); - } else if (titleObj->isString()) { - title = titleObj->getString()->copy(); - } else { - error(-1, "Movie action is missing both the Annot and T keys"); - } -} - -LinkMovie::~LinkMovie() { - if (title) { - delete title; - } -} - -//------------------------------------------------------------------------ -// LinkUnknown -//------------------------------------------------------------------------ - -LinkUnknown::LinkUnknown(char *actionA) { - action = new GString(actionA); -} - -LinkUnknown::~LinkUnknown() { - delete action; -} - -//------------------------------------------------------------------------ -// LinkBorderStyle -//------------------------------------------------------------------------ - -LinkBorderStyle::LinkBorderStyle(LinkBorderType typeA, double widthA, - double *dashA, int dashLengthA, - double rA, double gA, double bA) { - type = typeA; - width = widthA; - dash = dashA; - dashLength = dashLengthA; - r = rA; - g = gA; - b = bA; -} - -LinkBorderStyle::~LinkBorderStyle() { - if (dash) { - gfree(dash); - } -} - -//------------------------------------------------------------------------ -// Link -//------------------------------------------------------------------------ - -Link::Link(Dict *dict, GString *baseURI) { - Object obj1, obj2, obj3; - LinkBorderType borderType; - double borderWidth; - double *borderDash; - int borderDashLength; - double borderR, borderG, borderB; - double t; - int i; - - borderStyle = NULL; - action = NULL; - ok = gFalse; - - // get rectangle - if (!dict->lookup("Rect", &obj1)->isArray()) { - error(-1, "Annotation rectangle is wrong type"); - goto err2; - } - if (!obj1.arrayGet(0, &obj2)->isNum()) { - error(-1, "Bad annotation rectangle"); - goto err1; - } - x1 = obj2.getNum(); - obj2.free(); - if (!obj1.arrayGet(1, &obj2)->isNum()) { - error(-1, "Bad annotation rectangle"); - goto err1; - } - y1 = obj2.getNum(); - obj2.free(); - if (!obj1.arrayGet(2, &obj2)->isNum()) { - error(-1, "Bad annotation rectangle"); - goto err1; - } - x2 = obj2.getNum(); - obj2.free(); - if (!obj1.arrayGet(3, &obj2)->isNum()) { - error(-1, "Bad annotation rectangle"); - goto err1; - } - y2 = obj2.getNum(); - obj2.free(); - obj1.free(); - if (x1 > x2) { - t = x1; - x1 = x2; - x2 = t; - } - if (y1 > y2) { - t = y1; - y1 = y2; - y2 = t; - } - - // get the border style info - borderType = linkBorderSolid; - borderWidth = 1; - borderDash = NULL; - borderDashLength = 0; - borderR = 0; - borderG = 0; - borderB = 1; - if (dict->lookup("BS", &obj1)->isDict()) { - if (obj1.dictLookup("S", &obj2)->isName()) { - if (obj2.isName("S")) { - borderType = linkBorderSolid; - } else if (obj2.isName("D")) { - borderType = linkBorderDashed; - } else if (obj2.isName("B")) { - borderType = linkBorderEmbossed; - } else if (obj2.isName("I")) { - borderType = linkBorderEngraved; - } else if (obj2.isName("U")) { - borderType = linkBorderUnderlined; - } - } - obj2.free(); - if (obj1.dictLookup("W", &obj2)->isNum()) { - borderWidth = obj2.getNum(); - } - obj2.free(); - if (obj1.dictLookup("D", &obj2)->isArray()) { - borderDashLength = obj2.arrayGetLength(); - borderDash = (double *)gmalloc(borderDashLength * sizeof(double)); - for (i = 0; i < borderDashLength; ++i) { - if (obj2.arrayGet(i, &obj3)->isNum()) { - borderDash[i] = obj3.getNum(); - } else { - borderDash[i] = 1; - } - obj3.free(); - } - } - obj2.free(); - } else { - obj1.free(); - if (dict->lookup("Border", &obj1)->isArray()) { - if (obj1.arrayGetLength() >= 3) { - if (obj1.arrayGet(2, &obj2)->isNum()) { - borderWidth = obj2.getNum(); - } - obj2.free(); - if (obj1.arrayGetLength() >= 4) { - if (obj1.arrayGet(3, &obj2)->isArray()) { - borderType = linkBorderDashed; - borderDashLength = obj2.arrayGetLength(); - borderDash = (double *)gmalloc(borderDashLength * sizeof(double)); - for (i = 0; i < borderDashLength; ++i) { - if (obj2.arrayGet(i, &obj3)->isNum()) { - borderDash[i] = obj3.getNum(); - } else { - borderDash[i] = 1; - } - obj3.free(); - } - } - obj2.free(); - } - } - } - } - obj1.free(); - if (dict->lookup("C", &obj1)->isArray() && obj1.arrayGetLength() == 3) { - if (obj1.arrayGet(0, &obj2)->isNum()) { - borderR = obj2.getNum(); - } - obj1.free(); - if (obj1.arrayGet(1, &obj2)->isNum()) { - borderG = obj2.getNum(); - } - obj1.free(); - if (obj1.arrayGet(2, &obj2)->isNum()) { - borderB = obj2.getNum(); - } - obj1.free(); - } - obj1.free(); - borderStyle = new LinkBorderStyle(borderType, borderWidth, - borderDash, borderDashLength, - borderR, borderG, borderB); - - // look for destination - if (!dict->lookup("Dest", &obj1)->isNull()) { - action = LinkAction::parseDest(&obj1); - - // look for action - } else { - obj1.free(); - if (dict->lookup("A", &obj1)->isDict()) { - action = LinkAction::parseAction(&obj1, baseURI); - } - } - obj1.free(); - - // check for bad action - if (action) { - ok = gTrue; - } - - return; - - err1: - obj2.free(); - err2: - obj1.free(); -} - -Link::~Link() { - if (borderStyle) { - delete borderStyle; - } - if (action) { - delete action; - } -} - -//------------------------------------------------------------------------ -// Links -//------------------------------------------------------------------------ - -Links::Links(Object *annots, GString *baseURI) { - Link *link; - Object obj1, obj2; - int size; - int i; - - links = NULL; - size = 0; - numLinks = 0; - - if (annots->isArray()) { - for (i = 0; i < annots->arrayGetLength(); ++i) { - if (annots->arrayGet(i, &obj1)->isDict()) { - if (obj1.dictLookup("Subtype", &obj2)->isName("Link")) { - link = new Link(obj1.getDict(), baseURI); - if (link->isOk()) { - if (numLinks >= size) { - size += 16; - links = (Link **)grealloc(links, size * sizeof(Link *)); - } - links[numLinks++] = link; - } else { - delete link; - } - } - obj2.free(); - } - obj1.free(); - } - } -} - -Links::~Links() { - int i; - - for (i = 0; i < numLinks; ++i) - delete links[i]; - gfree(links); -} - -LinkAction *Links::find(double x, double y) { - int i; - - for (i = numLinks - 1; i >= 0; --i) { - if (links[i]->inRect(x, y)) { - return links[i]->getAction(); - } - } - return NULL; -} - -GBool Links::onLink(double x, double y) { - int i; - - for (i = 0; i < numLinks; ++i) { - if (links[i]->inRect(x, y)) - return gTrue; - } - return gFalse; -} diff --git a/src/plugins/pdf/Link.h b/src/plugins/pdf/Link.h @@ -1,409 +0,0 @@ -//======================================================================== -// -// Link.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef LINK_H -#define LINK_H - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "Object.h" - -class GString; -class Array; -class Dict; - -//------------------------------------------------------------------------ -// LinkAction -//------------------------------------------------------------------------ - -enum LinkActionKind { - actionGoTo, // go to destination - actionGoToR, // go to destination in new file - actionLaunch, // launch app (or open document) - actionURI, // URI - actionNamed, // named action - actionMovie, // movie action - actionUnknown // anything else -}; - -class LinkAction { -public: - - // Destructor. - virtual ~LinkAction() {} - - // Was the LinkAction created successfully? - virtual GBool isOk() = 0; - - // Check link action type. - virtual LinkActionKind getKind() = 0; - - // Parse a destination (old-style action) name, string, or array. - static LinkAction *parseDest(Object *obj); - - // Parse an action dictionary. - static LinkAction *parseAction(Object *obj, GString *baseURI = NULL); - - // Extract a file name from a file specification (string or - // dictionary). - static GString *getFileSpecName(Object *fileSpecObj); -}; - -//------------------------------------------------------------------------ -// LinkDest -//------------------------------------------------------------------------ - -enum LinkDestKind { - destXYZ, - destFit, - destFitH, - destFitV, - destFitR, - destFitB, - destFitBH, - destFitBV -}; - -class LinkDest { -public: - - // Build a LinkDest from the array. - LinkDest(Array *a); - - // Copy a LinkDest. - LinkDest *copy() { return new LinkDest(this); } - - // Was the LinkDest created successfully? - GBool isOk() { return ok; } - - // Accessors. - LinkDestKind getKind() { return kind; } - GBool isPageRef() { return pageIsRef; } - int getPageNum() { return pageNum; } - Ref getPageRef() { return pageRef; } - double getLeft() { return left; } - double getBottom() { return bottom; } - double getRight() { return right; } - double getTop() { return top; } - double getZoom() { return zoom; } - GBool getChangeLeft() { return changeLeft; } - GBool getChangeTop() { return changeTop; } - GBool getChangeZoom() { return changeZoom; } - -private: - - LinkDestKind kind; // destination type - GBool pageIsRef; // is the page a reference or number? - union { - Ref pageRef; // reference to page - int pageNum; // one-relative page number - }; - double left, bottom; // position - double right, top; - double zoom; // zoom factor - GBool changeLeft, changeTop; // for destXYZ links, which position - GBool changeZoom; // components to change - GBool ok; // set if created successfully - - LinkDest(LinkDest *dest); -}; - -//------------------------------------------------------------------------ -// LinkGoTo -//------------------------------------------------------------------------ - -class LinkGoTo: public LinkAction { -public: - - // Build a LinkGoTo from a destination (dictionary, name, or string). - LinkGoTo(Object *destObj); - - // Destructor. - virtual ~LinkGoTo(); - - // Was the LinkGoTo created successfully? - virtual GBool isOk() { return dest || namedDest; } - - // Accessors. - virtual LinkActionKind getKind() { return actionGoTo; } - LinkDest *getDest() { return dest; } - GString *getNamedDest() { return namedDest; } - -private: - - LinkDest *dest; // regular destination (NULL for remote - // link with bad destination) - GString *namedDest; // named destination (only one of dest and - // and namedDest may be non-NULL) -}; - -//------------------------------------------------------------------------ -// LinkGoToR -//------------------------------------------------------------------------ - -class LinkGoToR: public LinkAction { -public: - - // Build a LinkGoToR from a file spec (dictionary) and destination - // (dictionary, name, or string). - LinkGoToR(Object *fileSpecObj, Object *destObj); - - // Destructor. - virtual ~LinkGoToR(); - - // Was the LinkGoToR created successfully? - virtual GBool isOk() { return fileName && (dest || namedDest); } - - // Accessors. - virtual LinkActionKind getKind() { return actionGoToR; } - GString *getFileName() { return fileName; } - LinkDest *getDest() { return dest; } - GString *getNamedDest() { return namedDest; } - -private: - - GString *fileName; // file name - LinkDest *dest; // regular destination (NULL for remote - // link with bad destination) - GString *namedDest; // named destination (only one of dest and - // and namedDest may be non-NULL) -}; - -//------------------------------------------------------------------------ -// LinkLaunch -//------------------------------------------------------------------------ - -class LinkLaunch: public LinkAction { -public: - - // Build a LinkLaunch from an action dictionary. - LinkLaunch(Object *actionObj); - - // Destructor. - virtual ~LinkLaunch(); - - // Was the LinkLaunch created successfully? - virtual GBool isOk() { return fileName != NULL; } - - // Accessors. - virtual LinkActionKind getKind() { return actionLaunch; } - GString *getFileName() { return fileName; } - GString *getParams() { return params; } - -private: - - GString *fileName; // file name - GString *params; // parameters -}; - -//------------------------------------------------------------------------ -// LinkURI -//------------------------------------------------------------------------ - -class LinkURI: public LinkAction { -public: - - // Build a LinkURI given the URI (string) and base URI. - LinkURI(Object *uriObj, GString *baseURI); - - // Destructor. - virtual ~LinkURI(); - - // Was the LinkURI created successfully? - virtual GBool isOk() { return uri != NULL; } - - // Accessors. - virtual LinkActionKind getKind() { return actionURI; } - GString *getURI() { return uri; } - -private: - - GString *uri; // the URI -}; - -//------------------------------------------------------------------------ -// LinkNamed -//------------------------------------------------------------------------ - -class LinkNamed: public LinkAction { -public: - - // Build a LinkNamed given the action name. - LinkNamed(Object *nameObj); - - virtual ~LinkNamed(); - - virtual GBool isOk() { return name != NULL; } - - virtual LinkActionKind getKind() { return actionNamed; } - GString *getName() { return name; } - -private: - - GString *name; -}; - -//------------------------------------------------------------------------ -// LinkMovie -//------------------------------------------------------------------------ - -class LinkMovie: public LinkAction { -public: - - LinkMovie(Object *annotObj, Object *titleObj); - - virtual ~LinkMovie(); - - virtual GBool isOk() { return annotRef.num >= 0 || title != NULL; } - - virtual LinkActionKind getKind() { return actionMovie; } - GBool hasAnnotRef() { return annotRef.num >= 0; } - Ref *getAnnotRef() { return &annotRef; } - GString *getTitle() { return title; } - -private: - - Ref annotRef; - GString *title; -}; - -//------------------------------------------------------------------------ -// LinkUnknown -//------------------------------------------------------------------------ - -class LinkUnknown: public LinkAction { -public: - - // Build a LinkUnknown with the specified action type. - LinkUnknown(char *actionA); - - // Destructor. - virtual ~LinkUnknown(); - - // Was the LinkUnknown create successfully? - virtual GBool isOk() { return action != NULL; } - - // Accessors. - virtual LinkActionKind getKind() { return actionUnknown; } - GString *getAction() { return action; } - -private: - - GString *action; // action subtype -}; - -//------------------------------------------------------------------------ -// LinkBorderStyle -//------------------------------------------------------------------------ - -enum LinkBorderType { - linkBorderSolid, - linkBorderDashed, - linkBorderEmbossed, - linkBorderEngraved, - linkBorderUnderlined -}; - -class LinkBorderStyle { -public: - - LinkBorderStyle(LinkBorderType typeA, double widthA, - double *dashA, int dashLengthA, - double rA, double gA, double bA); - ~LinkBorderStyle(); - - LinkBorderType getType() { return type; } - double getWidth() { return width; } - void getDash(double **dashA, int *dashLengthA) - { *dashA = dash; *dashLengthA = dashLength; } - void getColor(double *rA, double *gA, double *bA) - { *rA = r; *gA = g; *bA = b; } - -private: - - LinkBorderType type; - double width; - double *dash; - int dashLength; - double r, g, b; -}; - -//------------------------------------------------------------------------ -// Link -//------------------------------------------------------------------------ - -class Link { -public: - - // Construct a link, given its dictionary. - Link(Dict *dict, GString *baseURI); - - // Destructor. - ~Link(); - - // Was the link created successfully? - GBool isOk() { return ok; } - - // Check if point is inside the link rectangle. - GBool inRect(double x, double y) - { return x1 <= x && x <= x2 && y1 <= y && y <= y2; } - - // Get action. - LinkAction *getAction() { return action; } - - // Get the link rectangle. - void getRect(double *xa1, double *ya1, double *xa2, double *ya2) - { *xa1 = x1; *ya1 = y1; *xa2 = x2; *ya2 = y2; } - - // Get the border style info. - LinkBorderStyle *getBorderStyle() { return borderStyle; } - -private: - - double x1, y1; // lower left corner - double x2, y2; // upper right corner - LinkBorderStyle *borderStyle; // border style - LinkAction *action; // action - GBool ok; // is link valid? -}; - -//------------------------------------------------------------------------ -// Links -//------------------------------------------------------------------------ - -class Links { -public: - - // Extract links from array of annotations. - Links(Object *annots, GString *baseURI); - - // Destructor. - ~Links(); - - // Iterate through list of links. - int getNumLinks() { return numLinks; } - Link *getLink(int i) { return links[i]; } - - // If point <x>,<y> is in a link, return the associated action; - // else return NULL. - LinkAction *find(double x, double y); - - // Return true if <x>,<y> is in a link. - GBool onLink(double x, double y); - -private: - - Link **links; - int numLinks; -}; - -#endif diff --git a/src/plugins/pdf/Makefile.am b/src/plugins/pdf/Makefile.am @@ -1,44 +0,0 @@ -include ../Makefile-plugins.am - -plugin_LTLIBRARIES = \ - libextractor_pdf.la - -libextractor_pdf_la_LINK = \ - /bin/sh ../../../libtool --mode=link $(CXXLD) -o libextractor_pdf.la -libextractor_pdf_la_LDFLAGS = \ - $(PLUGINFLAGS) $(retaincommand) \ - $(XTRA_CPPLIBS) -libextractor_pdf_la_LIBADD = \ - $(top_builddir)/src/main/libextractor.la \ - $(top_builddir)/src/common/libextractor_common.la \ - -lm - -libextractor_pdf_la_SOURCES = \ - aconf.h \ - aconf2.h \ - ErrorCodes.h \ - Stream-CCITT.h\ - gtypes.h \ - Array.cc Array.h \ - Catalog.cc Catalog.h \ - Decrypt.cc Decrypt.h \ - Dict.cc Dict.h \ - Error.cc Error.h\ - FontEncoding.cc FontEncoding.h\ - FontFile.cc FontFile.h StdFontInfo.h CompactFontInfo.h \ - Function.cc Function.h\ - GString.cc GString.h\ - Lexer.cc Lexer.h \ - Link.cc Link.h\ - Object.cc Object.h\ - PDFDoc.cc PDFDoc.h \ - Page.cc Page.h\ - Params.cc Params.h\ - Parser.cc Parser.h\ - Stream.cc Stream.h Stream-CCITT.h \ - XRef.cc XRef.h\ - gfile.cc gfile.h\ - gmem.cc gmem.h\ - gmempp.cc\ - parseargs.cc parseargs.h \ - pdfextractor.cc diff --git a/src/plugins/pdf/Object.cc b/src/plugins/pdf/Object.cc @@ -1,164 +0,0 @@ -//======================================================================== -// -// Object.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include <stddef.h> -#include "Object.h" -#include "Array.h" -#include "Dict.h" -#include "Error.h" -#include "Stream.h" -#include "XRef.h" - -//------------------------------------------------------------------------ -// Object -//------------------------------------------------------------------------ - -const char *objTypeNames[numObjTypes] = { - "boolean", - "integer", - "real", - "string", - "name", - "null", - "array", - "dictionary", - "stream", - "ref", - "cmd", - "error", - "eof", - "none" -}; - -#ifdef DEBUG_MEM -int Object::numAlloc[numObjTypes] = - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -#endif - -Object *Object::initArray(XRef *xref) { - initObj(objArray); - array = new Array(xref); - return this; -} - -Object *Object::initDict(XRef *xref) { - initObj(objDict); - dict = new Dict(xref); - return this; -} - -Object *Object::initDict(Dict *dictA) { - initObj(objDict); - dict = dictA; - dict->incRef(); - return this; -} - -Object *Object::initStream(Stream *streamA) { - initObj(objStream); - stream = streamA; - return this; -} - -Object *Object::copy(Object *obj) { - *obj = *this; - switch (type) { - case objString: - obj->string = string->copy(); - break; - case objName: - obj->name = copyString(name); - break; - case objArray: - array->incRef(); - break; - case objDict: - dict->incRef(); - break; - case objStream: - stream->incRef(); - break; - case objCmd: - obj->cmd = copyString(cmd); - break; - default: - break; - } -#ifdef DEBUG_MEM - ++numAlloc[type]; -#endif - return obj; -} - -Object *Object::fetch(XRef *xref, Object *obj) { - return (type == objRef && xref) ? - xref->fetch(ref.num, ref.gen, obj) : copy(obj); -} - -void Object::free() { - switch (type) { - case objString: - delete string; - break; - case objName: - gfree(name); - break; - case objArray: - if (!array->decRef()) { - delete array; - } - break; - case objDict: - if (!dict->decRef()) { - delete dict; - } - break; - case objStream: - if (!stream->decRef()) { - delete stream; - } - break; - case objCmd: - gfree(cmd); - break; - default: - break; - } -#ifdef DEBUG_MEM - --numAlloc[type]; -#endif - type = objNone; -} - -const char *Object::getTypeName() { - return objTypeNames[type]; -} - -void Object::memCheck(FILE *f) { -#ifdef DEBUG_MEM - int i; - int t; - - t = 0; - for (i = 0; i < numObjTypes; ++i) - t += numAlloc[i]; - if (t > 0) { - fprintf(f, "Allocated objects:\n"); - for (i = 0; i < numObjTypes; ++i) { - if (numAlloc[i] > 0) - fprintf(f, " %-20s: %6d\n", objTypeNames[i], numAlloc[i]); - } - } -#endif -} diff --git a/src/plugins/pdf/Object.h b/src/plugins/pdf/Object.h @@ -1,303 +0,0 @@ -//======================================================================== -// -// Object.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef OBJECT_H -#define OBJECT_H - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include <stdio.h> -#include <string.h> -#include "gtypes.h" -#include "gmem.h" -#include "GString.h" - -class XRef; -class Array; -class Dict; -class Stream; - -//------------------------------------------------------------------------ -// Ref -//------------------------------------------------------------------------ - -struct Ref { - int num; // object number - int gen; // generation number -}; - -//------------------------------------------------------------------------ -// object types -//------------------------------------------------------------------------ - -enum ObjType { - // simple objects - objBool, // boolean - objInt, // integer - objReal, // real - objString, // string - objName, // name - objNull, // null - - // complex objects - objArray, // array - objDict, // dictionary - objStream, // stream - objRef, // indirect reference - - // special objects - objCmd, // command name - objError, // error return from Lexer - objEOF, // end of file return from Lexer - objNone // uninitialized object -}; - -#define numObjTypes 14 // total number of object types - -//------------------------------------------------------------------------ -// Object -//------------------------------------------------------------------------ - -#ifdef DEBUG_MEM -#define initObj(t) zeroUnion(); ++numAlloc[type = t] -#else -#define initObj(t) zeroUnion(); type = t -#endif - -class Object { -public: - // attempt to clear the anonymous union - void zeroUnion() { this->name = NULL; } - // Default constructor. - Object(): - type(objNone) { zeroUnion(); } - - // Initialize an object. - Object *initBool(GBool boolnA) - { initObj(objBool); booln = boolnA; return this; } - Object *initInt(int intgA) - { initObj(objInt); intg = intgA; return this; } - Object *initReal(double realA) - { initObj(objReal); real = realA; return this; } - Object *initString(GString *stringA) - { initObj(objString); string = stringA; return this; } - Object *initName(char *nameA) - { initObj(objName); name = copyString(nameA); return this; } - Object *initNull() - { initObj(objNull); return this; } - Object *initArray(XRef *xref); - Object *initDict(XRef *xref); - Object *initDict(Dict *dictA); - Object *initStream(Stream *streamA); - Object *initRef(int numA, int genA) - { initObj(objRef); ref.num = numA; ref.gen = genA; return this; } - Object *initCmd(char *cmdA) - { initObj(objCmd); cmd = copyString(cmdA); return this; } - Object *initError() - { initObj(objError); return this; } - Object *initEOF() - { initObj(objEOF); return this; } - - // Copy an object. - Object *copy(Object *obj); - - // If object is a Ref, fetch and return the referenced object. - // Otherwise, return a copy of the object. - Object *fetch(XRef *xref, Object *obj); - - // Free object contents. - void free(); - - // Type checking. - ObjType getType() { return type; } - GBool isBool() { return type == objBool; } - GBool isInt() { return type == objInt; } - GBool isReal() { return type == objReal; } - GBool isNum() { return type == objInt || type == objReal; } - GBool isString() { return type == objString; } - GBool isName() { return type == objName; } - GBool isNull() { return type == objNull; } - GBool isArray() { return type == objArray; } - GBool isDict() { return type == objDict; } - GBool isStream() { return type == objStream; } - GBool isRef() { return type == objRef; } - GBool isCmd() { return type == objCmd; } - GBool isError() { return type == objError; } - GBool isEOF() { return type == objEOF; } - GBool isNone() { return type == objNone; } - - // Special type checking. - GBool isName(const char *nameA) - { return type == objName && !strcmp(name, nameA); } - GBool isDict(const char *dictType); - GBool isStream(const char *dictType); - GBool isCmd(const char *cmdA) - { return type == objCmd && !strcmp(cmd, cmdA); } - - // Accessors. NB: these assume object is of correct type. - GBool getBool() { return booln; } - int getInt() { return intg; } - double getReal() { return real; } - double getNum() { return type == objInt ? (double)intg : real; } - GString *getString() { return string; } - char *getName() { return name; } - Array *getArray() { return array; } - Dict *getDict() { return dict; } - Stream *getStream() { return stream; } - Ref getRef() { return ref; } - int getRefNum() { return ref.num; } - int getRefGen() { return ref.gen; } - char *getCmd() { return cmd; } - - // Array accessors. - int arrayGetLength(); - void arrayAdd(Object *elem); - Object *arrayGet(int i, Object *obj); - Object *arrayGetNF(int i, Object *obj); - - // Dict accessors. - int dictGetLength(); - void dictAdd(char *key, Object *val); - GBool dictIs(const char *dictType); - Object *dictLookup(const char *key, Object *obj); - Object *dictLookupNF(const char *key, Object *obj); - char *dictGetKey(int i); - Object *dictGetVal(int i, Object *obj); - Object *dictGetValNF(int i, Object *obj); - - // Stream accessors. - GBool streamIs(const char *dictType); - void streamReset(); - void streamClose(); - int streamGetChar(); - int streamLookChar(); - char *streamGetLine(char *buf, int size); - Guint streamGetPos(); - void streamSetPos(Guint pos, int dir = 0); - Dict *streamGetDict(); - - // Output. - const char *getTypeName(); - - // Memory testing. - static void memCheck(FILE *f); - -private: - - ObjType type; // object type - union { // value for each type: - GBool booln; // boolean - int intg; // integer - double real; // real - GString *string; // string - char *name; // name - Array *array; // array - Dict *dict; // dictionary - Stream *stream; // stream - Ref ref; // indirect reference - char *cmd; // command - }; - -#ifdef DEBUG_MEM - static int // number of each type of object - numAlloc[numObjTypes]; // currently allocated -#endif -}; - -//------------------------------------------------------------------------ -// Array accessors. -//------------------------------------------------------------------------ - -#include "Array.h" - -inline int Object::arrayGetLength() - { if (type != objArray) return 0; return array->getLength(); } - -inline void Object::arrayAdd(Object *elem) - { if (type == objArray) array->add(elem); } - -inline Object *Object::arrayGet(int i, Object *obj) - { if (type != objArray) return obj->initNull(); return array->get(i, obj); } - -inline Object *Object::arrayGetNF(int i, Object *obj) - { if (type != objArray) return obj->initNull(); return array->getNF(i, obj); } - -//------------------------------------------------------------------------ -// Dict accessors. -//------------------------------------------------------------------------ - -#include "Dict.h" - -inline int Object::dictGetLength() - { if (type != objDict) return 0; return dict->getLength(); } - -inline void Object::dictAdd(char *key, Object *val) - { if (type == objDict) dict->add(key, val); } - -inline GBool Object::dictIs(const char *dictType) - { return (type == objDict) && dict->is(dictType); } - -inline GBool Object::isDict(const char *dictType) - { return (type == objDict) && dictIs(dictType); } - -inline Object *Object::dictLookup(const char *key, Object *obj) - { if (type != objDict) return obj->initNull(); return dict->lookup(key, obj); } - -inline Object *Object::dictLookupNF(const char *key, Object *obj) - { if (type != objDict) return obj->initNull(); return dict->lookupNF(key, obj); } - -inline char *Object::dictGetKey(int i) - { if (type != objDict) return NULL; return dict->getKey(i); } - -inline Object *Object::dictGetVal(int i, Object *obj) - { if (type != objDict) return obj->initNull(); return dict->getVal(i, obj); } - -inline Object *Object::dictGetValNF(int i, Object *obj) - { if (type != objDict) return obj->initNull(); return dict->getValNF(i, obj); } - -//------------------------------------------------------------------------ -// Stream accessors. -//------------------------------------------------------------------------ - -#include "Stream.h" - -inline GBool Object::streamIs(const char *dictType) - { return (type == objStream) && stream->getDict()->is(dictType); } - -inline GBool Object::isStream(const char *dictType) - { return (type == objStream) && streamIs(dictType); } - -inline void Object::streamReset() - { if (type == objStream) stream->reset(); } - -inline void Object::streamClose() - { if (type == objStream) stream->close(); } - -inline int Object::streamGetChar() - { if (type != objStream) return EOF; return stream->getChar(); } - -inline int Object::streamLookChar() - { if (type != objStream) return EOF; return stream->lookChar(); } - -inline char *Object::streamGetLine(char *buf, int size) - { if (type != objStream) return NULL; return stream->getLine(buf, size); } - -inline Guint Object::streamGetPos() - { if (type != objStream) return 0; return stream->getPos(); } - -inline void Object::streamSetPos(Guint pos, int dir) - { if (type == objStream) stream->setPos(pos, dir); } - -inline Dict *Object::streamGetDict() - { if (type != objStream) return NULL; return stream->getDict(); } - -#endif diff --git a/src/plugins/pdf/PDFDoc.cc b/src/plugins/pdf/PDFDoc.cc @@ -1,296 +0,0 @@ -//======================================================================== -// -// PDFDoc.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include "GString.h" -#include "config.h" -#include "Page.h" -#include "Catalog.h" -#include "Stream.h" -#include "XRef.h" -#include "Link.h" -#include "Error.h" -#include "ErrorCodes.h" -#include "Lexer.h" -#include "Parser.h" -#define DISABLE_OUTLINE 1 -#include "PDFDoc.h" - -//------------------------------------------------------------------------ - -#define headerSearchSize 1024 // read this many bytes at beginning of - // file to look for '%PDF' - -//------------------------------------------------------------------------ -// PDFDoc -//------------------------------------------------------------------------ - -PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, - GString *userPassword) { - Object obj; - GString *fileName1, *fileName2; - - ok = gFalse; - errCode = errNone; - - file = NULL; - str = NULL; - xref = NULL; - catalog = NULL; - links = NULL; -#ifndef DISABLE_OUTLINE - outline = NULL; -#endif - - fileName = fileNameA; - fileName1 = fileName; - - - // try to open file - fileName2 = NULL; -#ifdef VMS - if (!(file = fopen(fileName1->getCString(), "rb", "ctx=stm"))) { - error(-1, "Couldn't open file '%s'", fileName1->getCString()); - errCode = errOpenFile; - return; - } -#else - if (!(file = fopen(fileName1->getCString(), "rb"))) { - fileName2 = fileName->copy(); - fileName2->lowerCase(); - if (!(file = fopen(fileName2->getCString(), "rb"))) { - fileName2->upperCase(); - if (!(file = fopen(fileName2->getCString(), "rb"))) { - error(-1, "Couldn't open file '%s'", fileName->getCString()); - delete fileName2; - errCode = errOpenFile; - return; - } - } - delete fileName2; - } -#endif - - // create stream - obj.initNull(); - str = new FileStream(file, 0, gFalse, 0, &obj); - - ok = setup(ownerPassword, userPassword); -} - -PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword, - GString *userPassword) { - ok = gFalse; - errCode = errNone; - fileName = NULL; - file = NULL; - str = strA; - xref = NULL; - catalog = NULL; - links = NULL; -#ifndef DISABLE_OUTLINE - outline = NULL; -#endif - ok = setup(ownerPassword, userPassword); -} - -GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { - str->reset(); - - // check header - checkHeader(); - if (pdfVersion == 0) - return gFalse; - - // read xref table - xref = new XRef(str, ownerPassword, userPassword); - if (!xref->isOk()) { - error(-1, "Couldn't read xref table"); - errCode = xref->getErrorCode(); - return gFalse; - } - - // read catalog - catalog = new Catalog(xref); - if (!catalog->isOk()) { - error(-1, "Couldn't read page catalog"); - errCode = errBadCatalog; - return gFalse; - } - -#ifndef DISABLE_OUTLINE - // read outline - outline = new Outline(catalog->getOutline(), xref); -#endif - - // done - return gTrue; -} - -PDFDoc::~PDFDoc() { -#ifndef DISABLE_OUTLINE - if (outline) { - delete outline; - } -#endif - if (catalog) { - delete catalog; - } - if (xref) { - delete xref; - } - if (str) { - delete str; - } - if (file) { - fclose(file); - } - if (fileName) { - delete fileName; - } - if (links) { - delete links; - } -} - -// Check for a PDF header on this stream. Skip past some garbage -// if necessary. -void PDFDoc::checkHeader() { - char hdrBuf[headerSearchSize+1]; - char *p; - int i; - - pdfVersion = 0; - for (i = 0; i < headerSearchSize; ++i) { - hdrBuf[i] = str->getChar(); - } - hdrBuf[headerSearchSize] = '\0'; - for (i = 0; i < headerSearchSize - 5; ++i) { - if (!strncmp(&hdrBuf[i], "%PDF-", 5)) { - break; - } - } - if (i >= headerSearchSize - 5) { - error(-1, "May not be a PDF file (continuing anyway)"); - return; - } - str->moveStart(i); - p = strtok(&hdrBuf[i+5], " \t\n\r"); - if (p != NULL) - pdfVersion = atof(p); -} - -void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI, - int rotate, GBool crop, GBool doLinks, - GBool (*abortCheckCbk)(void *data), - void *abortCheckCbkData) { - Page *p; - - p = catalog->getPage(page); - if (doLinks) { - if (links) { - delete links; - } - getLinks(p); - p->display(out, hDPI, vDPI, rotate, crop, links, catalog, - abortCheckCbk, abortCheckCbkData); - } else { - p->display(out, hDPI, vDPI, rotate, crop, NULL, catalog, - abortCheckCbk, abortCheckCbkData); - } -} - -void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage, - double hDPI, double vDPI, int rotate, - GBool crop, GBool doLinks, - GBool (*abortCheckCbk)(void *data), - void *abortCheckCbkData) { - int page; - - for (page = firstPage; page <= lastPage; ++page) { - displayPage(out, page, hDPI, vDPI, rotate, crop, doLinks, - abortCheckCbk, abortCheckCbkData); - } -} - -void PDFDoc::displayPageSlice(OutputDev *out, int page, - double hDPI, double vDPI, - int rotate, GBool crop, - int sliceX, int sliceY, int sliceW, int sliceH, - GBool (*abortCheckCbk)(void *data), - void *abortCheckCbkData) { - Page *p; - - p = catalog->getPage(page); - p->displaySlice(out, hDPI, vDPI, rotate, crop, - sliceX, sliceY, sliceW, sliceH, - NULL, catalog, abortCheckCbk, abortCheckCbkData); -} - -GBool PDFDoc::isLinearized() { - Parser *parser; - Object obj1, obj2, obj3, obj4, obj5; - GBool lin; - - lin = gFalse; - obj1.initNull(); - parser = new Parser(xref, - new Lexer(xref, - str->makeSubStream(str->getStart(), gFalse, 0, &obj1))); - parser->getObj(&obj1); - parser->getObj(&obj2); - parser->getObj(&obj3); - parser->getObj(&obj4); - if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && - obj4.isDict()) { - obj4.dictLookup("Linearized", &obj5); - if (obj5.isNum() && obj5.getNum() > 0) { - lin = gTrue; - } - obj5.free(); - } - obj4.free(); - obj3.free(); - obj2.free(); - obj1.free(); - delete parser; - return lin; -} - -GBool PDFDoc::saveAs(GString *name) { - FILE *f; - int c; - - if (!(f = fopen(name->getCString(), "wb"))) { - error(-1, "Couldn't open file '%s'", name->getCString()); - return gFalse; - } - str->reset(); - while ((c = str->getChar()) != EOF) { - fputc(c, f); - } - str->close(); - fclose(f); - return gTrue; -} - -void PDFDoc::getLinks(Page *page) { - Object obj; - - links = new Links(page->getAnnots(&obj), catalog->getBaseURI()); - obj.free(); -} diff --git a/src/plugins/pdf/PDFDoc.h b/src/plugins/pdf/PDFDoc.h @@ -1,173 +0,0 @@ -//======================================================================== -// -// PDFDoc.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef PDFDOC_H -#define PDFDOC_H - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include <stdio.h> -#include "XRef.h" -#include "Link.h" -#include "Catalog.h" -#include "Page.h" - -class GString; -class BaseStream; -class OutputDev; -class Links; -class LinkAction; -class LinkDest; -class Outline; - -//------------------------------------------------------------------------ -// PDFDoc -//------------------------------------------------------------------------ - -class PDFDoc { -public: - - PDFDoc(GString *fileNameA, GString *ownerPassword = NULL, - GString *userPassword = NULL); - PDFDoc(BaseStream *strA, GString *ownerPassword = NULL, - GString *userPassword = NULL); - ~PDFDoc(); - - // Was PDF document successfully opened? - GBool isOk() { return (xref != NULL) && ok; } - - // Get the error code (if isOk() returns false). - int getErrorCode() { return errCode; } - - // Get file name. - GString *getFileName() { return fileName; } - - // Get the xref table. - XRef *getXRef() { return xref; } - - // Get catalog. - Catalog *getCatalog() { return catalog; } - - // Get base stream. - BaseStream *getBaseStream() { return str; } - - // Get page parameters. - double getPageWidth(int page) - { return catalog->getPage(page)->getWidth(); } - double getPageHeight(int page) - { return catalog->getPage(page)->getHeight(); } - int getPageRotate(int page) - { return catalog->getPage(page)->getRotate(); } - - // Get number of pages. - int getNumPages() { return catalog->getNumPages(); } - - // Return the contents of the metadata stream, or NULL if there is - // no metadata. - GString *readMetadata() { return catalog->readMetadata(); } - - // Return the structure tree root object. - Object *getStructTreeRoot() { return catalog->getStructTreeRoot(); } - - // Display a page. - void displayPage(OutputDev *out, int page, double hDPI, double vDPI, - int rotate, GBool crop, GBool doLinks, - GBool (*abortCheckCbk)(void *data) = NULL, - void *abortCheckCbkData = NULL); - - // Display a range of pages. - void displayPages(OutputDev *out, int firstPage, int lastPage, - double hDPI, double vDPI, int rotate, - GBool crop, GBool doLinks, - GBool (*abortCheckCbk)(void *data) = NULL, - void *abortCheckCbkData = NULL); - - // Display part of a page. - void displayPageSlice(OutputDev *out, int page, - double hDPI, double vDPI, - int rotate, GBool crop, - int sliceX, int sliceY, int sliceW, int sliceH, - GBool (*abortCheckCbk)(void *data) = NULL, - void *abortCheckCbkData = NULL); - - // Find a page, given its object ID. Returns page number, or 0 if - // not found. - int findPage(int num, int gen) { return catalog->findPage(num, gen); } - - // If point <x>,<y> is in a link, return the associated action; - // else return NULL. - LinkAction *findLink(double x, double y) - { return links ? links->find(x, y) : (LinkAction *)NULL; } - - // Return true if <x>,<y> is in a link. - GBool onLink(double x, double y) { return links->onLink(x, y); } - - // Find a named destination. Returns the link destination, or - // NULL if <name> is not a destination. - LinkDest *findDest(GString *name) - { return catalog->findDest(name); } - -#ifndef DISABLE_OUTLINE - // Return the outline object. - Outline *getOutline() { return outline; } -#endif - - // Is the file encrypted? - GBool isEncrypted() { return xref->isEncrypted(); } - - // Check various permissions. - GBool okToPrint(GBool ignoreOwnerPW = gFalse) - { return xref->okToPrint(ignoreOwnerPW); } - GBool okToChange(GBool ignoreOwnerPW = gFalse) - { return xref->okToChange(ignoreOwnerPW); } - GBool okToCopy(GBool ignoreOwnerPW = gFalse) - { return xref->okToCopy(ignoreOwnerPW); } - GBool okToAddNotes(GBool ignoreOwnerPW = gFalse) - { return xref->okToAddNotes(ignoreOwnerPW); } - - // Is this document linearized? - GBool isLinearized(); - - // Return the document's Info dictionary (if any). - Object *getDocInfo(Object *obj) { return xref != NULL ? xref->getDocInfo(obj) : NULL; } - Object *getDocInfoNF(Object *obj) { return xref != NULL ? xref->getDocInfoNF(obj) : NULL; } - - // Return the PDF version specified by the file. - double getPDFVersion() { return pdfVersion; } - - // Save this file with another name. - GBool saveAs(GString *name); - - -private: - - GBool setup(GString *ownerPassword, GString *userPassword); - void checkHeader(); - void getLinks(Page *page); - - GString *fileName; - FILE *file; - BaseStream *str; - double pdfVersion; - XRef *xref; - Catalog *catalog; - Links *links; -#ifndef DISABLE_OUTLINE - Outline *outline; -#endif - - - GBool ok; - int errCode; -}; - -#endif diff --git a/src/plugins/pdf/Page.cc b/src/plugins/pdf/Page.cc @@ -1,349 +0,0 @@ -//======================================================================== -// -// Page.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include <stddef.h> -#include "Object.h" -#include "Array.h" -#include "Dict.h" -#include "XRef.h" -#include "Link.h" -#ifndef PDF_PARSER_ONLY -#include "Gfx.h" -#include "Annot.h" -#endif -#include "Error.h" -#include "Page.h" - -//------------------------------------------------------------------------ -// PageAttrs -//------------------------------------------------------------------------ - -PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { - Object obj1; - double w, h; - - // get old/default values - if (attrs) { - mediaBox = attrs->mediaBox; - cropBox = attrs->cropBox; - haveCropBox = attrs->haveCropBox; - rotate = attrs->rotate; - attrs->resources.copy(&resources); - } else { - // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary - // but some (non-compliant) PDF files don't specify a MediaBox - mediaBox.x1 = 0; - mediaBox.y1 = 0; - mediaBox.x2 = 612; - mediaBox.y2 = 792; - cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0; - haveCropBox = gFalse; - rotate = 0; - resources.initNull(); - } - - // media box - readBox(dict, "MediaBox", &mediaBox); - - // crop box - if (readBox(dict, "CropBox", &cropBox)) { - haveCropBox = gTrue; - } - if (!haveCropBox) { - cropBox = mediaBox; - } - - // if the MediaBox is excessively larger than the CropBox, - // just use the CropBox - limitToCropBox = gFalse; - if (haveCropBox) { - w = 0.25 * (cropBox.x2 - cropBox.x1); - h = 0.25 * (cropBox.y2 - cropBox.y1); - if ((cropBox.x1 - mediaBox.x1) + (mediaBox.x2 - cropBox.x2) > w || - (cropBox.y1 - mediaBox.y1) + (mediaBox.y2 - cropBox.y2) > h) { - limitToCropBox = gTrue; - } - } - - // other boxes - bleedBox = cropBox; - readBox(dict, "BleedBox", &bleedBox); - trimBox = cropBox; - readBox(dict, "TrimBox", &trimBox); - artBox = cropBox; - readBox(dict, "ArtBox", &artBox); - - // rotate - dict->lookup("Rotate", &obj1); - if (obj1.isInt()) { - rotate = obj1.getInt(); - } - obj1.free(); - while (rotate < 0) { - rotate += 360; - } - while (rotate >= 360) { - rotate -= 360; - } - - // misc attributes - dict->lookup("LastModified", &lastModified); - dict->lookup("BoxColorInfo", &boxColorInfo); - dict->lookup("Group", &group); - dict->lookup("Metadata", &metadata); - dict->lookup("PieceInfo", &pieceInfo); - dict->lookup("SeparationInfo", &separationInfo); - - // resource dictionary - dict->lookup("Resources", &obj1); - if (obj1.isDict()) { - resources.free(); - obj1.copy(&resources); - } - obj1.free(); -} - -PageAttrs::~PageAttrs() { - lastModified.free(); - boxColorInfo.free(); - group.free(); - metadata.free(); - pieceInfo.free(); - separationInfo.free(); - resources.free(); -} - -GBool PageAttrs::readBox(Dict *dict, const char *key, PDFRectangle *box) { - PDFRectangle tmp; - Object obj1, obj2; - GBool ok; - - dict->lookup(key, &obj1); - if (obj1.isArray() && obj1.arrayGetLength() == 4) { - ok = gTrue; - obj1.arrayGet(0, &obj2); - if (obj2.isNum()) { - tmp.x1 = obj2.getNum(); - } else { - ok = gFalse; - } - obj2.free(); - obj1.arrayGet(1, &obj2); - if (obj2.isNum()) { - tmp.y1 = obj2.getNum(); - } else { - ok = gFalse; - } - obj2.free(); - obj1.arrayGet(2, &obj2); - if (obj2.isNum()) { - tmp.x2 = obj2.getNum(); - } else { - ok = gFalse; - } - obj2.free(); - obj1.arrayGet(3, &obj2); - if (obj2.isNum()) { - tmp.y2 = obj2.getNum(); - } else { - ok = gFalse; - } - obj2.free(); - if (ok) { - *box = tmp; - } - } else { - ok = gFalse; - } - obj1.free(); - return ok; -} - -//------------------------------------------------------------------------ -// Page -//------------------------------------------------------------------------ - -Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA) { - ok = gTrue; - xref = xrefA; - num = numA; - - // get attributes - attrs = attrsA; - - // annotations - pageDict->lookupNF("Annots", &annots); - if (!(annots.isRef() || annots.isArray() || annots.isNull())) { - error(-1, "Page annotations object (page %d) is wrong type (%s)", - num, annots.getTypeName()); - annots.free(); - goto err2; - } - - // contents - pageDict->lookupNF("Contents", &contents); - if (!(contents.isRef() || contents.isArray() || - contents.isNull())) { - error(-1, "Page contents object (page %d) is wrong type (%s)", - num, contents.getTypeName()); - contents.free(); - goto err1; - } - - return; - - err2: - annots.initNull(); - err1: - contents.initNull(); - ok = gFalse; -} - -Page::~Page() { - delete attrs; - annots.free(); - contents.free(); -} - -void Page::display(OutputDev *out, double hDPI, double vDPI, - int rotate, GBool crop, - Links *links, Catalog *catalog, - GBool (*abortCheckCbk)(void *data), - void *abortCheckCbkData) { - displaySlice(out, hDPI, vDPI, rotate, crop, -1, -1, -1, -1, links, catalog, - abortCheckCbk, abortCheckCbkData); -} - -void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, - int rotate, GBool crop, - int sliceX, int sliceY, int sliceW, int sliceH, - Links *links, Catalog *catalog, - GBool (*abortCheckCbk)(void *data), - void *abortCheckCbkData) { -#ifndef PDF_PARSER_ONLY - PDFRectangle *mediaBox, *cropBox; - PDFRectangle box; - Gfx *gfx; - Object obj; - Link *link; - Annots *annotList; - double kx, ky; - int i; - - rotate += getRotate(); - if (rotate >= 360) { - rotate -= 360; - } else if (rotate < 0) { - rotate += 360; - } - - mediaBox = getBox(); - if (sliceW >= 0 && sliceH >= 0) { - kx = 72.0 / hDPI; - ky = 72.0 / vDPI; - if (rotate == 90) { - if (out->upsideDown()) { - box.x1 = mediaBox->x1 + ky * sliceY; - box.x2 = mediaBox->x1 + ky * (sliceY + sliceH); - } else { - box.x1 = mediaBox->x2 - ky * (sliceY + sliceH); - box.x2 = mediaBox->x2 - ky * sliceY; - } - box.y1 = mediaBox->y1 + kx * sliceX; - box.y2 = mediaBox->y1 + kx * (sliceX + sliceW); - } else if (rotate == 180) { - box.x1 = mediaBox->x2 - kx * (sliceX + sliceW); - box.x2 = mediaBox->x2 - kx * sliceX; - if (out->upsideDown()) { - box.y1 = mediaBox->y1 + ky * sliceY; - box.y2 = mediaBox->y1 + ky * (sliceY + sliceH); - } else { - box.y1 = mediaBox->y2 - ky * (sliceY + sliceH); - box.y2 = mediaBox->y2 - ky * sliceY; - } - } else if (rotate == 270) { - if (out->upsideDown()) { - box.x1 = mediaBox->x2 - ky * (sliceY + sliceH); - box.x2 = mediaBox->x2 - ky * sliceY; - } else { - box.x1 = mediaBox->x1 + ky * sliceY; - box.x2 = mediaBox->x1 + ky * (sliceY + sliceH); - } - box.y1 = mediaBox->y2 - kx * (sliceX + sliceW); - box.y2 = mediaBox->y2 - kx * sliceX; - } else { - box.x1 = mediaBox->x1 + kx * sliceX; - box.x2 = mediaBox->x1 + kx * (sliceX + sliceW); - if (out->upsideDown()) { - box.y1 = mediaBox->y2 - ky * (sliceY + sliceH); - box.y2 = mediaBox->y2 - ky * sliceY; - } else { - box.y1 = mediaBox->y1 + ky * sliceY; - box.y2 = mediaBox->y1 + ky * (sliceY + sliceH); - } - } - } else { - box = *mediaBox; - } - cropBox = getCropBox(); - - if (globalParams->getPrintCommands()) { - printf("***** MediaBox = ll:%g,%g ur:%g,%g\n", - box.x1, box.y1, box.x2, box.y2); - if (isCropped()) { - printf("***** CropBox = ll:%g,%g ur:%g,%g\n", - cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2); - } - printf("***** Rotate = %d\n", attrs->getRotate()); - } - - gfx = new Gfx(xref, out, num, attrs->getResourceDict(), - hDPI, vDPI, &box, crop && isCropped(), cropBox, rotate, - abortCheckCbk, abortCheckCbkData); - contents.fetch(xref, &obj); - if (!obj.isNull()) { - gfx->saveState(); - gfx->display(&obj); - gfx->restoreState(); - } - obj.free(); - - // draw links - if (links) { - gfx->saveState(); - for (i = 0; i < links->getNumLinks(); ++i) { - link = links->getLink(i); - out->drawLink(link, catalog); - } - gfx->restoreState(); - out->dump(); - } - - // draw non-link annotations - annotList = new Annots(xref, annots.fetch(xref, &obj)); - obj.free(); - if (annotList->getNumAnnots() > 0) { - if (globalParams->getPrintCommands()) { - printf("***** Annotations\n"); - } - for (i = 0; i < annotList->getNumAnnots(); ++i) { - annotList->getAnnot(i)->draw(gfx); - } - out->dump(); - } - delete annotList; - - delete gfx; -#endif -} diff --git a/src/plugins/pdf/Page.h b/src/plugins/pdf/Page.h @@ -1,168 +0,0 @@ -//======================================================================== -// -// Page.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef PAGE_H -#define PAGE_H - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "Object.h" - -class Dict; -class XRef; -class OutputDev; -class Links; -class Catalog; - -//------------------------------------------------------------------------ - -class PDFRectangle { -public: - double x1, y1, x2, y2; - - PDFRectangle() { x1 = y1 = x2 = y2 = 0; } - PDFRectangle(double x1A, double y1A, double x2A, double y2A) - { x1 = x1A; y1 = y1A; x2 = x2A; y2 = y2A; } - GBool isValid() { return x1 != 0 || y1 != 0 || x2 != 0 || y2 != 0; } -}; - -//------------------------------------------------------------------------ -// PageAttrs -//------------------------------------------------------------------------ - -class PageAttrs { -public: - - // Construct a new PageAttrs object by merging a dictionary - // (of type Pages or Page) into another PageAttrs object. If - // <attrs> is NULL, uses defaults. - PageAttrs(PageAttrs *attrs, Dict *dict); - - // Destructor. - ~PageAttrs(); - - // Accessors. - PDFRectangle *getBox() { return limitToCropBox ? &cropBox : &mediaBox; } - PDFRectangle *getMediaBox() { return &mediaBox; } - PDFRectangle *getCropBox() { return &cropBox; } - GBool isCropped() { return haveCropBox; } - PDFRectangle *getBleedBox() { return &bleedBox; } - PDFRectangle *getTrimBox() { return &trimBox; } - PDFRectangle *getArtBox() { return &artBox; } - int getRotate() { return rotate; } - GString *getLastModified() - { return lastModified.isString() - ? lastModified.getString() : (GString *)NULL; } - Dict *getBoxColorInfo() - { return boxColorInfo.isDict() ? boxColorInfo.getDict() : (Dict *)NULL; } - Dict *getGroup() - { return group.isDict() ? group.getDict() : (Dict *)NULL; } - Stream *getMetadata() - { return metadata.isStream() ? metadata.getStream() : (Stream *)NULL; } - Dict *getPieceInfo() - { return pieceInfo.isDict() ? pieceInfo.getDict() : (Dict *)NULL; } - Dict *getSeparationInfo() - { return separationInfo.isDict() - ? separationInfo.getDict() : (Dict *)NULL; } - Dict *getResourceDict() - { return resources.isDict() ? resources.getDict() : (Dict *)NULL; } - -private: - - GBool readBox(Dict *dict, const char *key, PDFRectangle *box); - - PDFRectangle mediaBox; - PDFRectangle cropBox; - GBool haveCropBox; - GBool limitToCropBox; - PDFRectangle bleedBox; - PDFRectangle trimBox; - PDFRectangle artBox; - int rotate; - Object lastModified; - Object boxColorInfo; - Object group; - Object metadata; - Object pieceInfo; - Object separationInfo; - Object resources; -}; - -//------------------------------------------------------------------------ -// Page -//------------------------------------------------------------------------ - -class Page { -public: - - // Constructor. - Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA); - - // Destructor. - ~Page(); - - // Is page valid? - GBool isOk() { return ok; } - - // Get page parameters. - PDFRectangle *getBox() { return attrs->getBox(); } - PDFRectangle *getMediaBox() { return attrs->getMediaBox(); } - PDFRectangle *getCropBox() { return attrs->getCropBox(); } - GBool isCropped() { return attrs->isCropped(); } - double getWidth() { return attrs->getBox()->x2 - attrs->getBox()->x1; } - double getHeight() { return attrs->getBox()->y2 - attrs->getBox()->y1; } - PDFRectangle *getBleedBox() { return attrs->getBleedBox(); } - PDFRectangle *getTrimBox() { return attrs->getTrimBox(); } - PDFRectangle *getArtBox() { return attrs->getArtBox(); } - int getRotate() { return attrs->getRotate(); } - GString *getLastModified() { return attrs->getLastModified(); } - Dict *getBoxColorInfo() { return attrs->getBoxColorInfo(); } - Dict *getGroup() { return attrs->getGroup(); } - Stream *getMetadata() { return attrs->getMetadata(); } - Dict *getPieceInfo() { return attrs->getPieceInfo(); } - Dict *getSeparationInfo() { return attrs->getSeparationInfo(); } - - // Get resource dictionary. - Dict *getResourceDict() { return attrs->getResourceDict(); } - - // Get annotations array. - Object *getAnnots(Object *obj) { return annots.fetch(xref, obj); } - - // Get contents. - Object *getContents(Object *obj) { return contents.fetch(xref, obj); } - - // Display a page. - void display(OutputDev *out, double hDPI, double vDPI, - int rotate, GBool crop, - Links *links, Catalog *catalog, - GBool (*abortCheckCbk)(void *data) = NULL, - void *abortCheckCbkData = NULL); - - // Display part of a page. - void displaySlice(OutputDev *out, double hDPI, double vDPI, - int rotate, GBool crop, - int sliceX, int sliceY, int sliceW, int sliceH, - Links *links, Catalog *catalog, - GBool (*abortCheckCbk)(void *data) = NULL, - void *abortCheckCbkData = NULL); - -private: - - XRef *xref; // the xref table for this PDF file - int num; // page number - PageAttrs *attrs; // page attributes - Object annots; // annotations array - Object contents; // page contents - GBool ok; // true if page is valid -}; - -#endif diff --git a/src/plugins/pdf/Params.cc b/src/plugins/pdf/Params.cc @@ -1,88 +0,0 @@ -//======================================================================== -// -// Params.cc -// -// Copyright 1996 Derek B. Noonburg -// -//======================================================================== - -#include "platform.h" -#include "gtypes.h" -#include "gmem.h" -#include "GString.h" -#include "gfile.h" -#include "Params.h" - -char **fontPath = NULL; -static int fontPathLen, fontPathSize; - -DevFontMapEntry *devFontMap = NULL; -static int devFontMapLen, devFontMapSize; - -void initParams(const char *userConfigFile, - const char *sysConfigFile) { - GString *fileName; - FILE *f; - char buf[256]; - char *p, *q; - - // initialize font path and font map - fontPath = (char **)gmalloc((fontPathSize = 8) * sizeof(char *)); - fontPath[fontPathLen = 0] = NULL; - devFontMap = (DevFontMapEntry *)gmalloc((devFontMapSize = 8) * - sizeof(DevFontMapEntry)); - devFontMap[devFontMapLen = 0].pdfFont = NULL; - - // read config file - fileName = appendToPath(getHomeDir(), userConfigFile); - if (!(f = FOPEN(fileName->getCString(), "r"))) { - f = FOPEN(sysConfigFile, "r"); - } - if (f) { - while (fgets(buf, sizeof(buf)-1, f)) { - buf[sizeof(buf)-1] = '\0'; - p = strtok(buf, " \t\n\r"); - if (p && !strcmp(p, "fontpath")) { - if (fontPathLen+1 >= fontPathSize) - fontPath = (char **) - grealloc(fontPath, (fontPathSize += 8) * sizeof(char *)); - p = strtok(NULL, " \t\n\r"); - fontPath[fontPathLen++] = copyString(p); - } else if (p && !strcmp(p, "fontmap")) { - if (devFontMapLen+1 >= devFontMapSize) - devFontMap = (DevFontMapEntry *) - grealloc(devFontMap, - (devFontMapSize += 8) * sizeof(DevFontMapEntry)); - p = strtok(NULL, " \t\n\r"); - devFontMap[devFontMapLen].pdfFont = copyString(p); - p = strtok(NULL, "\t\n\r"); - while (*p == ' ') - ++p; - for (q = p + strlen(p) - 1; q >= p && *q == ' '; --q) ; - q[1] = '\0'; - devFontMap[devFontMapLen++].devFont = copyString(p); - } - } - fclose(f); - fontPath[fontPathLen] = NULL; - devFontMap[devFontMapLen].pdfFont = NULL; - } - delete fileName; -} - -void freeParams() { - int i; - - if (fontPath) { - for (i = 0; i < fontPathLen; ++i) - gfree(fontPath[i]); - gfree(fontPath); - } - if (devFontMap) { - for (i = 0; i < devFontMapLen; ++i) { - gfree(devFontMap[i].pdfFont); - gfree(devFontMap[i].devFont); - } - gfree(devFontMap); - } -} diff --git a/src/plugins/pdf/Params.h b/src/plugins/pdf/Params.h @@ -1,40 +0,0 @@ -//======================================================================== -// -// Params.h -// -// Copyright 1996 Derek B. Noonburg -// -//======================================================================== - -#ifndef PARAMS_H -#define PARAMS_H - -// Print commands as they're executed. -extern GBool printCommands; - -// If this is set, error messages will be silently discarded. -extern GBool errQuiet; - -// Font search path. -extern char **fontPath; - -// Mapping from PDF font name to device font name. -struct DevFontMapEntry { - char *pdfFont; - char *devFont; -}; -extern DevFontMapEntry *devFontMap; - -//------------------------------------------------------------------------ - -// Initialize font path and font map, and read configuration file. If -// <userConfigFile> exists, read it; else if <sysConfigFile> exists, -// read it. <userConfigFile> is relative to the user's home -// directory; <sysConfigFile> should be an absolute path. -extern void initParams(const char *userConfigFile, - const char *sysConfigFile); - -// Free memory used for font path and font map. -extern void freeParams(); - -#endif diff --git a/src/plugins/pdf/Parser.cc b/src/plugins/pdf/Parser.cc @@ -1,231 +0,0 @@ -//======================================================================== -// -// Parser.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include <stddef.h> -#include "Object.h" -#include "Array.h" -#include "Dict.h" -#include "Parser.h" -#include "XRef.h" -#include "Error.h" -#ifndef NO_DECRYPTION -#include "Decrypt.h" -#endif - -Parser::Parser(XRef *xrefA, Lexer *lexerA) { - xref = xrefA; - lexer = lexerA; - inlineImg = 0; - lexer->getObj(&buf1); - lexer->getObj(&buf2); -} - -Parser::~Parser() { - buf1.free(); - buf2.free(); - delete lexer; -} - -#ifndef NO_DECRYPTION -Object *Parser::getObj(Object *obj, - Guchar *fileKey, int keyLength, - int objNum, int objGen) { -#else -Object *Parser::getObj(Object *obj) { -#endif - char *key; - Stream *str; - Object obj2; - int num; -#ifndef NO_DECRYPTION - Decrypt *decrypt; - GString *s; - char *p; - int i; -#endif - - // refill buffer after inline image data - if (inlineImg == 2) { - buf1.free(); - buf2.free(); - lexer->getObj(&buf1); - lexer->getObj(&buf2); - inlineImg = 0; - } - - // array - if (buf1.isCmd("[")) { - shift(); - obj->initArray(xref); - while (!buf1.isCmd("]") && !buf1.isEOF()) -#ifndef NO_DECRYPTION - obj->arrayAdd(getObj(&obj2, fileKey, keyLength, objNum, objGen)); -#else - obj->arrayAdd(getObj(&obj2)); -#endif - if (buf1.isEOF()) - error(getPos(), "End of file inside array"); - shift(); - - // dictionary or stream - } else if (buf1.isCmd("<<")) { - shift(); - obj->initDict(xref); - while (!buf1.isCmd(">>") && !buf1.isEOF()) { - if (!buf1.isName()) { - error(getPos(), "Dictionary key must be a name object"); - shift(); - } else { - key = copyString(buf1.getName()); - shift(); - if (buf1.isEOF() || buf1.isError()) { - gfree(key); - break; - } -#ifndef NO_DECRYPTION - obj->dictAdd(key, getObj(&obj2, fileKey, keyLength, objNum, objGen)); -#else - obj->dictAdd(key, getObj(&obj2)); -#endif - } - } - if (buf1.isEOF()) - error(getPos(), "End of file inside dictionary"); - if (buf2.isCmd("stream")) { - if ((str = makeStream(obj))) { - obj->initStream(str); -#ifndef NO_DECRYPTION - if (fileKey) { - str->getBaseStream()->doDecryption(fileKey, keyLength, - objNum, objGen); - } -#endif - } else { - obj->free(); - obj->initError(); - } - } else { - shift(); - } - - // indirect reference or integer - } else if (buf1.isInt()) { - num = buf1.getInt(); - shift(); - if (buf1.isInt() && buf2.isCmd("R")) { - obj->initRef(num, buf1.getInt()); - shift(); - shift(); - } else { - obj->initInt(num); - } - -#ifndef NO_DECRYPTION - // string - } else if (buf1.isString() && fileKey) { - buf1.copy(obj); - s = obj->getString(); - decrypt = new Decrypt(fileKey, keyLength, objNum, objGen); - for (i = 0, p = obj->getString()->getCString(); - i < s->getLength(); - ++i, ++p) { - *p = decrypt->decryptByte(*p); - } - delete decrypt; - shift(); -#endif - - // simple object - } else { - buf1.copy(obj); - shift(); - } - - return obj; -} - -Stream *Parser::makeStream(Object *dict) { - Object obj; - Stream *str; - Guint pos, endPos, length; - - // get stream start position - lexer->skipToNextLine(); - pos = lexer->getPos(); - - // get length - dict->dictLookup("Length", &obj); - if (obj.isInt()) { - length = (Guint)obj.getInt(); - obj.free(); - } else { - error(getPos(), "Bad 'Length' attribute in stream"); - obj.free(); - return NULL; - } - - // check for length in damaged file - if (xref && xref->getStreamEnd(pos, &endPos)) { - length = endPos - pos; - } - - // in badly damaged PDF files, we can run off the end of the input - // stream immediately after the "stream" token - if (!lexer->getStream()) { - return NULL; - } - - // make base stream - str = lexer->getStream()->getBaseStream()->makeSubStream(pos, gTrue, - length, dict); - - // get filters - str = str->addFilters(dict); - - // skip over stream data - lexer->setPos(pos + length); - - // refill token buffers and check for 'endstream' - shift(); // kill '>>' - shift(); // kill 'stream' - if (buf1.isCmd("endstream")) { - shift(); - } else { - error(getPos(), "Missing 'endstream'"); - str->ignoreLength(); - } - - return str; -} - -void Parser::shift() { - if (inlineImg > 0) { - if (inlineImg < 2) { - ++inlineImg; - } else { - // in a damaged content stream, if 'ID' shows up in the middle - // of a dictionary, we need to reset - inlineImg = 0; - } - } else if (buf2.isCmd("ID")) { - lexer->skipChar(); // skip char after 'ID' command - inlineImg = 1; - } - buf1.free(); - buf1 = buf2; - if (inlineImg > 0) // don't buffer inline image data - buf2.initNull(); - else - lexer->getObj(&buf2); -} diff --git a/src/plugins/pdf/Parser.h b/src/plugins/pdf/Parser.h @@ -1,60 +0,0 @@ -//======================================================================== -// -// Parser.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef PARSER_H -#define PARSER_H - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "Lexer.h" - -//------------------------------------------------------------------------ -// Parser -//------------------------------------------------------------------------ - -class Parser { -public: - - // Constructor. - Parser(XRef *xrefA, Lexer *lexerA); - - // Destructor. - ~Parser(); - - // Get the next object from the input stream. -#ifndef NO_DECRYPTION - Object *getObj(Object *obj, - Guchar *fileKey = NULL, int keyLength = 0, - int objNum = 0, int objGen = 0); -#else - Object *getObj(Object *obj); -#endif - - // Get stream. - Stream *getStream() { return lexer->getStream(); } - - // Get current position in file. - int getPos() { return lexer->getPos(); } - -private: - - XRef *xref; // the xref table for this PDF file - Lexer *lexer; // input stream - Object buf1, buf2; // next two tokens - int inlineImg; // set when inline image data is encountered - - Stream *makeStream(Object *dict); - void shift(); -}; - -#endif - diff --git a/src/plugins/pdf/StdFontInfo.h b/src/plugins/pdf/StdFontInfo.h @@ -1,546 +0,0 @@ -//======================================================================== -// -// StdFontInfo.h -// -// This file was automatically generated by makeFontInfo. -// -// Copyright 1999 Derek B. Noonburg -// -//======================================================================== - -#ifndef STDFONTINFO_H -#define STDFONTINFO_H - -//------------------------------------------------------------------------ -// type1StdEncoding -- Adobe Type 1 StandardEncoding -//------------------------------------------------------------------------ - -#define type1StdEncodingSize 256 -static char *type1StdEncodingNames[type1StdEncodingSize] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quoteright", - "parenleft", - "parenright", - "asterisk", - "plus", - "comma", - "hyphen", - "period", - "slash", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "colon", - "semicolon", - "less", - "equal", - "greater", - "question", - "at", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "bracketleft", - "backslash", - "bracketright", - "asciicircum", - "underscore", - "quoteleft", - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "braceleft", - "bar", - "braceright", - "asciitilde", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "exclamdown", - "cent", - "sterling", - "fraction", - "yen", - "florin", - "section", - "currency", - "quotesingle", - "quotedblleft", - "guillemotleft", - "guilsinglleft", - "guilsinglright", - "fi", - "fl", - NULL, - "endash", - "dagger", - "daggerdbl", - "periodcentered", - NULL, - "paragraph", - "bullet", - "quotesinglbase", - "quotedblbase", - "quotedblright", - "guillemotright", - "ellipsis", - "perthousand", - NULL, - "questiondown", - NULL, - "grave", - "acute", - "circumflex", - "tilde", - "macron", - "breve", - "dotaccent", - "dieresis", - NULL, - "ring", - "cedilla", - NULL, - "hungarumlaut", - "ogonek", - "caron", - "emdash", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "AE", - NULL, - "ordfeminine", - NULL, - NULL, - NULL, - NULL, - "Lslash", - "Oslash", - "OE", - "ordmasculine", - NULL, - NULL, - NULL, - NULL, - NULL, - "ae", - NULL, - NULL, - NULL, - "dotlessi", - NULL, - NULL, - "lslash", - "oslash", - "oe", - "germandbls", - NULL, - NULL, - NULL, - NULL -}; -static FontEncoding type1StdEncoding(type1StdEncodingNames, - type1StdEncodingSize); - -//------------------------------------------------------------------------ -// type1ExpertEncoding -- Adobe Type 1 ExpertEncoding -//------------------------------------------------------------------------ - -#define type1ExpertEncodingSize 256 -static char *type1ExpertEncodingNames[type1ExpertEncodingSize] = { - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "space", - "exclamsmall", - "Hungarumlautsmall", - NULL, - "dollaroldstyle", - "dollarsuperior", - "ampersandsmall", - "Acutesmall", - "parenleftsuperior", - "parenrightsuperior", - "twodotenleader", - "onedotenleader", - "comma", - "hyphen", - "period", - "fraction", - "zerooldstyle", - "oneoldstyle", - "twooldstyle", - "threeoldstyle", - "fouroldstyle", - "fiveoldstyle", - "sixoldstyle", - "sevenoldstyle", - "eightoldstyle", - "nineoldstyle", - "colon", - "semicolon", - "commasuperior", - "threequartersemdash", - "periodsuperior", - "questionsmall", - NULL, - "asuperior", - "bsuperior", - "centsuperior", - "dsuperior", - "esuperior", - NULL, - NULL, - NULL, - "isuperior", - NULL, - NULL, - "lsuperior", - "msuperior", - "nsuperior", - "osuperior", - NULL, - NULL, - "rsuperior", - "ssuperior", - "tsuperior", - NULL, - "ff", - "fi", - "fl", - "ffi", - "ffl", - "parenleftinferior", - NULL, - "parenrightinferior", - "Circumflexsmall", - "hyphensuperior", - "Gravesmall", - "Asmall", - "Bsmall", - "Csmall", - "Dsmall", - "Esmall", - "Fsmall", - "Gsmall", - "Hsmall", - "Ismall", - "Jsmall", - "Ksmall", - "Lsmall", - "Msmall", - "Nsmall", - "Osmall", - "Psmall", - "Qsmall", - "Rsmall", - "Ssmall", - "Tsmall", - "Usmall", - "Vsmall", - "Wsmall", - "Xsmall", - "Ysmall", - "Zsmall", - "colonmonetary", - "onefitted", - "rupiah", - "Tildesmall", - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - "exclamdownsmall", - "centoldstyle", - "Lslashsmall", - NULL, - NULL, - "Scaronsmall", - "Zcaronsmall", - "Dieresissmall", - "Brevesmall", - "Caronsmall", - NULL, - "Dotaccentsmall", - NULL, - NULL, - "Macronsmall", - NULL, - NULL, - "figuredash", - "hypheninferior", - NULL, - NULL, - "Ogoneksmall", - "Ringsmall", - "Cedillasmall", - NULL, - NULL, - NULL, - "onequarter", - "onehalf", - "threequarters", - "questiondownsmall", - "oneeighth", - "threeeighths", - "fiveeighths", - "seveneighths", - "onethird", - "twothirds", - NULL, - NULL, - "zerosuperior", - "onesuperior", - "twosuperior", - "threesuperior", - "foursuperior", - "fivesuperior", - "sixsuperior", - "sevensuperior", - "eightsuperior", - "ninesuperior", - "zeroinferior", - "oneinferior", - "twoinferior", - "threeinferior", - "fourinferior", - "fiveinferior", - "sixinferior", - "seveninferior", - "eightinferior", - "nineinferior", - "centinferior", - "dollarinferior", - "periodinferior", - "commainferior", - "Agravesmall", - "Aacutesmall", - "Acircumflexsmall", - "Atildesmall", - "Adieresissmall", - "Aringsmall", - "AEsmall", - "Ccedillasmall", - "Egravesmall", - "Eacutesmall", - "Ecircumflexsmall", - "Edieresissmall", - "Igravesmall", - "Iacutesmall", - "Icircumflexsmall", - "Idieresissmall", - "Ethsmall", - "Ntildesmall", - "Ogravesmall", - "Oacutesmall", - "Ocircumflexsmall", - "Otildesmall", - "Odieresissmall", - "OEsmall", - "Oslashsmall", - "Ugravesmall", - "Uacutesmall", - "Ucircumflexsmall", - "Udieresissmall", - "Yacutesmall", - "Thornsmall", - "Ydieresissmall" -}; -static FontEncoding type1ExpertEncoding(type1ExpertEncodingNames, - type1ExpertEncodingSize); - -#endif diff --git a/src/plugins/pdf/Stream-CCITT.h b/src/plugins/pdf/Stream-CCITT.h @@ -1,459 +0,0 @@ -//======================================================================== -// -// Stream-CCITT.h -// -// Tables for CCITT Fax decoding. -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -struct CCITTCode { - short bits; - short n; -}; - -#define ccittEOL -2 - -//------------------------------------------------------------------------ -// 2D codes -//------------------------------------------------------------------------ - -#define twoDimPass 0 -#define twoDimHoriz 1 -#define twoDimVert0 2 -#define twoDimVertR1 3 -#define twoDimVertL1 4 -#define twoDimVertR2 5 -#define twoDimVertL2 6 -#define twoDimVertR3 7 -#define twoDimVertL3 8 - -// 1-7 bit codes -static CCITTCode twoDimTab1[128] = { - {-1, -1}, {-1, -1}, // 000000x - {7, twoDimVertL3}, // 0000010 - {7, twoDimVertR3}, // 0000011 - {6, twoDimVertL2}, {6, twoDimVertL2}, // 000010x - {6, twoDimVertR2}, {6, twoDimVertR2}, // 000011x - {4, twoDimPass}, {4, twoDimPass}, // 0001xxx - {4, twoDimPass}, {4, twoDimPass}, - {4, twoDimPass}, {4, twoDimPass}, - {4, twoDimPass}, {4, twoDimPass}, - {3, twoDimHoriz}, {3, twoDimHoriz}, // 001xxxx - {3, twoDimHoriz}, {3, twoDimHoriz}, - {3, twoDimHoriz}, {3, twoDimHoriz}, - {3, twoDimHoriz}, {3, twoDimHoriz}, - {3, twoDimHoriz}, {3, twoDimHoriz}, - {3, twoDimHoriz}, {3, twoDimHoriz}, - {3, twoDimHoriz}, {3, twoDimHoriz}, - {3, twoDimHoriz}, {3, twoDimHoriz}, - {3, twoDimVertL1}, {3, twoDimVertL1}, // 010xxxx - {3, twoDimVertL1}, {3, twoDimVertL1}, - {3, twoDimVertL1}, {3, twoDimVertL1}, - {3, twoDimVertL1}, {3, twoDimVertL1}, - {3, twoDimVertL1}, {3, twoDimVertL1}, - {3, twoDimVertL1}, {3, twoDimVertL1}, - {3, twoDimVertL1}, {3, twoDimVertL1}, - {3, twoDimVertL1}, {3, twoDimVertL1}, - {3, twoDimVertR1}, {3, twoDimVertR1}, // 011xxxx - {3, twoDimVertR1}, {3, twoDimVertR1}, - {3, twoDimVertR1}, {3, twoDimVertR1}, - {3, twoDimVertR1}, {3, twoDimVertR1}, - {3, twoDimVertR1}, {3, twoDimVertR1}, - {3, twoDimVertR1}, {3, twoDimVertR1}, - {3, twoDimVertR1}, {3, twoDimVertR1}, - {3, twoDimVertR1}, {3, twoDimVertR1}, - {1, twoDimVert0}, {1, twoDimVert0}, // 1xxxxxx - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0}, - {1, twoDimVert0}, {1, twoDimVert0} -}; - -//------------------------------------------------------------------------ -// white run lengths -//------------------------------------------------------------------------ - -// 11-12 bit codes (upper 7 bits are 0) -static CCITTCode whiteTab1[32] = { - {-1, -1}, // 00000 - {12, ccittEOL}, // 00001 - {-1, -1}, {-1, -1}, // 0001x - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 001xx - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 010xx - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 011xx - {11, 1792}, {11, 1792}, // 1000x - {12, 1984}, // 10010 - {12, 2048}, // 10011 - {12, 2112}, // 10100 - {12, 2176}, // 10101 - {12, 2240}, // 10110 - {12, 2304}, // 10111 - {11, 1856}, {11, 1856}, // 1100x - {11, 1920}, {11, 1920}, // 1101x - {12, 2368}, // 11100 - {12, 2432}, // 11101 - {12, 2496}, // 11110 - {12, 2560} // 11111 -}; - -// 1-9 bit codes -static CCITTCode whiteTab2[512] = { - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 0000000xx - {8, 29}, {8, 29}, // 00000010x - {8, 30}, {8, 30}, // 00000011x - {8, 45}, {8, 45}, // 00000100x - {8, 46}, {8, 46}, // 00000101x - {7, 22}, {7, 22}, {7, 22}, {7, 22}, // 0000011xx - {7, 23}, {7, 23}, {7, 23}, {7, 23}, // 0000100xx - {8, 47}, {8, 47}, // 00001010x - {8, 48}, {8, 48}, // 00001011x - {6, 13}, {6, 13}, {6, 13}, {6, 13}, // 000011xxx - {6, 13}, {6, 13}, {6, 13}, {6, 13}, - {7, 20}, {7, 20}, {7, 20}, {7, 20}, // 0001000xx - {8, 33}, {8, 33}, // 00010010x - {8, 34}, {8, 34}, // 00010011x - {8, 35}, {8, 35}, // 00010100x - {8, 36}, {8, 36}, // 00010101x - {8, 37}, {8, 37}, // 00010110x - {8, 38}, {8, 38}, // 00010111x - {7, 19}, {7, 19}, {7, 19}, {7, 19}, // 0001100xx - {8, 31}, {8, 31}, // 00011010x - {8, 32}, {8, 32}, // 00011011x - {6, 1}, {6, 1}, {6, 1}, {6, 1}, // 000111xxx - {6, 1}, {6, 1}, {6, 1}, {6, 1}, - {6, 12}, {6, 12}, {6, 12}, {6, 12}, // 001000xxx - {6, 12}, {6, 12}, {6, 12}, {6, 12}, - {8, 53}, {8, 53}, // 00100100x - {8, 54}, {8, 54}, // 00100101x - {7, 26}, {7, 26}, {7, 26}, {7, 26}, // 0010011xx - {8, 39}, {8, 39}, // 00101000x - {8, 40}, {8, 40}, // 00101001x - {8, 41}, {8, 41}, // 00101010x - {8, 42}, {8, 42}, // 00101011x - {8, 43}, {8, 43}, // 00101100x - {8, 44}, {8, 44}, // 00101101x - {7, 21}, {7, 21}, {7, 21}, {7, 21}, // 0010111xx - {7, 28}, {7, 28}, {7, 28}, {7, 28}, // 0011000xx - {8, 61}, {8, 61}, // 00110010x - {8, 62}, {8, 62}, // 00110011x - {8, 63}, {8, 63}, // 00110100x - {8, 0}, {8, 0}, // 00110101x - {8, 320}, {8, 320}, // 00110110x - {8, 384}, {8, 384}, // 00110111x - {5, 10}, {5, 10}, {5, 10}, {5, 10}, // 00111xxxx - {5, 10}, {5, 10}, {5, 10}, {5, 10}, - {5, 10}, {5, 10}, {5, 10}, {5, 10}, - {5, 10}, {5, 10}, {5, 10}, {5, 10}, - {5, 11}, {5, 11}, {5, 11}, {5, 11}, // 01000xxxx - {5, 11}, {5, 11}, {5, 11}, {5, 11}, - {5, 11}, {5, 11}, {5, 11}, {5, 11}, - {5, 11}, {5, 11}, {5, 11}, {5, 11}, - {7, 27}, {7, 27}, {7, 27}, {7, 27}, // 0100100xx - {8, 59}, {8, 59}, // 01001010x - {8, 60}, {8, 60}, // 01001011x - {9, 1472}, // 010011000 - {9, 1536}, // 010011001 - {9, 1600}, // 010011010 - {9, 1728}, // 010011011 - {7, 18}, {7, 18}, {7, 18}, {7, 18}, // 0100111xx - {7, 24}, {7, 24}, {7, 24}, {7, 24}, // 0101000xx - {8, 49}, {8, 49}, // 01010010x - {8, 50}, {8, 50}, // 01010011x - {8, 51}, {8, 51}, // 01010100x - {8, 52}, {8, 52}, // 01010101x - {7, 25}, {7, 25}, {7, 25}, {7, 25}, // 0101011xx - {8, 55}, {8, 55}, // 01011000x - {8, 56}, {8, 56}, // 01011001x - {8, 57}, {8, 57}, // 01011010x - {8, 58}, {8, 58}, // 01011011x - {6, 192}, {6, 192}, {6, 192}, {6, 192}, // 010111xxx - {6, 192}, {6, 192}, {6, 192}, {6, 192}, - {6, 1664}, {6, 1664}, {6, 1664}, {6, 1664}, // 011000xxx - {6, 1664}, {6, 1664}, {6, 1664}, {6, 1664}, - {8, 448}, {8, 448}, // 01100100x - {8, 512}, {8, 512}, // 01100101x - {9, 704}, // 011001100 - {9, 768}, // 011001101 - {8, 640}, {8, 640}, // 01100111x - {8, 576}, {8, 576}, // 01101000x - {9, 832}, // 011010010 - {9, 896}, // 011010011 - {9, 960}, // 011010100 - {9, 1024}, // 011010101 - {9, 1088}, // 011010110 - {9, 1152}, // 011010111 - {9, 1216}, // 011011000 - {9, 1280}, // 011011001 - {9, 1344}, // 011011010 - {9, 1408}, // 011011011 - {7, 256}, {7, 256}, {7, 256}, {7, 256}, // 0110111xx - {4, 2}, {4, 2}, {4, 2}, {4, 2}, // 0111xxxxx - {4, 2}, {4, 2}, {4, 2}, {4, 2}, - {4, 2}, {4, 2}, {4, 2}, {4, 2}, - {4, 2}, {4, 2}, {4, 2}, {4, 2}, - {4, 2}, {4, 2}, {4, 2}, {4, 2}, - {4, 2}, {4, 2}, {4, 2}, {4, 2}, - {4, 2}, {4, 2}, {4, 2}, {4, 2}, - {4, 2}, {4, 2}, {4, 2}, {4, 2}, - {4, 3}, {4, 3}, {4, 3}, {4, 3}, // 1000xxxxx - {4, 3}, {4, 3}, {4, 3}, {4, 3}, - {4, 3}, {4, 3}, {4, 3}, {4, 3}, - {4, 3}, {4, 3}, {4, 3}, {4, 3}, - {4, 3}, {4, 3}, {4, 3}, {4, 3}, - {4, 3}, {4, 3}, {4, 3}, {4, 3}, - {4, 3}, {4, 3}, {4, 3}, {4, 3}, - {4, 3}, {4, 3}, {4, 3}, {4, 3}, - {5, 128}, {5, 128}, {5, 128}, {5, 128}, // 10010xxxx - {5, 128}, {5, 128}, {5, 128}, {5, 128}, - {5, 128}, {5, 128}, {5, 128}, {5, 128}, - {5, 128}, {5, 128}, {5, 128}, {5, 128}, - {5, 8}, {5, 8}, {5, 8}, {5, 8}, // 10011xxxx - {5, 8}, {5, 8}, {5, 8}, {5, 8}, - {5, 8}, {5, 8}, {5, 8}, {5, 8}, - {5, 8}, {5, 8}, {5, 8}, {5, 8}, - {5, 9}, {5, 9}, {5, 9}, {5, 9}, // 10100xxxx - {5, 9}, {5, 9}, {5, 9}, {5, 9}, - {5, 9}, {5, 9}, {5, 9}, {5, 9}, - {5, 9}, {5, 9}, {5, 9}, {5, 9}, - {6, 16}, {6, 16}, {6, 16}, {6, 16}, // 101010xxx - {6, 16}, {6, 16}, {6, 16}, {6, 16}, - {6, 17}, {6, 17}, {6, 17}, {6, 17}, // 101011xxx - {6, 17}, {6, 17}, {6, 17}, {6, 17}, - {4, 4}, {4, 4}, {4, 4}, {4, 4}, // 1011xxxxx - {4, 4}, {4, 4}, {4, 4}, {4, 4}, - {4, 4}, {4, 4}, {4, 4}, {4, 4}, - {4, 4}, {4, 4}, {4, 4}, {4, 4}, - {4, 4}, {4, 4}, {4, 4}, {4, 4}, - {4, 4}, {4, 4}, {4, 4}, {4, 4}, - {4, 4}, {4, 4}, {4, 4}, {4, 4}, - {4, 4}, {4, 4}, {4, 4}, {4, 4}, - {4, 5}, {4, 5}, {4, 5}, {4, 5}, // 1100xxxxx - {4, 5}, {4, 5}, {4, 5}, {4, 5}, - {4, 5}, {4, 5}, {4, 5}, {4, 5}, - {4, 5}, {4, 5}, {4, 5}, {4, 5}, - {4, 5}, {4, 5}, {4, 5}, {4, 5}, - {4, 5}, {4, 5}, {4, 5}, {4, 5}, - {4, 5}, {4, 5}, {4, 5}, {4, 5}, - {4, 5}, {4, 5}, {4, 5}, {4, 5}, - {6, 14}, {6, 14}, {6, 14}, {6, 14}, // 110100xxx - {6, 14}, {6, 14}, {6, 14}, {6, 14}, - {6, 15}, {6, 15}, {6, 15}, {6, 15}, // 110101xxx - {6, 15}, {6, 15}, {6, 15}, {6, 15}, - {5, 64}, {5, 64}, {5, 64}, {5, 64}, // 11011xxxx - {5, 64}, {5, 64}, {5, 64}, {5, 64}, - {5, 64}, {5, 64}, {5, 64}, {5, 64}, - {5, 64}, {5, 64}, {5, 64}, {5, 64}, - {4, 6}, {4, 6}, {4, 6}, {4, 6}, // 1110xxxxx - {4, 6}, {4, 6}, {4, 6}, {4, 6}, - {4, 6}, {4, 6}, {4, 6}, {4, 6}, - {4, 6}, {4, 6}, {4, 6}, {4, 6}, - {4, 6}, {4, 6}, {4, 6}, {4, 6}, - {4, 6}, {4, 6}, {4, 6}, {4, 6}, - {4, 6}, {4, 6}, {4, 6}, {4, 6}, - {4, 6}, {4, 6}, {4, 6}, {4, 6}, - {4, 7}, {4, 7}, {4, 7}, {4, 7}, // 1111xxxxx - {4, 7}, {4, 7}, {4, 7}, {4, 7}, - {4, 7}, {4, 7}, {4, 7}, {4, 7}, - {4, 7}, {4, 7}, {4, 7}, {4, 7}, - {4, 7}, {4, 7}, {4, 7}, {4, 7}, - {4, 7}, {4, 7}, {4, 7}, {4, 7}, - {4, 7}, {4, 7}, {4, 7}, {4, 7}, - {4, 7}, {4, 7}, {4, 7}, {4, 7} -}; - -//------------------------------------------------------------------------ -// black run lengths -//------------------------------------------------------------------------ - -// 10-13 bit codes (upper 6 bits are 0) -static CCITTCode blackTab1[128] = { - {-1, -1}, {-1, -1}, // 000000000000x - {12, ccittEOL}, {12, ccittEOL}, // 000000000001x - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000001xx - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000010xx - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000011xx - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000100xx - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000101xx - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000110xx - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000111xx - {11, 1792}, {11, 1792}, {11, 1792}, {11, 1792}, // 00000001000xx - {12, 1984}, {12, 1984}, // 000000010010x - {12, 2048}, {12, 2048}, // 000000010011x - {12, 2112}, {12, 2112}, // 000000010100x - {12, 2176}, {12, 2176}, // 000000010101x - {12, 2240}, {12, 2240}, // 000000010110x - {12, 2304}, {12, 2304}, // 000000010111x - {11, 1856}, {11, 1856}, {11, 1856}, {11, 1856}, // 00000001100xx - {11, 1920}, {11, 1920}, {11, 1920}, {11, 1920}, // 00000001101xx - {12, 2368}, {12, 2368}, // 000000011100x - {12, 2432}, {12, 2432}, // 000000011101x - {12, 2496}, {12, 2496}, // 000000011110x - {12, 2560}, {12, 2560}, // 000000011111x - {10, 18}, {10, 18}, {10, 18}, {10, 18}, // 0000001000xxx - {10, 18}, {10, 18}, {10, 18}, {10, 18}, - {12, 52}, {12, 52}, // 000000100100x - {13, 640}, // 0000001001010 - {13, 704}, // 0000001001011 - {13, 768}, // 0000001001100 - {13, 832}, // 0000001001101 - {12, 55}, {12, 55}, // 000000100111x - {12, 56}, {12, 56}, // 000000101000x - {13, 1280}, // 0000001010010 - {13, 1344}, // 0000001010011 - {13, 1408}, // 0000001010100 - {13, 1472}, // 0000001010101 - {12, 59}, {12, 59}, // 000000101011x - {12, 60}, {12, 60}, // 000000101100x - {13, 1536}, // 0000001011010 - {13, 1600}, // 0000001011011 - {11, 24}, {11, 24}, {11, 24}, {11, 24}, // 00000010111xx - {11, 25}, {11, 25}, {11, 25}, {11, 25}, // 00000011000xx - {13, 1664}, // 0000001100100 - {13, 1728}, // 0000001100101 - {12, 320}, {12, 320}, // 000000110011x - {12, 384}, {12, 384}, // 000000110100x - {12, 448}, {12, 448}, // 000000110101x - {13, 512}, // 0000001101100 - {13, 576}, // 0000001101101 - {12, 53}, {12, 53}, // 000000110111x - {12, 54}, {12, 54}, // 000000111000x - {13, 896}, // 0000001110010 - {13, 960}, // 0000001110011 - {13, 1024}, // 0000001110100 - {13, 1088}, // 0000001110101 - {13, 1152}, // 0000001110110 - {13, 1216}, // 0000001110111 - {10, 64}, {10, 64}, {10, 64}, {10, 64}, // 0000001111xxx - {10, 64}, {10, 64}, {10, 64}, {10, 64} -}; - -// 7-12 bit codes (upper 4 bits are 0) -static CCITTCode blackTab2[192] = { - {8, 13}, {8, 13}, {8, 13}, {8, 13}, // 00000100xxxx - {8, 13}, {8, 13}, {8, 13}, {8, 13}, - {8, 13}, {8, 13}, {8, 13}, {8, 13}, - {8, 13}, {8, 13}, {8, 13}, {8, 13}, - {11, 23}, {11, 23}, // 00000101000x - {12, 50}, // 000001010010 - {12, 51}, // 000001010011 - {12, 44}, // 000001010100 - {12, 45}, // 000001010101 - {12, 46}, // 000001010110 - {12, 47}, // 000001010111 - {12, 57}, // 000001011000 - {12, 58}, // 000001011001 - {12, 61}, // 000001011010 - {12, 256}, // 000001011011 - {10, 16}, {10, 16}, {10, 16}, {10, 16}, // 0000010111xx - {10, 17}, {10, 17}, {10, 17}, {10, 17}, // 0000011000xx - {12, 48}, // 000001100100 - {12, 49}, // 000001100101 - {12, 62}, // 000001100110 - {12, 63}, // 000001100111 - {12, 30}, // 000001101000 - {12, 31}, // 000001101001 - {12, 32}, // 000001101010 - {12, 33}, // 000001101011 - {12, 40}, // 000001101100 - {12, 41}, // 000001101101 - {11, 22}, {11, 22}, // 00000110111x - {8, 14}, {8, 14}, {8, 14}, {8, 14}, // 00000111xxxx - {8, 14}, {8, 14}, {8, 14}, {8, 14}, - {8, 14}, {8, 14}, {8, 14}, {8, 14}, - {8, 14}, {8, 14}, {8, 14}, {8, 14}, - {7, 10}, {7, 10}, {7, 10}, {7, 10}, // 0000100xxxxx - {7, 10}, {7, 10}, {7, 10}, {7, 10}, - {7, 10}, {7, 10}, {7, 10}, {7, 10}, - {7, 10}, {7, 10}, {7, 10}, {7, 10}, - {7, 10}, {7, 10}, {7, 10}, {7, 10}, - {7, 10}, {7, 10}, {7, 10}, {7, 10}, - {7, 10}, {7, 10}, {7, 10}, {7, 10}, - {7, 10}, {7, 10}, {7, 10}, {7, 10}, - {7, 11}, {7, 11}, {7, 11}, {7, 11}, // 0000101xxxxx - {7, 11}, {7, 11}, {7, 11}, {7, 11}, - {7, 11}, {7, 11}, {7, 11}, {7, 11}, - {7, 11}, {7, 11}, {7, 11}, {7, 11}, - {7, 11}, {7, 11}, {7, 11}, {7, 11}, - {7, 11}, {7, 11}, {7, 11}, {7, 11}, - {7, 11}, {7, 11}, {7, 11}, {7, 11}, - {7, 11}, {7, 11}, {7, 11}, {7, 11}, - {9, 15}, {9, 15}, {9, 15}, {9, 15}, // 000011000xxx - {9, 15}, {9, 15}, {9, 15}, {9, 15}, - {12, 128}, // 000011001000 - {12, 192}, // 000011001001 - {12, 26}, // 000011001010 - {12, 27}, // 000011001011 - {12, 28}, // 000011001100 - {12, 29}, // 000011001101 - {11, 19}, {11, 19}, // 00001100111x - {11, 20}, {11, 20}, // 00001101000x - {12, 34}, // 000011010010 - {12, 35}, // 000011010011 - {12, 36}, // 000011010100 - {12, 37}, // 000011010101 - {12, 38}, // 000011010110 - {12, 39}, // 000011010111 - {11, 21}, {11, 21}, // 00001101100x - {12, 42}, // 000011011010 - {12, 43}, // 000011011011 - {10, 0}, {10, 0}, {10, 0}, {10, 0}, // 0000110111xx - {7, 12}, {7, 12}, {7, 12}, {7, 12}, // 0000111xxxxx - {7, 12}, {7, 12}, {7, 12}, {7, 12}, - {7, 12}, {7, 12}, {7, 12}, {7, 12}, - {7, 12}, {7, 12}, {7, 12}, {7, 12}, - {7, 12}, {7, 12}, {7, 12}, {7, 12}, - {7, 12}, {7, 12}, {7, 12}, {7, 12}, - {7, 12}, {7, 12}, {7, 12}, {7, 12}, - {7, 12}, {7, 12}, {7, 12}, {7, 12} -}; - -// 2-6 bit codes -static CCITTCode blackTab3[64] = { - {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 0000xx - {6, 9}, // 000100 - {6, 8}, // 000101 - {5, 7}, {5, 7}, // 00011x - {4, 6}, {4, 6}, {4, 6}, {4, 6}, // 0010xx - {4, 5}, {4, 5}, {4, 5}, {4, 5}, // 0011xx - {3, 1}, {3, 1}, {3, 1}, {3, 1}, // 010xxx - {3, 1}, {3, 1}, {3, 1}, {3, 1}, - {3, 4}, {3, 4}, {3, 4}, {3, 4}, // 011xxx - {3, 4}, {3, 4}, {3, 4}, {3, 4}, - {2, 3}, {2, 3}, {2, 3}, {2, 3}, // 10xxxx - {2, 3}, {2, 3}, {2, 3}, {2, 3}, - {2, 3}, {2, 3}, {2, 3}, {2, 3}, - {2, 3}, {2, 3}, {2, 3}, {2, 3}, - {2, 2}, {2, 2}, {2, 2}, {2, 2}, // 11xxxx - {2, 2}, {2, 2}, {2, 2}, {2, 2}, - {2, 2}, {2, 2}, {2, 2}, {2, 2}, - {2, 2}, {2, 2}, {2, 2}, {2, 2} -}; diff --git a/src/plugins/pdf/Stream.cc b/src/plugins/pdf/Stream.cc @@ -1,4656 +0,0 @@ -//======================================================================== -// -// Stream.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include "platform.h" -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <limits.h> -#ifndef WIN32 -#include <unistd.h> -#endif -#include <string.h> -#include <ctype.h> -#include "gmem.h" -#include "gfile.h" -#include "config.h" -#include "Error.h" -#include "Object.h" -#ifndef NO_DECRYPTION -#include "Decrypt.h" -#endif -#include "Stream.h" -#include "Stream-CCITT.h" - -#ifdef __DJGPP__ -static GBool setDJSYSFLAGS = gFalse; -#endif - -#ifdef VMS -#ifdef __GNUC__ -#define SEEK_SET 0 -#define SEEK_CUR 1 -#define SEEK_END 2 -#endif -#endif - -//------------------------------------------------------------------------ -// Stream (base class) -//------------------------------------------------------------------------ - -Stream::Stream() { - ref = 1; -} - -Stream::~Stream() { -} - -void Stream::close() { -} - -int Stream::getRawChar() { - error(-1, "Internal: called getRawChar() on non-predictor stream"); - return EOF; -} - -char *Stream::getLine(char *buf, int size) { - int i; - int c; - - if (lookChar() == EOF) - return NULL; - for (i = 0; i < size - 1; ++i) { - c = getChar(); - if (c == EOF || c == '\n') - break; - if (c == '\r') { - if ((c = lookChar()) == '\n') - getChar(); - break; - } - buf[i] = c; - } - buf[i] = '\0'; - return buf; -} - -GString *Stream::getPSFilter(int psLevel, const char *indent) { - return new GString(); -} - -Stream *Stream::addFilters(Object *dict) { - Object obj, obj2; - Object params, params2; - Stream *str; - int i; - - str = this; - dict->dictLookup("Filter", &obj); - if (obj.isNull()) { - obj.free(); - dict->dictLookup("F", &obj); - } - dict->dictLookup("DecodeParms", &params); - if (params.isNull()) { - params.free(); - dict->dictLookup("DP", &params); - } - if (obj.isName()) { - str = makeFilter(obj.getName(), str, &params); - } else if (obj.isArray()) { - for (i = 0; i < obj.arrayGetLength(); ++i) { - obj.arrayGet(i, &obj2); - if (params.isArray()) - params.arrayGet(i, &params2); - else - params2.initNull(); - if (obj2.isName()) { - str = makeFilter(obj2.getName(), str, &params2); - } else { - error(getPos(), "Bad filter name"); - str = new EOFStream(str); - } - obj2.free(); - params2.free(); - } - } else if (!obj.isNull()) { - error(getPos(), "Bad 'Filter' attribute in stream"); - } - obj.free(); - params.free(); - - return str; -} - -Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { - int pred; // parameters - int colors; - int bits; - int early; - int encoding; - GBool endOfLine, byteAlign, endOfBlock, black; - int columns, rows; - Object globals, obj; - - if (!strcmp(name, "ASCIIHexDecode") || !strcmp(name, "AHx")) { - str = new ASCIIHexStream(str); - } else if (!strcmp(name, "ASCII85Decode") || !strcmp(name, "A85")) { - str = new ASCII85Stream(str); - } else if (!strcmp(name, "LZWDecode") || !strcmp(name, "LZW")) { - pred = 1; - columns = 1; - colors = 1; - bits = 8; - early = 1; - if (params->isDict()) { - params->dictLookup("Predictor", &obj); - if (obj.isInt()) - pred = obj.getInt(); - obj.free(); - params->dictLookup("Columns", &obj); - if (obj.isInt()) - columns = obj.getInt(); - obj.free(); - params->dictLookup("Colors", &obj); - if (obj.isInt()) - colors = obj.getInt(); - obj.free(); - params->dictLookup("BitsPerComponent", &obj); - if (obj.isInt()) - bits = obj.getInt(); - obj.free(); - params->dictLookup("EarlyChange", &obj); - if (obj.isInt()) - early = obj.getInt(); - obj.free(); - } - str = new LZWStream(str, pred, columns, colors, bits, early); - } else if (!strcmp(name, "RunLengthDecode") || !strcmp(name, "RL")) { - str = new RunLengthStream(str); - } else if (!strcmp(name, "CCITTFaxDecode") || !strcmp(name, "CCF")) { - encoding = 0; - endOfLine = gFalse; - byteAlign = gFalse; - columns = 1728; - rows = 0; - endOfBlock = gTrue; - black = gFalse; - if (params->isDict()) { - params->dictLookup("K", &obj); - if (obj.isInt()) { - encoding = obj.getInt(); - } - obj.free(); - params->dictLookup("EndOfLine", &obj); - if (obj.isBool()) { - endOfLine = obj.getBool(); - } - obj.free(); - params->dictLookup("EncodedByteAlign", &obj); - if (obj.isBool()) { - byteAlign = obj.getBool(); - } - obj.free(); - params->dictLookup("Columns", &obj); - if (obj.isInt()) { - columns = obj.getInt(); - } - obj.free(); - params->dictLookup("Rows", &obj); - if (obj.isInt()) { - rows = obj.getInt(); - } - obj.free(); - params->dictLookup("EndOfBlock", &obj); - if (obj.isBool()) { - endOfBlock = obj.getBool(); - } - obj.free(); - params->dictLookup("BlackIs1", &obj); - if (obj.isBool()) { - black = obj.getBool(); - } - obj.free(); - } - str = new CCITTFaxStream(str, encoding, endOfLine, byteAlign, - columns, rows, endOfBlock, black); - } else if (!strcmp(name, "DCTDecode") || !strcmp(name, "DCT")) { - str = new DCTStream(str); - } else if (!strcmp(name, "FlateDecode") || !strcmp(name, "Fl")) { - pred = 1; - columns = 1; - colors = 1; - bits = 8; - if (params->isDict()) { - params->dictLookup("Predictor", &obj); - if (obj.isInt()) - pred = obj.getInt(); - obj.free(); - params->dictLookup("Columns", &obj); - if (obj.isInt()) - columns = obj.getInt(); - obj.free(); - params->dictLookup("Colors", &obj); - if (obj.isInt()) - colors = obj.getInt(); - obj.free(); - params->dictLookup("BitsPerComponent", &obj); - if (obj.isInt()) - bits = obj.getInt(); - obj.free(); - } - str = new FlateStream(str, pred, columns, colors, bits); - } -#if 0 -else if (!strcmp(name, "JBIG2Decode")) { - if (params->isDict()) { - params->dictLookup("JBIG2Globals", &globals); - } - str = new JBIG2Stream(str, &globals); - globals.free(); - } else if (!strcmp(name, "JPXDecode")) { - str = new JPXStream(str); - } -#endif -else { - error(getPos(), "Unknown filter '%s'", name); - str = new EOFStream(str); - } - return str; -} - -//------------------------------------------------------------------------ -// BaseStream -//------------------------------------------------------------------------ - -BaseStream::BaseStream(Object *dictA) { - dict = *dictA; -#ifndef NO_DECRYPTION - decrypt = NULL; -#endif -} - -BaseStream::~BaseStream() { - dict.free(); -#ifndef NO_DECRYPTION - if (decrypt) - delete decrypt; -#endif -} - -#ifndef NO_DECRYPTION -void BaseStream::doDecryption(Guchar *fileKey, int keyLength, - int objNum, int objGen) { - decrypt = new Decrypt(fileKey, keyLength, objNum, objGen); -} -#endif - -//------------------------------------------------------------------------ -// FilterStream -//------------------------------------------------------------------------ - -FilterStream::FilterStream(Stream *strA) { - str = strA; -} - -FilterStream::~FilterStream() { -} - -void FilterStream::close() { - str->close(); -} - -void FilterStream::setPos(Guint pos, int dir) { - error(-1, "Internal: called setPos() on FilterStream"); -} - -//------------------------------------------------------------------------ -// ImageStream -//------------------------------------------------------------------------ - -ImageStream::ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA) { - int imgLineSize; - - str = strA; - width = widthA; - nComps = nCompsA; - nBits = nBitsA; - - nVals = width * nComps; - if (nBits == 1) { - imgLineSize = (nVals + 7) & ~7; - } else { - imgLineSize = nVals; - } - imgLine = (Guchar *)gmalloc(imgLineSize * sizeof(Guchar)); - imgIdx = nVals; -} - -ImageStream::~ImageStream() { - gfree(imgLine); -} - -void ImageStream::reset() { - str->reset(); -} - -GBool ImageStream::getPixel(Guchar *pix) { - int i; - - if (imgIdx >= nVals) { - getLine(); - imgIdx = 0; - } - for (i = 0; i < nComps; ++i) { - pix[i] = imgLine[imgIdx++]; - } - return gTrue; -} - -Guchar *ImageStream::getLine() { - Gulong buf, bitMask; - int bits; - int c; - int i; - - if (nBits == 1) { - for (i = 0; i < nVals; i += 8) { - c = str->getChar(); - imgLine[i+0] = (Guchar)((c >> 7) & 1); - imgLine[i+1] = (Guchar)((c >> 6) & 1); - imgLine[i+2] = (Guchar)((c >> 5) & 1); - imgLine[i+3] = (Guchar)((c >> 4) & 1); - imgLine[i+4] = (Guchar)((c >> 3) & 1); - imgLine[i+5] = (Guchar)((c >> 2) & 1); - imgLine[i+6] = (Guchar)((c >> 1) & 1); - imgLine[i+7] = (Guchar)(c & 1); - } - } else if (nBits == 8) { - for (i = 0; i < nVals; ++i) { - imgLine[i] = str->getChar(); - } - } else { - bitMask = (1 << nBits) - 1; - buf = 0; - bits = 0; - for (i = 0; i < nVals; ++i) { - if (bits < nBits) { - buf = (buf << 8) | (str->getChar() & 0xff); - bits += 8; - } - imgLine[i] = (Guchar)((buf >> (bits - nBits)) & bitMask); - bits -= nBits; - } - } - return imgLine; -} - -void ImageStream::skipLine() { - int n, i; - - n = (nVals * nBits + 7) >> 3; - for (i = 0; i < n; ++i) { - str->getChar(); - } -} - -//------------------------------------------------------------------------ -// StreamPredictor -//------------------------------------------------------------------------ - -StreamPredictor::StreamPredictor(Stream *strA, int predictorA, - int widthA, int nCompsA, int nBitsA) { - int totalBits; - - str = strA; - predictor = predictorA; - width = widthA; - nComps = nCompsA; - nBits = nBitsA; - predLine = NULL; - ok = gFalse; - nVals = width * nComps; - - if (width <= 0 || nComps <= 0 || nBits <= 0 || - nComps >= 4 || nBits > 16 || - width >= INT_MAX / nComps || - nVals >= (INT_MAX - 7) / nBits) { - return; - } - - totalBits = nVals * nBits; - if (totalBits == 0 || - (totalBits / nBits) / nComps != width || - totalBits + 7 < 0) { - return; - } - pixBytes = (nComps * nBits + 7) >> 3; - rowBytes = ((totalBits + 7) >> 3) + pixBytes; - if (rowBytes < 0) { - return; - } - predLine = (Guchar *)gmalloc(rowBytes); - memset(predLine, 0, rowBytes); - predIdx = rowBytes; - ok = gTrue; -} - -StreamPredictor::~StreamPredictor() { - gfree(predLine); -} - -int StreamPredictor::lookChar() { - if (predIdx >= rowBytes) { - if (!getNextLine()) { - return EOF; - } - } - return predLine[predIdx]; -} - -int StreamPredictor::getChar() { - if (predIdx >= rowBytes) { - if (!getNextLine()) { - return EOF; - } - } - return predLine[predIdx++]; -} - -GBool StreamPredictor::getNextLine() { - int curPred; - Guchar upLeftBuf[4]; - int left, up, upLeft, p, pa, pb, pc; - int c; - Gulong inBuf, outBuf, bitMask; - int inBits, outBits; - int i, j, k; - - // get PNG optimum predictor number - if (predictor >= 10) { - if ((curPred = str->getRawChar()) == EOF) { - return gFalse; - } - curPred += 10; - } else { - curPred = predictor; - } - - // read the raw line, apply PNG (byte) predictor - upLeftBuf[0] = upLeftBuf[1] = upLeftBuf[2] = upLeftBuf[3] = 0; - for (i = pixBytes; i < rowBytes; ++i) { - upLeftBuf[3] = upLeftBuf[2]; - upLeftBuf[2] = upLeftBuf[1]; - upLeftBuf[1] = upLeftBuf[0]; - upLeftBuf[0] = predLine[i]; - if ((c = str->getRawChar()) == EOF) { - return gFalse; - } - switch (curPred) { - case 11: // PNG sub - predLine[i] = predLine[i - pixBytes] + (Guchar)c; - break; - case 12: // PNG up - predLine[i] = predLine[i] + (Guchar)c; - break; - case 13: // PNG average - predLine[i] = ((predLine[i - pixBytes] + predLine[i]) >> 1) + - (Guchar)c; - break; - case 14: // PNG Paeth - left = predLine[i - pixBytes]; - up = predLine[i]; - upLeft = upLeftBuf[pixBytes]; - p = left + up - upLeft; - if ((pa = p - left) < 0) - pa = -pa; - if ((pb = p - up) < 0) - pb = -pb; - if ((pc = p - upLeft) < 0) - pc = -pc; - if (pa <= pb && pa <= pc) - predLine[i] = left + (Guchar)c; - else if (pb <= pc) - predLine[i] = up + (Guchar)c; - else - predLine[i] = upLeft + (Guchar)c; - break; - case 10: // PNG none - default: // no predictor or TIFF predictor - predLine[i] = (Guchar)c; - break; - } - } - - // apply TIFF (component) predictor - if (predictor == 2) { - if (nBits == 1) { - inBuf = predLine[pixBytes - 1]; - for (i = pixBytes; i < rowBytes; i += 8) { - // 1-bit add is just xor - inBuf = (inBuf << 8) | predLine[i]; - predLine[i] ^= inBuf >> nComps; - } - } else if (nBits == 8) { - for (i = pixBytes; i < rowBytes; ++i) { - predLine[i] += predLine[i - nComps]; - } - } else { - upLeftBuf[0] = upLeftBuf[1] = upLeftBuf[2] = upLeftBuf[3] = 0; - bitMask = (1 << nBits) - 1; - inBuf = outBuf = 0; - inBits = outBits = 0; - j = k = pixBytes; - for (i = 0; i < nVals; ++i) { - if (inBits < nBits) { - inBuf = (inBuf << 8) | (predLine[j++] & 0xff); - inBits += 8; - } - upLeftBuf[3] = upLeftBuf[2]; - upLeftBuf[2] = upLeftBuf[1]; - upLeftBuf[1] = upLeftBuf[0]; - upLeftBuf[0] = (upLeftBuf[nComps] + - (inBuf >> (inBits - nBits))) & bitMask; - outBuf = (outBuf << nBits) | upLeftBuf[0]; - inBits -= nBits; - outBits += nBits; - if (outBits > 8) { - predLine[k++] = (Guchar)(outBuf >> (outBits - 8)); - } - } - if (outBits > 0) { - predLine[k++] = (Guchar)(outBuf << (8 - outBits)); - } - } - } - - // reset to start of line - predIdx = pixBytes; - - return gTrue; -} - -//------------------------------------------------------------------------ -// FileStream -//------------------------------------------------------------------------ - -FileStream::FileStream(FILE *fA, Guint startA, GBool limitedA, - Guint lengthA, Object *dictA): - BaseStream(dictA) { - f = fA; - start = startA; - limited = limitedA; - length = lengthA; - bufPtr = bufEnd = buf; - bufPos = start; - savePos = 0; - saved = gFalse; -} - -FileStream::~FileStream() { - close(); -} - -Stream *FileStream::makeSubStream(Guint startA, GBool limitedA, - Guint lengthA, Object *dictA) { - return new FileStream(f, startA, limitedA, lengthA, dictA); -} - -void FileStream::reset() { -#if HAVE_FSEEKO - savePos = (Guint)ftello(f); - fseeko(f, start, SEEK_SET); -#elif HAVE_FSEEK64 - savePos = (Guint)ftell64(f); - fseek64(f, start, SEEK_SET); -#else - savePos = (Guint)ftell(f); - fseek(f, start, SEEK_SET); -#endif - saved = gTrue; - bufPtr = bufEnd = buf; - bufPos = start; -#ifndef NO_DECRYPTION - if (decrypt) - decrypt->reset(); -#endif -} - -void FileStream::close() { - if (saved) { -#if HAVE_FSEEKO - fseeko(f, savePos, SEEK_SET); -#elif HAVE_FSEEK64 - fseek64(f, savePos, SEEK_SET); -#else - fseek(f, savePos, SEEK_SET); -#endif - saved = gFalse; - } -} - -GBool FileStream::fillBuf() { - int n; -#ifndef NO_DECRYPTION - char *p; -#endif - - bufPos += bufEnd - buf; - bufPtr = bufEnd = buf; - if (limited && bufPos >= start + length) { - return gFalse; - } - if (limited && bufPos + fileStreamBufSize > start + length) { - n = start + length - bufPos; - } else { - n = fileStreamBufSize; - } - n = fread(buf, 1, n, f); - bufEnd = buf + n; - if (bufPtr >= bufEnd) { - return gFalse; - } -#ifndef NO_DECRYPTION - if (decrypt) { - for (p = buf; p < bufEnd; ++p) { - *p = (char)decrypt->decryptByte((Guchar)*p); - } - } -#endif - return gTrue; -} - -void FileStream::setPos(Guint pos, int dir) { - Guint size; - - if (dir >= 0) { -#if HAVE_FSEEKO - fseeko(f, pos, SEEK_SET); -#elif HAVE_FSEEK64 - fseek64(f, pos, SEEK_SET); -#else - fseek(f, pos, SEEK_SET); -#endif - bufPos = pos; - } else { -#if HAVE_FSEEKO - fseeko(f, 0, SEEK_END); - size = (Guint)ftello(f); -#elif HAVE_FSEEK64 - fseek64(f, 0, SEEK_END); - size = (Guint)ftell64(f); -#else - fseek(f, 0, SEEK_END); - size = (Guint)ftell(f); -#endif - if (pos > size) - pos = (Guint)size; -#ifdef __CYGWIN32__ - //~ work around a bug in cygwin's implementation of fseek - rewind(f); -#endif -#if HAVE_FSEEKO - fseeko(f, -(int)pos, SEEK_END); - bufPos = (Guint)ftello(f); -#elif HAVE_FSEEK64 - fseek64(f, -(int)pos, SEEK_END); - bufPos = (Guint)ftell64(f); -#else - fseek(f, -(int)pos, SEEK_END); - bufPos = (Guint)ftell(f); -#endif - } - bufPtr = bufEnd = buf; -} - -void FileStream::moveStart(int delta) { - start += delta; - bufPtr = bufEnd = buf; - bufPos = start; -} - -//------------------------------------------------------------------------ -// MemStream -//------------------------------------------------------------------------ - -MemStream::MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA): - BaseStream(dictA) { - buf = bufA; - start = startA; - length = lengthA; - bufEnd = buf + start + length; - bufPtr = buf + start; - needFree = gFalse; -} - -MemStream::~MemStream() { - if (needFree) { - gfree(buf); - } -} - -Stream *MemStream::makeSubStream(Guint startA, GBool limited, - Guint lengthA, Object *dictA) { - MemStream *subStr; - Guint newLength; - - if (!limited || startA + lengthA > start + length) { - newLength = start + length - startA; - } else { - newLength = lengthA; - } - subStr = new MemStream(buf, startA, newLength, dictA); - return subStr; -} - -void MemStream::reset() { - bufPtr = buf + start; -#ifndef NO_DECRYPTION - if (decrypt) { - decrypt->reset(); - } -#endif -} - -void MemStream::close() { -} - -void MemStream::setPos(Guint pos, int dir) { - Guint i; - - if (dir >= 0) { - i = pos; - } else { - i = start + length - pos; - } - if (i < start) { - i = start; - } else if (i > start + length) { - i = start + length; - } - bufPtr = buf + i; -} - -void MemStream::moveStart(int delta) { - start += delta; - bufPtr = buf + start; -} - -#ifndef NO_DECRYPTION -void MemStream::doDecryption(Guchar *fileKey, int keyLength, - int objNum, int objGen) { - char *newBuf; - char *p, *q; - - this->BaseStream::doDecryption(fileKey, keyLength, objNum, objGen); - if (decrypt) { - newBuf = (char *)gmalloc(length); - for (p = buf + start, q = newBuf; p < bufEnd; ++p, ++q) { - *q = (char)decrypt->decryptByte((Guchar)*p); - } - bufEnd = newBuf + length; - bufPtr = newBuf + (bufPtr - (buf + start)); - start = 0; - buf = newBuf; - needFree = gTrue; - } -} -#endif - -//------------------------------------------------------------------------ -// EmbedStream -//------------------------------------------------------------------------ - -EmbedStream::EmbedStream(Stream *strA, Object *dictA, - GBool limitedA, Guint lengthA): - BaseStream(dictA) { - str = strA; - limited = limitedA; - length = lengthA; -} - -EmbedStream::~EmbedStream() { -} - -Stream *EmbedStream::makeSubStream(Guint start, GBool limitedA, - Guint lengthA, Object *dictA) { - error(-1, "Internal: called makeSubStream() on EmbedStream"); - return NULL; -} - -int EmbedStream::getChar() { - if (limited && !length) { - return EOF; - } - --length; - return str->getChar(); -} - -int EmbedStream::lookChar() { - if (limited && !length) { - return EOF; - } - return str->lookChar(); -} - -void EmbedStream::setPos(Guint pos, int dir) { - error(-1, "Internal: called setPos() on EmbedStream"); -} - -Guint EmbedStream::getStart() { - error(-1, "Internal: called getStart() on EmbedStream"); - return 0; -} - -void EmbedStream::moveStart(int delta) { - error(-1, "Internal: called moveStart() on EmbedStream"); -} - -//------------------------------------------------------------------------ -// ASCIIHexStream -//------------------------------------------------------------------------ - -ASCIIHexStream::ASCIIHexStream(Stream *strA): - FilterStream(strA) { - buf = EOF; - eof = gFalse; -} - -ASCIIHexStream::~ASCIIHexStream() { - delete str; -} - -void ASCIIHexStream::reset() { - str->reset(); - buf = EOF; - eof = gFalse; -} - -int ASCIIHexStream::lookChar() { - int c1, c2, x; - - if (buf != EOF) - return buf; - if (eof) { - buf = EOF; - return EOF; - } - do { - c1 = str->getChar(); - } while (isspace(c1)); - if (c1 == '>') { - eof = gTrue; - buf = EOF; - return buf; - } - do { - c2 = str->getChar(); - } while (isspace(c2)); - if (c2 == '>') { - eof = gTrue; - c2 = '0'; - } - if (c1 >= '0' && c1 <= '9') { - x = (c1 - '0') << 4; - } else if (c1 >= 'A' && c1 <= 'F') { - x = (c1 - 'A' + 10) << 4; - } else if (c1 >= 'a' && c1 <= 'f') { - x = (c1 - 'a' + 10) << 4; - } else if (c1 == EOF) { - eof = gTrue; - x = 0; - } else { - error(getPos(), "Illegal character <%02x> in ASCIIHex stream", c1); - x = 0; - } - if (c2 >= '0' && c2 <= '9') { - x += c2 - '0'; - } else if (c2 >= 'A' && c2 <= 'F') { - x += c2 - 'A' + 10; - } else if (c2 >= 'a' && c2 <= 'f') { - x += c2 - 'a' + 10; - } else if (c2 == EOF) { - eof = gTrue; - x = 0; - } else { - error(getPos(), "Illegal character <%02x> in ASCIIHex stream", c2); - } - buf = x & 0xff; - return buf; -} - -GString *ASCIIHexStream::getPSFilter(int psLevel, const char *indent) { - GString *s; - - if (psLevel < 2) { - return NULL; - } - if (!(s = str->getPSFilter(psLevel, indent))) { - return NULL; - } - s->append(indent)->append("/ASCIIHexDecode filter\n"); - return s; -} - -GBool ASCIIHexStream::isBinary(GBool last) { - return str->isBinary(gFalse); -} - -//------------------------------------------------------------------------ -// ASCII85Stream -//------------------------------------------------------------------------ - -ASCII85Stream::ASCII85Stream(Stream *strA): - FilterStream(strA) { - index = n = 0; - eof = gFalse; -} - -ASCII85Stream::~ASCII85Stream() { - delete str; -} - -void ASCII85Stream::reset() { - str->reset(); - index = n = 0; - eof = gFalse; -} - -int ASCII85Stream::lookChar() { - int k; - Gulong t; - - if (index >= n) { - if (eof) - return EOF; - index = 0; - do { - c[0] = str->getChar(); - } while (c[0] == '\n' || c[0] == '\r'); - if (c[0] == '~' || c[0] == EOF) { - eof = gTrue; - n = 0; - return EOF; - } else if (c[0] == 'z') { - b[0] = b[1] = b[2] = b[3] = 0; - n = 4; - } else { - for (k = 1; k < 5; ++k) { - do { - c[k] = str->getChar(); - } while (c[k] == '\n' || c[k] == '\r'); - if (c[k] == '~' || c[k] == EOF) - break; - } - n = k - 1; - if (k < 5 && (c[k] == '~' || c[k] == EOF)) { - for (++k; k < 5; ++k) - c[k] = 0x21 + 84; - eof = gTrue; - } - t = 0; - for (k = 0; k < 5; ++k) - t = t * 85 + (c[k] - 0x21); - for (k = 3; k >= 0; --k) { - b[k] = (int)(t & 0xff); - t >>= 8; - } - } - } - return b[index]; -} - -GString *ASCII85Stream::getPSFilter(int psLevel, const char *indent) { - GString *s; - - if (psLevel < 2) { - return NULL; - } - if (!(s = str->getPSFilter(psLevel, indent))) { - return NULL; - } - s->append(indent)->append("/ASCII85Decode filter\n"); - return s; -} - -GBool ASCII85Stream::isBinary(GBool last) { - return str->isBinary(gFalse); -} - -//------------------------------------------------------------------------ -// LZWStream -//------------------------------------------------------------------------ - -LZWStream::LZWStream(Stream *strA, int predictor, int columns, int colors, - int bits, int earlyA): - FilterStream(strA) { - if (predictor != 1) { - pred = new StreamPredictor(this, predictor, columns, colors, bits); - if (! pred->isOk()) { - delete pred; - pred = NULL; - } - } else { - pred = NULL; - } - early = earlyA; - eof = gFalse; - inputBits = 0; - clearTable(); -} - -LZWStream::~LZWStream() { - if (pred) { - delete pred; - } - delete str; -} - -int LZWStream::getChar() { - if (pred) { - return pred->getChar(); - } - if (eof) { - return EOF; - } - if (seqIndex >= seqLength) { - if (!processNextCode()) { - return EOF; - } - } - return seqBuf[seqIndex++]; -} - -int LZWStream::lookChar() { - if (pred) { - return pred->lookChar(); - } - if (eof) { - return EOF; - } - if (seqIndex >= seqLength) { - if (!processNextCode()) { - return EOF; - } - } - return seqBuf[seqIndex]; -} - -int LZWStream::getRawChar() { - if (eof) { - return EOF; - } - if (seqIndex >= seqLength) { - if (!processNextCode()) { - return EOF; - } - } - return seqBuf[seqIndex++]; -} - -void LZWStream::reset() { - str->reset(); - eof = gFalse; - inputBits = 0; - clearTable(); -} - -GBool LZWStream::processNextCode() { - int code; - int nextLength; - int i, j; - - // check for EOF - if (eof) { - return gFalse; - } - - // check for eod and clear-table codes - start: - code = getCode(); - if (code == EOF || code == 257) { - eof = gTrue; - return gFalse; - } - if (code == 256) { - clearTable(); - goto start; - } - if (nextCode >= 4097) { - error(getPos(), "Bad LZW stream - expected clear-table code"); - clearTable(); - } - - // process the next code - nextLength = seqLength + 1; - if (code < 256) { - seqBuf[0] = code; - seqLength = 1; - } else if (code < nextCode) { - seqLength = table[code].length; - for (i = seqLength - 1, j = code; i > 0; --i) { - seqBuf[i] = table[j].tail; - j = table[j].head; - } - seqBuf[0] = j; - } else if (code == nextCode) { - seqBuf[seqLength] = newChar; - ++seqLength; - } else { - error(getPos(), "Bad LZW stream - unexpected code"); - eof = gTrue; - return gFalse; - } - newChar = seqBuf[0]; - if (first) { - first = gFalse; - } else { - table[nextCode].length = nextLength; - table[nextCode].head = prevCode; - table[nextCode].tail = newChar; - ++nextCode; - if (nextCode + early == 512) - nextBits = 10; - else if (nextCode + early == 1024) - nextBits = 11; - else if (nextCode + early == 2048) - nextBits = 12; - } - prevCode = code; - - // reset buffer - seqIndex = 0; - - return gTrue; -} - -void LZWStream::clearTable() { - nextCode = 258; - nextBits = 9; - seqIndex = seqLength = 0; - first = gTrue; -} - -int LZWStream::getCode() { - int c; - int code; - - while (inputBits < nextBits) { - if ((c = str->getChar()) == EOF) - return EOF; - inputBuf = (inputBuf << 8) | (c & 0xff); - inputBits += 8; - } - code = (inputBuf >> (inputBits - nextBits)) & ((1 << nextBits) - 1); - inputBits -= nextBits; - return code; -} - -GString *LZWStream::getPSFilter(int psLevel, const char *indent) { - GString *s; - - if (psLevel < 2 || pred) { - return NULL; - } - if (!(s = str->getPSFilter(psLevel, indent))) { - return NULL; - } - s->append(indent)->append("/LZWDecode filter\n"); - return s; -} - -GBool LZWStream::isBinary(GBool last) { - return str->isBinary(gTrue); -} - -//------------------------------------------------------------------------ -// RunLengthStream -//------------------------------------------------------------------------ - -RunLengthStream::RunLengthStream(Stream *strA): - FilterStream(strA) { - bufPtr = bufEnd = buf; - eof = gFalse; -} - -RunLengthStream::~RunLengthStream() { - delete str; -} - -void RunLengthStream::reset() { - str->reset(); - bufPtr = bufEnd = buf; - eof = gFalse; -} - -GString *RunLengthStream::getPSFilter(int psLevel, const char *indent) { - GString *s; - - if (psLevel < 2) { - return NULL; - } - if (!(s = str->getPSFilter(psLevel, indent))) { - return NULL; - } - s->append(indent)->append("/RunLengthDecode filter\n"); - return s; -} - -GBool RunLengthStream::isBinary(GBool last) { - return str->isBinary(gTrue); -} - -GBool RunLengthStream::fillBuf() { - int c; - int n, i; - - if (eof) - return gFalse; - c = str->getChar(); - if (c == 0x80 || c == EOF) { - eof = gTrue; - return gFalse; - } - if (c < 0x80) { - n = c + 1; - for (i = 0; i < n; ++i) - buf[i] = (char)str->getChar(); - } else { - n = 0x101 - c; - c = str->getChar(); - for (i = 0; i < n; ++i) - buf[i] = (char)c; - } - bufPtr = buf; - bufEnd = buf + n; - return gTrue; -} - -//------------------------------------------------------------------------ -// CCITTFaxStream -//------------------------------------------------------------------------ - -#if 0 -CCITTFaxStream::CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA, - GBool byteAlignA, int columnsA, int rowsA, - GBool endOfBlockA, GBool blackA): - FilterStream(strA) { - encoding = encodingA; - endOfLine = endOfLineA; - byteAlign = byteAlignA; - columns = columnsA; - - if (columns < 1) - columns = 1; - if (columns + 4 <= 0) - columns = INT_MAX - 4; - - rows = rowsA; - endOfBlock = endOfBlockA; - black = blackA; - - eof = gFalse; - row = 0; - nextLine2D = encoding < 0; - inputBits = 0; - codingLine[0] = 0; - codingLine[1] = refLine[2] = columns; - a0 = 1; - buf = EOF; - if (columns + 4 < 1 || (columns + 4) >= INT_MAX / sizeof(short)) { - /* illegal value, bail out */ - eof = gTrue; - columns = 0; - } - refLine = (short *)gmalloc((columns + 3) * sizeof(short)); - codingLine = (short *)gmalloc((columns + 2) * sizeof(short)); -} - -CCITTFaxStream::~CCITTFaxStream() { - delete str; - gfree(refLine); - gfree(codingLine); -} - -void CCITTFaxStream::reset() { - short code1; - - str->reset(); - eof = gFalse; - row = 0; - nextLine2D = encoding < 0; - inputBits = 0; - codingLine[0] = 0; - codingLine[1] = refLine[2] = columns; - a0 = 1; - buf = EOF; - - // skip any initial zero bits and end-of-line marker, and get the 2D - // encoding tag - while ((code1 = lookBits(12)) == 0) { - eatBits(1); - } - if (code1 == 0x001) { - eatBits(12); - } - if (encoding > 0) { - nextLine2D = !lookBits(1); - eatBits(1); - } -} - -int CCITTFaxStream::lookChar() { - short code1, code2, code3; - int a0New; - GBool err, gotEOL; - int ret; - int bits, i; - - // if at eof just return EOF - if (eof && codingLine[a0] >= columns) { - return EOF; - } - - // read the next row - err = gFalse; - if (codingLine[a0] >= columns) { - - // 2-D encoding - if (nextLine2D) { - for (i = 0; codingLine[i] < columns; ++i) - refLine[i] = codingLine[i]; - refLine[i] = refLine[i + 1] = columns; - b1 = 1; - a0New = codingLine[a0 = 0] = 0; - do { - code1 = getTwoDimCode(); - switch (code1) { - case twoDimPass: - if (refLine[b1] < columns) { - a0New = refLine[b1 + 1]; - b1 += 2; - } - break; - case twoDimHoriz: - if ((a0 & 1) == 0) { - code1 = code2 = 0; - do { - code1 += code3 = getWhiteCode(); - } while (code3 >= 64); - do { - code2 += code3 = getBlackCode(); - } while (code3 >= 64); - } else { - code1 = code2 = 0; - do { - code1 += code3 = getBlackCode(); - } while (code3 >= 64); - do { - code2 += code3 = getWhiteCode(); - } while (code3 >= 64); - } - if (code1 > 0 || code2 > 0) { - codingLine[a0 + 1] = a0New + code1; - ++a0; - a0New = codingLine[a0 + 1] = codingLine[a0] + code2; - ++a0; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; - } - break; - case twoDimVert0: - a0New = codingLine[++a0] = refLine[b1]; - if (refLine[b1] < columns) { - ++b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; - } - break; - case twoDimVertR1: - a0New = codingLine[++a0] = refLine[b1] + 1; - if (refLine[b1] < columns) { - ++b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; - } - break; - case twoDimVertL1: - a0New = codingLine[++a0] = refLine[b1] - 1; - --b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; - break; - case twoDimVertR2: - a0New = codingLine[++a0] = refLine[b1] + 2; - if (refLine[b1] < columns) { - ++b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; - } - break; - case twoDimVertL2: - a0New = codingLine[++a0] = refLine[b1] - 2; - --b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; - break; - case twoDimVertR3: - a0New = codingLine[++a0] = refLine[b1] + 3; - if (refLine[b1] < columns) { - ++b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; - } - break; - case twoDimVertL3: - a0New = codingLine[++a0] = refLine[b1] - 3; - --b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) - b1 += 2; - break; - case EOF: - eof = gTrue; - codingLine[a0 = 0] = columns; - return EOF; - default: - error(getPos(), "Bad 2D code %04x in CCITTFax stream", code1); - err = gTrue; - break; - } - } while (codingLine[a0] < columns); - - // 1-D encoding - } else { - codingLine[a0 = 0] = 0; - while (1) { - code1 = 0; - do { - code1 += code3 = getWhiteCode(); - } while (code3 >= 64); - codingLine[a0+1] = codingLine[a0] + code1; - ++a0; - if (codingLine[a0] >= columns) - break; - code2 = 0; - do { - code2 += code3 = getBlackCode(); - } while (code3 >= 64); - codingLine[a0+1] = codingLine[a0] + code2; - ++a0; - if (codingLine[a0] >= columns) - break; - } - } - - if (codingLine[a0] != columns) { - error(getPos(), "CCITTFax row is wrong length (%d)", codingLine[a0]); - // force the row to be the correct length - while (codingLine[a0] > columns) { - --a0; - } - codingLine[++a0] = columns; - err = gTrue; - } - - // byte-align the row - if (byteAlign) { - inputBits &= ~7; - } - - // check for end-of-line marker, skipping over any extra zero bits - gotEOL = gFalse; - if (!endOfBlock && row == rows - 1) { - eof = gTrue; - } else { - code1 = lookBits(12); - while (code1 == 0) { - eatBits(1); - code1 = lookBits(12); - } - if (code1 == 0x001) { - eatBits(12); - gotEOL = gTrue; - } else if (code1 == EOF) { - eof = gTrue; - } - } - - // get 2D encoding tag - if (!eof && encoding > 0) { - nextLine2D = !lookBits(1); - eatBits(1); - } - - // check for end-of-block marker - if (endOfBlock && gotEOL) { - code1 = lookBits(12); - if (code1 == 0x001) { - eatBits(12); - if (encoding > 0) { - lookBits(1); - eatBits(1); - } - if (encoding >= 0) { - for (i = 0; i < 4; ++i) { - code1 = lookBits(12); - if (code1 != 0x001) { - error(getPos(), "Bad RTC code in CCITTFax stream"); - } - eatBits(12); - if (encoding > 0) { - lookBits(1); - eatBits(1); - } - } - } - eof = gTrue; - } - - // look for an end-of-line marker after an error -- we only do - // this if we know the stream contains end-of-line markers because - // the "just plow on" technique tends to work better otherwise - } else if (err && endOfLine) { - do { - if (code1 == EOF) { - eof = gTrue; - return EOF; - } - eatBits(1); - code1 = lookBits(13); - } while ((code1 >> 1) != 0x001); - eatBits(12); - if (encoding > 0) { - eatBits(1); - nextLine2D = !(code1 & 1); - } - } - - a0 = 0; - outputBits = codingLine[1] - codingLine[0]; - if (outputBits == 0) { - a0 = 1; - outputBits = codingLine[2] - codingLine[1]; - } - - ++row; - } - - // get a byte - if (outputBits >= 8) { - ret = ((a0 & 1) == 0) ? 0xff : 0x00; - if ((outputBits -= 8) == 0) { - ++a0; - if (codingLine[a0] < columns) { - outputBits = codingLine[a0 + 1] - codingLine[a0]; - } - } - } else { - bits = 8; - ret = 0; - do { - if (outputBits > bits) { - i = bits; - bits = 0; - if ((a0 & 1) == 0) { - ret |= 0xff >> (8 - i); - } - outputBits -= i; - } else { - i = outputBits; - bits -= outputBits; - if ((a0 & 1) == 0) { - ret |= (0xff >> (8 - i)) << bits; - } - outputBits = 0; - ++a0; - if (codingLine[a0] < columns) { - outputBits = codingLine[a0 + 1] - codingLine[a0]; - } - } - } while (bits > 0 && codingLine[a0] < columns); - } - buf = black ? (ret ^ 0xff) : ret; - return buf; -} - -short CCITTFaxStream::getTwoDimCode() { - short code; - CCITTCode *p; - int n; - - code = 0; // make gcc happy - if (endOfBlock) { - code = lookBits(7); - p = &twoDimTab1[code]; - if (p->bits > 0) { - eatBits(p->bits); - return p->n; - } - } else { - for (n = 1; n <= 7; ++n) { - code = lookBits(n); - if (n < 7) { - code <<= 7 - n; - } - p = &twoDimTab1[code]; - if (p->bits == n) { - eatBits(n); - return p->n; - } - } - } - error(getPos(), "Bad two dim code (%04x) in CCITTFax stream", code); - return EOF; -} - -short CCITTFaxStream::getWhiteCode() { - short code; - CCITTCode *p; - int n; - - code = 0; // make gcc happy - if (endOfBlock) { - code = lookBits(12); - if ((code >> 5) == 0) { - p = &whiteTab1[code]; - } else { - p = &whiteTab2[code >> 3]; - } - if (p->bits > 0) { - eatBits(p->bits); - return p->n; - } - } else { - for (n = 1; n <= 9; ++n) { - code = lookBits(n); - if (n < 9) { - code <<= 9 - n; - } - p = &whiteTab2[code]; - if (p->bits == n) { - eatBits(n); - return p->n; - } - } - for (n = 11; n <= 12; ++n) { - code = lookBits(n); - if (n < 12) { - code <<= 12 - n; - } - p = &whiteTab1[code]; - if (p->bits == n) { - eatBits(n); - return p->n; - } - } - } - error(getPos(), "Bad white code (%04x) in CCITTFax stream", code); - // eat a bit and return a positive number so that the caller doesn't - // go into an infinite loop - eatBits(1); - return 1; -} - -short CCITTFaxStream::getBlackCode() { - short code; - CCITTCode *p; - int n; - - code = 0; // make gcc happy - if (endOfBlock) { - code = lookBits(13); - if ((code >> 7) == 0) { - p = &blackTab1[code]; - } else if ((code >> 9) == 0) { - p = &blackTab2[(code >> 1) - 64]; - } else { - p = &blackTab3[code >> 7]; - } - if (p->bits > 0) { - eatBits(p->bits); - return p->n; - } - } else { - for (n = 2; n <= 6; ++n) { - code = lookBits(n); - if (n < 6) { - code <<= 6 - n; - } - p = &blackTab3[code]; - if (p->bits == n) { - eatBits(n); - return p->n; - } - } - for (n = 7; n <= 12; ++n) { - code = lookBits(n); - if (n < 12) { - code <<= 12 - n; - } - if (code >= 64) { - p = &blackTab2[code - 64]; - if (p->bits == n) { - eatBits(n); - return p->n; - } - } - } - for (n = 10; n <= 13; ++n) { - code = lookBits(n); - if (n < 13) { - code <<= 13 - n; - } - p = &blackTab1[code]; - if (p->bits == n) { - eatBits(n); - return p->n; - } - } - } - error(getPos(), "Bad black code (%04x) in CCITTFax stream", code); - // eat a bit and return a positive number so that the caller doesn't - // go into an infinite loop - eatBits(1); - return 1; -} - -short CCITTFaxStream::lookBits(int n) { - int c; - - while (inputBits < n) { - if ((c = str->getChar()) == EOF) { - if (inputBits == 0) { - return EOF; - } - // near the end of the stream, the caller may ask for more bits - // than are available, but there may still be a valid code in - // however many bits are available -- we need to return correct - // data in this case - return (inputBuf << (n - inputBits)) & (0xffff >> (16 - n)); - } - inputBuf = (inputBuf << 8) + c; - inputBits += 8; - } - return (inputBuf >> (inputBits - n)) & (0xffff >> (16 - n)); -} -#else // secfix -CCITTFaxStream::CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA, - GBool byteAlignA, int columnsA, int rowsA, - GBool endOfBlockA, GBool blackA): - FilterStream(strA) { - encoding = encodingA; - endOfLine = endOfLineA; - byteAlign = byteAlignA; - columns = columnsA; - if (columns < 1) { - columns = 1; - } else if (columns > (INT_MAX - 2)/sizeof(int)) { - columns = (INT_MAX - 2)/sizeof(int); - } - rows = rowsA; - endOfBlock = endOfBlockA; - black = blackA; - // 0 <= codingLine[0] < codingLine[1] < ... < codingLine[n] = columns - // ---> max codingLine size = columns + 1 - // refLine has one extra guard entry at the end - // ---> max refLine size = columns + 2 - codingLine = (int *)gmalloc((columns + 1) * sizeof(int)); - refLine = (int *)gmalloc((columns + 2) * sizeof(int)); - - eof = gFalse; - row = 0; - nextLine2D = encoding < 0; - inputBits = 0; - codingLine[0] = columns; - a0i = 0; - outputBits = 0; - - buf = EOF; -} - -CCITTFaxStream::~CCITTFaxStream() { - delete str; - gfree(refLine); - gfree(codingLine); -} - -void CCITTFaxStream::reset() { - short code1; - - str->reset(); - eof = gFalse; - row = 0; - nextLine2D = encoding < 0; - inputBits = 0; - codingLine[0] = columns; - a0i = 0; - outputBits = 0; - buf = EOF; - - // skip any initial zero bits and end-of-line marker, and get the 2D - // encoding tag - while ((code1 = lookBits(12)) == 0) { - eatBits(1); - } - if (code1 == 0x001) { - eatBits(12); - } - if (encoding > 0) { - nextLine2D = !lookBits(1); - eatBits(1); - } -} - -inline void CCITTFaxStream::addPixels(int a1, int blackPixels) { - if (a1 > codingLine[a0i]) { - if (a1 > columns) { - error(getPos(), "CCITTFax row is wrong length (%d)", a1); - err = gTrue; - a1 = columns; - } - if ((a0i & 1) ^ blackPixels) { - ++a0i; - } - codingLine[a0i] = a1; - } -} - -inline void CCITTFaxStream::addPixelsNeg(int a1, int blackPixels) { - if (a1 > codingLine[a0i]) { - if (a1 > columns) { - error(getPos(), "CCITTFax row is wrong length (%d)", a1); - err = gTrue; - a1 = columns; - } - if ((a0i & 1) ^ blackPixels) { - ++a0i; - } - codingLine[a0i] = a1; - } else if (a1 < codingLine[a0i]) { - if (a1 < 0) { - error(getPos(), "Invalid CCITTFax code"); - err = gTrue; - a1 = 0; - } - while (a0i > 0 && a1 <= codingLine[a0i - 1]) { - --a0i; - } - codingLine[a0i] = a1; - } -} - -int CCITTFaxStream::lookChar() { - short code1, code2, code3; - int b1i, blackPixels, i, bits; - GBool gotEOL; - - if (buf != EOF) { - return buf; - } - - // read the next row - if (outputBits == 0) { - - // if at eof just return EOF - if (eof) { - return EOF; - } - - err = gFalse; - - // 2-D encoding - if (nextLine2D) { - for (i = 0; codingLine[i] < columns; ++i) { - refLine[i] = codingLine[i]; - } - refLine[i++] = columns; - refLine[i] = columns; - codingLine[0] = 0; - a0i = 0; - b1i = 0; - blackPixels = 0; - // invariant: - // refLine[b1i-1] <= codingLine[a0i] < refLine[b1i] < refLine[b1i+1] - // <= columns - // exception at left edge: - // codingLine[a0i = 0] = refLine[b1i = 0] = 0 is possible - // exception at right edge: - // refLine[b1i] = refLine[b1i+1] = columns is possible - while (codingLine[a0i] < columns) { - code1 = getTwoDimCode(); - switch (code1) { - case twoDimPass: - addPixels(refLine[b1i + 1], blackPixels); - if (refLine[b1i + 1] < columns) { - b1i += 2; - } - break; - case twoDimHoriz: - code1 = code2 = 0; - if (blackPixels) { - do { - code1 += code3 = getBlackCode(); - } while (code3 >= 64); - do { - code2 += code3 = getWhiteCode(); - } while (code3 >= 64); - } else { - do { - code1 += code3 = getWhiteCode(); - } while (code3 >= 64); - do { - code2 += code3 = getBlackCode(); - } while (code3 >= 64); - } - addPixels(codingLine[a0i] + code1, blackPixels); - if (codingLine[a0i] < columns) { - addPixels(codingLine[a0i] + code2, blackPixels ^ 1); - } - while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { - b1i += 2; - } - break; - case twoDimVertR3: - addPixels(refLine[b1i] + 3, blackPixels); - blackPixels ^= 1; - if (codingLine[a0i] < columns) { - ++b1i; - while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { - b1i += 2; - } - } - break; - case twoDimVertR2: - addPixels(refLine[b1i] + 2, blackPixels); - blackPixels ^= 1; - if (codingLine[a0i] < columns) { - ++b1i; - while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { - b1i += 2; - } - } - break; - case twoDimVertR1: - addPixels(refLine[b1i] + 1, blackPixels); - blackPixels ^= 1; - if (codingLine[a0i] < columns) { - ++b1i; - while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { - b1i += 2; - } - } - break; - case twoDimVert0: - addPixels(refLine[b1i], blackPixels); - blackPixels ^= 1; - if (codingLine[a0i] < columns) { - ++b1i; - while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { - b1i += 2; - } - } - break; - case twoDimVertL3: - addPixelsNeg(refLine[b1i] - 3, blackPixels); - blackPixels ^= 1; - if (codingLine[a0i] < columns) { - if (b1i > 0) { - --b1i; - } else { - ++b1i; - } - while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { - b1i += 2; - } - } - break; - case twoDimVertL2: - addPixelsNeg(refLine[b1i] - 2, blackPixels); - blackPixels ^= 1; - if (codingLine[a0i] < columns) { - if (b1i > 0) { - --b1i; - } else { - ++b1i; - } - while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { - b1i += 2; - } - } - break; - case twoDimVertL1: - addPixelsNeg(refLine[b1i] - 1, blackPixels); - blackPixels ^= 1; - if (codingLine[a0i] < columns) { - if (b1i > 0) { - --b1i; - } else { - ++b1i; - } - while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { - b1i += 2; - } - } - break; - case EOF: - addPixels(columns, 0); - eof = gTrue; - break; - default: - error(getPos(), "Bad 2D code %04x in CCITTFax stream", code1); - addPixels(columns, 0); - err = gTrue; - break; - } - } - - // 1-D encoding - } else { - codingLine[0] = 0; - a0i = 0; - blackPixels = 0; - while (codingLine[a0i] < columns) { - code1 = 0; - if (blackPixels) { - do { - code1 += code3 = getBlackCode(); - } while (code3 >= 64); - } else { - do { - code1 += code3 = getWhiteCode(); - } while (code3 >= 64); - } - addPixels(codingLine[a0i] + code1, blackPixels); - blackPixels ^= 1; - } - } - - // byte-align the row - if (byteAlign) { - inputBits &= ~7; - } - - // check for end-of-line marker, skipping over any extra zero bits - gotEOL = gFalse; - if (!endOfBlock && row == rows - 1) { - eof = gTrue; - } else { - code1 = lookBits(12); - while (code1 == 0) { - eatBits(1); - code1 = lookBits(12); - } - if (code1 == 0x001) { - eatBits(12); - gotEOL = gTrue; - } else if (code1 == EOF) { - eof = gTrue; - } - } - - // get 2D encoding tag - if (!eof && encoding > 0) { - nextLine2D = !lookBits(1); - eatBits(1); - } - - // check for end-of-block marker - if (endOfBlock && gotEOL) { - code1 = lookBits(12); - if (code1 == 0x001) { - eatBits(12); - if (encoding > 0) { - lookBits(1); - eatBits(1); - } - if (encoding >= 0) { - for (i = 0; i < 4; ++i) { - code1 = lookBits(12); - if (code1 != 0x001) { - error(getPos(), "Bad RTC code in CCITTFax stream"); - } - eatBits(12); - if (encoding > 0) { - lookBits(1); - eatBits(1); - } - } - } - eof = gTrue; - } - - // look for an end-of-line marker after an error -- we only do - // this if we know the stream contains end-of-line markers because - // the "just plow on" technique tends to work better otherwise - } else if (err && endOfLine) { - while (1) { - code1 = lookBits(13); - if (code1 == EOF) { - eof = gTrue; - return EOF; - } - if ((code1 >> 1) == 0x001) { - break; - } - eatBits(1); - } - eatBits(12); - if (encoding > 0) { - eatBits(1); - nextLine2D = !(code1 & 1); - } - } - - // set up for output - if (codingLine[0] > 0) { - outputBits = codingLine[a0i = 0]; - } else { - outputBits = codingLine[a0i = 1]; - } - - ++row; - } - - // get a byte - if (outputBits >= 8) { - buf = (a0i & 1) ? 0x00 : 0xff; - outputBits -= 8; - if (outputBits == 0 && codingLine[a0i] < columns) { - ++a0i; - outputBits = codingLine[a0i] - codingLine[a0i - 1]; - } - } else { - bits = 8; - buf = 0; - do { - if (outputBits > bits) { - buf <<= bits; - if (!(a0i & 1)) { - buf |= 0xff >> (8 - bits); - } - outputBits -= bits; - bits = 0; - } else { - buf <<= outputBits; - if (!(a0i & 1)) { - buf |= 0xff >> (8 - outputBits); - } - bits -= outputBits; - outputBits = 0; - if (codingLine[a0i] < columns) { - ++a0i; - outputBits = codingLine[a0i] - codingLine[a0i - 1]; - } else if (bits > 0) { - buf <<= bits; - bits = 0; - } - } - } while (bits); - } - if (black) { - buf ^= 0xff; - } - return buf; -} - -short CCITTFaxStream::getTwoDimCode() { - short code; - CCITTCode *p; - int n; - - code = 0; // make gcc happy - if (endOfBlock) { - code = lookBits(7); - if (code < 0) - return EOF; - p = &twoDimTab1[code]; - if (p->bits > 0) { - eatBits(p->bits); - return p->n; - } - } else { - for (n = 1; n <= 7; ++n) { - code = lookBits(n); - if (code < 0) - return EOF; - if (n < 7) { - code <<= 7 - n; - } - p = &twoDimTab1[code]; - if (p->bits == n) { - eatBits(n); - return p->n; - } - } - } - error(getPos(), "Bad two dim code (%04x) in CCITTFax stream", code); - return EOF; -} - -short CCITTFaxStream::getWhiteCode() { - short code; - CCITTCode *p; - int n; - - code = 0; // make gcc happy - if (endOfBlock) { - code = lookBits(12); - if (code == EOF) { - return 1; - } - if ((code >> 5) == 0) { - p = &whiteTab1[code]; - } else { - p = &whiteTab2[code >> 3]; - } - if (p->bits > 0) { - eatBits(p->bits); - return p->n; - } - } else { - for (n = 1; n <= 9; ++n) { - code = lookBits(n); - if (code == EOF) { - return 1; - } - if (n < 9) { - code <<= 9 - n; - } - p = &whiteTab2[code]; - if (p->bits == n) { - eatBits(n); - return p->n; - } - } - for (n = 11; n <= 12; ++n) { - code = lookBits(n); - if (code == EOF) { - return 1; - } - if (n < 12) { - code <<= 12 - n; - } - p = &whiteTab1[code]; - if (p->bits == n) { - eatBits(n); - return p->n; - } - } - } - error(getPos(), "Bad white code (%04x) in CCITTFax stream", code); - // eat a bit and return a positive number so that the caller doesn't - // go into an infinite loop - eatBits(1); - return 1; -} - -short CCITTFaxStream::getBlackCode() { - short code; - CCITTCode *p; - int n; - - code = 0; // make gcc happy - if (endOfBlock) { - code = lookBits(13); - if (code == EOF) { - return 1; - } - if ((code >> 7) == 0) { - p = &blackTab1[code]; - } else if ((code >> 9) == 0 && (code >> 7) != 0) { - p = &blackTab2[(code >> 1) - 64]; - } else { - p = &blackTab3[code >> 7]; - } - if (p->bits > 0) { - eatBits(p->bits); - return p->n; - } - } else { - for (n = 2; n <= 6; ++n) { - code = lookBits(n); - if (code == EOF) { - return 1; - } - if (n < 6) { - code <<= 6 - n; - } - p = &blackTab3[code]; - if (p->bits == n) { - eatBits(n); - return p->n; - } - } - for (n = 7; n <= 12; ++n) { - code = lookBits(n); - if (code == EOF) { - return 1; - } - if (n < 12) { - code <<= 12 - n; - } - if (code >= 64) { - p = &blackTab2[code - 64]; - if (p->bits == n) { - eatBits(n); - return p->n; - } - } - } - for (n = 10; n <= 13; ++n) { - code = lookBits(n); - if (code == EOF) { - return 1; - } - if (n < 13) { - code <<= 13 - n; - } - p = &blackTab1[code]; - if (p->bits == n) { - eatBits(n); - return p->n; - } - } - } - error(getPos(), "Bad black code (%04x) in CCITTFax stream", code); - // eat a bit and return a positive number so that the caller doesn't - // go into an infinite loop - eatBits(1); - return 1; -} - -short CCITTFaxStream::lookBits(int n) { - int c; - - while (inputBits < n) { - if ((c = str->getChar()) == EOF) { - if (inputBits == 0) { - return EOF; - } - // near the end of the stream, the caller may ask for more bits - // than are available, but there may still be a valid code in - // however many bits are available -- we need to return correct - // data in this case - return (inputBuf << (n - inputBits)) & (0xffff >> (16 - n)); - } - inputBuf = (inputBuf << 8) + c; - inputBits += 8; - } - return (inputBuf >> (inputBits - n)) & (0xffff >> (16 - n)); -} - -#endif - -GString *CCITTFaxStream::getPSFilter(int psLevel, const char *indent) { - GString *s; - char s1[50]; - - if (psLevel < 2) { - return NULL; - } - if (!(s = str->getPSFilter(psLevel, indent))) { - return NULL; - } - s->append(indent)->append("<< "); - if (encoding != 0) { - sprintf(s1, "/K %d ", encoding); - s->append(s1); - } - if (endOfLine) { - s->append("/EndOfLine true "); - } - if (byteAlign) { - s->append("/EncodedByteAlign true "); - } - sprintf(s1, "/Columns %d ", columns); - s->append(s1); - if (rows != 0) { - sprintf(s1, "/Rows %d ", rows); - s->append(s1); - } - if (!endOfBlock) { - s->append("/EndOfBlock false "); - } - if (black) { - s->append("/BlackIs1 true "); - } - s->append(">> /CCITTFaxDecode filter\n"); - return s; -} - -GBool CCITTFaxStream::isBinary(GBool last) { - return str->isBinary(gTrue); -} - -//------------------------------------------------------------------------ -// DCTStream -//------------------------------------------------------------------------ - -// IDCT constants (20.12 fixed point format) -#define dctCos1 4017 // cos(pi/16) -#define dctSin1 799 // sin(pi/16) -#define dctCos3 3406 // cos(3*pi/16) -#define dctSin3 2276 // sin(3*pi/16) -#define dctCos6 1567 // cos(6*pi/16) -#define dctSin6 3784 // sin(6*pi/16) -#define dctSqrt2 5793 // sqrt(2) -#define dctSqrt1d2 2896 // sqrt(2) / 2 - -// color conversion parameters (16.16 fixed point format) -#define dctCrToR 91881 // 1.4020 -#define dctCbToG -22553 // -0.3441363 -#define dctCrToG -46802 // -0.71413636 -#define dctCbToB 116130 // 1.772 - -// clip [-256,511] --> [0,255] -#define dctClipOffset 256 -static Guchar dctClip[768]; -static int dctClipInit = 0; - -// zig zag decode map -static int dctZigZag[64] = { - 0, - 1, 8, - 16, 9, 2, - 3, 10, 17, 24, - 32, 25, 18, 11, 4, - 5, 12, 19, 26, 33, 40, - 48, 41, 34, 27, 20, 13, 6, - 7, 14, 21, 28, 35, 42, 49, 56, - 57, 50, 43, 36, 29, 22, 15, - 23, 30, 37, 44, 51, 58, - 59, 52, 45, 38, 31, - 39, 46, 53, 60, - 61, 54, 47, - 55, 62, - 63 -}; - -DCTStream::DCTStream(Stream *strA): - FilterStream(strA) { - int i, j; - - progressive = interleaved = gFalse; - width = height = 0; - mcuWidth = mcuHeight = 0; - numComps = 0; - comp = 0; - x = y = dy = 0; - for (i = 0; i < 4; ++i) { - for (j = 0; j < 32; ++j) { - rowBuf[i][j] = NULL; - } - frameBuf[i] = NULL; - } - - if (!dctClipInit) { - for (i = -256; i < 0; ++i) - dctClip[dctClipOffset + i] = 0; - for (i = 0; i < 256; ++i) - dctClip[dctClipOffset + i] = i; - for (i = 256; i < 512; ++i) - dctClip[dctClipOffset + i] = 255; - dctClipInit = 1; - } -} - -DCTStream::~DCTStream() { - int i, j; - - delete str; - if (progressive || !interleaved) { - for (i = 0; i < numComps; ++i) { - gfree(frameBuf[i]); - } - } else { - for (i = 0; i < numComps; ++i) { - for (j = 0; j < mcuHeight; ++j) { - gfree(rowBuf[i][j]); - } - } - } -} - -void DCTStream::reset() { - int minHSample, minVSample; - int i, j; - - str->reset(); - - progressive = interleaved = gFalse; - width = height = 0; - numComps = 0; - numQuantTables = 0; - numDCHuffTables = 0; - numACHuffTables = 0; - colorXform = 0; - gotJFIFMarker = gFalse; - gotAdobeMarker = gFalse; - restartInterval = 0; - - if (!readHeader()) { - y = height; - return; - } - - // compute MCU size - mcuWidth = minHSample = compInfo[0].hSample; - mcuHeight = minVSample = compInfo[0].vSample; - for (i = 1; i < numComps; ++i) { - if (compInfo[i].hSample < minHSample) - minHSample = compInfo[i].hSample; - if (compInfo[i].vSample < minVSample) - minVSample = compInfo[i].vSample; - if (compInfo[i].hSample > mcuWidth) - mcuWidth = compInfo[i].hSample; - if (compInfo[i].vSample > mcuHeight) - mcuHeight = compInfo[i].vSample; - } - for (i = 0; i < numComps; ++i) { - compInfo[i].hSample /= minHSample; - compInfo[i].vSample /= minVSample; - } - mcuWidth = (mcuWidth / minHSample) * 8; - mcuHeight = (mcuHeight / minVSample) * 8; - - // figure out color transform - if (!gotAdobeMarker && numComps == 3) { - if (gotJFIFMarker) { - colorXform = 1; - } else if (compInfo[0].id == 82 && compInfo[1].id == 71 && - compInfo[2].id == 66) { // ASCII "RGB" - colorXform = 0; - } else { - colorXform = 1; - } - } - - if (progressive || !interleaved) { - - // allocate a buffer for the whole image - bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; - bufHeight = ((height + mcuHeight - 1) / mcuHeight) * mcuHeight; - if (bufWidth <= 0 || bufHeight <= 0 || - bufWidth > INT_MAX / bufWidth / (int)sizeof(int)) { - error(getPos(), "Invalid image size in DCT stream"); - y = height; - return; - } - for (i = 0; i < numComps; ++i) { - frameBuf[i] = (int *)gmalloc(bufWidth * bufHeight * sizeof(int)); - memset(frameBuf[i], 0, bufWidth * bufHeight * sizeof(int)); - } - - // read the image data - do { - restartMarker = 0xd0; - restart(); - readScan(); - } while (readHeader()); - - // decode - decodeImage(); - - // initialize counters - comp = 0; - x = 0; - y = 0; - - } else { - - // allocate a buffer for one row of MCUs - bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; - for (i = 0; i < numComps; ++i) { - for (j = 0; j < mcuHeight; ++j) { - rowBuf[i][j] = (Guchar *)gmalloc(bufWidth * sizeof(Guchar)); - } - } - - // initialize counters - comp = 0; - x = 0; - y = 0; - dy = mcuHeight; - - restartMarker = 0xd0; - restart(); - } -} - -int DCTStream::getChar() { - int c; - - if (y >= height) { - return EOF; - } - if (progressive || !interleaved) { - c = frameBuf[comp][y * bufWidth + x]; - if (++comp == numComps) { - comp = 0; - if (++x == width) { - x = 0; - ++y; - } - } - } else { - if (dy >= mcuHeight) { - if (!readMCURow()) { - y = height; - return EOF; - } - comp = 0; - x = 0; - dy = 0; - } - c = rowBuf[comp][dy][x]; - if (++comp == numComps) { - comp = 0; - if (++x == width) { - x = 0; - ++y; - ++dy; - if (y == height) { - readTrailer(); - } - } - } - } - return c; -} - -int DCTStream::lookChar() { - if (y >= height) { - return EOF; - } - if (progressive || !interleaved) { - return frameBuf[comp][y * bufWidth + x]; - } else { - if (dy >= mcuHeight) { - if (!readMCURow()) { - y = height; - return EOF; - } - comp = 0; - x = 0; - dy = 0; - } - return rowBuf[comp][dy][x]; - } -} - -void DCTStream::restart() { - int i; - - inputBits = 0; - restartCtr = restartInterval; - for (i = 0; i < numComps; ++i) { - compInfo[i].prevDC = 0; - } - eobRun = 0; -} - -// Read one row of MCUs from a sequential JPEG stream. -GBool DCTStream::readMCURow() { - int data1[64]; - Guchar data2[64]; - Guchar *p1, *p2; - int pY, pCb, pCr, pR, pG, pB; - int h, v, horiz, vert, hSub, vSub; - int x1, x2, y2, x3, y3, x4, y4, x5, y5, cc, i; - int c; - - for (x1 = 0; x1 < width; x1 += mcuWidth) { - - // deal with restart marker - if (restartInterval > 0 && restartCtr == 0) { - c = readMarker(); - if (c != restartMarker) { - error(getPos(), "Bad DCT data: incorrect restart marker"); - return gFalse; - } - if (++restartMarker == 0xd8) - restartMarker = 0xd0; - restart(); - } - - // read one MCU - for (cc = 0; cc < numComps; ++cc) { - h = compInfo[cc].hSample; - v = compInfo[cc].vSample; - horiz = mcuWidth / h; - vert = mcuHeight / v; - hSub = horiz / 8; - vSub = vert / 8; - for (y2 = 0; y2 < mcuHeight; y2 += vert) { - for (x2 = 0; x2 < mcuWidth; x2 += horiz) { - if (!readDataUnit(&dcHuffTables[scanInfo.dcHuffTable[cc]], - &acHuffTables[scanInfo.acHuffTable[cc]], - &compInfo[cc].prevDC, - data1)) { - return gFalse; - } - transformDataUnit(quantTables[compInfo[cc].quantTable], - data1, data2); - if (hSub == 1 && vSub == 1) { - for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { - p1 = &rowBuf[cc][y2+y3][x1+x2]; - p1[0] = data2[i]; - p1[1] = data2[i+1]; - p1[2] = data2[i+2]; - p1[3] = data2[i+3]; - p1[4] = data2[i+4]; - p1[5] = data2[i+5]; - p1[6] = data2[i+6]; - p1[7] = data2[i+7]; - } - } else if (hSub == 2 && vSub == 2) { - for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) { - p1 = &rowBuf[cc][y2+y3][x1+x2]; - p2 = &rowBuf[cc][y2+y3+1][x1+x2]; - p1[0] = p1[1] = p2[0] = p2[1] = data2[i]; - p1[2] = p1[3] = p2[2] = p2[3] = data2[i+1]; - p1[4] = p1[5] = p2[4] = p2[5] = data2[i+2]; - p1[6] = p1[7] = p2[6] = p2[7] = data2[i+3]; - p1[8] = p1[9] = p2[8] = p2[9] = data2[i+4]; - p1[10] = p1[11] = p2[10] = p2[11] = data2[i+5]; - p1[12] = p1[13] = p2[12] = p2[13] = data2[i+6]; - p1[14] = p1[15] = p2[14] = p2[15] = data2[i+7]; - } - } else { - i = 0; - for (y3 = 0, y4 = 0; y3 < 8; ++y3, y4 += vSub) { - for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) { - for (y5 = 0; y5 < vSub; ++y5) - for (x5 = 0; x5 < hSub; ++x5) - rowBuf[cc][y2+y4+y5][x1+x2+x4+x5] = data2[i]; - ++i; - } - } - } - } - } - } - --restartCtr; - - // color space conversion - if (colorXform) { - // convert YCbCr to RGB - if (numComps == 3) { - for (y2 = 0; y2 < mcuHeight; ++y2) { - for (x2 = 0; x2 < mcuWidth; ++x2) { - pY = rowBuf[0][y2][x1+x2]; - pCb = rowBuf[1][y2][x1+x2] - 128; - pCr = rowBuf[2][y2][x1+x2] - 128; - pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; - rowBuf[0][y2][x1+x2] = dctClip[dctClipOffset + pR]; - pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32768) >> 16; - rowBuf[1][y2][x1+x2] = dctClip[dctClipOffset + pG]; - pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; - rowBuf[2][y2][x1+x2] = dctClip[dctClipOffset + pB]; - } - } - // convert YCbCrK to CMYK (K is passed through unchanged) - } else if (numComps == 4) { - for (y2 = 0; y2 < mcuHeight; ++y2) { - for (x2 = 0; x2 < mcuWidth; ++x2) { - pY = rowBuf[0][y2][x1+x2]; - pCb = rowBuf[1][y2][x1+x2] - 128; - pCr = rowBuf[2][y2][x1+x2] - 128; - pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; - rowBuf[0][y2][x1+x2] = 255 - dctClip[dctClipOffset + pR]; - pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32768) >> 16; - rowBuf[1][y2][x1+x2] = 255 - dctClip[dctClipOffset + pG]; - pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; - rowBuf[2][y2][x1+x2] = 255 - dctClip[dctClipOffset + pB]; - } - } - } - } - } - return gTrue; -} - -// Read one scan from a progressive or non-interleaved JPEG stream. -void DCTStream::readScan() { - int data[64]; - int x1, y1, dx1, dy1, x2, y2, y3, cc, i; - int h, v, horiz, vert, vSub; - int *p1; - int c; - - if (scanInfo.numComps == 1) { - for (cc = 0; cc < numComps; ++cc) { - if (scanInfo.comp[cc]) { - break; - } - } - dx1 = mcuWidth / compInfo[cc].hSample; - dy1 = mcuHeight / compInfo[cc].vSample; - } else { - dx1 = mcuWidth; - dy1 = mcuHeight; - } - - for (y1 = 0; y1 < height; y1 += dy1) { - for (x1 = 0; x1 < width; x1 += dx1) { - - // deal with restart marker - if (restartInterval > 0 && restartCtr == 0) { - c = readMarker(); - if (c != restartMarker) { - error(getPos(), "Bad DCT data: incorrect restart marker"); - return; - } - if (++restartMarker == 0xd8) { - restartMarker = 0xd0; - } - restart(); - } - - // read one MCU - for (cc = 0; cc < numComps; ++cc) { - if (!scanInfo.comp[cc]) { - continue; - } - - h = compInfo[cc].hSample; - v = compInfo[cc].vSample; - horiz = mcuWidth / h; - vert = mcuHeight / v; - vSub = vert / 8; - for (y2 = 0; y2 < dy1; y2 += vert) { - for (x2 = 0; x2 < dx1; x2 += horiz) { - - // pull out the current values - p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; - for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { - data[i] = p1[0]; - data[i+1] = p1[1]; - data[i+2] = p1[2]; - data[i+3] = p1[3]; - data[i+4] = p1[4]; - data[i+5] = p1[5]; - data[i+6] = p1[6]; - data[i+7] = p1[7]; - p1 += bufWidth * vSub; - } - - // read one data unit - if (progressive) { - if (!readProgressiveDataUnit( - &dcHuffTables[scanInfo.dcHuffTable[cc]], - &acHuffTables[scanInfo.acHuffTable[cc]], - &compInfo[cc].prevDC, - data)) { - return; - } - } else { - if (!readDataUnit(&dcHuffTables[scanInfo.dcHuffTable[cc]], - &acHuffTables[scanInfo.acHuffTable[cc]], - &compInfo[cc].prevDC, - data)) { - return; - } - } - - // add the data unit into frameBuf - p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; - for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { - p1[0] = data[i]; - p1[1] = data[i+1]; - p1[2] = data[i+2]; - p1[3] = data[i+3]; - p1[4] = data[i+4]; - p1[5] = data[i+5]; - p1[6] = data[i+6]; - p1[7] = data[i+7]; - p1 += bufWidth * vSub; - } - } - } - } - --restartCtr; - } - } -} - -// Read one data unit from a sequential JPEG stream. -GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, - DCTHuffTable *acHuffTable, - int *prevDC, int data[64]) { - int run, size, amp; - int c; - int i, j; - - if ((size = readHuffSym(dcHuffTable)) == 9999) { - return gFalse; - } - if (size > 0) { - if ((amp = readAmp(size)) == 9999) { - return gFalse; - } - } else { - amp = 0; - } - data[0] = *prevDC += amp; - for (i = 1; i < 64; ++i) { - data[i] = 0; - } - i = 1; - while (i < 64) { - run = 0; - while ((c = readHuffSym(acHuffTable)) == 0xf0 && run < 0x30) { - run += 0x10; - } - if (c == 9999) { - return gFalse; - } - if (c == 0x00) { - break; - } else { - run += (c >> 4) & 0x0f; - size = c & 0x0f; - amp = readAmp(size); - if (amp == 9999) { - return gFalse; - } - i += run; - if (i < 64) { - j = dctZigZag[i++]; - data[j] = amp; - } - } - } - return gTrue; -} - -// Read one data unit from a sequential JPEG stream. -GBool DCTStream::readProgressiveDataUnit(DCTHuffTable *dcHuffTable, - DCTHuffTable *acHuffTable, - int *prevDC, int data[64]) { - int run, size, amp, bit, c; - int i, j, k; - - // get the DC coefficient - i = scanInfo.firstCoeff; - if (i == 0) { - if (scanInfo.ah == 0) { - if ((size = readHuffSym(dcHuffTable)) == 9999) { - return gFalse; - } - if (size > 0) { - if ((amp = readAmp(size)) == 9999) { - return gFalse; - } - } else { - amp = 0; - } - data[0] += (*prevDC += amp) << scanInfo.al; - } else { - if ((bit = readBit()) == 9999) { - return gFalse; - } - data[0] += bit << scanInfo.al; - } - ++i; - } - if (scanInfo.lastCoeff == 0) { - return gTrue; - } - - // check for an EOB run - if (eobRun > 0) { - while (i <= scanInfo.lastCoeff) { - j = dctZigZag[i++]; - if (data[j] != 0) { - if ((bit = readBit()) == EOF) { - return gFalse; - } - if (bit) { - data[j] += 1 << scanInfo.al; - } - } - } - --eobRun; - return gTrue; - } - - // read the AC coefficients - while (i <= scanInfo.lastCoeff) { - if ((c = readHuffSym(acHuffTable)) == 9999) { - return gFalse; - } - - // ZRL - if (c == 0xf0) { - k = 0; - while (k < 16) { - j = dctZigZag[i++]; - if (data[j] == 0) { - ++k; - } else { - if ((bit = readBit()) == EOF) { - return gFalse; - } - if (bit) { - data[j] += 1 << scanInfo.al; - } - } - } - - // EOB run - } else if ((c & 0x0f) == 0x00) { - j = c >> 4; - eobRun = 0; - for (k = 0; k < j; ++k) { - if ((bit = readBit()) == EOF) { - return gFalse; - } - eobRun = (eobRun << 1) | bit; - } - eobRun += 1 << j; - while (i <= scanInfo.lastCoeff) { - j = dctZigZag[i++]; - if (data[j] != 0) { - if ((bit = readBit()) == EOF) { - return gFalse; - } - if (bit) { - data[j] += 1 << scanInfo.al; - } - } - } - --eobRun; - break; - - // zero run and one AC coefficient - } else { - run = (c >> 4) & 0x0f; - size = c & 0x0f; - if ((amp = readAmp(size)) == 9999) { - return gFalse; - } - k = 0; - do { - j = dctZigZag[i++]; - while (data[j] != 0) { - if ((bit = readBit()) == EOF) { - return gFalse; - } - if (bit) { - data[j] += 1 << scanInfo.al; - } - j = dctZigZag[i++]; - } - ++k; - } while (k <= run); - data[j] = amp << scanInfo.al; - } - } - - return gTrue; -} - -// Decode a progressive JPEG image. -void DCTStream::decodeImage() { - int dataIn[64]; - Guchar dataOut[64]; - Guchar *quantTable; - int pY, pCb, pCr, pR, pG, pB; - int x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, cc, i; - int h, v, horiz, vert, hSub, vSub; - int *p0, *p1, *p2; - - for (y1 = 0; y1 < bufHeight; y1 += mcuHeight) { - for (x1 = 0; x1 < bufWidth; x1 += mcuWidth) { - for (cc = 0; cc < numComps; ++cc) { - quantTable = quantTables[compInfo[cc].quantTable]; - h = compInfo[cc].hSample; - v = compInfo[cc].vSample; - horiz = mcuWidth / h; - vert = mcuHeight / v; - hSub = horiz / 8; - vSub = vert / 8; - for (y2 = 0; y2 < mcuHeight; y2 += vert) { - for (x2 = 0; x2 < mcuWidth; x2 += horiz) { - - // pull out the coded data unit - p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; - for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { - dataIn[i] = p1[0]; - dataIn[i+1] = p1[1]; - dataIn[i+2] = p1[2]; - dataIn[i+3] = p1[3]; - dataIn[i+4] = p1[4]; - dataIn[i+5] = p1[5]; - dataIn[i+6] = p1[6]; - dataIn[i+7] = p1[7]; - p1 += bufWidth * vSub; - } - - // transform - transformDataUnit(quantTable, dataIn, dataOut); - - // store back into frameBuf, doing replication for - // subsampled components - p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; - if (hSub == 1 && vSub == 1) { - for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { - p1[0] = dataOut[i] & 0xff; - p1[1] = dataOut[i+1] & 0xff; - p1[2] = dataOut[i+2] & 0xff; - p1[3] = dataOut[i+3] & 0xff; - p1[4] = dataOut[i+4] & 0xff; - p1[5] = dataOut[i+5] & 0xff; - p1[6] = dataOut[i+6] & 0xff; - p1[7] = dataOut[i+7] & 0xff; - p1 += bufWidth; - } - } else if (hSub == 2 && vSub == 2) { - p2 = p1 + bufWidth; - for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) { - p1[0] = p1[1] = p2[0] = p2[1] = dataOut[i] & 0xff; - p1[2] = p1[3] = p2[2] = p2[3] = dataOut[i+1] & 0xff; - p1[4] = p1[5] = p2[4] = p2[5] = dataOut[i+2] & 0xff; - p1[6] = p1[7] = p2[6] = p2[7] = dataOut[i+3] & 0xff; - p1[8] = p1[9] = p2[8] = p2[9] = dataOut[i+4] & 0xff; - p1[10] = p1[11] = p2[10] = p2[11] = dataOut[i+5] & 0xff; - p1[12] = p1[13] = p2[12] = p2[13] = dataOut[i+6] & 0xff; - p1[14] = p1[15] = p2[14] = p2[15] = dataOut[i+7] & 0xff; - p1 += bufWidth * 2; - p2 += bufWidth * 2; - } - } else { - i = 0; - for (y3 = 0, y4 = 0; y3 < 8; ++y3, y4 += vSub) { - for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) { - p2 = p1 + x4; - for (y5 = 0; y5 < vSub; ++y5) { - for (x5 = 0; x5 < hSub; ++x5) { - p2[x5] = dataOut[i] & 0xff; - } - p2 += bufWidth; - } - ++i; - } - p1 += bufWidth * vSub; - } - } - } - } - } - - // color space conversion - if (colorXform) { - // convert YCbCr to RGB - if (numComps == 3) { - for (y2 = 0; y2 < mcuHeight; ++y2) { - p0 = &frameBuf[0][(y1+y2) * bufWidth + x1]; - p1 = &frameBuf[1][(y1+y2) * bufWidth + x1]; - p2 = &frameBuf[2][(y1+y2) * bufWidth + x1]; - for (x2 = 0; x2 < mcuWidth; ++x2) { - pY = *p0; - pCb = *p1 - 128; - pCr = *p2 - 128; - pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; - *p0++ = dctClip[dctClipOffset + pR]; - pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + - 32768) >> 16; - *p1++ = dctClip[dctClipOffset + pG]; - pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; - *p2++ = dctClip[dctClipOffset + pB]; - } - } - // convert YCbCrK to CMYK (K is passed through unchanged) - } else if (numComps == 4) { - for (y2 = 0; y2 < mcuHeight; ++y2) { - p0 = &frameBuf[0][(y1+y2) * bufWidth + x1]; - p1 = &frameBuf[1][(y1+y2) * bufWidth + x1]; - p2 = &frameBuf[2][(y1+y2) * bufWidth + x1]; - for (x2 = 0; x2 < mcuWidth; ++x2) { - pY = *p0; - pCb = *p1 - 128; - pCr = *p2 - 128; - pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; - *p0++ = 255 - dctClip[dctClipOffset + pR]; - pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + - 32768) >> 16; - *p1++ = 255 - dctClip[dctClipOffset + pG]; - pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; - *p2++ = 255 - dctClip[dctClipOffset + pB]; - } - } - } - } - } - } -} - -// Transform one data unit -- this performs the dequantization and -// IDCT steps. This IDCT algorithm is taken from: -// Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz, -// "Practical Fast 1-D DCT Algorithms with 11 Multiplications", -// IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989, -// 988-991. -// The stage numbers mentioned in the comments refer to Figure 1 in this -// paper. -void DCTStream::transformDataUnit(Guchar *quantTable, - int dataIn[64], Guchar dataOut[64]) { - int v0, v1, v2, v3, v4, v5, v6, v7, t; - int *p; - int i; - - // dequant - for (i = 0; i < 64; ++i) { - dataIn[i] *= quantTable[i]; - } - - // inverse DCT on rows - for (i = 0; i < 64; i += 8) { - p = dataIn + i; - - // check for all-zero AC coefficients - if (p[1] == 0 && p[2] == 0 && p[3] == 0 && - p[4] == 0 && p[5] == 0 && p[6] == 0 && p[7] == 0) { - t = (dctSqrt2 * p[0] + 512) >> 10; - p[0] = t; - p[1] = t; - p[2] = t; - p[3] = t; - p[4] = t; - p[5] = t; - p[6] = t; - p[7] = t; - continue; - } - - // stage 4 - v0 = (dctSqrt2 * p[0] + 128) >> 8; - v1 = (dctSqrt2 * p[4] + 128) >> 8; - v2 = p[2]; - v3 = p[6]; - v4 = (dctSqrt1d2 * (p[1] - p[7]) + 128) >> 8; - v7 = (dctSqrt1d2 * (p[1] + p[7]) + 128) >> 8; - v5 = p[3] << 4; - v6 = p[5] << 4; - - // stage 3 - t = (v0 - v1+ 1) >> 1; - v0 = (v0 + v1 + 1) >> 1; - v1 = t; - t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8; - v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8; - v3 = t; - t = (v4 - v6 + 1) >> 1; - v4 = (v4 + v6 + 1) >> 1; - v6 = t; - t = (v7 + v5 + 1) >> 1; - v5 = (v7 - v5 + 1) >> 1; - v7 = t; - - // stage 2 - t = (v0 - v3 + 1) >> 1; - v0 = (v0 + v3 + 1) >> 1; - v3 = t; - t = (v1 - v2 + 1) >> 1; - v1 = (v1 + v2 + 1) >> 1; - v2 = t; - t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12; - v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12; - v7 = t; - t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12; - v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12; - v6 = t; - - // stage 1 - p[0] = v0 + v7; - p[7] = v0 - v7; - p[1] = v1 + v6; - p[6] = v1 - v6; - p[2] = v2 + v5; - p[5] = v2 - v5; - p[3] = v3 + v4; - p[4] = v3 - v4; - } - - // inverse DCT on columns - for (i = 0; i < 8; ++i) { - p = dataIn + i; - - // check for all-zero AC coefficients - if (p[1*8] == 0 && p[2*8] == 0 && p[3*8] == 0 && - p[4*8] == 0 && p[5*8] == 0 && p[6*8] == 0 && p[7*8] == 0) { - t = (dctSqrt2 * dataIn[i+0] + 8192) >> 14; - p[0*8] = t; - p[1*8] = t; - p[2*8] = t; - p[3*8] = t; - p[4*8] = t; - p[5*8] = t; - p[6*8] = t; - p[7*8] = t; - continue; - } - - // stage 4 - v0 = (dctSqrt2 * p[0*8] + 2048) >> 12; - v1 = (dctSqrt2 * p[4*8] + 2048) >> 12; - v2 = p[2*8]; - v3 = p[6*8]; - v4 = (dctSqrt1d2 * (p[1*8] - p[7*8]) + 2048) >> 12; - v7 = (dctSqrt1d2 * (p[1*8] + p[7*8]) + 2048) >> 12; - v5 = p[3*8]; - v6 = p[5*8]; - - // stage 3 - t = (v0 - v1 + 1) >> 1; - v0 = (v0 + v1 + 1) >> 1; - v1 = t; - t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12; - v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12; - v3 = t; - t = (v4 - v6 + 1) >> 1; - v4 = (v4 + v6 + 1) >> 1; - v6 = t; - t = (v7 + v5 + 1) >> 1; - v5 = (v7 - v5 + 1) >> 1; - v7 = t; - - // stage 2 - t = (v0 - v3 + 1) >> 1; - v0 = (v0 + v3 + 1) >> 1; - v3 = t; - t = (v1 - v2 + 1) >> 1; - v1 = (v1 + v2 + 1) >> 1; - v2 = t; - t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12; - v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12; - v7 = t; - t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12; - v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12; - v6 = t; - - // stage 1 - p[0*8] = v0 + v7; - p[7*8] = v0 - v7; - p[1*8] = v1 + v6; - p[6*8] = v1 - v6; - p[2*8] = v2 + v5; - p[5*8] = v2 - v5; - p[3*8] = v3 + v4; - p[4*8] = v3 - v4; - } - - // convert to 8-bit integers - for (i = 0; i < 64; ++i) { - dataOut[i] = dctClip[dctClipOffset + 128 + ((dataIn[i] + 8) >> 4)]; - } -} - -int DCTStream::readHuffSym(DCTHuffTable *table) { - Gushort code; - int bit; - int codeBits; - - code = 0; - codeBits = 0; - do { - // add a bit to the code - if ((bit = readBit()) == EOF) - return 9999; - code = (code << 1) + bit; - ++codeBits; - - // look up code - if (code - table->firstCode[codeBits] < table->numCodes[codeBits]) { - code -= table->firstCode[codeBits]; - return table->sym[table->firstSym[codeBits] + code]; - } - } while (codeBits < 16); - - error(getPos(), "Bad Huffman code in DCT stream"); - return 9999; -} - -int DCTStream::readAmp(int size) { - int amp, bit; - int bits; - - amp = 0; - for (bits = 0; bits < size; ++bits) { - if ((bit = readBit()) == EOF) - return 9999; - amp = (amp << 1) + bit; - } - if (amp < (1 << (size - 1))) - amp -= (1 << size) - 1; - return amp; -} - -int DCTStream::readBit() { - int bit; - int c, c2; - - if (inputBits == 0) { - if ((c = str->getChar()) == EOF) - return EOF; - if (c == 0xff) { - do { - c2 = str->getChar(); - } while (c2 == 0xff); - if (c2 != 0x00) { - error(getPos(), "Bad DCT data: missing 00 after ff"); - return EOF; - } - } - inputBuf = c; - inputBits = 8; - } - bit = (inputBuf >> (inputBits - 1)) & 1; - --inputBits; - return bit; -} - -GBool DCTStream::readHeader() { - GBool doScan; - int n; - int c = 0; - int i; - - // read headers - doScan = gFalse; - while (!doScan) { - c = readMarker(); - switch (c) { - case 0xc0: // SOF0 - if (!readBaselineSOF()) { - return gFalse; - } - break; - case 0xc2: // SOF2 - if (!readProgressiveSOF()) { - return gFalse; - } - break; - case 0xc4: // DHT - if (!readHuffmanTables()) { - return gFalse; - } - break; - case 0xd8: // SOI - break; - case 0xd9: // EOI - return gFalse; - case 0xda: // SOS - if (!readScanInfo()) { - return gFalse; - } - doScan = gTrue; - break; - case 0xdb: // DQT - if (!readQuantTables()) { - return gFalse; - } - break; - case 0xdd: // DRI - if (!readRestartInterval()) { - return gFalse; - } - break; - case 0xe0: // APP0 - if (!readJFIFMarker()) { - return gFalse; - } - break; - case 0xee: // APP14 - if (!readAdobeMarker()) { - return gFalse; - } - break; - case EOF: - error(getPos(), "Bad DCT header"); - return gFalse; - default: - // skip APPn / COM / etc. - if (c >= 0xe0) { - n = read16() - 2; - for (i = 0; i < n; ++i) { - str->getChar(); - } - } else { - error(getPos(), "Unknown DCT marker <%02x>", c); - return gFalse; - } - break; - } - } - - return gTrue; -} - -GBool DCTStream::readBaselineSOF() { - int length; - int prec; - int i; - int c; - - length = read16(); - prec = str->getChar(); - height = read16(); - width = read16(); - numComps = str->getChar(); - if (numComps <= 0 || numComps > 4) { - numComps = 0; - return gFalse; - } - - if (prec != 8) { - error(getPos(), "Bad DCT precision %d", prec); - return gFalse; - } - for (i = 0; i < numComps; ++i) { - compInfo[i].id = str->getChar(); - c = str->getChar(); - compInfo[i].hSample = (c >> 4) & 0x0f; - compInfo[i].vSample = c & 0x0f; - compInfo[i].quantTable = str->getChar(); - } - progressive = gFalse; - return gTrue; -} - -GBool DCTStream::readProgressiveSOF() { - int length; - int prec; - int i; - int c; - - length = read16(); - prec = str->getChar(); - height = read16(); - width = read16(); - numComps = str->getChar(); - if (numComps <= 0 || numComps > 4) { - numComps = 0; - return gFalse; - } - if (prec != 8) { - error(getPos(), "Bad DCT precision %d", prec); - return gFalse; - } - for (i = 0; i < numComps; ++i) { - compInfo[i].id = str->getChar(); - c = str->getChar(); - compInfo[i].hSample = (c >> 4) & 0x0f; - compInfo[i].vSample = c & 0x0f; - compInfo[i].quantTable = str->getChar(); - } - progressive = gTrue; - return gTrue; -} - -GBool DCTStream::readScanInfo() { - int length; - int id, c; - int i, j; - - length = read16() - 2; - scanInfo.numComps = str->getChar(); - if (scanInfo.numComps <= 0 || scanInfo.numComps > 4) { - scanInfo.numComps = 0; - error(getPos(), "Bad number of components in DCT stream"); - return gFalse; - } - --length; - if (length != 2 * scanInfo.numComps + 3) { - error(getPos(), "Bad DCT scan info block"); - return gFalse; - } - interleaved = scanInfo.numComps == numComps; - for (j = 0; j < numComps; ++j) { - scanInfo.comp[j] = gFalse; - } - for (i = 0; i < scanInfo.numComps; ++i) { - id = str->getChar(); - // some (broken) DCT streams reuse ID numbers, but at least they - // keep the components in order, so we check compInfo[i] first to - // work around the problem - if (id == compInfo[i].id) { - j = i; - } else { - for (j = 0; j < numComps; ++j) { - if (id == compInfo[j].id) { - break; - } - } - if (j == numComps) { - error(getPos(), "Bad DCT component ID in scan info block"); - return gFalse; - } - } - scanInfo.comp[j] = gTrue; - c = str->getChar(); - scanInfo.dcHuffTable[j] = (c >> 4) & 0x0f; - scanInfo.acHuffTable[j] = c & 0x0f; - } - scanInfo.firstCoeff = str->getChar(); - scanInfo.lastCoeff = str->getChar(); - if (scanInfo.firstCoeff < 0 || scanInfo.lastCoeff > 63 || - scanInfo.firstCoeff > scanInfo.lastCoeff) { - error(getPos(), "Bad DCT coefficient numbers in scan info block"); - return gFalse; - } - c = str->getChar(); - scanInfo.ah = (c >> 4) & 0x0f; - scanInfo.al = c & 0x0f; - return gTrue; -} - -GBool DCTStream::readQuantTables() { - int length; - int i; - int index; - - length = read16() - 2; - while (length > 0) { - index = str->getChar(); - if ((index & 0xf0) || index >= 4) { - error(getPos(), "Bad DCT quantization table"); - return gFalse; - } - if (index == numQuantTables) - numQuantTables = index + 1; - for (i = 0; i < 64; ++i) - quantTables[index][dctZigZag[i]] = str->getChar(); - length -= 65; - } - return gTrue; -} - -GBool DCTStream::readHuffmanTables() { - DCTHuffTable *tbl; - int length; - int index; - Gushort code; - Guchar sym; - int i; - int c; - - length = read16() - 2; - while (length > 0) { - index = str->getChar(); - --length; - if (((index & 0x0f) >= 4) || ((index & ~0x10) < 0)) { - error(getPos(), "Bad DCT Huffman table"); - return gFalse; - } - if (index & 0x10) { - index &= 0x03; - if (index >= numACHuffTables) - numACHuffTables = index+1; - tbl = &acHuffTables[index]; - } else { - index &= 0x0f; - if (index >= numDCHuffTables) - numDCHuffTables = index+1; - tbl = &dcHuffTables[index]; - } - sym = 0; - code = 0; - for (i = 1; i <= 16; ++i) { - c = str->getChar(); - tbl->firstSym[i] = sym; - tbl->firstCode[i] = code; - tbl->numCodes[i] = c; - sym += c; - code = (code + c) << 1; - } - length -= 16; - for (i = 0; i < sym; ++i) - tbl->sym[i] = str->getChar(); - length -= sym; - } - return gTrue; -} - -GBool DCTStream::readRestartInterval() { - int length; - - length = read16(); - if (length != 4) { - error(getPos(), "Bad DCT restart interval"); - return gFalse; - } - restartInterval = read16(); - return gTrue; -} - -GBool DCTStream::readJFIFMarker() { - int length, i; - char buf[5]; - int c; - - length = read16(); - length -= 2; - if (length >= 5) { - for (i = 0; i < 5; ++i) { - if ((c = str->getChar()) == EOF) { - error(getPos(), "Bad DCT APP0 marker"); - return gFalse; - } - buf[i] = c; - } - length -= 5; - if (!memcmp(buf, "JFIF\0", 5)) { - gotJFIFMarker = gTrue; - } - } - while (length > 0) { - if (str->getChar() == EOF) { - error(getPos(), "Bad DCT APP0 marker"); - return gFalse; - } - --length; - } - return gTrue; -} - -GBool DCTStream::readAdobeMarker() { - int length, i; - char buf[12]; - int c; - - length = read16(); - if (length < 14) { - goto err; - } - for (i = 0; i < 12; ++i) { - if ((c = str->getChar()) == EOF) { - goto err; - } - buf[i] = c; - } - if (strncmp(buf, "Adobe", 5)) { - goto err; - } - colorXform = buf[11]; - gotAdobeMarker = gTrue; - for (i = 14; i < length; ++i) { - if (str->getChar() == EOF) { - goto err; - } - } - return gTrue; - - err: - error(getPos(), "Bad DCT Adobe APP14 marker"); - return gFalse; -} - -GBool DCTStream::readTrailer() { - int c; - - c = readMarker(); - if (c != 0xd9) { // EOI - error(getPos(), "Bad DCT trailer"); - return gFalse; - } - return gTrue; -} - -int DCTStream::readMarker() { - int c; - - do { - do { - c = str->getChar(); - } while (c != 0xff); - do { - c = str->getChar(); - } while (c == 0xff); - } while (c == 0x00); - return c; -} - -int DCTStream::read16() { - int c1, c2; - - if ((c1 = str->getChar()) == EOF) - return EOF; - if ((c2 = str->getChar()) == EOF) - return EOF; - return (c1 << 8) + c2; -} - -GString *DCTStream::getPSFilter(int psLevel, const char *indent) { - GString *s; - - if (psLevel < 2) { - return NULL; - } - if (!(s = str->getPSFilter(psLevel, indent))) { - return NULL; - } - s->append(indent)->append("<< >> /DCTDecode filter\n"); - return s; -} - -GBool DCTStream::isBinary(GBool last) { - return str->isBinary(gTrue); -} - -//------------------------------------------------------------------------ -// FlateStream -//------------------------------------------------------------------------ - -int FlateStream::codeLenCodeMap[flateMaxCodeLenCodes] = { - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 -}; - -FlateDecode FlateStream::lengthDecode[flateMaxLitCodes-257] = { - {0, 3}, - {0, 4}, - {0, 5}, - {0, 6}, - {0, 7}, - {0, 8}, - {0, 9}, - {0, 10}, - {1, 11}, - {1, 13}, - {1, 15}, - {1, 17}, - {2, 19}, - {2, 23}, - {2, 27}, - {2, 31}, - {3, 35}, - {3, 43}, - {3, 51}, - {3, 59}, - {4, 67}, - {4, 83}, - {4, 99}, - {4, 115}, - {5, 131}, - {5, 163}, - {5, 195}, - {5, 227}, - {0, 258} -}; - -FlateDecode FlateStream::distDecode[flateMaxDistCodes] = { - { 0, 1}, - { 0, 2}, - { 0, 3}, - { 0, 4}, - { 1, 5}, - { 1, 7}, - { 2, 9}, - { 2, 13}, - { 3, 17}, - { 3, 25}, - { 4, 33}, - { 4, 49}, - { 5, 65}, - { 5, 97}, - { 6, 129}, - { 6, 193}, - { 7, 257}, - { 7, 385}, - { 8, 513}, - { 8, 769}, - { 9, 1025}, - { 9, 1537}, - {10, 2049}, - {10, 3073}, - {11, 4097}, - {11, 6145}, - {12, 8193}, - {12, 12289}, - {13, 16385}, - {13, 24577} -}; - -FlateStream::FlateStream(Stream *strA, int predictor, int columns, - int colors, int bits): - FilterStream(strA) { - if (predictor != 1) { - pred = new StreamPredictor(this, predictor, columns, colors, bits); - if (! pred->isOk()) { - delete pred; - pred = NULL; - } - } else { - pred = NULL; - } - litCodeTab.codes = NULL; - distCodeTab.codes = NULL; -} - -FlateStream::~FlateStream() { - gfree(litCodeTab.codes); - gfree(distCodeTab.codes); - if (pred) { - delete pred; - } - delete str; -} - -void FlateStream::reset() { - int cmf, flg; - - index = 0; - remain = 0; - codeBuf = 0; - codeSize = 0; - compressedBlock = gFalse; - endOfBlock = gTrue; - eof = gTrue; - - str->reset(); - - // read header - //~ need to look at window size? - endOfBlock = eof = gTrue; - cmf = str->getChar(); - flg = str->getChar(); - if (cmf == EOF || flg == EOF) - return; - if ((cmf & 0x0f) != 0x08) { - error(getPos(), "Unknown compression method in flate stream"); - return; - } - if ((((cmf << 8) + flg) % 31) != 0) { - error(getPos(), "Bad FCHECK in flate stream"); - return; - } - if (flg & 0x20) { - error(getPos(), "FDICT bit set in flate stream"); - return; - } - - eof = gFalse; -} - -int FlateStream::getChar() { - int c; - - if (pred) { - return pred->getChar(); - } - while (remain == 0) { - if (endOfBlock && eof) - return EOF; - readSome(); - } - c = buf[index]; - index = (index + 1) & flateMask; - --remain; - return c; -} - -int FlateStream::lookChar() { - int c; - - if (pred) { - return pred->lookChar(); - } - while (remain == 0) { - if (endOfBlock && eof) - return EOF; - readSome(); - } - c = buf[index]; - return c; -} - -int FlateStream::getRawChar() { - int c; - - while (remain == 0) { - if (endOfBlock && eof) - return EOF; - readSome(); - } - c = buf[index]; - index = (index + 1) & flateMask; - --remain; - return c; -} - -GString *FlateStream::getPSFilter(int psLevel, const char *indent) { - GString *s; - - if (psLevel < 3 || pred) { - return NULL; - } - if (!(s = str->getPSFilter(psLevel, indent))) { - return NULL; - } - s->append(indent)->append("<< >> /FlateDecode filter\n"); - return s; -} - -GBool FlateStream::isBinary(GBool last) { - return str->isBinary(gTrue); -} - -void FlateStream::readSome() { - int code1, code2; - int len, dist; - int i, j, k; - int c; - - if (endOfBlock) { - if (!startBlock()) - return; - } - - if (compressedBlock) { - if ((code1 = getHuffmanCodeWord(&litCodeTab)) == EOF) - goto err; - if (code1 < 256) { - buf[index] = code1; - remain = 1; - } else if (code1 == 256) { - endOfBlock = gTrue; - remain = 0; - } else { - code1 -= 257; - code2 = lengthDecode[code1].bits; - if (code2 > 0 && (code2 = getCodeWord(code2)) == EOF) - goto err; - len = lengthDecode[code1].first + code2; - if ((code1 = getHuffmanCodeWord(&distCodeTab)) == EOF) - goto err; - code2 = distDecode[code1].bits; - if (code2 > 0 && (code2 = getCodeWord(code2)) == EOF) - goto err; - dist = distDecode[code1].first + code2; - i = index; - j = (index - dist) & flateMask; - for (k = 0; k < len; ++k) { - buf[i] = buf[j]; - i = (i + 1) & flateMask; - j = (j + 1) & flateMask; - } - remain = len; - } - - } else { - len = (blockLen < flateWindow) ? blockLen : flateWindow; - for (i = 0, j = index; i < len; ++i, j = (j + 1) & flateMask) { - if ((c = str->getChar()) == EOF) { - endOfBlock = eof = gTrue; - break; - } - buf[j] = c & 0xff; - } - remain = i; - blockLen -= len; - if (blockLen == 0) - endOfBlock = gTrue; - } - - return; - -err: - error(getPos(), "Unexpected end of file in flate stream"); - endOfBlock = eof = gTrue; - remain = 0; -} - -GBool FlateStream::startBlock() { - int blockHdr; - int c; - int check; - - // free the code tables from the previous block - gfree(litCodeTab.codes); - litCodeTab.codes = NULL; - gfree(distCodeTab.codes); - distCodeTab.codes = NULL; - - // read block header - blockHdr = getCodeWord(3); - if (blockHdr & 1) - eof = gTrue; - blockHdr >>= 1; - - // uncompressed block - if (blockHdr == 0) { - compressedBlock = gFalse; - if ((c = str->getChar()) == EOF) - goto err; - blockLen = c & 0xff; - if ((c = str->getChar()) == EOF) - goto err; - blockLen |= (c & 0xff) << 8; - if ((c = str->getChar()) == EOF) - goto err; - check = c & 0xff; - if ((c = str->getChar()) == EOF) - goto err; - check |= (c & 0xff) << 8; - if (check != (~blockLen & 0xffff)) - error(getPos(), "Bad uncompressed block length in flate stream"); - codeBuf = 0; - codeSize = 0; - - // compressed block with fixed codes - } else if (blockHdr == 1) { - compressedBlock = gTrue; - loadFixedCodes(); - - // compressed block with dynamic codes - } else if (blockHdr == 2) { - compressedBlock = gTrue; - if (!readDynamicCodes()) { - goto err; - } - - // unknown block type - } else { - goto err; - } - - endOfBlock = gFalse; - return gTrue; - -err: - error(getPos(), "Bad block header in flate stream"); - endOfBlock = eof = gTrue; - return gFalse; -} - -void FlateStream::loadFixedCodes() { - int i; - - // build the literal code table - for (i = 0; i <= 143; ++i) { - codeLengths[i] = 8; - } - for (i = 144; i <= 255; ++i) { - codeLengths[i] = 9; - } - for (i = 256; i <= 279; ++i) { - codeLengths[i] = 7; - } - for (i = 280; i <= 287; ++i) { - codeLengths[i] = 8; - } - compHuffmanCodes(codeLengths, flateMaxLitCodes, &litCodeTab); - - // build the distance code table - for (i = 0; i < flateMaxDistCodes; ++i) { - codeLengths[i] = 5; - } - compHuffmanCodes(codeLengths, flateMaxDistCodes, &distCodeTab); -} - -GBool FlateStream::readDynamicCodes() { - int numCodeLenCodes; - int numLitCodes; - int numDistCodes; - int codeLenCodeLengths[flateMaxCodeLenCodes]; - FlateHuffmanTab codeLenCodeTab; - int len, repeat, code; - int i; - - codeLenCodeTab.codes = NULL; - - // read lengths - if ((numLitCodes = getCodeWord(5)) == EOF) { - goto err; - } - numLitCodes += 257; - if ((numDistCodes = getCodeWord(5)) == EOF) { - goto err; - } - numDistCodes += 1; - if ((numCodeLenCodes = getCodeWord(4)) == EOF) { - goto err; - } - numCodeLenCodes += 4; - if (numLitCodes > flateMaxLitCodes || - numDistCodes > flateMaxDistCodes || - numCodeLenCodes > flateMaxCodeLenCodes) { - goto err; - } - - // build the code length code table - for (i = 0; i < flateMaxCodeLenCodes; ++i) { - codeLenCodeLengths[i] = 0; - } - for (i = 0; i < numCodeLenCodes; ++i) { - if ((codeLenCodeLengths[codeLenCodeMap[i]] = getCodeWord(3)) == -1) { - goto err; - } - } - compHuffmanCodes(codeLenCodeLengths, flateMaxCodeLenCodes, &codeLenCodeTab); - - // build the literal and distance code tables - len = 0; - repeat = 0; - i = 0; - while (i < numLitCodes + numDistCodes) { - if ((code = getHuffmanCodeWord(&codeLenCodeTab)) == EOF) { - goto err; - } - if (code == 16) { - if ((repeat = getCodeWord(2)) == EOF) { - goto err; - } - repeat += 3; - if (i + repeat > numLitCodes + numDistCodes) { - goto err; - } - for (; repeat > 0; --repeat) { - codeLengths[i++] = len; - } - } else if (code == 17) { - if ((repeat = getCodeWord(3)) == EOF) { - goto err; - } - repeat += 3; - if (i + repeat > numLitCodes + numDistCodes) { - goto err; - } - len = 0; - for (; repeat > 0; --repeat) { - codeLengths[i++] = 0; - } - } else if (code == 18) { - if ((repeat = getCodeWord(7)) == EOF) { - goto err; - } - repeat += 11; - if (i + repeat > numLitCodes + numDistCodes) { - goto err; - } - len = 0; - for (; repeat > 0; --repeat) { - codeLengths[i++] = 0; - } - } else { - codeLengths[i++] = len = code; - } - } - compHuffmanCodes(codeLengths, numLitCodes, &litCodeTab); - compHuffmanCodes(codeLengths + numLitCodes, numDistCodes, &distCodeTab); - - gfree(codeLenCodeTab.codes); - return gTrue; - -err: - error(getPos(), "Bad dynamic code table in flate stream"); - gfree(codeLenCodeTab.codes); - return gFalse; -} - -// Convert an array <lengths> of <n> lengths, in value order, into a -// Huffman code lookup table. -void FlateStream::compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab) { - int tabSize, len, code, code2, skip, val, i, t; - - // find max code length - tab->maxLen = 0; - for (val = 0; val < n; ++val) { - if (lengths[val] > tab->maxLen) { - tab->maxLen = lengths[val]; - } - } - - // allocate the table - tabSize = 1 << tab->maxLen; - tab->codes = (FlateCode *)gmalloc(tabSize * sizeof(FlateCode)); - - // clear the table - for (i = 0; i < tabSize; ++i) { - tab->codes[i].len = 0; - tab->codes[i].val = 0; - } - - // build the table - for (len = 1, code = 0, skip = 2; - len <= tab->maxLen; - ++len, code <<= 1, skip <<= 1) { - for (val = 0; val < n; ++val) { - if (lengths[val] == len) { - - // bit-reverse the code - code2 = 0; - t = code; - for (i = 0; i < len; ++i) { - code2 = (code2 << 1) | (t & 1); - t >>= 1; - } - - // fill in the table entries - for (i = code2; i < tabSize; i += skip) { - tab->codes[i].len = (Gushort)len; - tab->codes[i].val = (Gushort)val; - } - - ++code; - } - } - } -} - -int FlateStream::getHuffmanCodeWord(FlateHuffmanTab *tab) { - FlateCode *code; - int c; - - while (codeSize < tab->maxLen) { - if ((c = str->getChar()) == EOF) { - break; - } - codeBuf |= (c & 0xff) << codeSize; - codeSize += 8; - } - code = &tab->codes[codeBuf & ((1 << tab->maxLen) - 1)]; - if (codeSize == 0 || codeSize < code->len || code->len == 0) { - return EOF; - } - codeBuf >>= code->len; - codeSize -= code->len; - return (int)code->val; -} - -int FlateStream::getCodeWord(int bits) { - int c; - - while (codeSize < bits) { - if ((c = str->getChar()) == EOF) - return EOF; - codeBuf |= (c & 0xff) << codeSize; - codeSize += 8; - } - c = codeBuf & ((1 << bits) - 1); - codeBuf >>= bits; - codeSize -= bits; - return c; -} - -//------------------------------------------------------------------------ -// EOFStream -//------------------------------------------------------------------------ - -EOFStream::EOFStream(Stream *strA): - FilterStream(strA) { -} - -EOFStream::~EOFStream() { - delete str; -} - -//------------------------------------------------------------------------ -// FixedLengthEncoder -//------------------------------------------------------------------------ - -FixedLengthEncoder::FixedLengthEncoder(Stream *strA, int lengthA): - FilterStream(strA) { - length = lengthA; - count = 0; -} - -FixedLengthEncoder::~FixedLengthEncoder() { - if (str->isEncoder()) - delete str; -} - -void FixedLengthEncoder::reset() { - str->reset(); - count = 0; -} - -int FixedLengthEncoder::getChar() { - if (length >= 0 && count >= length) - return EOF; - ++count; - return str->getChar(); -} - -int FixedLengthEncoder::lookChar() { - if (length >= 0 && count >= length) - return EOF; - return str->getChar(); -} - -GBool FixedLengthEncoder::isBinary(GBool last) { - return str->isBinary(gTrue); -} - -//------------------------------------------------------------------------ -// ASCIIHexEncoder -//------------------------------------------------------------------------ - -ASCIIHexEncoder::ASCIIHexEncoder(Stream *strA): - FilterStream(strA) { - bufPtr = bufEnd = buf; - lineLen = 0; - eof = gFalse; -} - -ASCIIHexEncoder::~ASCIIHexEncoder() { - if (str->isEncoder()) { - delete str; - } -} - -void ASCIIHexEncoder::reset() { - str->reset(); - bufPtr = bufEnd = buf; - lineLen = 0; - eof = gFalse; -} - -GBool ASCIIHexEncoder::fillBuf() { - static const char *hex = "0123456789abcdef"; - int c; - - if (eof) { - return gFalse; - } - bufPtr = bufEnd = buf; - if ((c = str->getChar()) == EOF) { - *bufEnd++ = '>'; - eof = gTrue; - } else { - if (lineLen >= 64) { - *bufEnd++ = '\n'; - lineLen = 0; - } - *bufEnd++ = hex[(c >> 4) & 0x0f]; - *bufEnd++ = hex[c & 0x0f]; - lineLen += 2; - } - return gTrue; -} - -//------------------------------------------------------------------------ -// ASCII85Encoder -//------------------------------------------------------------------------ - -ASCII85Encoder::ASCII85Encoder(Stream *strA): - FilterStream(strA) { - bufPtr = bufEnd = buf; - lineLen = 0; - eof = gFalse; -} - -ASCII85Encoder::~ASCII85Encoder() { - if (str->isEncoder()) - delete str; -} - -void ASCII85Encoder::reset() { - str->reset(); - bufPtr = bufEnd = buf; - lineLen = 0; - eof = gFalse; -} - -GBool ASCII85Encoder::fillBuf() { - Gulong t; - char buf1[5]; - int c; - int n, i; - - if (eof) - return gFalse; - t = 0; - for (n = 0; n < 4; ++n) { - if ((c = str->getChar()) == EOF) - break; - t = (t << 8) + c; - } - bufPtr = bufEnd = buf; - if (n > 0) { - if (n == 4 && t == 0) { - *bufEnd++ = 'z'; - if (++lineLen == 65) { - *bufEnd++ = '\n'; - lineLen = 0; - } - } else { - if (n < 4) - t <<= 8 * (4 - n); - for (i = 4; i >= 0; --i) { - buf1[i] = (char)(t % 85 + 0x21); - t /= 85; - } - for (i = 0; i <= n; ++i) { - *bufEnd++ = buf1[i]; - if (++lineLen == 65) { - *bufEnd++ = '\n'; - lineLen = 0; - } - } - } - } - if (n < 4) { - *bufEnd++ = '~'; - *bufEnd++ = '>'; - eof = gTrue; - } - return bufPtr < bufEnd; -} - -//------------------------------------------------------------------------ -// RunLengthEncoder -//------------------------------------------------------------------------ - -RunLengthEncoder::RunLengthEncoder(Stream *strA): - FilterStream(strA) { - bufPtr = bufEnd = nextEnd = buf; - eof = gFalse; -} - -RunLengthEncoder::~RunLengthEncoder() { - if (str->isEncoder()) - delete str; -} - -void RunLengthEncoder::reset() { - str->reset(); - bufPtr = bufEnd = nextEnd = buf; - eof = gFalse; -} - -// -// When fillBuf finishes, buf[] looks like this: -// +-----+--------------+-----------------+-- -// + tag | ... data ... | next 0, 1, or 2 | -// +-----+--------------+-----------------+-- -// ^ ^ ^ -// bufPtr bufEnd nextEnd -// -GBool RunLengthEncoder::fillBuf() { - int c, c1, c2; - int n; - - // already hit EOF? - if (eof) - return gFalse; - - // grab two bytes - if (nextEnd < bufEnd + 1) { - if ((c1 = str->getChar()) == EOF) { - eof = gTrue; - return gFalse; - } - } else { - c1 = bufEnd[0] & 0xff; - } - if (nextEnd < bufEnd + 2) { - if ((c2 = str->getChar()) == EOF) { - eof = gTrue; - buf[0] = 0; - buf[1] = c1; - bufPtr = buf; - bufEnd = &buf[2]; - return gTrue; - } - } else { - c2 = bufEnd[1] & 0xff; - } - - // check for repeat - c = 0; // make gcc happy - if (c1 == c2) { - n = 2; - while (n < 128 && (c = str->getChar()) == c1) - ++n; - buf[0] = (char)(257 - n); - buf[1] = c1; - bufEnd = &buf[2]; - if (c == EOF) { - eof = gTrue; - } else if (n < 128) { - buf[2] = c; - nextEnd = &buf[3]; - } else { - nextEnd = bufEnd; - } - - // get up to 128 chars - } else { - buf[1] = c1; - buf[2] = c2; - n = 2; - while (n < 128) { - if ((c = str->getChar()) == EOF) { - eof = gTrue; - break; - } - ++n; - buf[n] = c; - if (buf[n] == buf[n-1]) - break; - } - if (buf[n] == buf[n-1]) { - buf[0] = (char)(n-2-1); - bufEnd = &buf[n-1]; - nextEnd = &buf[n+1]; - } else { - buf[0] = (char)(n-1); - bufEnd = nextEnd = &buf[n+1]; - } - } - bufPtr = buf; - return gTrue; -} diff --git a/src/plugins/pdf/Stream.h b/src/plugins/pdf/Stream.h @@ -1,848 +0,0 @@ -//======================================================================== -// -// Stream.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef STREAM_H -#define STREAM_H - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include <stdio.h> -#include "gtypes.h" -#include "Object.h" - -#ifndef NO_DECRYPTION -class Decrypt; -#endif -class BaseStream; - -//------------------------------------------------------------------------ - -enum StreamKind { - strFile, - strASCIIHex, - strASCII85, - strLZW, - strRunLength, - strCCITTFax, - strDCT, - strFlate, - strJBIG2, - strJPX, - strWeird // internal-use stream types -}; - -//------------------------------------------------------------------------ -// Stream (base class) -//------------------------------------------------------------------------ - -class Stream { -public: - - // Constructor. - Stream(); - - // Destructor. - virtual ~Stream(); - - // Reference counting. - int incRef() { return ++ref; } - int decRef() { return --ref; } - - // Get kind of stream. - virtual StreamKind getKind() = 0; - - // Reset stream to beginning. - virtual void reset() = 0; - - // Close down the stream. - virtual void close(); - - // Get next char from stream. - virtual int getChar() = 0; - - // Peek at next char in stream. - virtual int lookChar() = 0; - - // Get next char from stream without using the predictor. - // This is only used by StreamPredictor. - virtual int getRawChar(); - - // Get next line from stream. - virtual char *getLine(char *buf, int size); - - // Get current position in file. - virtual int getPos() = 0; - - // Go to a position in the stream. If <dir> is negative, the - // position is from the end of the file; otherwise the position is - // from the start of the file. - virtual void setPos(Guint pos, int dir = 0) = 0; - - // Get PostScript command for the filter(s). - virtual GString *getPSFilter(int psLevel, const char *indent); - - // Does this stream type potentially contain non-printable chars? - virtual GBool isBinary(GBool last = gTrue) = 0; - - // Get the BaseStream of this stream. - virtual BaseStream *getBaseStream() = 0; - - // Get the dictionary associated with this stream. - virtual Dict *getDict() = 0; - - // Is this an encoding filter? - virtual GBool isEncoder() { return gFalse; } - - // Add filters to this stream according to the parameters in <dict>. - // Returns the new stream. - Stream *addFilters(Object *dict); - - // Tell this stream to ignore any length limitation -- this only - // applies to BaseStream subclasses, and is used as a hack to work - // around broken PDF files with incorrect stream lengths. - virtual void ignoreLength() {} - -private: - - Stream *makeFilter(char *name, Stream *str, Object *params); - - int ref; // reference count -}; - -//------------------------------------------------------------------------ -// BaseStream -// -// This is the base class for all streams that read directly from a file. -//------------------------------------------------------------------------ - -class BaseStream: public Stream { -public: - - BaseStream(Object *dictA); - virtual ~BaseStream(); - virtual Stream *makeSubStream(Guint start, GBool limited, - Guint length, Object *dict) = 0; - virtual void setPos(Guint pos, int dir = 0) = 0; - virtual GBool isBinary(GBool last = gTrue) { return last; } - virtual BaseStream *getBaseStream() { return this; } - virtual Dict *getDict() { return dict.getDict(); } - - // Get/set position of first byte of stream within the file. - virtual Guint getStart() = 0; - virtual void moveStart(int delta) = 0; - -#ifndef NO_DECRYPTION - // Set decryption for this stream. - virtual void doDecryption(Guchar *fileKey, int keyLength, - int objNum, int objGen); -#endif - -#ifndef NO_DECRYPTION -protected: - - Decrypt *decrypt; -#endif - -private: - - Object dict; -}; - -//------------------------------------------------------------------------ -// FilterStream -// -// This is the base class for all streams that filter another stream. -//------------------------------------------------------------------------ - -class FilterStream: public Stream { -public: - - FilterStream(Stream *strA); - virtual ~FilterStream(); - virtual void close(); - virtual int getPos() { return str->getPos(); } - virtual void setPos(Guint pos, int dir = 0); - virtual BaseStream *getBaseStream() { return str->getBaseStream(); } - virtual Dict *getDict() { return str->getDict(); } - virtual void ignoreLength() { str->ignoreLength(); } - -protected: - - Stream *str; -}; - -//------------------------------------------------------------------------ -// ImageStream -//------------------------------------------------------------------------ - -class ImageStream { -public: - - // Create an image stream object for an image with the specified - // parameters. Note that these are the actual image parameters, - // which may be different from the predictor parameters. - ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA); - - ~ImageStream(); - - // Reset the stream. - void reset(); - - // Gets the next pixel from the stream. <pix> should be able to hold - // at least nComps elements. Returns false at end of file. - GBool getPixel(Guchar *pix); - - // Returns a pointer to the next line of pixels. Returns NULL at - // end of file. - Guchar *getLine(); - - // Skip an entire line from the image. - void skipLine(); - -private: - - Stream *str; // base stream - int width; // pixels per line - int nComps; // components per pixel - int nBits; // bits per component - int nVals; // components per line - Guchar *imgLine; // line buffer - int imgIdx; // current index in imgLine -}; - -//------------------------------------------------------------------------ -// StreamPredictor -//------------------------------------------------------------------------ - -class StreamPredictor { -public: - - // Create a predictor object. Note that the parameters are for the - // predictor, and may not match the actual image parameters. - StreamPredictor(Stream *strA, int predictorA, - int widthA, int nCompsA, int nBitsA); - - GBool isOk() { return ok; } - - ~StreamPredictor(); - - int lookChar(); - int getChar(); - -private: - - GBool getNextLine(); - - Stream *str; // base stream - int predictor; // predictor - int width; // pixels per line - int nComps; // components per pixel - int nBits; // bits per component - int nVals; // components per line - int pixBytes; // bytes per pixel - int rowBytes; // bytes per line - Guchar *predLine; // line buffer - int predIdx; // current index in predLine - GBool ok; -}; - -//------------------------------------------------------------------------ -// FileStream -//------------------------------------------------------------------------ - -#define fileStreamBufSize 256 - -class FileStream: public BaseStream { -public: - - FileStream(FILE *fA, Guint startA, GBool limitedA, - Guint lengthA, Object *dictA); - virtual ~FileStream(); - virtual Stream *makeSubStream(Guint startA, GBool limitedA, - Guint lengthA, Object *dictA); - virtual StreamKind getKind() { return strFile; } - virtual void reset(); - virtual void close(); - virtual int getChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } - virtual int lookChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } - virtual int getPos() { return bufPos + (bufPtr - buf); } - virtual void setPos(Guint pos, int dir = 0); - virtual void ignoreLength() { limited = gFalse; } - virtual Guint getStart() { return start; } - virtual void moveStart(int delta); - -private: - - GBool fillBuf(); - - FILE *f; - Guint start; - GBool limited; - Guint length; - char buf[fileStreamBufSize]; - char *bufPtr; - char *bufEnd; - Guint bufPos; - int savePos; - GBool saved; -}; - -//------------------------------------------------------------------------ -// MemStream -//------------------------------------------------------------------------ - -class MemStream: public BaseStream { -public: - - MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA); - virtual ~MemStream(); - virtual Stream *makeSubStream(Guint start, GBool limited, - Guint lengthA, Object *dictA); - virtual StreamKind getKind() { return strWeird; } - virtual void reset(); - virtual void close(); - virtual int getChar() - { return (bufPtr < bufEnd) ? (*bufPtr++ & 0xff) : EOF; } - virtual int lookChar() - { return (bufPtr < bufEnd) ? (*bufPtr & 0xff) : EOF; } - virtual int getPos() { return (int)(bufPtr - buf); } - virtual void setPos(Guint pos, int dir = 0); - virtual Guint getStart() { return start; } - virtual void moveStart(int delta); -#ifndef NO_DECRYPTION - virtual void doDecryption(Guchar *fileKey, int keyLength, - int objNum, int objGen); -#endif - -private: - - char *buf; - Guint start; - Guint length; - char *bufEnd; - char *bufPtr; - GBool needFree; -}; - -//------------------------------------------------------------------------ -// EmbedStream -// -// This is a special stream type used for embedded streams (inline -// images). It reads directly from the base stream -- after the -// EmbedStream is deleted, reads from the base stream will proceed where -// the BaseStream left off. Note that this is very different behavior -// that creating a new FileStream (using makeSubStream). -//------------------------------------------------------------------------ - -class EmbedStream: public BaseStream { -public: - - EmbedStream(Stream *strA, Object *dictA, GBool limitedA, Guint lengthA); - virtual ~EmbedStream(); - virtual Stream *makeSubStream(Guint start, GBool limitedA, - Guint lengthA, Object *dictA); - virtual StreamKind getKind() { return str->getKind(); } - virtual void reset() {} - virtual int getChar(); - virtual int lookChar(); - virtual int getPos() { return str->getPos(); } - virtual void setPos(Guint pos, int dir = 0); - virtual Guint getStart(); - virtual void moveStart(int delta); - -private: - - Stream *str; - GBool limited; - Guint length; -}; - -//------------------------------------------------------------------------ -// ASCIIHexStream -//------------------------------------------------------------------------ - -class ASCIIHexStream: public FilterStream { -public: - - ASCIIHexStream(Stream *strA); - virtual ~ASCIIHexStream(); - virtual StreamKind getKind() { return strASCIIHex; } - virtual void reset(); - virtual int getChar() - { int c = lookChar(); buf = EOF; return c; } - virtual int lookChar(); - virtual GString *getPSFilter(int psLevel, const char *indent); - virtual GBool isBinary(GBool last = gTrue); - -private: - - int buf; - GBool eof; -}; - -//------------------------------------------------------------------------ -// ASCII85Stream -//------------------------------------------------------------------------ - -class ASCII85Stream: public FilterStream { -public: - - ASCII85Stream(Stream *strA); - virtual ~ASCII85Stream(); - virtual StreamKind getKind() { return strASCII85; } - virtual void reset(); - virtual int getChar() - { int ch = lookChar(); ++index; return ch; } - virtual int lookChar(); - virtual GString *getPSFilter(int psLevel, const char *indent); - virtual GBool isBinary(GBool last = gTrue); - -private: - - int c[5]; - int b[4]; - int index, n; - GBool eof; -}; - -//------------------------------------------------------------------------ -// LZWStream -//------------------------------------------------------------------------ - -class LZWStream: public FilterStream { -public: - - LZWStream(Stream *strA, int predictor, int columns, int colors, - int bits, int earlyA); - virtual ~LZWStream(); - virtual StreamKind getKind() { return strLZW; } - virtual void reset(); - virtual int getChar(); - virtual int lookChar(); - virtual int getRawChar(); - virtual GString *getPSFilter(int psLevel, const char *indent); - virtual GBool isBinary(GBool last = gTrue); - -private: - - StreamPredictor *pred; // predictor - int early; // early parameter - GBool eof; // true if at eof - int inputBuf; // input buffer - int inputBits; // number of bits in input buffer - struct { // decoding table - int length; - int head; - Guchar tail; - } table[4097]; - int nextCode; // next code to be used - int nextBits; // number of bits in next code word - int prevCode; // previous code used in stream - int newChar; // next char to be added to table - Guchar seqBuf[4097]; // buffer for current sequence - int seqLength; // length of current sequence - int seqIndex; // index into current sequence - GBool first; // first code after a table clear - - GBool processNextCode(); - void clearTable(); - int getCode(); -}; - -//------------------------------------------------------------------------ -// RunLengthStream -//------------------------------------------------------------------------ - -class RunLengthStream: public FilterStream { -public: - - RunLengthStream(Stream *strA); - virtual ~RunLengthStream(); - virtual StreamKind getKind() { return strRunLength; } - virtual void reset(); - virtual int getChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } - virtual int lookChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } - virtual GString *getPSFilter(int psLevel, const char *indent); - virtual GBool isBinary(GBool last = gTrue); - -private: - - char buf[128]; // buffer - char *bufPtr; // next char to read - char *bufEnd; // end of buffer - GBool eof; - - GBool fillBuf(); -}; - -//------------------------------------------------------------------------ -// CCITTFaxStream -//------------------------------------------------------------------------ - -struct CCITTCodeTable; - -class CCITTFaxStream: public FilterStream { -public: - - CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA, - GBool byteAlignA, int columnsA, int rowsA, - GBool endOfBlockA, GBool blackA); - virtual ~CCITTFaxStream(); - virtual StreamKind getKind() { return strCCITTFax; } - virtual void reset(); - virtual int getChar() - { int c = lookChar(); buf = EOF; return c; } - virtual int lookChar(); - virtual GString *getPSFilter(int psLevel, const char *indent); - virtual GBool isBinary(GBool last = gTrue); - -private: - - int encoding; // 'K' parameter - GBool endOfLine; // 'EndOfLine' parameter - GBool byteAlign; // 'EncodedByteAlign' parameter - int columns; // 'Columns' parameter - int rows; // 'Rows' parameter - GBool endOfBlock; // 'EndOfBlock' parameter - GBool black; // 'BlackIs1' parameter - GBool eof; // true if at eof - GBool nextLine2D; // true if next line uses 2D encoding - int row; // current row - int inputBuf; // input buffer - int inputBits; // number of bits in input buffer - int *codingLine; // coding line changing elements - int *refLine; // reference line changing elements - int a0i; // index into codingLine - GBool err; // error on current line - int outputBits; // remaining ouput bits - int buf; // character buffer - - void addPixels(int a1, int black); - void addPixelsNeg(int a1, int black); - short getTwoDimCode(); - short getWhiteCode(); - short getBlackCode(); - short lookBits(int n); - void eatBits(int n) { if ((inputBits -= n) < 0) inputBits = 0; } -}; - -//------------------------------------------------------------------------ -// DCTStream -//------------------------------------------------------------------------ - -// DCT component info -struct DCTCompInfo { - int id; // component ID - int hSample, vSample; // horiz/vert sampling resolutions - int quantTable; // quantization table number - int prevDC; // DC coefficient accumulator -}; - -struct DCTScanInfo { - GBool comp[4]; // comp[i] is set if component i is - // included in this scan - int numComps; // number of components in the scan - int dcHuffTable[4]; // DC Huffman table numbers - int acHuffTable[4]; // AC Huffman table numbers - int firstCoeff, lastCoeff; // first and last DCT coefficient - int ah, al; // successive approximation parameters -}; - -// DCT Huffman decoding table -struct DCTHuffTable { - Guchar firstSym[17]; // first symbol for this bit length - Gushort firstCode[17]; // first code for this bit length - Gushort numCodes[17]; // number of codes of this bit length - Guchar sym[256]; // symbols -}; - -class DCTStream: public FilterStream { -public: - - DCTStream(Stream *strA); - virtual ~DCTStream(); - virtual StreamKind getKind() { return strDCT; } - virtual void reset(); - virtual int getChar(); - virtual int lookChar(); - virtual GString *getPSFilter(int psLevel, const char *indent); - virtual GBool isBinary(GBool last = gTrue); - Stream *getRawStream() { return str; } - -private: - - GBool progressive; // set if in progressive mode - GBool interleaved; // set if in interleaved mode - int width, height; // image size - int mcuWidth, mcuHeight; // size of min coding unit, in data units - int bufWidth, bufHeight; // frameBuf size - DCTCompInfo compInfo[4]; // info for each component - DCTScanInfo scanInfo; // info for the current scan - int numComps; // number of components in image - int colorXform; // need YCbCr-to-RGB transform? - GBool gotJFIFMarker; // set if APP0 JFIF marker was present - GBool gotAdobeMarker; // set if APP14 Adobe marker was present - int restartInterval; // restart interval, in MCUs - Guchar quantTables[4][64]; // quantization tables - int numQuantTables; // number of quantization tables - DCTHuffTable dcHuffTables[4]; // DC Huffman tables - DCTHuffTable acHuffTables[4]; // AC Huffman tables - int numDCHuffTables; // number of DC Huffman tables - int numACHuffTables; // number of AC Huffman tables - Guchar *rowBuf[4][32]; // buffer for one MCU (non-progressive mode) - int *frameBuf[4]; // buffer for frame (progressive mode) - int comp, x, y, dy; // current position within image/MCU - int restartCtr; // MCUs left until restart - int restartMarker; // next restart marker - int eobRun; // number of EOBs left in the current run - int inputBuf; // input buffer for variable length codes - int inputBits; // number of valid bits in input buffer - - void restart(); - GBool readMCURow(); - void readScan(); - GBool readDataUnit(DCTHuffTable *dcHuffTable, - DCTHuffTable *acHuffTable, - int *prevDC, int data[64]); - GBool readProgressiveDataUnit(DCTHuffTable *dcHuffTable, - DCTHuffTable *acHuffTable, - int *prevDC, int data[64]); - void decodeImage(); - void transformDataUnit(Guchar *quantTable, - int dataIn[64], Guchar dataOut[64]); - int readHuffSym(DCTHuffTable *table); - int readAmp(int size); - int readBit(); - GBool readHeader(); - GBool readBaselineSOF(); - GBool readProgressiveSOF(); - GBool readScanInfo(); - GBool readQuantTables(); - GBool readHuffmanTables(); - GBool readRestartInterval(); - GBool readJFIFMarker(); - GBool readAdobeMarker(); - GBool readTrailer(); - int readMarker(); - int read16(); -}; - -//------------------------------------------------------------------------ -// FlateStream -//------------------------------------------------------------------------ - -#define flateWindow 32768 // buffer size -#define flateMask (flateWindow-1) -#define flateMaxHuffman 15 // max Huffman code length -#define flateMaxCodeLenCodes 19 // max # code length codes -#define flateMaxLitCodes 288 // max # literal codes -#define flateMaxDistCodes 30 // max # distance codes - -// Huffman code table entry -struct FlateCode { - Gushort len; // code length, in bits - Gushort val; // value represented by this code -}; - -struct FlateHuffmanTab { - FlateCode *codes; - int maxLen; -}; - -// Decoding info for length and distance code words -struct FlateDecode { - int bits; // # extra bits - int first; // first length/distance -}; - -class FlateStream: public FilterStream { -public: - - FlateStream(Stream *strA, int predictor, int columns, - int colors, int bits); - virtual ~FlateStream(); - virtual StreamKind getKind() { return strFlate; } - virtual void reset(); - virtual int getChar(); - virtual int lookChar(); - virtual int getRawChar(); - virtual GString *getPSFilter(int psLevel, const char *indent); - virtual GBool isBinary(GBool last = gTrue); - -private: - - StreamPredictor *pred; // predictor - Guchar buf[flateWindow]; // output data buffer - int index; // current index into output buffer - int remain; // number valid bytes in output buffer - int codeBuf; // input buffer - int codeSize; // number of bits in input buffer - int // literal and distance code lengths - codeLengths[flateMaxLitCodes + flateMaxDistCodes]; - FlateHuffmanTab litCodeTab; // literal code table - FlateHuffmanTab distCodeTab; // distance code table - GBool compressedBlock; // set if reading a compressed block - int blockLen; // remaining length of uncompressed block - GBool endOfBlock; // set when end of block is reached - GBool eof; // set when end of stream is reached - - static int // code length code reordering - codeLenCodeMap[flateMaxCodeLenCodes]; - static FlateDecode // length decoding info - lengthDecode[flateMaxLitCodes-257]; - static FlateDecode // distance decoding info - distDecode[flateMaxDistCodes]; - - void readSome(); - GBool startBlock(); - void loadFixedCodes(); - GBool readDynamicCodes(); - void compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab); - int getHuffmanCodeWord(FlateHuffmanTab *tab); - int getCodeWord(int bits); -}; - -//------------------------------------------------------------------------ -// EOFStream -//------------------------------------------------------------------------ - -class EOFStream: public FilterStream { -public: - - EOFStream(Stream *strA); - virtual ~EOFStream(); - virtual StreamKind getKind() { return strWeird; } - virtual void reset() {} - virtual int getChar() { return EOF; } - virtual int lookChar() { return EOF; } - virtual GString *getPSFilter(int psLevel, const char *indent) { return NULL; } - virtual GBool isBinary(GBool last = gTrue) { return gFalse; } -}; - -//------------------------------------------------------------------------ -// FixedLengthEncoder -//------------------------------------------------------------------------ - -class FixedLengthEncoder: public FilterStream { -public: - - FixedLengthEncoder(Stream *strA, int lengthA); - ~FixedLengthEncoder(); - virtual StreamKind getKind() { return strWeird; } - virtual void reset(); - virtual int getChar(); - virtual int lookChar(); - virtual GString *getPSFilter(int psLevel, const char *indent) { return NULL; } - virtual GBool isBinary(GBool last = gTrue); - virtual GBool isEncoder() { return gTrue; } - -private: - - int length; - int count; -}; - -//------------------------------------------------------------------------ -// ASCIIHexEncoder -//------------------------------------------------------------------------ - -class ASCIIHexEncoder: public FilterStream { -public: - - ASCIIHexEncoder(Stream *strA); - virtual ~ASCIIHexEncoder(); - virtual StreamKind getKind() { return strWeird; } - virtual void reset(); - virtual int getChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } - virtual int lookChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } - virtual GString *getPSFilter(int psLevel, const char *indent) { return NULL; } - virtual GBool isBinary(GBool last = gTrue) { return gFalse; } - virtual GBool isEncoder() { return gTrue; } - -private: - - char buf[4]; - char *bufPtr; - char *bufEnd; - int lineLen; - GBool eof; - - GBool fillBuf(); -}; - -//------------------------------------------------------------------------ -// ASCII85Encoder -//------------------------------------------------------------------------ - -class ASCII85Encoder: public FilterStream { -public: - - ASCII85Encoder(Stream *strA); - virtual ~ASCII85Encoder(); - virtual StreamKind getKind() { return strWeird; } - virtual void reset(); - virtual int getChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } - virtual int lookChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } - virtual GString *getPSFilter(int psLevel, const char *indent) { return NULL; } - virtual GBool isBinary(GBool last = gTrue) { return gFalse; } - virtual GBool isEncoder() { return gTrue; } - -private: - - char buf[8]; - char *bufPtr; - char *bufEnd; - int lineLen; - GBool eof; - - GBool fillBuf(); -}; - -//------------------------------------------------------------------------ -// RunLengthEncoder -//------------------------------------------------------------------------ - -class RunLengthEncoder: public FilterStream { -public: - - RunLengthEncoder(Stream *strA); - virtual ~RunLengthEncoder(); - virtual StreamKind getKind() { return strWeird; } - virtual void reset(); - virtual int getChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } - virtual int lookChar() - { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } - virtual GString *getPSFilter(int psLevel, const char *indent) { return NULL; } - virtual GBool isBinary(GBool last = gTrue) { return gTrue; } - virtual GBool isEncoder() { return gTrue; } - -private: - - char buf[131]; - char *bufPtr; - char *bufEnd; - char *nextEnd; - GBool eof; - - GBool fillBuf(); -}; - -#endif diff --git a/src/plugins/pdf/XRef.cc b/src/plugins/pdf/XRef.cc @@ -1,965 +0,0 @@ -//======================================================================== -// -// XRef.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <ctype.h> -#include "gmem.h" -#include "Object.h" -#include "Stream.h" -#include "Lexer.h" -#include "Parser.h" -#include "Dict.h" -#ifndef NO_DECRYPTION -#include "Decrypt.h" -#endif -#include "Error.h" -#include "ErrorCodes.h" -#include "XRef.h" - -//------------------------------------------------------------------------ - -#define xrefSearchSize 1024 // read this many bytes at end of file - // to look for 'startxref' - -#ifndef NO_DECRYPTION -//------------------------------------------------------------------------ -// Permission bits -//------------------------------------------------------------------------ - -#define permPrint (1<<2) -#define permChange (1<<3) -#define permCopy (1<<4) -#define permNotes (1<<5) -#define defPermFlags 0xfffc -#endif - -//------------------------------------------------------------------------ -// ObjectStream -//------------------------------------------------------------------------ - -class ObjectStream { -public: - - // Create an object stream, using object number <objStrNum>, - // generation 0. - ObjectStream(XRef *xref, int objStrNumA); - - ~ObjectStream(); - - // Return the object number of this object stream. - int getObjStrNum() { return objStrNum; } - - // Get the <objIdx>th object from this stream, which should be - // object number <objNum>, generation 0. - Object *getObject(int objIdx, int objNum, Object *obj); - -private: - - int objStrNum; // object number of the object stream - int nObjects; // number of objects in the stream - Object *objs; // the objects (length = nObjects) - int *objNums; // the object numbers (length = nObjects) -}; - -ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { - Stream *str; - Parser *parser; - int *offsets; - Object objStr, obj1, obj2; - int first, i; - - objStrNum = objStrNumA; - nObjects = 0; - objs = NULL; - objNums = NULL; - - if (!xref->fetch(objStrNum, 0, &objStr)->isStream()) { - goto err1; - } - - if (!objStr.streamGetDict()->lookup("N", &obj1)->isInt()) { - obj1.free(); - goto err1; - } - nObjects = obj1.getInt(); - obj1.free(); - if (nObjects == 0) { - goto err1; - } - - if (!objStr.streamGetDict()->lookup("First", &obj1)->isInt()) { - obj1.free(); - goto err1; - } - first = obj1.getInt(); - obj1.free(); - - objs = new Object[nObjects]; - objNums = (int *)gmalloc(nObjects * sizeof(int)); - offsets = (int *)gmalloc(nObjects * sizeof(int)); - - // parse the header: object numbers and offsets - objStr.streamReset(); - obj1.initNull(); - str = new EmbedStream(objStr.getStream(), &obj1, gTrue, first); - parser = new Parser(xref, new Lexer(xref, str)); - for (i = 0; i < nObjects; ++i) { - parser->getObj(&obj1); - parser->getObj(&obj2); - if (!obj1.isInt() || !obj2.isInt()) { - obj1.free(); - obj2.free(); - delete parser; - gfree(offsets); - goto err1; - } - objNums[i] = obj1.getInt(); - offsets[i] = obj2.getInt(); - obj1.free(); - obj2.free(); - } - while (str->getChar() != EOF) ; - delete parser; - - // skip to the first object - this shouldn't be necessary because - // the First key is supposed to be equal to offsets[0], but just in - // case... - for (i = first; i < offsets[0]; ++i) { - objStr.getStream()->getChar(); - } - - // parse the objects - for (i = 0; i < nObjects; ++i) { - obj1.initNull(); - if (i == nObjects - 1) { - str = new EmbedStream(objStr.getStream(), &obj1, gFalse, 0); - } else { - str = new EmbedStream(objStr.getStream(), &obj1, gTrue, - offsets[i+1] - offsets[i]); - } - parser = new Parser(xref, new Lexer(xref, str)); - parser->getObj(&objs[i]); - while (str->getChar() != EOF) ; - delete parser; - } - - gfree(offsets); - - err1: - objStr.free(); - return; -} - -ObjectStream::~ObjectStream() { - int i; - - if (objs) { - for (i = 0; i < nObjects; ++i) { - objs[i].free(); - } - delete[] objs; - } - gfree(objNums); -} - -Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) { - if (objIdx < 0 || objIdx >= nObjects || objNum != objNums[objIdx]) { - return obj->initNull(); - } - return objs[objIdx].copy(obj); -} - -//------------------------------------------------------------------------ -// XRef -//------------------------------------------------------------------------ - -XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { - Guint pos; - Object obj; - - ok = gTrue; - errCode = errNone; - size = 0; - entries = NULL; - streamEnds = NULL; - streamEndsLen = 0; - objStr = NULL; - - // read the trailer - str = strA; - start = str->getStart(); - pos = getStartXref(); - - // if there was a problem with the 'startxref' position, try to - // reconstruct the xref table - if (pos == 0) { - if (!(ok = constructXRef())) { - errCode = errDamaged; - return; - } - - // read the xref table - } else { - while (readXRef(&pos)) ; - - // if there was a problem with the xref table, - // try to reconstruct it - if (!ok) { - if (!(ok = constructXRef())) { - errCode = errDamaged; - return; - } - } - } - - // get the root dictionary (catalog) object - trailerDict.dictLookupNF("Root", &obj); - if (obj.isRef()) { - rootNum = obj.getRefNum(); - rootGen = obj.getRefGen(); - obj.free(); - } else { - obj.free(); - if (!(ok = constructXRef())) { - errCode = errDamaged; - return; - } - } - - // now set the trailer dictionary's xref pointer so we can fetch - // indirect objects from it - trailerDict.getDict()->setXRef(this); - - // check for encryption -#ifndef NO_DECRYPTION - encrypted = gFalse; -#endif - if (checkEncrypted(ownerPassword, userPassword)) { - ok = gFalse; - errCode = errEncrypted; - return; - } -} - -XRef::~XRef() { - gfree(entries); - trailerDict.free(); - if (streamEnds) { - gfree(streamEnds); - } - if (objStr) { - delete objStr; - } -} - -// Read the 'startxref' position. -Guint XRef::getStartXref() { - char buf[xrefSearchSize+1]; - char *p; - int c, n, i; - - // read last xrefSearchSize bytes - str->setPos(xrefSearchSize, -1); - for (n = 0; n < xrefSearchSize; ++n) { - if ((c = str->getChar()) == EOF) { - break; - } - buf[n] = c; - } - buf[n] = '\0'; - - // find startxref - for (i = n - 9; i >= 0; --i) { - if (!strncmp(&buf[i], "startxref", 9)) { - break; - } - } - if (i < 0) { - return 0; - } - for (p = &buf[i+9]; isspace(*p); ++p) ; - lastXRefPos = strToUnsigned(p); - - return lastXRefPos; -} - -// Read one xref table section. Also reads the associated trailer -// dictionary, and returns the prev pointer (if any). -GBool XRef::readXRef(Guint *pos) { - Parser *parser; - Object obj; - GBool more; - - // start up a parser, parse one token - obj.initNull(); - parser = new Parser(NULL, - new Lexer(NULL, - str->makeSubStream(start + *pos, gFalse, 0, &obj))); - parser->getObj(&obj); - - // parse an old-style xref table - if (obj.isCmd("xref")) { - obj.free(); - more = readXRefTable(parser, pos); - - // parse an xref stream - } else if (obj.isInt()) { - obj.free(); - if (!parser->getObj(&obj)->isInt()) { - goto err1; - } - obj.free(); - if (!parser->getObj(&obj)->isCmd("obj")) { - goto err1; - } - obj.free(); - if (!parser->getObj(&obj)->isStream()) { - goto err1; - } - more = readXRefStream(obj.getStream(), pos); - obj.free(); - - } else { - goto err1; - } - - delete parser; - return more; - - err1: - obj.free(); - delete parser; - ok = gFalse; - return gFalse; -} - -GBool XRef::readXRefTable(Parser *parser, Guint *pos) { - XRefEntry entry; - GBool more; - Object obj, obj2; - Guint pos2; - int first, n, newSize, i; - - while (1) { - parser->getObj(&obj); - if (obj.isCmd("trailer")) { - obj.free(); - break; - } - if (!obj.isInt()) { - goto err1; - } - first = obj.getInt(); - obj.free(); - if (!parser->getObj(&obj)->isInt()) { - goto err1; - } - n = obj.getInt(); - obj.free(); - if (first + n > size) { - for (newSize = size ? 2 * size : 1024; - first + n > newSize; - newSize <<= 1) ; - entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); - for (i = size; i < newSize; ++i) { - entries[i].offset = 0xffffffff; - entries[i].type = xrefEntryFree; - } - size = newSize; - } - for (i = first; i < first + n; ++i) { - if (!parser->getObj(&obj)->isInt()) { - goto err1; - } - entry.offset = (Guint)obj.getInt(); - obj.free(); - if (!parser->getObj(&obj)->isInt()) { - goto err1; - } - entry.gen = obj.getInt(); - obj.free(); - parser->getObj(&obj); - if (obj.isCmd("n")) { - entry.type = xrefEntryUncompressed; - } else if (obj.isCmd("f")) { - entry.type = xrefEntryFree; - } else { - goto err1; - } - obj.free(); - if (entries[i].offset == 0xffffffff) { - entries[i] = entry; - // PDF files of patents from the IBM Intellectual Property - // Network have a bug: the xref table claims to start at 1 - // instead of 0. - if (i == 1 && first == 1 && - entries[1].offset == 0 && entries[1].gen == 65535 && - entries[1].type == xrefEntryFree) { - i = first = 0; - entries[0] = entries[1]; - entries[1].offset = 0xffffffff; - } - } - } - } - - // read the trailer dictionary - if (!parser->getObj(&obj)->isDict()) { - goto err1; - } - - // get the 'Prev' pointer - obj.getDict()->lookupNF("Prev", &obj2); - if (obj2.isInt()) { - *pos = (Guint)obj2.getInt(); - more = gTrue; - } else if (obj2.isRef()) { - // certain buggy PDF generators generate "/Prev NNN 0 R" instead - // of "/Prev NNN" - *pos = (Guint)obj2.getRefNum(); - more = gTrue; - } else { - more = gFalse; - } - obj2.free(); - - // save the first trailer dictionary - if (trailerDict.isNone()) { - obj.copy(&trailerDict); - } - - // check for an 'XRefStm' key - if (obj.getDict()->lookup("XRefStm", &obj2)->isInt()) { - pos2 = obj2.getInt(); - readXRef(&pos2); - if (!ok) { - goto err1; - } - } - obj2.free(); - - obj.free(); - return more; - - err1: - obj.free(); - ok = gFalse; - return gFalse; -} - -GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) { - Dict *dict; - int w[3]; - GBool more; - Object obj, obj2, idx; - int newSize, first, n, i; - - dict = xrefStr->getDict(); - - if (!dict->lookupNF("Size", &obj)->isInt()) { - goto err1; - } - newSize = obj.getInt(); - obj.free(); - if (newSize > size) { - entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); - for (i = size; i < newSize; ++i) { - entries[i].offset = 0xffffffff; - entries[i].type = xrefEntryFree; - } - size = newSize; - } - - if (!dict->lookupNF("W", &obj)->isArray() || - obj.arrayGetLength() < 3) { - goto err1; - } - for (i = 0; i < 3; ++i) { - if (!obj.arrayGet(i, &obj2)->isInt()) { - obj2.free(); - goto err1; - } - w[i] = obj2.getInt(); - obj2.free(); - } - obj.free(); - - xrefStr->reset(); - dict->lookupNF("Index", &idx); - if (idx.isArray()) { - for (i = 0; i+1 < idx.arrayGetLength(); i += 2) { - if (!idx.arrayGet(i, &obj)->isInt()) { - idx.free(); - goto err1; - } - first = obj.getInt(); - obj.free(); - if (!idx.arrayGet(i+1, &obj)->isInt()) { - idx.free(); - goto err1; - } - n = obj.getInt(); - obj.free(); - if (!readXRefStreamSection(xrefStr, w, first, n)) { - idx.free(); - goto err0; - } - } - } else { - if (!readXRefStreamSection(xrefStr, w, 0, size)) { - idx.free(); - goto err0; - } - } - idx.free(); - - dict->lookupNF("Prev", &obj); - if (obj.isInt()) { - *pos = (Guint)obj.getInt(); - more = gTrue; - } else { - more = gFalse; - } - obj.free(); - if (trailerDict.isNone()) { - trailerDict.initDict(dict); - } - - return more; - - err1: - obj.free(); - err0: - ok = gFalse; - return gFalse; -} - -GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) { - Guint offset; - int type, gen, c, newSize, i, j; - - if (first + n > size) { - for (newSize = size ? 2 * size : 1024; - first + n > newSize; - newSize <<= 1) ; - entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); - for (i = size; i < newSize; ++i) { - entries[i].offset = 0xffffffff; - entries[i].type = xrefEntryFree; - } - size = newSize; - } - for (i = first; i < first + n; ++i) { - if (w[0] == 0) { - type = 1; - } else { - for (type = 0, j = 0; j < w[0]; ++j) { - if ((c = xrefStr->getChar()) == EOF) { - return gFalse; - } - type = (type << 8) + c; - } - } - for (offset = 0, j = 0; j < w[1]; ++j) { - if ((c = xrefStr->getChar()) == EOF) { - return gFalse; - } - offset = (offset << 8) + c; - } - for (gen = 0, j = 0; j < w[2]; ++j) { - if ((c = xrefStr->getChar()) == EOF) { - return gFalse; - } - gen = (gen << 8) + c; - } - switch (type) { - case 0: - entries[i].offset = offset; - entries[i].gen = gen; - entries[i].type = xrefEntryFree; - break; - case 1: - entries[i].offset = offset; - entries[i].gen = gen; - entries[i].type = xrefEntryUncompressed; - break; - case 2: - entries[i].offset = offset; - entries[i].gen = gen; - entries[i].type = xrefEntryCompressed; - break; - default: - return gFalse; - } - } - - return gTrue; -} - -// Attempt to construct an xref table for a damaged file. -GBool XRef::constructXRef() { - Parser *parser; - Object newTrailerDict, obj; - char buf[256]; - Guint pos; - int num, gen; - int newSize; - int streamEndsSize; - char *p; - int i; - GBool gotRoot; - - gfree(entries); - size = 0; - entries = NULL; - - error(0, "PDF file is damaged - attempting to reconstruct xref table..."); - gotRoot = gFalse; - streamEndsLen = streamEndsSize = 0; - - str->reset(); - while (1) { - pos = str->getPos(); - if (!str->getLine(buf, 256)) { - break; - } - p = buf; - - // got trailer dictionary - if (!strncmp(p, "trailer", 7)) { - obj.initNull(); - parser = new Parser(NULL, - new Lexer(NULL, - str->makeSubStream(start + pos + 7, gFalse, 0, &obj))); - parser->getObj(&newTrailerDict); - if (newTrailerDict.isDict()) { - newTrailerDict.dictLookupNF("Root", &obj); - if (obj.isRef()) { - rootNum = obj.getRefNum(); - rootGen = obj.getRefGen(); - if (!trailerDict.isNone()) { - trailerDict.free(); - } - newTrailerDict.copy(&trailerDict); - gotRoot = gTrue; - } - obj.free(); - } - newTrailerDict.free(); - delete parser; - - // look for object - } else if (isdigit(*p)) { - num = atoi(p); - do { - ++p; - } while (*p && isdigit(*p)); - if (isspace(*p)) { - do { - ++p; - } while (*p && isspace(*p)); - if (isdigit(*p)) { - gen = atoi(p); - do { - ++p; - } while (*p && isdigit(*p)); - if (isspace(*p)) { - do { - ++p; - } while (*p && isspace(*p)); - if (!strncmp(p, "obj", 3)) { - if (num >= size) { - newSize = (num + 1 + 255) & ~255; - entries = (XRefEntry *) - grealloc(entries, newSize * sizeof(XRefEntry)); - for (i = size; i < newSize; ++i) { - entries[i].offset = 0xffffffff; - entries[i].type = xrefEntryFree; - } - size = newSize; - } - if (entries[num].type == xrefEntryFree || - gen >= entries[num].gen) { - entries[num].offset = pos - start; - entries[num].gen = gen; - entries[num].type = xrefEntryUncompressed; - } - } - } - } - } - - } else if (!strncmp(p, "endstream", 9)) { - if (streamEndsLen == streamEndsSize) { - streamEndsSize += 64; - streamEnds = (Guint *)grealloc(streamEnds, - streamEndsSize * sizeof(int)); - } - streamEnds[streamEndsLen++] = pos; - } - } - - if (gotRoot) - return gTrue; - - error(-1, "Couldn't find trailer dictionary"); - return gFalse; -} - -#ifndef NO_DECRYPTION -GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) { - Object encrypt, filterObj, versionObj, revisionObj, lengthObj; - Object ownerKey, userKey, permissions, fileID, fileID1; - GBool encrypted1; - GBool ret; - - keyLength = 0; - encVersion = encRevision = 0; - ret = gFalse; - - permFlags = defPermFlags; - ownerPasswordOk = gFalse; - trailerDict.dictLookup("Encrypt", &encrypt); - if ((encrypted1 = encrypt.isDict())) { - ret = gTrue; - encrypt.dictLookup("Filter", &filterObj); - if (filterObj.isName("Standard")) { - encrypt.dictLookup("V", &versionObj); - encrypt.dictLookup("R", &revisionObj); - encrypt.dictLookup("Length", &lengthObj); - encrypt.dictLookup("O", &ownerKey); - encrypt.dictLookup("U", &userKey); - encrypt.dictLookup("P", &permissions); - trailerDict.dictLookup("ID", &fileID); - if (versionObj.isInt() && - revisionObj.isInt() && - ownerKey.isString() && ownerKey.getString()->getLength() == 32 && - userKey.isString() && userKey.getString()->getLength() == 32 && - permissions.isInt() && - fileID.isArray()) { - encVersion = versionObj.getInt(); - encRevision = revisionObj.getInt(); - if (lengthObj.isInt()) { - keyLength = lengthObj.getInt() / 8; - } else { - keyLength = 5; - } - if (keyLength > 16) { - keyLength = 16; - } - permFlags = permissions.getInt(); - if (encVersion >= 1 && encVersion <= 2 && - encRevision >= 2 && encRevision <= 3) { - fileID.arrayGet(0, &fileID1); - if (fileID1.isString()) { - if (Decrypt::makeFileKey(encVersion, encRevision, keyLength, - ownerKey.getString(), userKey.getString(), - permFlags, fileID1.getString(), - ownerPassword, userPassword, fileKey, - &ownerPasswordOk)) { - if (ownerPassword && !ownerPasswordOk) { - error(-1, "Incorrect owner password"); - } - ret = gFalse; - } else { - error(-1, "Incorrect password"); - } - } else { - error(-1, "Weird encryption info"); - } - fileID1.free(); - } else { - error(-1, "Unsupported version/revision (%d/%d) of Standard security handler", - encVersion, encRevision); - } - } else { - error(-1, "Weird encryption info"); - } - fileID.free(); - permissions.free(); - userKey.free(); - ownerKey.free(); - lengthObj.free(); - revisionObj.free(); - versionObj.free(); - } else { - error(-1, "Unknown security handler '%s'", - filterObj.isName() ? filterObj.getName() : "???"); - } - filterObj.free(); - } - encrypt.free(); - - // this flag has to be set *after* we read the O/U/P strings - encrypted = encrypted1; - - return ret; -} -#else -GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) { - Object obj; - GBool encrypted; - - trailerDict.dictLookup("Encrypt", &obj); - if ((encrypted = !obj.isNull())) { - error(-1, "PDF file is encrypted and this version of the Xpdf tools"); - error(-1, "was built without decryption support."); - } - obj.free(); - return encrypted; -} -#endif - -GBool XRef::okToPrint(GBool ignoreOwnerPW) { -#ifndef NO_DECRYPTION - return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permPrint); -#else - return gTrue; -#endif -} - -GBool XRef::okToChange(GBool ignoreOwnerPW) { -#ifndef NO_DECRYPTION - return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permChange); -#else - return gTrue; -#endif -} - -GBool XRef::okToCopy(GBool ignoreOwnerPW) { -#ifndef NO_DECRYPTION - return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permCopy); -#else - return gTrue; -#endif -} - -GBool XRef::okToAddNotes(GBool ignoreOwnerPW) { -#ifndef NO_DECRYPTION - return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permNotes); -#else - return gTrue; -#endif -} - -Object *XRef::fetch(int num, int gen, Object *obj) { - XRefEntry *e; - Parser *parser; - Object obj1, obj2, obj3; - - // check for bogus ref - this can happen in corrupted PDF files - if (num < 0 || num >= size) { - goto err; - } - - e = &entries[num]; - switch (e->type) { - - case xrefEntryUncompressed: - if (e->gen != gen) { - goto err; - } - obj1.initNull(); - parser = new Parser(this, - new Lexer(this, - str->makeSubStream(start + e->offset, gFalse, 0, &obj1))); - parser->getObj(&obj1); - parser->getObj(&obj2); - parser->getObj(&obj3); - if (!obj1.isInt() || obj1.getInt() != num || - !obj2.isInt() || obj2.getInt() != gen || - !obj3.isCmd("obj")) { - delete parser; - goto err; - } -#ifndef NO_DECRYPTION - parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, keyLength, - num, gen); -#else - parser->getObj(obj); -#endif - obj1.free(); - obj2.free(); - obj3.free(); - delete parser; - break; - - case xrefEntryCompressed: - if (gen != 0) { - goto err; - } - if (!objStr || objStr->getObjStrNum() != (int)e->offset) { - if (objStr) { - delete objStr; - } - objStr = new ObjectStream(this, e->offset); - } - objStr->getObject(e->gen, num, obj); - break; - - default: - goto err; - } - - return obj; - - err: - return obj->initNull(); -} - -Object *XRef::getDocInfo(Object *obj) { - return trailerDict.dictLookup("Info", obj); -} - -// Added for the pdftex project. -Object *XRef::getDocInfoNF(Object *obj) { - return trailerDict.dictLookupNF("Info", obj); -} - -GBool XRef::getStreamEnd(Guint streamStart, Guint *streamEnd) { - int a, b, m; - - if (streamEndsLen == 0 || - streamStart > streamEnds[streamEndsLen - 1]) { - return gFalse; - } - - a = -1; - b = streamEndsLen - 1; - // invariant: streamEnds[a] < streamStart <= streamEnds[b] - while (b - a > 1) { - m = (a + b) / 2; - if (streamStart <= streamEnds[m]) { - b = m; - } else { - a = m; - } - } - *streamEnd = streamEnds[b]; - return gTrue; -} - -Guint XRef::strToUnsigned(char *s) { - Guint x; - char *p; - int i; - - x = 0; - for (p = s, i = 0; *p && isdigit(*p) && i < 10; ++p, ++i) { - x = 10 * x + (*p - '0'); - } - return x; -} diff --git a/src/plugins/pdf/XRef.h b/src/plugins/pdf/XRef.h @@ -1,135 +0,0 @@ -//======================================================================== -// -// XRef.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef XREF_H -#define XREF_H - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include "gtypes.h" -#include "Object.h" - -class Dict; -class Stream; -class Parser; -class ObjectStream; - -//------------------------------------------------------------------------ -// XRef -//------------------------------------------------------------------------ - -enum XRefEntryType { - xrefEntryFree, - xrefEntryUncompressed, - xrefEntryCompressed -}; - -struct XRefEntry { - Guint offset; - int gen; - XRefEntryType type; -}; - -class XRef { -public: - - // Constructor. Read xref table from stream. - XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword); - - // Destructor. - ~XRef(); - - // Is xref table valid? - GBool isOk() { return ok; } - - // Get the error code (if isOk() returns false). - int getErrorCode() { return errCode; } - - // Is the file encrypted? -#ifndef NO_DECRYPTION - GBool isEncrypted() { return encrypted; } -#else - GBool isEncrypted() { return gFalse; } -#endif - - // Check various permissions. - GBool okToPrint(GBool ignoreOwnerPW = gFalse); - GBool okToChange(GBool ignoreOwnerPW = gFalse); - GBool okToCopy(GBool ignoreOwnerPW = gFalse); - GBool okToAddNotes(GBool ignoreOwnerPW = gFalse); - - // Get catalog object. - Object *getCatalog(Object *obj) { return fetch(rootNum, rootGen, obj); } - - // Fetch an indirect reference. - Object *fetch(int num, int gen, Object *obj); - - // Return the document's Info dictionary (if any). - Object *getDocInfo(Object *obj); - Object *getDocInfoNF(Object *obj); - - // Return the number of objects in the xref table. - int getNumObjects() { return size; } - - // Return the offset of the last xref table. - Guint getLastXRefPos() { return lastXRefPos; } - - // Return the catalog object reference. - int getRootNum() { return rootNum; } - int getRootGen() { return rootGen; } - - // Get end position for a stream in a damaged file. - // Returns false if unknown or file is not damaged. - GBool getStreamEnd(Guint streamStart, Guint *streamEnd); - - // Direct access. - int getSize() { return size; } - XRefEntry *getEntry(int i) { return &entries[i]; } - Object *getTrailerDict() { return &trailerDict; } - -private: - - BaseStream *str; // input stream - Guint start; // offset in file (to allow for garbage - // at beginning of file) - XRefEntry *entries; // xref entries - int size; // size of <entries> array - int rootNum, rootGen; // catalog dict - GBool ok; // true if xref table is valid - int errCode; // error code (if <ok> is false) - Object trailerDict; // trailer dictionary - Guint lastXRefPos; // offset of last xref table - Guint *streamEnds; // 'endstream' positions - only used in - // damaged files - int streamEndsLen; // number of valid entries in streamEnds - ObjectStream *objStr; // cached object stream -#ifndef NO_DECRYPTION - GBool encrypted; // true if file is encrypted - int encVersion; // encryption algorithm - int encRevision; // security handler revision - int keyLength; // length of key, in bytes - int permFlags; // permission bits - Guchar fileKey[16]; // file decryption key - GBool ownerPasswordOk; // true if owner password is correct -#endif - - Guint getStartXref(); - GBool readXRef(Guint *pos); - GBool readXRefTable(Parser *parser, Guint *pos); - GBool readXRefStreamSection(Stream *xrefStr, int *w, int first, int n); - GBool readXRefStream(Stream *xrefStr, Guint *pos); - GBool constructXRef(); - GBool checkEncrypted(GString *ownerPassword, GString *userPassword); - Guint strToUnsigned(char *s); -}; - -#endif diff --git a/src/plugins/pdf/aconf.h b/src/plugins/pdf/aconf.h @@ -1,92 +0,0 @@ -/* - * aconf.h - * - * Copyright 2002-2003 Glyph & Cog, LLC - */ - -#ifndef ACONF_H -#define ACONF_H - -#include <aconf2.h> - -/* - * Use A4 paper size instead of Letter for PostScript output. - */ -#undef A4_PAPER - -/* - * Do not allow text selection. - */ -#undef NO_TEXT_SELECT - -/* - * Include support for OPI comments. - */ -#undef OPI_SUPPORT - -/* - * Enable multithreading support. - */ -#undef MULTITHREADED - -/* - * Enable word list support. - */ -#undef TEXTOUT_WORD_LIST - -/* - * Directory with the Xpdf app-defaults file. - */ -#undef APPDEFDIR - -/* - * Full path for the system-wide xpdfrc file. - */ -#undef SYSTEM_XPDFRC - -/* - * Various include files and functions. - */ -#undef HAVE_DIRENT_H -#undef HAVE_SYS_NDIR_H -#undef HAVE_SYS_DIR_H -#undef HAVE_NDIR_H -#undef HAVE_SYS_SELECT_H -#undef HAVE_SYS_BSDTYPES_H -#undef HAVE_STRINGS_H -#undef HAVE_BSTRING_H -#undef HAVE_POPEN -#undef HAVE_MKSTEMP -#undef HAVE_MKSTEMPS -#undef SELECT_TAKES_INT -#undef HAVE_FSEEKO -#undef HAVE_FSEEK64 -#undef _FILE_OFFSET_BITS -#undef _LARGE_FILES -#undef _LARGEFILE_SOURCE -#undef HAVE_XTAPPSETEXITFLAG - -/* - * This is defined if using libXpm. - */ -#undef HAVE_X11_XPM_H - -/* - * This is defined if using t1lib. - */ -#undef HAVE_T1LIB_H - -/* - * One of these is defined if using FreeType 2. - */ -#undef HAVE_FREETYPE_H -#undef HAVE_FREETYPE_FREETYPE_H - -/* - * This is defined if using libpaper. - */ -#undef HAVE_PAPER_H - -#define PDF_PARSER_ONLY 1 - -#endif diff --git a/src/plugins/pdf/aconf2.h b/src/plugins/pdf/aconf2.h @@ -1,38 +0,0 @@ -/* - * aconf2.h - * - * This gets included by aconf.h, and contains miscellaneous global - * settings not directly controlled by autoconf. This is a separate - * file because otherwise the configure script will munge any - * #define/#undef constructs. - * - * Copyright 2002-2003 Glyph & Cog, LLC - */ - -#ifndef ACONF2_H -#define ACONF2_H - -/* - * This controls the use of the interface/implementation pragmas. - */ -#ifdef __GNUC__ -#define USE_GCC_PRAGMAS -#endif -/* There is a bug in the version of gcc which ships with MacOS X 10.2 */ -#if defined(__APPLE__) && defined(__MACH__) -# include <AvailabilityMacros.h> -#endif -#ifdef MAC_OS_X_VERSION_MAX_ALLOWED -# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_2 -# undef USE_GCC_PRAGMAS -# endif -#endif - -/* - * Make sure WIN32 is defined if appropriate. - */ -#if defined(_WIN32) && !defined(WIN32) -# define WIN32 -#endif - -#endif diff --git a/src/plugins/pdf/gfile.cc b/src/plugins/pdf/gfile.cc @@ -1,387 +0,0 @@ -//======================================================================== -// -// gfile.cc -// -// Miscellaneous file and directory name manipulation. -// -// Copyright 1996 Derek B. Noonburg -// -//======================================================================== - -#include "config.h" -#ifdef CYGWIN -#define WIN32 1 -#endif -#ifndef WIN32 -#include <pwd.h> -#endif -#include "GString.h" -#include "gfile.h" -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -// Some systems don't define this, so just make it something reasonably -// large. -#ifndef PATH_MAX -#define PATH_MAX 1024 -#endif - -//------------------------------------------------------------------------ - -GString *getHomeDir() { -#if defined(WIN32) - //---------- OS/2+EMX and Win32 ---------- - char *s; - GString *ret; - - if ((s = getenv("HOME"))) - ret = new GString(s); - else - ret = new GString("."); - return ret; - -#else - //---------- Unix ---------- - char *s; - struct passwd *pw; - GString *ret; - - if ((s = getenv("HOME"))) { - ret = new GString(s); - } else { - if ((s = getenv("USER"))) - pw = getpwnam(s); - else - pw = getpwuid(getuid()); - if (pw) - ret = new GString(pw->pw_dir); - else - ret = new GString("."); - } - return ret; -#endif -} - -GString *getCurrentDir() { - char buf[PATH_MAX+1]; - -#if defined(WIN32) - if (GetCurrentDirectory(sizeof(buf), buf)) -#else - if (getcwd(buf, sizeof(buf))) -#endif - return new GString(buf); - return new GString(); -} - -GString *appendToPath(GString *path, const char *fileName) { -#if defined(WIN32) - //---------- Win32 ---------- - GString *tmp; - char buf[256]; - char *fp; - - tmp = new GString(path); - tmp->append('/'); - tmp->append(fileName); - GetFullPathName(tmp->getCString(), sizeof(buf), buf, &fp); - delete tmp; - path->clear(); - path->append(buf); - return path; -#else - //---------- Unix ---------- - int i; - - // appending "." does nothing - if (!strcmp(fileName, ".")) - return path; - - // appending ".." goes up one directory - if (!strcmp(fileName, "..")) { - for (i = path->getLength() - 2; i >= 0; --i) { - if (path->getChar(i) == '/') - break; - } - if (i <= 0) { - if (path->getChar(0) == '/') { - path->del(1, path->getLength() - 1); - } else { - path->clear(); - path->append(".."); - } - } else { - path->del(i, path->getLength() - i); - } - return path; - } - - // otherwise, append "/" and new path component - if (path->getLength() > 0 && - path->getChar(path->getLength() - 1) != '/') - path->append('/'); - path->append(fileName); - return path; -#endif -} - -GString *grabPath(char *fileName) { -#if defined(WIN32) - //---------- OS/2+EMX and Win32 ---------- - char *p; - - if ((p = strrchr(fileName, '/'))) - return new GString(fileName, p - fileName); - if ((p = strrchr(fileName, '\\'))) - return new GString(fileName, p - fileName); - if ((p = strrchr(fileName, ':'))) - return new GString(fileName, p + 1 - fileName); - return new GString(); -#else - //---------- Unix ---------- - char *p; - - if ((p = strrchr(fileName, '/'))) - return new GString(fileName, p - fileName); - return new GString(); -#endif -} - -GBool isAbsolutePath(char *path) { -#if defined(WIN32) - //---------- OS/2+EMX and Win32 ---------- - return path[0] == '/' || path[0] == '\\' || path[1] == ':'; - -#else - //---------- Unix ---------- - return path[0] == '/'; -#endif -} - -GString *makePathAbsolute(GString *path) { -#if defined(WIN32) - //---------- Win32 ---------- - char buf[_MAX_PATH]; - char *fp; - - buf[0] = '\0'; - if (!GetFullPathName(path->getCString(), _MAX_PATH, buf, &fp)) { - path->clear(); - return path; - } - path->clear(); - path->append(buf); - return path; -#else - //---------- Unix and OS/2+EMX ---------- - struct passwd *pw; - char buf[PATH_MAX+1]; - GString *s; - char *p1, *p2; - int n; - - if (path->getChar(0) == '~') { - if (path->getChar(1) == '/' || - path->getLength() == 1) { - path->del(0, 1); - s = getHomeDir(); - path->insert(0, s); - delete s; - } else { - p1 = path->getCString() + 1; - for (p2 = p1; *p2 && *p2 != '/'; ++p2) ; - if ((n = p2 - p1) > PATH_MAX) - n = PATH_MAX; - strncpy(buf, p1, n); - buf[n] = '\0'; - if ((pw = getpwnam(buf))) { - path->del(0, p2 - p1 + 1); - path->insert(0, pw->pw_dir); - } - } - } else if (!isAbsolutePath(path->getCString())) { - if (getcwd(buf, sizeof(buf))) { - path->insert(0, '/'); - path->insert(0, buf); - } - } - return path; -#endif -} - -time_t getModTime(char *fileName) { -#ifdef WIN32 - //~ should implement this, but it's (currently) only used in xpdf - return 0; -#else - struct stat statBuf; - - if (stat(fileName, &statBuf)) { - return 0; - } - return statBuf.st_mtime; -#endif -} - - -GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) { -#if defined(WIN32) - //---------- non-Unix ---------- - char *s; - - // There is a security hole here: an attacker can create a symlink - // with this file name after the tmpnam call and before the fopen - // call. I will happily accept fixes to this function for non-Unix - // OSs. - if (!(s = tmpnam(NULL))) { - return gFalse; - } - *name = new GString(s); - if (ext) { - (*name)->append(ext); - } - if (!(*f = FOPEN((*name)->getCString(), mode))) { - delete (*name); - return gFalse; - } - return gTrue; -#else - //---------- Unix ---------- - char *s, *p; - int fd; - - if (ext) { - if (!(s = tmpnam(NULL))) { - return gFalse; - } - *name = new GString(s); - s = (*name)->getCString(); - if ((p = strrchr(s, '.'))) { - (*name)->del(p - s, (*name)->getLength() - (p - s)); - } - (*name)->append(ext); - fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600); - } else { -#if HAVE_MKSTEMP - if ((s = getenv("TMPDIR"))) { - *name = new GString(s); - } else { - *name = new GString("/tmp"); - } - (*name)->append("/XXXXXX"); - fd = mkstemp((*name)->getCString()); -#else // HAVE_MKSTEMP - if (!(s = tmpnam(NULL))) { - return gFalse; - } - *name = new GString(s); - fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600); -#endif // HAVE_MKSTEMP - } - if (fd < 0 || !(*f = fdopen(fd, mode))) { - delete *name; - return gFalse; - } - return gTrue; -#endif -} - -//------------------------------------------------------------------------ -// GDir and GDirEntry -//------------------------------------------------------------------------ - -GDirEntry::GDirEntry(char *dirPath, char *nameA, GBool doStat) { -#if defined(WIN32) - int fa; - GString *s; -#else - struct stat st; - GString *s; -#endif - - name = new GString(nameA); - dir = gFalse; - if (doStat) { - s = new GString(dirPath); - appendToPath(s, nameA); -#ifdef WIN32 - fa = GetFileAttributes(s->getCString()); - dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY)); -#else - if (stat(s->getCString(), &st) == 0) - dir = S_ISDIR(st.st_mode); -#endif - delete s; - } -} - -GDirEntry::~GDirEntry() { - delete name; -} - -GDir::GDir(char *name, GBool doStatA) { - path = new GString(name); - doStat = doStatA; -#if defined(WIN32) - GString *tmp; - - tmp = path->copy(); - tmp->append("/*.*"); - hnd = FindFirstFile(tmp->getCString(), &ffd); - delete tmp; -#else - dir = opendir(name); -#endif -} - -GDir::~GDir() { - delete path; -#if defined(WIN32) - if (hnd) { - FindClose(hnd); - hnd = NULL; - } -#else - if (dir) - closedir(dir); -#endif -} - -GDirEntry *GDir::getNextEntry() { - struct dirent *ent; - GDirEntry *e; - - e = NULL; -#if defined(WIN32) - e = new GDirEntry(path->getCString(), ffd.cFileName, doStat); - if (hnd && !FindNextFile(hnd, &ffd)) { - FindClose(hnd); - hnd = NULL; - } -#else - if (dir) { - ent = readdir(dir); - if (ent && !strcmp(ent->d_name, ".")) - ent = readdir(dir); - if (ent) - e = new GDirEntry(path->getCString(), ent->d_name, doStat); - } -#endif - return e; -} - -void GDir::rewind() { -#ifdef WIN32 - GString *tmp; - - if (hnd) - FindClose(hnd); - tmp = path->copy(); - tmp->append("/*.*"); - hnd = FindFirstFile(tmp->getCString(), &ffd); -#else - if (dir) - rewinddir(dir); -#endif -} diff --git a/src/plugins/pdf/gfile.h b/src/plugins/pdf/gfile.h @@ -1,104 +0,0 @@ -//======================================================================== -// -// gfile.h -// -// Miscellaneous file and directory name manipulation. -// -// Copyright 1996 Derek B. Noonburg -// -//======================================================================== - -#ifndef GFILE_H -#define GFILE_H - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <sys/types.h> -#include <dirent.h> -#define NAMLEN(d) strlen((d)->d_name) -#include "gtypes.h" -#include "../../include/platform.h" - -class GString; - -//------------------------------------------------------------------------ - -// Get home directory path. -extern GString *getHomeDir(); - -// Get current directory. -extern GString *getCurrentDir(); - -// Append a file name to a path string. <path> may be an empty -// string, denoting the current directory). Returns <path>. -extern GString *appendToPath(GString *path, const char *fileName); - -// Grab the path from the front of the file name. If there is no -// directory component in <fileName>, returns an empty string. -extern GString *grabPath(char *fileName); - -// Is this an absolute path or file name? -extern GBool isAbsolutePath(char *path); - -// Make this path absolute by prepending current directory (if path is -// relative) or prepending user's directory (if path starts with '~'). -GString *makePathAbsolute(GString *path); - -// Get the modification time for <fileName>. Returns 0 if there is an -// error. -time_t getModTime(char *fileName); - -// Create a temporary file and open it for writing. If <ext> is not -// NULL, it will be used as the file name extension. Returns both the -// name and the file pointer. For security reasons, all writing -// should be done to the returned file pointer; the file may be -// reopened later for reading, but not for writing. The <mode> string -// should be "w" or "wb". Returns true on success. -GBool openTempFile(GString **name, FILE **f, char *mode, char *ext); - -//------------------------------------------------------------------------ -// GDir and GDirEntry -//------------------------------------------------------------------------ - -class GDirEntry { -public: - - GDirEntry(char *dirPath, char *nameA, GBool doStat); - ~GDirEntry(); - GString *getName() { return name; } - GBool isDir() { return dir; } - -private: - - GString *name; // dir/file name - GBool dir; // is it a directory? -}; - -class GDir { -public: - - GDir(char *name, GBool doStatA = gTrue); - ~GDir(); - GDirEntry *getNextEntry(); - void rewind(); - -private: - - GString *path; // directory path - GBool doStat; // call stat() for each entry? -#if defined(WIN32) - WIN32_FIND_DATA ffd; - HANDLE hnd; -#elif defined(ACORN) -#elif defined(MACOS) -#else - DIR *dir; // the DIR structure from opendir() -#ifdef VMS - GBool needParent; // need to return an entry for [-] -#endif -#endif -}; - -#endif diff --git a/src/plugins/pdf/gmem.cc b/src/plugins/pdf/gmem.cc @@ -1,204 +0,0 @@ -/* - * gmem.c - * - * Memory routines with out-of-memory checking. - * - * Copyright 1996 Derek B. Noonburg - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <limits.h> -#include "gmem.h" - -#ifdef DEBUG_MEM - -typedef struct _GMemHdr { - int size; - int index; - struct _GMemHdr *next; -} GMemHdr; - -#define gMemHdrSize ((sizeof(GMemHdr) + 7) & ~7) -#define gMemTrlSize (sizeof(long)) - -#if gmemTrlSize==8 -#define gMemDeadVal 0xdeadbeefdeadbeefUL -#else -#define gMemDeadVal 0xdeadbeefUL -#endif - -/* round data size so trailer will be aligned */ -#define gMemDataSize(size) \ - ((((size) + gMemTrlSize - 1) / gMemTrlSize) * gMemTrlSize) - -#define gMemNLists 64 -#define gMemListShift 4 -#define gMemListMask (gMemNLists - 1) -static GMemHdr *gMemList[gMemNLists] = { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; - -static int gMemIndex = 0; -static int gMemAlloc = 0; - -#endif /* DEBUG_MEM */ - -void *gmalloc(int size) { -#ifdef DEBUG_MEM - int size1; - char *mem; - GMemHdr *hdr; - void *data; - int lst; - unsigned long *trl, *p; - - if (size <= 0) - return NULL; - size1 = gMemDataSize(size); - if (!(mem = (char *)malloc(size1 + gMemHdrSize + gMemTrlSize))) { - fprintf(stderr, "Out of memory\n"); - exit(1); - } - hdr = (GMemHdr *)mem; - data = (void *)(mem + gMemHdrSize); - trl = (unsigned long *)(mem + gMemHdrSize + size1); - hdr->size = size; - hdr->index = gMemIndex++; - lst = ((int)hdr >> gMemListShift) & gMemListMask; - hdr->next = gMemList[lst]; - gMemList[lst] = hdr; - ++gMemAlloc; - for (p = (unsigned long *)data; p <= trl; ++p) - *p = gMemDeadVal; - return data; -#else - void *p; - - if (size <= 0) - return NULL; - if (!(p = malloc(size))) { - fprintf(stderr, "Out of memory\n"); - exit(1); - } - return p; -#endif -} - -void *grealloc(void *p, int size) { -#ifdef DEBUG_MEM - GMemHdr *hdr; - void *q; - int oldSize; - - if (size <= 0) { - if (p) - gfree(p); - return NULL; - } - if (p) { - hdr = (GMemHdr *)((char *)p - gMemHdrSize); - oldSize = hdr->size; - q = gmalloc(size); - memcpy(q, p, size < oldSize ? size : oldSize); - gfree(p); - } else { - q = gmalloc(size); - } - return q; -#else - void *q; - - if (size <= 0) { - if (p) - free(p); - return NULL; - } - if (p) - q = realloc(p, size); - else - q = malloc(size); - if (!q) { - fprintf(stderr, "Out of memory\n"); - exit(1); - } - return q; -#endif -} - -void gfree(void *p) { -#ifdef DEBUG_MEM - int size; - GMemHdr *hdr; - GMemHdr *prevHdr, *q; - int lst; - unsigned long *trl, *clr; - - if (p) { - hdr = (GMemHdr *)((char *)p - gMemHdrSize); - lst = ((int)hdr >> gMemListShift) & gMemListMask; - for (prevHdr = NULL, q = gMemList[lst]; q; prevHdr = q, q = q->next) { - if (q == hdr) - break; - } - if (q) { - if (prevHdr) - prevHdr->next = hdr->next; - else - gMemList[lst] = hdr->next; - --gMemAlloc; - size = gMemDataSize(hdr->size); - trl = (unsigned long *)((char *)hdr + gMemHdrSize + size); - if (*trl != gMemDeadVal) { - fprintf(stderr, "Overwrite past end of block %d at address %p\n", - hdr->index, p); - } - for (clr = (unsigned long *)hdr; clr <= trl; ++clr) - *clr = gMemDeadVal; - free(hdr); - } else { - fprintf(stderr, "Attempted to free bad address %p\n", p); - } - } -#else - if (p) - free(p); -#endif -} - -#ifdef DEBUG_MEM -void gMemReport(FILE *f) { - GMemHdr *p; - int lst; - - fprintf(f, "%d memory allocations in all\n", gMemIndex); - if (gMemAlloc > 0) { - fprintf(f, "%d memory blocks left allocated:\n", gMemAlloc); - fprintf(f, " index size\n"); - fprintf(f, "-------- --------\n"); - for (lst = 0; lst < gMemNLists; ++lst) { - for (p = gMemList[lst]; p; p = p->next) - fprintf(f, "%8d %8d\n", p->index, p->size); - } - } else { - fprintf(f, "No memory blocks left allocated\n"); - } -} -#endif - -char *copyString(char *s) { - char *s1; - - s1 = (char *)gmalloc(strlen(s) + 1); - strcpy(s1, s); - return s1; -} diff --git a/src/plugins/pdf/gmem.h b/src/plugins/pdf/gmem.h @@ -1,53 +0,0 @@ -/* - * gmem.h - * - * Memory routines with out-of-memory checking. - * - * Copyright 1996 Derek B. Noonburg - */ - -#ifndef GMEM_H -#define GMEM_H - -#include <stdio.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Same as malloc, but prints error message and exits if malloc() - * returns NULL. - */ -extern void *gmalloc(int size); - -/* - * Same as realloc, but prints error message and exits if realloc() - * returns NULL. If <p> is NULL, calls malloc instead of realloc(). - */ -extern void *grealloc(void *p, int size); - -/* - * Same as free, but checks for and ignores NULL pointers. - */ -extern void gfree(void *p); - -#ifdef DEBUG_MEM -/* - * Report on unfreed memory. - */ -extern void gMemReport(FILE *f); -#else -#define gMemReport(f) -#endif - -/* - * Allocate memory and copy a string into it. - */ -extern char *copyString(char *s); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/plugins/pdf/gmempp.cc b/src/plugins/pdf/gmempp.cc @@ -1,31 +0,0 @@ -//======================================================================== -// -// gmempp.cc -// -// Use gmalloc/gfree for C++ new/delete operators. -// -// Copyright 1996 Derek B. Noonburg -// -//======================================================================== - -#include "gmem.h" - -#ifdef DEBUG_MEM - -void *operator new(size_t size) { - return gmalloc((int)size); -} - -void *operator new[](size_t size) { - return gmalloc((int)size); -} - -void operator delete(void *p) { - gfree(p); -} - -void operator delete[](void *p) { - gfree(p); -} - -#endif diff --git a/src/plugins/pdf/gtypes.h b/src/plugins/pdf/gtypes.h @@ -1,29 +0,0 @@ -/* - * gtypes.h - * - * Some useful simple types. - * - * Copyright 1996 Derek B. Noonburg - */ - -#ifndef GTYPES_H -#define GTYPES_H - -/* - * These have stupid names to avoid conflicts with some (but not all) - * C++ compilers which define them. - */ -typedef int GBool; -#define gTrue 1 -#define gFalse 0 - -/* - * These have stupid names to avoid conflicts with <sys/types.h>, - * which on various systems defines some random subset of these. - */ -typedef unsigned char Guchar; -typedef unsigned short Gushort; -typedef unsigned int Guint; -typedef unsigned long Gulong; - -#endif diff --git a/src/plugins/pdf/parseargs.cc b/src/plugins/pdf/parseargs.cc @@ -1,190 +0,0 @@ -/* - * parseargs.h - * - * Command line argument parser. - * - * Copyright 1996 Derek B. Noonburg - */ - -#include <stdio.h> -#include <stddef.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include "parseargs.h" - -static ArgDesc *findArg(ArgDesc *args, char *arg); -static GBool grabArg(ArgDesc *arg, int i, int *argc, char *argv[]); - -GBool parseArgs(ArgDesc *args, int *argc, char *argv[]) { - ArgDesc *arg; - int i, j; - GBool ok; - - ok = gTrue; - i = 1; - while (i < *argc) { - if (!strcmp(argv[i], "--")) { - --*argc; - for (j = i; j < *argc; ++j) - argv[j] = argv[j+1]; - break; - } else if ((arg = findArg(args, argv[i]))) { - if (!grabArg(arg, i, argc, argv)) - ok = gFalse; - } else { - ++i; - } - } - return ok; -} - -void printUsage(char *program, char *otherArgs, ArgDesc *args) { - ArgDesc *arg; - char *typ; - int w, w1; - - w = 0; - for (arg = args; arg->arg; ++arg) { - if ((w1 = strlen(arg->arg)) > w) - w = w1; - } - - fprintf(stderr, "Usage: %s [options]", program); - if (otherArgs) - fprintf(stderr, " %s", otherArgs); - fprintf(stderr, "\n"); - - for (arg = args; arg->arg; ++arg) { - fprintf(stderr, " %s", arg->arg); - w1 = 9 + w - strlen(arg->arg); - switch (arg->kind) { - case argInt: - case argIntDummy: - typ = " <int>"; - break; - case argFP: - case argFPDummy: - typ = " <fp>"; - break; - case argString: - case argStringDummy: - typ = " <string>"; - break; - case argFlag: - case argFlagDummy: - default: - typ = ""; - break; - } - fprintf(stderr, "%-*s", w1, typ); - if (arg->usage) - fprintf(stderr, ": %s", arg->usage); - fprintf(stderr, "\n"); - } -} - -static ArgDesc *findArg(ArgDesc *args, char *arg) { - ArgDesc *p; - - for (p = args; p->arg; ++p) { - if (p->kind < argFlagDummy && !strcmp(p->arg, arg)) - return p; - } - return NULL; -} - -static GBool grabArg(ArgDesc *arg, int i, int *argc, char *argv[]) { - int n; - int j; - GBool ok; - - ok = gTrue; - n = 0; - switch (arg->kind) { - case argFlag: - *(GBool *)arg->val = gTrue; - n = 1; - break; - case argInt: - if (i + 1 < *argc && isInt(argv[i+1])) { - *(int *)arg->val = atoi(argv[i+1]); - n = 2; - } else { - ok = gFalse; - n = 1; - } - break; - case argFP: - if (i + 1 < *argc && isFP(argv[i+1])) { - *(double *)arg->val = atof(argv[i+1]); - n = 2; - } else { - ok = gFalse; - n = 1; - } - break; - case argString: - if (i + 1 < *argc) { - strncpy((char *)arg->val, argv[i+1], arg->size - 1); - ((char *)arg->val)[arg->size - 1] = '\0'; - n = 2; - } else { - ok = gFalse; - n = 1; - } - break; - default: - fprintf(stderr, "Internal error in arg table\n"); - n = 1; - break; - } - if (n > 0) { - *argc -= n; - for (j = i; j < *argc; ++j) - argv[j] = argv[j+n]; - } - return ok; -} - -GBool isInt(char *s) { - if (*s == '-' || *s == '+') - ++s; - while (isdigit(*s)) - ++s; - if (*s) - return gFalse; - return gTrue; -} - -GBool isFP(char *s) { - int n; - - if (*s == '-' || *s == '+') - ++s; - n = 0; - while (isdigit(*s)) { - ++s; - ++n; - } - if (*s == '.') - ++s; - while (isdigit(*s)) { - ++s; - ++n; - } - if (n > 0 && (*s == 'e' || *s == 'E')) { - ++s; - if (*s == '-' || *s == '+') - ++s; - n = 0; - if (!isdigit(*s)) - return gFalse; - do { - ++s; - } while (isdigit(*s)); - } - if (*s) - return gFalse; - return gTrue; -} diff --git a/src/plugins/pdf/parseargs.h b/src/plugins/pdf/parseargs.h @@ -1,71 +0,0 @@ -/* - * parseargs.h - * - * Command line argument parser. - * - * Copyright 1996 Derek B. Noonburg - */ - -#ifndef PARSEARGS_H -#define PARSEARGS_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "gtypes.h" - -/* - * Argument kinds. - */ -typedef enum { - argFlag, /* flag (present / not-present) */ - /* [val: GBool *] */ - argInt, /* integer arg */ - /* [val: int *] */ - argFP, /* floating point arg */ - /* [val: double *] */ - argString, /* string arg */ - /* [val: char *] */ - /* dummy entries -- these show up in the usage listing only; */ - /* useful for X args, for example */ - argFlagDummy, - argIntDummy, - argFPDummy, - argStringDummy -} ArgKind; - -/* - * Argument descriptor. - */ -typedef struct { - char *arg; /* the command line switch */ - ArgKind kind; /* kind of arg */ - void *val; /* place to store value */ - int size; /* for argString: size of string */ - char *usage; /* usage string */ -} ArgDesc; - -/* - * Parse command line. Removes all args which are found in the arg - * descriptor list <args>. Stops parsing if "--" is found (and removes - * it). Returns gFalse if there was an error. - */ -extern GBool parseArgs(ArgDesc *args, int *argc, char *argv[]); - -/* - * Print usage message, based on arg descriptor list. - */ -extern void printUsage(char *program, char *otherArgs, ArgDesc *args); - -/* - * Check if a string is a valid integer or floating point number. - */ -extern GBool isInt(char *s); -extern GBool isFP(char *s); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/plugins/pdf/pdfextractor.cc b/src/plugins/pdf/pdfextractor.cc @@ -1,306 +0,0 @@ -/* - This file is part of libextractor. - (C) 2002, 2003 Vidyut Samanta and Christian Grothoff - - libextractor 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, or (at your - option) any later version. - - libextractor 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 libextractor; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - This code was inspired by pdfinfo and depends heavily - on the xpdf code that pdfinfo is a part of. See also - the INFO file in this directory. - */ - -#include "platform.h" -#include "extractor.h" -#include "convert.h" -#include <math.h> - -#include "parseargs.h" -#include "GString.h" -#include "gmem.h" -#include "Object.h" -#include "Stream.h" -#include "Array.h" -#include "Dict.h" -#include "XRef.h" -#include "Catalog.h" -#include "Page.h" -#include "PDFDoc.h" -#include "Params.h" -#include "Error.h" -#include "config.h" - -extern "C" { - - static struct EXTRACTOR_Keywords * addKeyword(EXTRACTOR_KeywordType type, - char * keyword, - struct EXTRACTOR_Keywords * next) { - EXTRACTOR_KeywordList * result; - - if (keyword == NULL) - return next; - result = (EXTRACTOR_KeywordList*) malloc(sizeof(EXTRACTOR_KeywordList)); - result->next = next; - result->keyword = keyword; - result->keywordType = type; - return result; - } - - - static struct EXTRACTOR_Keywords * printInfoString(Dict *infoDict, - const char *key, - EXTRACTOR_KeywordType type, - struct EXTRACTOR_Keywords * next) { - Object obj; - GString *s1; - const char * s; - - if (infoDict->lookup(key, &obj)->isString()) { - s1 = obj.getString(); - s = s1->getCString(); - if ((((unsigned char)s[0]) & 0xff) == 0xfe && - (((unsigned char)s[1]) & 0xff) == 0xff) { - char * result; - - result = EXTRACTOR_common_convert_to_utf8(&s[2], s1->getLength() - 2, "UTF-16BE"); - next = addKeyword(type, - result, - next); - } else { - size_t len = strlen(s); - - while(0 < len) { - /* - * Avoid outputting trailing spaces. - * - * The following expression might be rewritten as - * (! isspace(s[len - 1]) && 0xA0 != s[len - 1]). - * There seem to exist isspace() implementations - * which do return non-zero from NBSP (maybe locale-dependent). - * Remove ISO-8859 non-breaking space (NBSP, hex value 0xA0) from - * the expression if it looks suspicious (locale issues for instance). - * - * Squeezing out all non-printable characters might also be useful. - */ - if ( (' ' != s[len - 1]) && ((char)0xA0 != s[len - 1]) && - ('\r' != s[len - 1]) && ('\n' != s[len - 1]) && - ('\t' != s[len - 1]) && ('\v' != s[len - 1]) && - ('\f' != s[len - 1]) ) - break; - - else - len --; - } - - /* there should be a check to truncate preposterously long values. */ - - if (0 < len) { - next = addKeyword(type, - EXTRACTOR_common_convert_to_utf8(s, len, - "ISO-8859-1"), - next); - } - } - } - obj.free(); - return next; - } - - static struct EXTRACTOR_Keywords * printInfoDate(Dict *infoDict, - const char *key, - EXTRACTOR_KeywordType type, - struct EXTRACTOR_Keywords * next) { - Object obj; - char *s; - GString *s1; - - if (infoDict->lookup(key, &obj)->isString()) { - s1 = obj.getString(); - s = s1->getCString(); - - if ((s1->getChar(0) & 0xff) == 0xfe && - (s1->getChar(1) & 0xff) == 0xff) { - /* isUnicode */ - char * result; - - result = EXTRACTOR_common_convert_to_utf8((const char*)&s[2], s1->getLength() - 2, "UTF-16BE"); - next = addKeyword(type, - result, - next); - } else { - if (s[0] == 'D' && s[1] == ':') { - s += 2; - } - next = addKeyword(type, strdup(s), next); - } - /* printf(fmt, s);*/ - } - obj.free(); - return next; - } - - - /* which mime-types should not be subjected to - the PDF extractor? (no use trying!) */ - static const char * blacklist[] = { - "image/jpeg", - "image/gif", - "image/png", - "image/x-png", - "audio/real", - "audio/mpeg", - "application/x-gzip", - "application/x-dpkg", - "application/bz2", - "application/x-rpm", - "application/x-rar", - "application/x-zip", - "application/x-arj", - "application/x-compress", - "application/x-tar", - "application/x-lha", - "application/x-gtar", - "application/x-dpkg", - "application/ogg", - "video/real", - "video/asf", - "video/quicktime", - NULL, - }; - - - static const char * - extractLast (const EXTRACTOR_KeywordType type, - EXTRACTOR_KeywordList * keywords) - { - char *result = NULL; - while (keywords != NULL) - { - if (keywords->keywordType == type) - result = keywords->keyword; - keywords = keywords->next; - } - return result; - } - - struct EXTRACTOR_Keywords * libextractor_pdf_extract(const char * filename, - char * data, - size_t size, - struct EXTRACTOR_Keywords * prev) { - PDFDoc * doc; - Object info; - Object obj; - BaseStream * stream; - struct EXTRACTOR_Keywords * result; - const char * mime; - - /* if the mime-type of the file is blacklisted, don't - run the printable extactor! */ - mime = extractLast(EXTRACTOR_MIMETYPE, - prev); - if (mime != NULL) { - int j; - j = 0; - while (blacklist[j] != NULL) { - if (0 == strcmp(blacklist[j], mime)) - return prev; - - j++; - } - } - - /* errorInit(); -- keep commented out, otherwise errors are printed to stderr for non-pdf files! */ - obj.initNull(); - stream = new MemStream(data, 0, size, &obj); - doc = new PDFDoc(stream, NULL, NULL); - if (! doc->isOk()) { - delete doc; - return prev; - } - - result = addKeyword(EXTRACTOR_MIMETYPE, - strdup("application/pdf"), - prev); - if ( (NULL != doc->getDocInfo(&info)) && - (info.isDict()) ) { - result = printInfoString(info.getDict(), - "Title", - EXTRACTOR_TITLE, - result); - result = printInfoString(info.getDict(), - "Subject", - EXTRACTOR_SUBJECT, - result); - result = printInfoString(info.getDict(), - "Keywords", - EXTRACTOR_KEYWORDS, - result); - result = printInfoString(info.getDict(), - "Author", - EXTRACTOR_AUTHOR, - result); - /* - * we now believe that Adobe's Creator - * is not a person nor an organisation, - * but just a piece of software. - */ - result = printInfoString(info.getDict(), - "Creator", - EXTRACTOR_SOFTWARE, - result); - result = printInfoString(info.getDict(), - "Producer", - EXTRACTOR_PRODUCER, - result); - { - char pcnt[20]; - sprintf(pcnt, "%d", doc->getNumPages()); - result = addKeyword(EXTRACTOR_PAGE_COUNT, - strdup(pcnt), - result); - } - { - char pcnt[20]; - sprintf(pcnt, "PDF %.1f", doc->getPDFVersion()); - result = addKeyword(EXTRACTOR_FORMAT, - strdup(pcnt), - result); - } - result = printInfoDate(info.getDict(), - "CreationDate", - EXTRACTOR_CREATION_DATE, - result); - result = printInfoDate(info.getDict(), - "ModDate", - EXTRACTOR_MODIFICATION_DATE, - result); - } - - info.free(); - delete doc; - - return result; - } -} - - - -void __attribute__ ((constructor)) xpdf_init(void) { - initParams(".xpdfrc", ".xpdfrc"); -} - -void __attribute__ ((destructor)) xpdf_done(void) { - freeParams(); -} diff --git a/src/plugins/pdf_extractor.cc b/src/plugins/pdf_extractor.cc @@ -0,0 +1,216 @@ +/* + This file is part of libextractor. + (C) 2002, 2003 Vidyut Samanta and Christian Grothoff + + libextractor 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, or (at your + option) any later version. + + libextractor 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 libextractor; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + This code was inspired by pdfinfo and depends heavily + on the xpdf code that pdfinfo is a part of. See also + the INFO file in this directory. + */ + +#include "platform.h" +#include "extractor.h" +#include "convert.h" +#include <math.h> + +#include <poppler/goo/gmem.h> +#include <poppler/Object.h> +#include <poppler/Stream.h> +#include <poppler/Array.h> +#include <poppler/Dict.h> +#include <poppler/XRef.h> +#include <poppler/Catalog.h> +#include <poppler/Page.h> +#include <poppler/PDFDoc.h> +#include <poppler/Error.h> +#include <poppler/goo/GooString.h> + +#define ADD(s, type) do { if (0!=proc(proc_cls, "pdf", type, EXTRACTOR_METAFORMAT_UTF8, "text/plain", s, strlen(s)+1)) { err = 1; goto EXIT; }} while (0) + +static int +printInfoString(Dict *infoDict, + const char *key, + enum EXTRACTOR_MetaType type, + EXTRACTOR_MetaDataProcessor proc, + void *proc_cls) +{ + Object obj; + GooString *s1; + const char * s; + char *ckey = strdup (key); + int err = 0; + char * result; + + result = NULL; + if (infoDict->lookup(ckey, &obj)->isString()) { + s1 = obj.getString(); + s = s1->getCString(); + if ((((unsigned char)s[0]) & 0xff) == 0xfe && + (((unsigned char)s[1]) & 0xff) == 0xff) { + result = EXTRACTOR_common_convert_to_utf8(&s[2], s1->getLength() - 2, "UTF-16BE"); + ADD (result, type); + } else { + size_t len = strlen(s); + + while(0 < len) { + /* + * Avoid outputting trailing spaces. + * + * The following expression might be rewritten as + * (! isspace(s[len - 1]) && 0xA0 != s[len - 1]). + * There seem to exist isspace() implementations + * which do return non-zero from NBSP (maybe locale-dependent). + * Remove ISO-8859 non-breaking space (NBSP, hex value 0xA0) from + * the expression if it looks suspicious (locale issues for instance). + * + * Squeezing out all non-printable characters might also be useful. + */ + if ( (' ' != s[len - 1]) && ((char)0xA0 != s[len - 1]) && + ('\r' != s[len - 1]) && ('\n' != s[len - 1]) && + ('\t' != s[len - 1]) && ('\v' != s[len - 1]) && + ('\f' != s[len - 1]) ) + break; + + else + len --; + } + + /* there should be a check to truncate preposterously long values. */ + + if (0 < len) { + result = EXTRACTOR_common_convert_to_utf8(s, len, + "ISO-8859-1"); + ADD (result, type); + } + } + } + EXIT: + obj.free(); + free (result); + free (ckey); + return err; +} + +static int +printInfoDate(Dict *infoDict, + const char *key, + enum EXTRACTOR_MetaType type, + EXTRACTOR_MetaDataProcessor proc, + void *proc_cls) +{ + Object obj; + const char *s; + GooString *s1; + char *gkey; + char * result; + int err; + + err = 0; + result = NULL; + gkey = strdup (key); + if (infoDict->lookup(gkey, &obj)->isString()) { + s1 = obj.getString(); + s = s1->getCString(); + + if ((s1->getChar(0) & 0xff) == 0xfe && + (s1->getChar(1) & 0xff) == 0xff) { + /* isUnicode */ + + result = EXTRACTOR_common_convert_to_utf8((const char*)&s[2], s1->getLength() - 2, "UTF-16BE"); + ADD (result, type); + } else { + if (s[0] == 'D' && s[1] == ':') + s += 2; + + ADD (s, type); + } + /* printf(fmt, s);*/ + } + EXIT: + obj.free(); + free (result); + free (gkey); + return err; +} + +#define PIS(s,t) do { if (0 != (err = printInfoString (info.getDict(), s, t, proc, proc_cls))) goto EXIT; } while (0) + +#define PID(s,t) do { if (0 != (err = printInfoDate (info.getDict(), s, t, proc, proc_cls))) goto EXIT; } while (0) + +extern "C" { + + + int + EXTRACTOR_pdf_extract (const char *data, + size_t size, + EXTRACTOR_MetaDataProcessor proc, + void *proc_cls, + const char *options) + { + PDFDoc * doc; + Object info; + Object obj; + BaseStream * stream; + int err; + + /* errorInit(); -- keep commented out, otherwise errors are printed to stderr for non-pdf files! */ + obj.initNull(); + err = 0; + stream = new MemStream( (char*) data, 0, size, &obj); + doc = new PDFDoc(stream, NULL, NULL); + if (! doc->isOk()) { + delete doc; + return 0; + } + + ADD ("application/pdf", + EXTRACTOR_METATYPE_MIMETYPE); + if ( (NULL != doc->getDocInfo(&info)) && + (info.isDict()) ) { + PIS ("Title", EXTRACTOR_METATYPE_TITLE); + PIS ("Subject", EXTRACTOR_METATYPE_SUBJECT); + PIS ("Keywords", EXTRACTOR_METATYPE_KEYWORDS); + PIS ("Author", EXTRACTOR_METATYPE_AUTHOR_NAME); + /* + * we now believe that Adobe's Creator is not a person nor an + * organisation, but just a piece of software. + */ + PIS ("Creator", EXTRACTOR_METATYPE_CREATED_BY_SOFTWARE); + PIS ("Producer", EXTRACTOR_METATYPE_PRODUCED_BY_SOFTWARE); + { + char pcnt[20]; + sprintf(pcnt, "%d", doc->getNumPages()); + ADD (pcnt, EXTRACTOR_METATYPE_PAGE_COUNT); + } + { + char pcnt[64]; + sprintf(pcnt, "PDF %d.%d", + doc->getPDFMajorVersion(), + doc->getPDFMinorVersion()); + ADD (pcnt, EXTRACTOR_METATYPE_FORMAT); + } + PID ("CreationDate", EXTRACTOR_METATYPE_CREATION_DATE); + PID ("ModDate", EXTRACTOR_METATYPE_MODIFICATION_DATE); + } + EXIT: + info.free(); + delete doc; + + return err; + } +} +