pax_global_header00006660000000000000000000000064147705606470014532gustar00rootroot0000000000000052 comment=184a3f409b7a138c309a73b43851a4f27e28c812 camlpdf-2.8.1/000077500000000000000000000000001477056064700131505ustar00rootroot00000000000000camlpdf-2.8.1/Changes000066400000000000000000000140541477056064700144470ustar00rootroot000000000000002.8.1 (April 2025) o Pdf.lookup_chain can look within arrays o Pdf.replace_chain can replace within arrays o Repair name/number trees with duplicate keys o Pdfpage.pagenumber_of_target works on GoTo actions o Allow optional shallow reading of destinations o Ensure that shallow destinations are transformed o Empty name now a warning not an error (written as /) 2.8 (December 2024) o Read and write bookmark colour and flags o Fixed a bug in Pdfst.renumber_parent_trees o Only call renumber_parent_trees when processing struct trees 2.7.2 (October 2024) o Process destination name tree in Pdfpage.pdf_of_pages o Options to change the whitespace between operators o Allow writing of comments in streams o Allow addition of top-level Document in struct tree when merging o New lookup_chain / replace_chain functions in Pdf o Revert 2.7 "Remember and reapply inline image decode parameters" 2.7.1 (July 2024) o Fix sign extension in js_of_ocaml o Pdfannot expanded to more annotation types o Extract code to Pdftree module (API subject to change) o Structure tree optionally trimmed on Pdf.pdf_of_pages o Structure tree optionally trimmed & merged in Pdfmerge 2.7 (February 2024) o Add opam file in-source o Cope with more malformed bookmarks o Remember and reapply inline image decode parameters o Pdfimage extracts and stores JBIG2Globals o Option to compress a stream only if it is made smaller o Encode predictor for PNG Sub (bpc = 8, 3 components) o Fix for LZWDecode streams which overfill the table o New endpage_fast o Remove some very old unused Pdfimage code o Reconstruct tree in Pdfpage.pdf_of_pages for better bookmarks o Cope with predictor dictionary not being end of inline image dictionary 2.6 (July 2023) Merging improvements: o Keep major PDF version number o Merge /StructTreeRoot entries (Structure hierarchy / Tagged PDF) o Disambiguate destination name trees when merging o Preserve named destinations in bookmarks when merging o Remove /OpenAction on merge o Preserve first metadata seen on merge Other: o Cope with files with no /MediaBox at all o Write IDs as Hexadecimal strings o Replace Stream/Genlex and other deprecations for OCaml 5 o Allows malformed numbers --1, --2.5 etc. o Support for alternative stubs for js_of_ocaml o Push mk_id down to pdf_to_output so it works when writing to non-file destinations o Fix Pdf.getnum and Pdf.parse_rectangle to cope with indirects o Ignore data check errors in flate decoding o Now reads many more files from Stressful PDF Corpus o Revert 'build byte code top level camlpdf.top by default' o Pdfpage.add_prefix now detects and fixes non-ISO PDFs o Loosen EI check on inline image lexing o Compress inline images upon writing if uncompressed o Retired old unused modules to old/ o Cope with /Crypt identity filters o Ability to redirect error output o Harden ASCII85Decode against whitespace 2.5 (January 2022) o Build byte code top level camlpdf.top by default o Replace deprecated C interface functions for OCaml 5.0 o Document most undocumented functions o Pdfpage.change_pages now preserves object streams o Width calculation in Pdfstandard14 now more efficient o Charcode and text extractors have font not fontdict counterparts o Pdftext.charcode_extractor_of_font copes with more encodings o Add Pdftext.simplify_utf16be o Merge now merges AcroForms o Fix Pdfio.setinit and friends to deal with 0-length data o Harden Pdfmarks against erroneous empty /Title in doc outline o AFM and glyphlists loaded from compressed sources o Environment variable CAMLPDF_REPRODUCIBLE_IDS for testing o Effectively make stderr unbuffered for all output o A dictionary entry with null for its value now does not exist o A missing mediabox now not fatal - we use the most-recently-seen 2.4 (June 2021) o Prefixed all C stubs to avoid clashes with zlib / cryptokit o Fix for zero-sized Pdfio.input_outputs o Bad interaction between deferred decryption and object streams fixed o Optional content groups merged when merging o Pdfpage.change_pages can now alter bookmark destinations for transformed pages o Preserves zero bytes in malformed names o Merged files get fresh /ID o Pdfpagelabels.write now removes labels when given an empty list 2.3 (patchlevel 2, 2020) o Bad interaction between deferred decryption and object streams worked around 2.3 (patchlevel 1, December 2019) o Updated Makefile to build on bytecode-only architectures (thanks Ralf Treinen) 2.3 (October 2019) o Malformed file reading for files with content before the header now works o Switches to disable malformed file reading or always read as if malformed o Fix to preserve integers > 2^30 or < -2^30 on 32 bit systems o Allow [/DCT] as well as /DCT in inline image filter specifications o Improvements to text width calculation (thanks Alain Frisch) 2.2 (patchlevel 1, September 2017) o Code for adding annotations (thanks @waclena) o Indirect encryption dictionaries o Workaround for Adobe "Error 21" on re-saving encrypted files o Fix reading of null objects in streams 2.2 (2017) o Keeps was_linearized flag with every loaded PDF 2.1 (November 2014) o Excised linearization. We recommend qpdflib / qpdf for this task now. o Encryption now performed by fast C routines, replacing the OCaml ones o Faster parsing of delayed object streams on large files o New implementation of Pdf.page_reference_numbers. More robust o Faster parsing by using better primitive operations for I/O o Tighter spacing of output in Pdfwrite leading to smaller files o Fixed pdf_of_pages not to produce duplicate page objects when multiple parts of the output pdf come from the same input pdf o Pdfpagelabels bug fixes, especially to alphabetic labels o Read StemV etc. values from the AFM header directly o Object streams may be written uncompressed for manual inspection o Recrypting overhauled. Now a first class citizen. 1.7 (30th August 2013) o Support for writing with object streams o AES256ISO encryption support o More compact writing of files o Support for reading many malformed files o Now under a standard LGPL license o Has no dependencies o First import into git for use with GitHub for open development o Support for ocamlfind camlpdf-2.8.1/LICENSE000066400000000000000000000656571477056064700142000ustar00rootroot00000000000000This Library is distributed under the terms of the GNU Lesser General Public License (LGPL) version 2.1 or above (included below). As a special exception to the GNU Lesser General Public License, you may link, statically or dynamically, a "work that uses the Library" with a publicly distributed version of the Library to produce an executable file containing portions of the Library, and distribute that executable file under terms of your choice, without any of the additional requirements listed in clause 6 of the GNU Lesser General Public License. By "a publicly distributed version of the Library", we mean either the unmodified Library as distributed by Coherent Graphics Ltd, or a modified version of the Library that is distributed under the conditions defined in clause 3 of the GNU Lesser General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU Lesser General Public License. ---------------------------------------------------------------------- GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! camlpdf-2.8.1/META000066400000000000000000000002111477056064700136130ustar00rootroot00000000000000name="camlpdf" description="Read, write and modify PDF files" version="2.8.1" archive(byte)="camlpdf.cma" archive(native)="camlpdf.cmxa" camlpdf-2.8.1/Makefile000066400000000000000000000024521477056064700146130ustar00rootroot00000000000000# Build the camlpdf library as byte code and, if available, native code PDFMODS = pdfe pdfutil pdfio pdftransform pdfunits pdfpaper \ pdfcryptprimitives pdf pdfcrypt pdfflate pdfcodec pdfwrite pdfgenlex \ pdfread pdfjpeg pdfops pdfdest pdfmarks pdfpagelabels pdftree pdfst pdfpage \ pdfannot pdffun pdfspace pdfimage pdfafm pdfafmdata pdfglyphlist pdfcmap \ pdftext pdfstandard14 pdfdate pdfocg pdfmerge SOURCES = flatestubs.c rijndael-alg-fst.c stubs-aes.c sha2.c stubs-sha2.c \ $(foreach x,$(PDFMODS),$(x).ml $(x).mli) RESULT = camlpdf CFLAGS = -o2 OCAMLFLAGS = -bin-annot OCAMLNCFLAGS = -g -safe-string OCAMLBCFLAGS = -g -safe-string OCAMLLDFLAGS = -g TARGETS := byte-code-library htdoc LIBINSTALL_FILES = \ camlpdf.cma libcamlpdf_stubs.a dllcamlpdf_stubs.* \ $(foreach x,$(PDFMODS),$x.mli) $(foreach x,$(PDFMODS),$x.cmt) \ $(foreach x,$(PDFMODS),$x.cmi) $(foreach x,$(PDFMODS),$x.cmti) ifneq ($(shell ocamlopt -version),) TARGETS += native-code-library LIBINSTALL_FILES += camlpdf.a camlpdf.cmxa $(foreach x,$(PDFMODS),$x.cmx) endif all : $(TARGETS) clean :: rm -rf doc foo foo2 out.pdf out2.pdf *.ps *.cmt *.cmti *.zlib rm -rf examples/out.pdf examples/out2.pdf examples/foo examples/foo rm -rf examples/hello.pdf cd examples; make clean install : libinstall -include OCamlMakefile camlpdf-2.8.1/OCamlMakefile000077500000000000000000001052461477056064700155370ustar00rootroot00000000000000########################################################################### # OCamlMakefile # Copyright (C) 1999- Markus Mottl # # For updates see: # http://www.ocaml.info/home/ocaml_sources.html # ########################################################################### # Modified by damien for .glade.ml compilation # Set these variables to the names of the sources to be processed and # the result variable. Order matters during linkage! ifndef SOURCES SOURCES := foo.ml endif export SOURCES ifndef RES_CLIB_SUF RES_CLIB_SUF := _stubs endif export RES_CLIB_SUF ifndef RESULT RESULT := foo endif export RESULT := $(strip $(RESULT)) export LIB_PACK_NAME ifndef DOC_FILES DOC_FILES := $(filter %.mli, $(SOURCES)) endif export DOC_FILES FIRST_DOC_FILE := $(firstword $(DOC_FILES)) export BCSUFFIX export NCSUFFIX ifndef TOPSUFFIX TOPSUFFIX := .top endif export TOPSUFFIX # Eventually set include- and library-paths, libraries to link, # additional compilation-, link- and ocamlyacc-flags # Path- and library information needs not be written with "-I" and such... # Define THREADS if you need it, otherwise leave it unset (same for # USE_CAMLP4)! export THREADS export VMTHREADS export ANNOTATE export USE_CAMLP4 export INCDIRS export LIBDIRS export EXTLIBDIRS export RESULTDEPS export OCAML_DEFAULT_DIRS export LIBS export CLIBS export CFRAMEWORKS export OCAMLFLAGS export OCAMLNCFLAGS export OCAMLBCFLAGS export OCAMLLDFLAGS export OCAMLNLDFLAGS export OCAMLBLDFLAGS export OCAMLMKLIB_FLAGS ifndef OCAMLCPFLAGS OCAMLCPFLAGS := a endif export OCAMLCPFLAGS ifndef DOC_DIR DOC_DIR := doc endif export DOC_DIR export PPFLAGS export LFLAGS export YFLAGS export IDLFLAGS export OCAMLDOCFLAGS export OCAMLFIND_INSTFLAGS export DVIPSFLAGS export STATIC # Add a list of optional trash files that should be deleted by "make clean" export TRASH ECHO := echo ifdef REALLY_QUIET export REALLY_QUIET ECHO := true LFLAGS := $(LFLAGS) -q YFLAGS := $(YFLAGS) -q endif #################### variables depending on your OCaml-installation SYSTEM := $(shell ocamlc -config 2>/dev/null | grep system | sed 's/system: //') # This may be # - mingw # - mingw64 # - win32 # - cygwin # - some other string means Unix # - empty means ocamlc does not support -config ifeq ($(SYSTEM),$(filter $(SYSTEM),mingw mingw64)) MINGW=1 endif ifeq ($(SYSTEM),win32) MSVC=1 endif ifdef MINGW export MINGW WIN32 := 1 # The default value 'cc' makes 'ocamlc -cc "cc"' raises the error 'The # NTVDM CPU has encountered an illegal instruction'. ifndef CC MNO_CYGWIN := $(shell gcc -Wextra -v --help 2>/dev/null | grep -q '\-mno-cygwin'; echo $$?) CC := gcc else MNO_CYGWIN := $(shell $$CC -Wextra -v --help 2>/dev/null | grep -q '\-mno-cygwin'; echo $$?) endif # We are compiling with cygwin tools: ifeq ($(MNO_CYGWIN),0) CFLAGS_WIN32 := -mno-cygwin endif # The OCaml C header files use this flag: CFLAGS += -D__MINGW32__ endif ifdef MSVC export MSVC WIN32 := 1 ifndef STATIC CPPFLAGS_WIN32 := -DCAML_DLL endif CFLAGS_WIN32 += -nologo EXT_OBJ := obj EXT_LIB := lib ifeq ($(CC),gcc) # work around GNU Make default value ifdef THREADS CC := cl -MT else CC := cl endif endif ifeq ($(CXX),g++) # work around GNU Make default value CXX := $(CC) endif CFLAG_O := -Fo endif ifdef WIN32 EXT_CXX := cpp EXE := .exe endif ifndef EXT_OBJ EXT_OBJ := o endif ifndef EXT_LIB EXT_LIB := a endif ifndef EXT_CXX EXT_CXX := cc endif ifndef EXE EXE := # empty endif ifndef CFLAG_O CFLAG_O := -o # do not delete this comment (preserves trailing whitespace)! endif export CC export CXX export CFLAGS export CXXFLAGS export LDFLAGS export CPPFLAGS ifndef RPATH_FLAG ifdef ELF_RPATH_FLAG RPATH_FLAG := $(ELF_RPATH_FLAG) else RPATH_FLAG := -R endif endif export RPATH_FLAG ifndef MSVC ifndef PIC_CFLAGS PIC_CFLAGS := -fPIC endif ifndef PIC_CPPFLAGS PIC_CPPFLAGS := -DPIC endif endif export PIC_CFLAGS export PIC_CPPFLAGS BCRESULT := $(addsuffix $(BCSUFFIX), $(RESULT)) NCRESULT := $(addsuffix $(NCSUFFIX), $(RESULT)) TOPRESULT := $(addsuffix $(TOPSUFFIX), $(RESULT)) ifndef OCAMLFIND OCAMLFIND := ocamlfind endif export OCAMLFIND ifndef OCAML OCAML := ocaml endif export OCAML ifndef OCAMLC OCAMLC := ocamlc endif export OCAMLC ifndef OCAMLOPT OCAMLOPT := ocamlopt endif export OCAMLOPT ifndef OCAMLMKTOP OCAMLMKTOP := ocamlmktop endif export OCAMLMKTOP ifndef OCAMLCP OCAMLCP := ocamlcp endif export OCAMLCP ifndef OCAMLDEP OCAMLDEP := ocamldep endif export OCAMLDEP ifndef OCAMLLEX OCAMLLEX := ocamllex endif export OCAMLLEX ifndef OCAMLYACC OCAMLYACC := ocamlyacc endif export OCAMLYACC ifndef OCAMLMKLIB OCAMLMKLIB := ocamlmklib endif export OCAMLMKLIB ifndef OCAML_GLADECC OCAML_GLADECC := lablgladecc2 endif export OCAML_GLADECC ifndef OCAML_GLADECC_FLAGS OCAML_GLADECC_FLAGS := endif export OCAML_GLADECC_FLAGS ifndef CAMELEON_REPORT CAMELEON_REPORT := report endif export CAMELEON_REPORT ifndef CAMELEON_REPORT_FLAGS CAMELEON_REPORT_FLAGS := endif export CAMELEON_REPORT_FLAGS ifndef CAMELEON_ZOGGY CAMELEON_ZOGGY := camlp4o pa_zog.cma pr_o.cmo endif export CAMELEON_ZOGGY ifndef CAMELEON_ZOGGY_FLAGS CAMELEON_ZOGGY_FLAGS := endif export CAMELEON_ZOGGY_FLAGS ifndef OXRIDL OXRIDL := oxridl endif export OXRIDL ifndef CAMLIDL CAMLIDL := camlidl endif export CAMLIDL ifndef CAMLIDLDLL CAMLIDLDLL := camlidldll endif export CAMLIDLDLL ifndef NOIDLHEADER MAYBE_IDL_HEADER := -header endif export NOIDLHEADER export NO_CUSTOM ifndef CAMLP4 CAMLP4 := camlp4 endif export CAMLP4 ifndef REAL_OCAMLFIND ifdef PACKS ifndef CREATE_LIB ifdef THREADS PACKS += threads endif endif empty := space := $(empty) $(empty) comma := , ifdef PREDS PRE_OCAML_FIND_PREDICATES := $(subst $(space),$(comma),$(PREDS)) PRE_OCAML_FIND_PACKAGES := $(subst $(space),$(comma),$(PACKS)) OCAML_FIND_PREDICATES := -predicates $(PRE_OCAML_FIND_PREDICATES) # OCAML_DEP_PREDICATES := -syntax $(PRE_OCAML_FIND_PREDICATES) OCAML_FIND_PACKAGES := $(OCAML_FIND_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES) OCAML_DEP_PACKAGES := $(OCAML_DEP_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES) else OCAML_FIND_PACKAGES := -package $(subst $(space),$(comma),$(PACKS)) OCAML_DEP_PACKAGES := endif OCAML_FIND_LINKPKG := -linkpkg REAL_OCAMLFIND := $(OCAMLFIND) endif endif export OCAML_FIND_PACKAGES export OCAML_DEP_PACKAGES export OCAML_FIND_LINKPKG export REAL_OCAMLFIND ifndef OCAMLDOC OCAMLDOC := ocamldoc endif export OCAMLDOC ifndef LATEX LATEX := latex endif export LATEX ifndef DVIPS DVIPS := dvips endif export DVIPS ifndef PS2PDF PS2PDF := ps2pdf endif export PS2PDF ifndef OCAMLMAKEFILE OCAMLMAKEFILE := OCamlMakefile endif export OCAMLMAKEFILE ifndef OCAMLLIBPATH OCAMLLIBPATH := \ $(shell $(OCAMLC) 2>/dev/null -where || echo /usr/local/lib/ocaml) endif export OCAMLLIBPATH ifndef OCAML_LIB_INSTALL OCAML_LIB_INSTALL := $(OCAMLLIBPATH)/contrib endif export OCAML_LIB_INSTALL ########################################################################### #################### change following sections only if #################### you know what you are doing! # delete target files when a build command fails .PHONY: .DELETE_ON_ERROR .DELETE_ON_ERROR: # for pedants using "--warn-undefined-variables" export MAYBE_IDL export REAL_RESULT export CAMLIDLFLAGS export THREAD_FLAG export RES_CLIB export MAKEDLL export ANNOT_FLAG export C_OXRIDL export SUBPROJS export CFLAGS_WIN32 export CPPFLAGS_WIN32 INCFLAGS := SHELL := /bin/sh MLDEPDIR := ._d BCDIDIR := ._bcdi NCDIDIR := ._ncdi FILTER_EXTNS := %.mli %.ml %.mll %.mly %.idl %.oxridl %.c %.m %.$(EXT_CXX) %.rep %.zog %.glade FILTERED := $(filter $(FILTER_EXTNS), $(SOURCES)) SOURCE_DIRS := $(filter-out ./, $(sort $(dir $(FILTERED)))) FILTERED_REP := $(filter %.rep, $(FILTERED)) DEP_REP := $(FILTERED_REP:%.rep=$(MLDEPDIR)/%.d) AUTO_REP := $(FILTERED_REP:.rep=.ml) FILTERED_ZOG := $(filter %.zog, $(FILTERED)) DEP_ZOG := $(FILTERED_ZOG:%.zog=$(MLDEPDIR)/%.d) AUTO_ZOG := $(FILTERED_ZOG:.zog=.ml) FILTERED_GLADE := $(filter %.glade, $(FILTERED)) DEP_GLADE := $(FILTERED_GLADE:%.glade=$(MLDEPDIR)/%.d) AUTO_GLADE := $(FILTERED_GLADE:.glade=.ml) FILTERED_ML := $(filter %.ml, $(FILTERED)) DEP_ML := $(FILTERED_ML:%.ml=$(MLDEPDIR)/%.d) FILTERED_MLI := $(filter %.mli, $(FILTERED)) DEP_MLI := $(FILTERED_MLI:.mli=.di) FILTERED_MLL := $(filter %.mll, $(FILTERED)) DEP_MLL := $(FILTERED_MLL:%.mll=$(MLDEPDIR)/%.d) AUTO_MLL := $(FILTERED_MLL:.mll=.ml) FILTERED_MLY := $(filter %.mly, $(FILTERED)) DEP_MLY := $(FILTERED_MLY:%.mly=$(MLDEPDIR)/%.d) $(FILTERED_MLY:.mly=.di) AUTO_MLY := $(FILTERED_MLY:.mly=.mli) $(FILTERED_MLY:.mly=.ml) FILTERED_IDL := $(filter %.idl, $(FILTERED)) DEP_IDL := $(FILTERED_IDL:%.idl=$(MLDEPDIR)/%.d) $(FILTERED_IDL:.idl=.di) C_IDL := $(FILTERED_IDL:%.idl=%_stubs.c) ifndef NOIDLHEADER C_IDL += $(FILTERED_IDL:.idl=.h) endif OBJ_C_IDL := $(FILTERED_IDL:%.idl=%_stubs.$(EXT_OBJ)) AUTO_IDL := $(FILTERED_IDL:.idl=.mli) $(FILTERED_IDL:.idl=.ml) $(C_IDL) FILTERED_OXRIDL := $(filter %.oxridl, $(FILTERED)) DEP_OXRIDL := $(FILTERED_OXRIDL:%.oxridl=$(MLDEPDIR)/%.d) $(FILTERED_OXRIDL:.oxridl=.di) AUTO_OXRIDL := $(FILTERED_OXRIDL:.oxridl=.mli) $(FILTERED_OXRIDL:.oxridl=.ml) $(C_OXRIDL) FILTERED_C_CXX := $(filter %.c %.m %.$(EXT_CXX), $(FILTERED)) OBJ_C_CXX := $(FILTERED_C_CXX:.c=.$(EXT_OBJ)) OBJ_C_CXX := $(OBJ_C_CXX:.m=.$(EXT_OBJ)) OBJ_C_CXX := $(OBJ_C_CXX:.$(EXT_CXX)=.$(EXT_OBJ)) PRE_TARGETS += $(AUTO_MLL) $(AUTO_MLY) $(AUTO_IDL) $(AUTO_OXRIDL) $(AUTO_ZOG) $(AUTO_REP) $(AUTO_GLADE) ALL_DEPS := $(DEP_ML) $(DEP_MLI) $(DEP_MLL) $(DEP_MLY) $(DEP_IDL) $(DEP_OXRIDL) $(DEP_ZOG) $(DEP_REP) $(DEP_GLADE) MLDEPS := $(filter %.d, $(ALL_DEPS)) MLIDEPS := $(filter %.di, $(ALL_DEPS)) BCDEPIS := $(MLIDEPS:%.di=$(BCDIDIR)/%.di) NCDEPIS := $(MLIDEPS:%.di=$(NCDIDIR)/%.di) ALLML := $(filter %.mli %.ml %.mll %.mly %.idl %.oxridl %.rep %.zog %.glade, $(FILTERED)) IMPLO_INTF := $(ALLML:%.mli=%.mli.__) IMPLO_INTF := $(foreach file, $(IMPLO_INTF), \ $(basename $(file)).cmi $(basename $(file)).cmo) IMPLO_INTF := $(filter-out %.mli.cmo, $(IMPLO_INTF)) IMPLO_INTF := $(IMPLO_INTF:%.mli.cmi=%.cmi) IMPLX_INTF := $(IMPLO_INTF:.cmo=.cmx) INTF := $(filter %.cmi, $(IMPLO_INTF)) IMPL_CMO := $(filter %.cmo, $(IMPLO_INTF)) IMPL_CMX := $(IMPL_CMO:.cmo=.cmx) IMPL_ASM := $(IMPL_CMO:.cmo=.asm) IMPL_S := $(IMPL_CMO:.cmo=.s) OBJ_LINK := $(OBJ_C_IDL) $(OBJ_C_CXX) OBJ_FILES := $(IMPL_CMO:.cmo=.$(EXT_OBJ)) $(OBJ_LINK) EXECS := $(addsuffix $(EXE), \ $(sort $(TOPRESULT) $(BCRESULT) $(NCRESULT))) ifdef WIN32 EXECS += $(BCRESULT).dll $(NCRESULT).dll endif CLIB_BASE := $(RESULT)$(RES_CLIB_SUF) ifneq ($(strip $(OBJ_LINK)),) RES_CLIB := lib$(CLIB_BASE).$(EXT_LIB) endif ifdef WIN32 DLLSONAME := dll$(CLIB_BASE).dll else DLLSONAME := dll$(CLIB_BASE).so endif NONEXECS := $(INTF) $(IMPL_CMO) $(IMPL_CMX) $(IMPL_ASM) $(IMPL_S) \ $(OBJ_FILES) $(PRE_TARGETS) $(BCRESULT).cma $(NCRESULT).cmxa \ $(NCRESULT).$(EXT_LIB) $(BCRESULT).cmi $(BCRESULT).cmo \ $(NCRESULT).cmi $(NCRESULT).cmx $(NCRESULT).$(EXT_OBJ) \ $(RES_CLIB) $(IMPL_CMO:.cmo=.annot) \ $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(LIB_PACK_NAME).cmx \ $(LIB_PACK_NAME).$(EXT_OBJ) ifndef STATIC NONEXECS += $(DLLSONAME) endif ifndef LIBINSTALL_FILES LIBINSTALL_FILES := $(RESULT).mli $(RESULT).cmi $(RESULT).cma \ $(RESULT).cmxa $(RESULT).$(EXT_LIB) $(RES_CLIB) ifndef STATIC ifneq ($(strip $(OBJ_LINK)),) LIBINSTALL_FILES += $(DLLSONAME) endif endif endif export LIBINSTALL_FILES ifdef WIN32 # some extra stuff is created while linking DLLs NONEXECS += $(BCRESULT).$(EXT_LIB) $(BCRESULT).exp $(NCRESULT).exp $(CLIB_BASE).exp $(CLIB_BASE).lib endif TARGETS := $(EXECS) $(NONEXECS) # If there are IDL-files ifneq ($(strip $(FILTERED_IDL)),) MAYBE_IDL := -cclib -lcamlidl endif ifdef USE_CAMLP4 CAMLP4PATH := \ $(shell $(CAMLP4) -where 2>/dev/null || echo /usr/local/lib/camlp4) INCFLAGS := -I $(CAMLP4PATH) CINCFLAGS := -I$(CAMLP4PATH) endif INCFLAGS := $(INCFLAGS) $(INCDIRS:%=-I %) $(SOURCE_DIRS:%=-I %) $(OCAML_DEFAULT_DIRS:%=-I %) CINCFLAGS += $(SOURCE_DIRS:%=-I%) $(INCDIRS:%=-I%) $(OCAML_DEFAULT_DIRS:%=-I%) ifndef MSVC CLIBFLAGS += $(SOURCE_DIRS:%=-L%) $(LIBDIRS:%=-L%) \ $(EXTLIBDIRS:%=-L%) $(OCAML_DEFAULT_DIRS:%=-L%) ifeq ($(ELF_RPATH), yes) CLIBFLAGS += $(EXTLIBDIRS:%=-Wl,$(RPATH_FLAG)%) endif endif ifndef PROFILING INTF_OCAMLC := $(OCAMLC) else ifndef THREADS INTF_OCAMLC := $(OCAMLCP) -p $(OCAMLCPFLAGS) else # OCaml does not support profiling byte code # with threads (yet), therefore we force an error. ifndef REAL_OCAMLC $(error Profiling of multithreaded byte code not yet supported by OCaml) endif INTF_OCAMLC := $(OCAMLC) endif endif ifndef MSVC COMMON_LDFLAGS := $(LDFLAGS:%=-ccopt %) $(SOURCE_DIRS:%=-ccopt -L%) \ $(LIBDIRS:%=-ccopt -L%) $(EXTLIBDIRS:%=-ccopt -L%) \ $(EXTLIBDIRS:%=-ccopt -Wl $(OCAML_DEFAULT_DIRS:%=-ccopt -L%)) ifeq ($(ELF_RPATH),yes) COMMON_LDFLAGS += $(EXTLIBDIRS:%=-ccopt -Wl,$(RPATH_FLAG)%) endif else COMMON_LDFLAGS := -ccopt "/link -NODEFAULTLIB:LIBC $(LDFLAGS:%=%) $(SOURCE_DIRS:%=-LIBPATH:%) \ $(LIBDIRS:%=-LIBPATH:%) $(EXTLIBDIRS:%=-LIBPATH:%) \ $(OCAML_DEFAULT_DIRS:%=-LIBPATH:%) " endif CLIBS_OPTS := $(CLIBS:%=-cclib -l%) $(CFRAMEWORKS:%=-cclib '-framework %') ifdef MSVC ifndef STATIC # MSVC libraries do not have 'lib' prefix CLIBS_OPTS := $(CLIBS:%=-cclib %.lib) endif endif ifneq ($(strip $(OBJ_LINK)),) ifdef CREATE_LIB OBJS_LIBS := -cclib -l$(CLIB_BASE) $(CLIBS_OPTS) $(MAYBE_IDL) else OBJS_LIBS := $(OBJ_LINK) $(CLIBS_OPTS) $(MAYBE_IDL) endif else OBJS_LIBS := $(CLIBS_OPTS) $(MAYBE_IDL) endif ifdef LIB_PACK_NAME FOR_PACK_NAME := $(shell echo $(LIB_PACK_NAME) | awk '{print toupper(substr($$0,1,1))substr($$0,2)}') endif # If we have to make byte-code ifndef REAL_OCAMLC BYTE_OCAML := y # EXTRADEPS is added dependencies we have to insert for all # executable files we generate. Ideally it should be all of the # libraries we use, but it's hard to find the ones that get searched on # the path since I don't know the paths built into the compiler, so # just include the ones with slashes in their names. EXTRADEPS := $(addsuffix .cma,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i)))) ifndef LIB_PACK_NAME SPECIAL_OCAMLFLAGS := $(OCAMLBCFLAGS) else SPECIAL_OCAMLFLAGS := -for-pack $(FOR_PACK_NAME) $(OCAMLBCFLAGS) endif REAL_OCAMLC := $(INTF_OCAMLC) REAL_IMPL := $(IMPL_CMO) REAL_IMPL_INTF := $(IMPLO_INTF) IMPL_SUF := .cmo DEPFLAGS := MAKE_DEPS := $(MLDEPS) $(BCDEPIS) ifdef CREATE_LIB override CFLAGS := $(PIC_CFLAGS) $(CFLAGS) override CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS) ifndef STATIC ifneq ($(strip $(OBJ_LINK)),) MAKEDLL := $(DLLSONAME) ALL_LDFLAGS := -dllib $(DLLSONAME) endif endif endif ifndef NO_CUSTOM ifneq "$(strip $(OBJ_LINK) $(THREADS) $(MAYBE_IDL) $(CLIBS) $(CFRAMEWORKS))" "" ALL_LDFLAGS += -custom endif endif ALL_LDFLAGS += $(INCFLAGS) $(OCAMLLDFLAGS) $(OCAMLBLDFLAGS) \ $(COMMON_LDFLAGS) $(LIBS:%=%.cma) CAMLIDLDLLFLAGS := ifdef THREADS ifdef VMTHREADS THREAD_FLAG := -vmthread else THREAD_FLAG := -thread endif ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS) ifndef CREATE_LIB ifndef REAL_OCAMLFIND ALL_LDFLAGS := unix.cma threads.cma $(ALL_LDFLAGS) endif endif endif # we have to make native-code else EXTRADEPS := $(addsuffix .cmxa,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i)))) ifndef PROFILING SPECIAL_OCAMLFLAGS := $(OCAMLNCFLAGS) PLDFLAGS := else SPECIAL_OCAMLFLAGS := -p $(OCAMLNCFLAGS) PLDFLAGS := -p endif ifndef LIB_PACK_NAME SPECIAL_OCAMLFLAGS := $(OCAMLNCFLAGS) else SPECIAL_OCAMLFLAGS := -for-pack $(FOR_PACK_NAME) $(OCAMLNCFLAGS) endif REAL_IMPL := $(IMPL_CMX) REAL_IMPL_INTF := $(IMPLX_INTF) IMPL_SUF := .cmx override CPPFLAGS := -DNATIVE_CODE $(CPPFLAGS) DEPFLAGS := -native MAKE_DEPS := $(MLDEPS) $(NCDEPIS) ALL_LDFLAGS := $(PLDFLAGS) $(INCFLAGS) $(OCAMLLDFLAGS) \ $(OCAMLNLDFLAGS) $(COMMON_LDFLAGS) CAMLIDLDLLFLAGS := -opt ifndef CREATE_LIB ALL_LDFLAGS += $(LIBS:%=%.cmxa) else override CFLAGS := $(PIC_CFLAGS) $(CFLAGS) override CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS) endif ifdef THREADS THREAD_FLAG := -thread ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS) ifndef CREATE_LIB ifndef REAL_OCAMLFIND ALL_LDFLAGS := unix.cmxa threads.cmxa $(ALL_LDFLAGS) endif endif endif endif export MAKE_DEPS ifdef ANNOTATE ANNOT_FLAG := -annot -bin-annot else endif ALL_OCAMLCFLAGS := $(THREAD_FLAG) $(ANNOT_FLAG) $(OCAMLFLAGS) \ $(INCFLAGS) $(SPECIAL_OCAMLFLAGS) ifdef make_deps -include $(MAKE_DEPS) PRE_TARGETS := endif ########################################################################### # USER RULES # Call "OCamlMakefile QUIET=" to get rid of all of the @'s. QUIET=@ # generates byte-code (default) byte-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ REAL_RESULT="$(BCRESULT)" make_deps=yes bc: byte-code byte-code-nolink: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ REAL_RESULT="$(BCRESULT)" make_deps=yes bcnl: byte-code-nolink top: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(TOPRESULT) \ REAL_RESULT="$(BCRESULT)" make_deps=yes # generates native-code native-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ make_deps=yes nc: native-code native-code-nolink: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ make_deps=yes ncnl: native-code-nolink # generates byte-code libraries byte-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).cma \ REAL_RESULT="$(BCRESULT)" \ CREATE_LIB=yes \ make_deps=yes bcl: byte-code-library # generates native-code libraries native-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(NCRESULT).cmxa \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ CREATE_LIB=yes \ make_deps=yes ncl: native-code-library ifdef WIN32 # generates byte-code dll byte-code-dll: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).dll \ REAL_RESULT="$(BCRESULT)" \ make_deps=yes bcd: byte-code-dll # generates native-code dll native-code-dll: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(NCRESULT).dll \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ make_deps=yes ncd: native-code-dll endif # generates byte-code with debugging information debug-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ REAL_RESULT="$(BCRESULT)" make_deps=yes \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dc: debug-code debug-code-nolink: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ REAL_RESULT="$(BCRESULT)" make_deps=yes \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dcnl: debug-code-nolink # generates byte-code with debugging information (native code) debug-native-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \ REAL_RESULT="$(NCRESULT)" make_deps=yes \ REAL_OCAMLC="$(OCAMLOPT)" \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dnc: debug-native-code debug-native-code-nolink: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ REAL_RESULT="$(NCRESULT)" make_deps=yes \ REAL_OCAMLC="$(OCAMLOPT)" \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dncnl: debug-native-code-nolink # generates byte-code libraries with debugging information debug-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).cma \ REAL_RESULT="$(BCRESULT)" make_deps=yes \ CREATE_LIB=yes \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dcl: debug-code-library # generates byte-code libraries with debugging information (native code) debug-native-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(NCRESULT).cmxa \ REAL_RESULT="$(NCRESULT)" make_deps=yes \ REAL_OCAMLC="$(OCAMLOPT)" \ CREATE_LIB=yes \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dncl: debug-native-code-library # generates byte-code for profiling profiling-byte-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ REAL_RESULT="$(BCRESULT)" PROFILING="y" \ make_deps=yes pbc: profiling-byte-code # generates native-code profiling-native-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ PROFILING="y" \ make_deps=yes pnc: profiling-native-code # generates byte-code libraries profiling-byte-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).cma \ REAL_RESULT="$(BCRESULT)" PROFILING="y" \ CREATE_LIB=yes \ make_deps=yes pbcl: profiling-byte-code-library # generates native-code libraries profiling-native-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(NCRESULT).cmxa \ REAL_RESULT="$(NCRESULT)" PROFILING="y" \ REAL_OCAMLC="$(OCAMLOPT)" \ CREATE_LIB=yes \ make_deps=yes pncl: profiling-native-code-library # packs byte-code objects pack-byte-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT).cmo \ REAL_RESULT="$(BCRESULT)" \ PACK_LIB=yes make_deps=yes pabc: pack-byte-code # packs native-code objects pack-native-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(NCRESULT).cmx $(NCRESULT).$(EXT_OBJ) \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ PACK_LIB=yes make_deps=yes panc: pack-native-code # generates HTML-documentation htdoc: $(DOC_DIR)/$(RESULT)/html/index.html # generates Latex-documentation ladoc: $(DOC_DIR)/$(RESULT)/latex/doc.tex # generates PostScript-documentation psdoc: $(DOC_DIR)/$(RESULT)/latex/doc.ps # generates PDF-documentation pdfdoc: $(DOC_DIR)/$(RESULT)/latex/doc.pdf # generates all supported forms of documentation doc: htdoc ladoc psdoc pdfdoc ########################################################################### # LOW LEVEL RULES $(REAL_RESULT): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(REAL_OCAMLC) \ $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \ $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@$(EXE) \ $(REAL_IMPL) nolink: $(REAL_IMPL_INTF) $(OBJ_LINK) ifdef WIN32 $(REAL_RESULT).dll: $(REAL_IMPL_INTF) $(OBJ_LINK) $(CAMLIDLDLL) $(CAMLIDLDLLFLAGS) $(OBJ_LINK) $(CLIBS) \ -o $@ $(REAL_IMPL) endif %$(TOPSUFFIX): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) $(REAL_OCAMLFIND) $(OCAMLMKTOP) \ $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \ $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@$(EXE) \ $(REAL_IMPL) .SUFFIXES: .mli .ml .cmi .cmo .cmx .cma .cmxa .$(EXT_OBJ) \ .mly .di .d .$(EXT_LIB) .idl %.oxridl .c .m .$(EXT_CXX) .h .so \ .rep .zog .glade ifndef STATIC ifdef MINGW # From OCaml 3.11.0, ocamlmklib is available on windows OCAMLMLIB_EXISTS = $(shell which $(OCAMLMKLIB)) ifeq ($(strip $(OCAMLMLIB_EXISTS)),) $(DLLSONAME): $(OBJ_LINK) $(CC) $(CFLAGS) $(CFLAGS_WIN32) $(OBJ_LINK) -shared -o $@ \ $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/lib%.a))) \ '$(OCAMLLIBPATH)/ocamlrun.a' \ -Wl,--whole-archive \ -Wl,--export-all-symbols \ -Wl,--allow-multiple-definition \ -Wl,--enable-auto-import else $(DLLSONAME): $(OBJ_LINK) $(OCAMLMKLIB) $(INCFLAGS) $(CLIBFLAGS) \ -o $(CLIB_BASE) $(OBJ_LINK) $(CLIBS:%=-l%) \ $(CFRAMEWORKS:%=-framework %) \ $(OCAMLMKLIB_FLAGS) endif else ifdef MSVC $(DLLSONAME): $(OBJ_LINK) link /NOLOGO /DLL /OUT:$@ $(OBJ_LINK) \ $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/%.lib))) \ '$(OCAMLLIBPATH)/ocamlrun.lib' else $(DLLSONAME): $(OBJ_LINK) $(OCAMLMKLIB) $(INCFLAGS) $(CLIBFLAGS) \ -o $(CLIB_BASE) $(OBJ_LINK) $(CLIBS:%=-l%) $(CFRAMEWORKS:%=-framework %) \ $(OCAMLMKLIB_FLAGS) endif endif endif ifndef LIB_PACK_NAME $(RESULT).cma: $(REAL_IMPL_INTF) $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@ $(REAL_IMPL) $(RESULT).cmxa $(RESULT).$(EXT_LIB): $(REAL_IMPL_INTF) $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(OCAMLOPT) -a $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@ $(REAL_IMPL) else # Packing a bytecode library LIB_PACK_NAME_MLI = $(wildcard $(LIB_PACK_NAME).mli) ifeq ($(LIB_PACK_NAME_MLI),) LIB_PACK_NAME_CMI = $(LIB_PACK_NAME).cmi else # $(LIB_PACK_NAME).mli exists, it likely depends on other compiled interfaces LIB_PACK_NAME_CMI = $(LIB_PACK_NAME).cmi: $(REAL_IMPL_INTF) endif ifdef BYTE_OCAML $(LIB_PACK_NAME_CMI) $(LIB_PACK_NAME).cmo: $(REAL_IMPL_INTF) $(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack -o $(LIB_PACK_NAME).cmo $(OCAMLLDFLAGS) $(REAL_IMPL) # Packing into a unit which can be transformed into a library # Remember the .ml's must have been compiled with -for-pack $(LIB_PACK_NAME) else $(LIB_PACK_NAME_CMI) $(LIB_PACK_NAME).cmx: $(REAL_IMPL_INTF) $(REAL_OCAMLFIND) $(OCAMLOPT) -pack -o $(LIB_PACK_NAME).cmx $(OCAMLLDFLAGS) $(REAL_IMPL) endif $(RESULT).cma: $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@ $(LIB_PACK_NAME).cmo $(RESULT).cmxa $(RESULT).$(EXT_LIB): $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmx $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(OCAMLOPT) -a $(OBJS_LIBS) $(filter-out -custom, $(ALL_LDFLAGS)) -o $@ $(LIB_PACK_NAME).cmx endif $(RES_CLIB): $(OBJ_LINK) ifndef MSVC ifneq ($(strip $(OBJ_LINK)),) $(AR) rcs $@ $(OBJ_LINK) endif else ifneq ($(strip $(OBJ_LINK)),) lib -nologo -debugtype:cv -out:$(RES_CLIB) $(OBJ_LINK) endif endif %.cmi: %.mli $(EXTRADEPS) $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ $(ECHO) $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ else \ $(ECHO) $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp \"$$pp $(PPFLAGS)\" $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp "$$pp $(PPFLAGS)" $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ fi %.cmi: %$(IMPL_SUF); %$(IMPL_SUF) %.$(EXT_OBJ): %.ml $(EXTRADEPS) $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ $(ECHO) $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(ALL_OCAMLCFLAGS) $<; \ $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(ALL_OCAMLCFLAGS) $<; \ else \ $(ECHO) $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp \"$$pp $(PPFLAGS)\" $(ALL_OCAMLCFLAGS) $<; \ $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp "$$pp $(PPFLAGS)" $(ALL_OCAMLCFLAGS) $<; \ fi .PRECIOUS: %.ml %.ml: %.mll $(OCAMLLEX) $(LFLAGS) $< .PRECIOUS: %.ml %.mli %.ml %.mli: %.mly $(OCAMLYACC) $(YFLAGS) $< $(QUIET)pp=`sed -n -e 's/.*(\*pp \([^*]*\) \*).*/\1/p;q' $<`; \ if [ ! -z "$$pp" ]; then \ mv $*.ml $*.ml.temporary; \ echo "(*pp $$pp $(PPFLAGS)*)" > $*.ml; \ cat $*.ml.temporary >> $*.ml; \ rm $*.ml.temporary; \ mv $*.mli $*.mli.temporary; \ echo "(*pp $$pp $(PPFLAGS)*)" > $*.mli; \ cat $*.mli.temporary >> $*.mli; \ rm $*.mli.temporary; \ fi .PRECIOUS: %.ml %.ml: %.rep $(CAMELEON_REPORT) $(CAMELEON_REPORT_FLAGS) -gen $< .PRECIOUS: %.ml %.ml: %.zog $(CAMELEON_ZOGGY) $(CAMELEON_ZOGGY_FLAGS) -impl $< > $@ .PRECIOUS: %.ml %.ml: %.glade $(OCAML_GLADECC) $(OCAML_GLADECC_FLAGS) $< > $@ .PRECIOUS: %.ml %.mli %.ml %.mli: %.oxridl $(OXRIDL) $< .PRECIOUS: %.ml %.mli %_stubs.c %.h %.ml %.mli %_stubs.c %.h: %.idl $(CAMLIDL) $(MAYBE_IDL_HEADER) $(IDLFLAGS) \ $(CAMLIDLFLAGS) $< $(QUIET)if [ $(NOIDLHEADER) ]; then touch $*.h; fi %.$(EXT_OBJ): %.c $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(THREAD_FLAG) $(OCAML_FIND_PACKAGES) \ -c -cc "$(CC)" $(INCFLAGS) -ccopt "$(CFLAGS) \ $(CPPFLAGS) $(CPPFLAGS_WIN32) \ $(CFLAGS_WIN32) $(CINCFLAGS) $(CFLAG_O)$@ " $< %.$(EXT_OBJ): %.m $(CC) -c $(CFLAGS) $(CINCFLAGS) $(CPPFLAGS) \ -I'$(OCAMLLIBPATH)' \ $< $(CFLAG_O)$@ %.$(EXT_OBJ): %.$(EXT_CXX) $(CXX) -c $(CXXFLAGS) $(CINCFLAGS) $(CPPFLAGS) \ -I'$(OCAMLLIBPATH)' \ $< $(CFLAG_O)$@ $(MLDEPDIR)/%.d: %.ml $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ $(INCFLAGS) $< \> $@; \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ $(INCFLAGS) $< > $@; \ else \ $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ -pp \"$$pp $(PPFLAGS)\" $(INCFLAGS) $< \> $@; \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ -pp "$$pp $(PPFLAGS)" $(INCFLAGS) $< > $@; \ fi $(BCDIDIR)/%.di $(NCDIDIR)/%.di: %.mli $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(INCFLAGS) $< \> $@; \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(INCFLAGS) $< > $@; \ else \ $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \ -pp \"$$pp $(PPFLAGS)\" $(INCFLAGS) $< \> $@; \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \ -pp "$$pp $(PPFLAGS)" $(INCFLAGS) $< > $@; \ fi $(DOC_DIR)/$(RESULT)/html: mkdir -p $@ $(DOC_DIR)/$(RESULT)/html/index.html: $(DOC_DIR)/$(RESULT)/html $(DOC_FILES) rm -rf $= "4.10"} "ocamlfind" {build} ] synopsis: "Read, write and modify PDF files" camlpdf-2.8.1/compressor/000077500000000000000000000000001477056064700153445ustar00rootroot00000000000000camlpdf-2.8.1/compressor/Courier-Bold.afm000066400000000000000000000357451477056064700203350ustar00rootroot00000000000000StartFontMetrics 4.1 Comment Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. Comment Creation Date: Mon Jun 23 16:28:00 1997 Comment UniqueID 43048 Comment VMusage 41139 52164 FontName Courier-Bold FullName Courier Bold FamilyName Courier Weight Bold ItalicAngle 0 IsFixedPitch true CharacterSet ExtendedRoman FontBBox -113 -250 749 801 UnderlinePosition -100 UnderlineThickness 50 Version 003.000 Notice Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. EncodingScheme AdobeStandardEncoding CapHeight 562 XHeight 439 Ascender 629 Descender -157 StdHW 84 StdVW 106 StartCharMetrics 315 C 32 ; WX 600 ; N space ; B 0 0 0 0 ; C 33 ; WX 600 ; N exclam ; B 202 -15 398 572 ; C 34 ; WX 600 ; N quotedbl ; B 135 277 465 562 ; C 35 ; WX 600 ; N numbersign ; B 56 -45 544 651 ; C 36 ; WX 600 ; N dollar ; B 82 -126 519 666 ; C 37 ; WX 600 ; N percent ; B 5 -15 595 616 ; C 38 ; WX 600 ; N ampersand ; B 36 -15 546 543 ; C 39 ; WX 600 ; N quoteright ; B 171 277 423 562 ; C 40 ; WX 600 ; N parenleft ; B 219 -102 461 616 ; C 41 ; WX 600 ; N parenright ; B 139 -102 381 616 ; C 42 ; WX 600 ; N asterisk ; B 91 219 509 601 ; C 43 ; WX 600 ; N plus ; B 71 39 529 478 ; C 44 ; WX 600 ; N comma ; B 123 -111 393 174 ; C 45 ; WX 600 ; N hyphen ; B 100 203 500 313 ; C 46 ; WX 600 ; N period ; B 192 -15 408 171 ; C 47 ; WX 600 ; N slash ; B 98 -77 502 626 ; C 48 ; WX 600 ; N zero ; B 87 -15 513 616 ; C 49 ; WX 600 ; N one ; B 81 0 539 616 ; C 50 ; WX 600 ; N two ; B 61 0 499 616 ; C 51 ; WX 600 ; N three ; B 63 -15 501 616 ; C 52 ; WX 600 ; N four ; B 53 0 507 616 ; C 53 ; WX 600 ; N five ; B 70 -15 521 601 ; C 54 ; WX 600 ; N six ; B 90 -15 521 616 ; C 55 ; WX 600 ; N seven ; B 55 0 494 601 ; C 56 ; WX 600 ; N eight ; B 83 -15 517 616 ; C 57 ; WX 600 ; N nine ; B 79 -15 510 616 ; C 58 ; WX 600 ; N colon ; B 191 -15 407 425 ; C 59 ; WX 600 ; N semicolon ; B 123 -111 408 425 ; C 60 ; WX 600 ; N less ; B 66 15 523 501 ; C 61 ; WX 600 ; N equal ; B 71 118 529 398 ; C 62 ; WX 600 ; N greater ; B 77 15 534 501 ; C 63 ; WX 600 ; N question ; B 98 -14 501 580 ; C 64 ; WX 600 ; N at ; B 16 -15 584 616 ; C 65 ; WX 600 ; N A ; B -9 0 609 562 ; C 66 ; WX 600 ; N B ; B 30 0 573 562 ; C 67 ; WX 600 ; N C ; B 22 -18 560 580 ; C 68 ; WX 600 ; N D ; B 30 0 594 562 ; C 69 ; WX 600 ; N E ; B 25 0 560 562 ; C 70 ; WX 600 ; N F ; B 39 0 570 562 ; C 71 ; WX 600 ; N G ; B 22 -18 594 580 ; C 72 ; WX 600 ; N H ; B 20 0 580 562 ; C 73 ; WX 600 ; N I ; B 77 0 523 562 ; C 74 ; WX 600 ; N J ; B 37 -18 601 562 ; C 75 ; WX 600 ; N K ; B 21 0 599 562 ; C 76 ; WX 600 ; N L ; B 39 0 578 562 ; C 77 ; WX 600 ; N M ; B -2 0 602 562 ; C 78 ; WX 600 ; N N ; B 8 -12 610 562 ; C 79 ; WX 600 ; N O ; B 22 -18 578 580 ; C 80 ; WX 600 ; N P ; B 48 0 559 562 ; C 81 ; WX 600 ; N Q ; B 32 -138 578 580 ; C 82 ; WX 600 ; N R ; B 24 0 599 562 ; C 83 ; WX 600 ; N S ; B 47 -22 553 582 ; C 84 ; WX 600 ; N T ; B 21 0 579 562 ; C 85 ; WX 600 ; N U ; B 4 -18 596 562 ; C 86 ; WX 600 ; N V ; B -13 0 613 562 ; C 87 ; WX 600 ; N W ; B -18 0 618 562 ; C 88 ; WX 600 ; N X ; B 12 0 588 562 ; C 89 ; WX 600 ; N Y ; B 12 0 589 562 ; C 90 ; WX 600 ; N Z ; B 62 0 539 562 ; C 91 ; WX 600 ; N bracketleft ; B 245 -102 475 616 ; C 92 ; WX 600 ; N backslash ; B 99 -77 503 626 ; C 93 ; WX 600 ; N bracketright ; B 125 -102 355 616 ; C 94 ; WX 600 ; N asciicircum ; B 108 250 492 616 ; C 95 ; WX 600 ; N underscore ; B 0 -125 600 -75 ; C 96 ; WX 600 ; N quoteleft ; B 178 277 428 562 ; C 97 ; WX 600 ; N a ; B 35 -15 570 454 ; C 98 ; WX 600 ; N b ; B 0 -15 584 626 ; C 99 ; WX 600 ; N c ; B 40 -15 545 459 ; C 100 ; WX 600 ; N d ; B 20 -15 591 626 ; C 101 ; WX 600 ; N e ; B 40 -15 563 454 ; C 102 ; WX 600 ; N f ; B 83 0 547 626 ; L i fi ; L l fl ; C 103 ; WX 600 ; N g ; B 30 -146 580 454 ; C 104 ; WX 600 ; N h ; B 5 0 592 626 ; C 105 ; WX 600 ; N i ; B 77 0 523 658 ; C 106 ; WX 600 ; N j ; B 63 -146 440 658 ; C 107 ; WX 600 ; N k ; B 20 0 585 626 ; C 108 ; WX 600 ; N l ; B 77 0 523 626 ; C 109 ; WX 600 ; N m ; B -22 0 626 454 ; C 110 ; WX 600 ; N n ; B 18 0 592 454 ; C 111 ; WX 600 ; N o ; B 30 -15 570 454 ; C 112 ; WX 600 ; N p ; B -1 -142 570 454 ; C 113 ; WX 600 ; N q ; B 20 -142 591 454 ; C 114 ; WX 600 ; N r ; B 47 0 580 454 ; C 115 ; WX 600 ; N s ; B 68 -17 535 459 ; C 116 ; WX 600 ; N t ; B 47 -15 532 562 ; C 117 ; WX 600 ; N u ; B -1 -15 569 439 ; C 118 ; WX 600 ; N v ; B -1 0 601 439 ; C 119 ; WX 600 ; N w ; B -18 0 618 439 ; C 120 ; WX 600 ; N x ; B 6 0 594 439 ; C 121 ; WX 600 ; N y ; B -4 -142 601 439 ; C 122 ; WX 600 ; N z ; B 81 0 520 439 ; C 123 ; WX 600 ; N braceleft ; B 160 -102 464 616 ; C 124 ; WX 600 ; N bar ; B 255 -250 345 750 ; C 125 ; WX 600 ; N braceright ; B 136 -102 440 616 ; C 126 ; WX 600 ; N asciitilde ; B 71 153 530 356 ; C 161 ; WX 600 ; N exclamdown ; B 202 -146 398 449 ; C 162 ; WX 600 ; N cent ; B 66 -49 518 614 ; C 163 ; WX 600 ; N sterling ; B 72 -28 558 611 ; C 164 ; WX 600 ; N fraction ; B 25 -60 576 661 ; C 165 ; WX 600 ; N yen ; B 10 0 590 562 ; C 166 ; WX 600 ; N florin ; B -30 -131 572 616 ; C 167 ; WX 600 ; N section ; B 83 -70 517 580 ; C 168 ; WX 600 ; N currency ; B 54 49 546 517 ; C 169 ; WX 600 ; N quotesingle ; B 227 277 373 562 ; C 170 ; WX 600 ; N quotedblleft ; B 71 277 535 562 ; C 171 ; WX 600 ; N guillemotleft ; B 8 70 553 446 ; C 172 ; WX 600 ; N guilsinglleft ; B 141 70 459 446 ; C 173 ; WX 600 ; N guilsinglright ; B 141 70 459 446 ; C 174 ; WX 600 ; N fi ; B 12 0 593 626 ; C 175 ; WX 600 ; N fl ; B 12 0 593 626 ; C 177 ; WX 600 ; N endash ; B 65 203 535 313 ; C 178 ; WX 600 ; N dagger ; B 106 -70 494 580 ; C 179 ; WX 600 ; N daggerdbl ; B 106 -70 494 580 ; C 180 ; WX 600 ; N periodcentered ; B 196 165 404 351 ; C 182 ; WX 600 ; N paragraph ; B 6 -70 576 580 ; C 183 ; WX 600 ; N bullet ; B 140 132 460 430 ; C 184 ; WX 600 ; N quotesinglbase ; B 175 -142 427 143 ; C 185 ; WX 600 ; N quotedblbase ; B 65 -142 529 143 ; C 186 ; WX 600 ; N quotedblright ; B 61 277 525 562 ; C 187 ; WX 600 ; N guillemotright ; B 47 70 592 446 ; C 188 ; WX 600 ; N ellipsis ; B 26 -15 574 116 ; C 189 ; WX 600 ; N perthousand ; B -113 -15 713 616 ; C 191 ; WX 600 ; N questiondown ; B 99 -146 502 449 ; C 193 ; WX 600 ; N grave ; B 132 508 395 661 ; C 194 ; WX 600 ; N acute ; B 205 508 468 661 ; C 195 ; WX 600 ; N circumflex ; B 103 483 497 657 ; C 196 ; WX 600 ; N tilde ; B 89 493 512 636 ; C 197 ; WX 600 ; N macron ; B 88 505 512 585 ; C 198 ; WX 600 ; N breve ; B 83 468 517 631 ; C 199 ; WX 600 ; N dotaccent ; B 230 498 370 638 ; C 200 ; WX 600 ; N dieresis ; B 128 498 472 638 ; C 202 ; WX 600 ; N ring ; B 198 481 402 678 ; C 203 ; WX 600 ; N cedilla ; B 205 -206 387 0 ; C 205 ; WX 600 ; N hungarumlaut ; B 68 488 588 661 ; C 206 ; WX 600 ; N ogonek ; B 169 -199 400 0 ; C 207 ; WX 600 ; N caron ; B 103 493 497 667 ; C 208 ; WX 600 ; N emdash ; B -10 203 610 313 ; C 225 ; WX 600 ; N AE ; B -29 0 602 562 ; C 227 ; WX 600 ; N ordfeminine ; B 147 196 453 580 ; C 232 ; WX 600 ; N Lslash ; B 39 0 578 562 ; C 233 ; WX 600 ; N Oslash ; B 22 -22 578 584 ; C 234 ; WX 600 ; N OE ; B -25 0 595 562 ; C 235 ; WX 600 ; N ordmasculine ; B 147 196 453 580 ; C 241 ; WX 600 ; N ae ; B -4 -15 601 454 ; C 245 ; WX 600 ; N dotlessi ; B 77 0 523 439 ; C 248 ; WX 600 ; N lslash ; B 77 0 523 626 ; C 249 ; WX 600 ; N oslash ; B 30 -24 570 463 ; C 250 ; WX 600 ; N oe ; B -18 -15 611 454 ; C 251 ; WX 600 ; N germandbls ; B 22 -15 596 626 ; C -1 ; WX 600 ; N Idieresis ; B 77 0 523 761 ; C -1 ; WX 600 ; N eacute ; B 40 -15 563 661 ; C -1 ; WX 600 ; N abreve ; B 35 -15 570 661 ; C -1 ; WX 600 ; N uhungarumlaut ; B -1 -15 628 661 ; C -1 ; WX 600 ; N ecaron ; B 40 -15 563 667 ; C -1 ; WX 600 ; N Ydieresis ; B 12 0 589 761 ; C -1 ; WX 600 ; N divide ; B 71 16 529 500 ; C -1 ; WX 600 ; N Yacute ; B 12 0 589 784 ; C -1 ; WX 600 ; N Acircumflex ; B -9 0 609 780 ; C -1 ; WX 600 ; N aacute ; B 35 -15 570 661 ; C -1 ; WX 600 ; N Ucircumflex ; B 4 -18 596 780 ; C -1 ; WX 600 ; N yacute ; B -4 -142 601 661 ; C -1 ; WX 600 ; N scommaaccent ; B 68 -250 535 459 ; C -1 ; WX 600 ; N ecircumflex ; B 40 -15 563 657 ; C -1 ; WX 600 ; N Uring ; B 4 -18 596 801 ; C -1 ; WX 600 ; N Udieresis ; B 4 -18 596 761 ; C -1 ; WX 600 ; N aogonek ; B 35 -199 586 454 ; C -1 ; WX 600 ; N Uacute ; B 4 -18 596 784 ; C -1 ; WX 600 ; N uogonek ; B -1 -199 585 439 ; C -1 ; WX 600 ; N Edieresis ; B 25 0 560 761 ; C -1 ; WX 600 ; N Dcroat ; B 30 0 594 562 ; C -1 ; WX 600 ; N commaaccent ; B 205 -250 397 -57 ; C -1 ; WX 600 ; N copyright ; B 0 -18 600 580 ; C -1 ; WX 600 ; N Emacron ; B 25 0 560 708 ; C -1 ; WX 600 ; N ccaron ; B 40 -15 545 667 ; C -1 ; WX 600 ; N aring ; B 35 -15 570 678 ; C -1 ; WX 600 ; N Ncommaaccent ; B 8 -250 610 562 ; C -1 ; WX 600 ; N lacute ; B 77 0 523 801 ; C -1 ; WX 600 ; N agrave ; B 35 -15 570 661 ; C -1 ; WX 600 ; N Tcommaaccent ; B 21 -250 579 562 ; C -1 ; WX 600 ; N Cacute ; B 22 -18 560 784 ; C -1 ; WX 600 ; N atilde ; B 35 -15 570 636 ; C -1 ; WX 600 ; N Edotaccent ; B 25 0 560 761 ; C -1 ; WX 600 ; N scaron ; B 68 -17 535 667 ; C -1 ; WX 600 ; N scedilla ; B 68 -206 535 459 ; C -1 ; WX 600 ; N iacute ; B 77 0 523 661 ; C -1 ; WX 600 ; N lozenge ; B 66 0 534 740 ; C -1 ; WX 600 ; N Rcaron ; B 24 0 599 790 ; C -1 ; WX 600 ; N Gcommaaccent ; B 22 -250 594 580 ; C -1 ; WX 600 ; N ucircumflex ; B -1 -15 569 657 ; C -1 ; WX 600 ; N acircumflex ; B 35 -15 570 657 ; C -1 ; WX 600 ; N Amacron ; B -9 0 609 708 ; C -1 ; WX 600 ; N rcaron ; B 47 0 580 667 ; C -1 ; WX 600 ; N ccedilla ; B 40 -206 545 459 ; C -1 ; WX 600 ; N Zdotaccent ; B 62 0 539 761 ; C -1 ; WX 600 ; N Thorn ; B 48 0 557 562 ; C -1 ; WX 600 ; N Omacron ; B 22 -18 578 708 ; C -1 ; WX 600 ; N Racute ; B 24 0 599 784 ; C -1 ; WX 600 ; N Sacute ; B 47 -22 553 784 ; C -1 ; WX 600 ; N dcaron ; B 20 -15 727 626 ; C -1 ; WX 600 ; N Umacron ; B 4 -18 596 708 ; C -1 ; WX 600 ; N uring ; B -1 -15 569 678 ; C -1 ; WX 600 ; N threesuperior ; B 138 222 433 616 ; C -1 ; WX 600 ; N Ograve ; B 22 -18 578 784 ; C -1 ; WX 600 ; N Agrave ; B -9 0 609 784 ; C -1 ; WX 600 ; N Abreve ; B -9 0 609 784 ; C -1 ; WX 600 ; N multiply ; B 81 39 520 478 ; C -1 ; WX 600 ; N uacute ; B -1 -15 569 661 ; C -1 ; WX 600 ; N Tcaron ; B 21 0 579 790 ; C -1 ; WX 600 ; N partialdiff ; B 63 -38 537 728 ; C -1 ; WX 600 ; N ydieresis ; B -4 -142 601 638 ; C -1 ; WX 600 ; N Nacute ; B 8 -12 610 784 ; C -1 ; WX 600 ; N icircumflex ; B 73 0 523 657 ; C -1 ; WX 600 ; N Ecircumflex ; B 25 0 560 780 ; C -1 ; WX 600 ; N adieresis ; B 35 -15 570 638 ; C -1 ; WX 600 ; N edieresis ; B 40 -15 563 638 ; C -1 ; WX 600 ; N cacute ; B 40 -15 545 661 ; C -1 ; WX 600 ; N nacute ; B 18 0 592 661 ; C -1 ; WX 600 ; N umacron ; B -1 -15 569 585 ; C -1 ; WX 600 ; N Ncaron ; B 8 -12 610 790 ; C -1 ; WX 600 ; N Iacute ; B 77 0 523 784 ; C -1 ; WX 600 ; N plusminus ; B 71 24 529 515 ; C -1 ; WX 600 ; N brokenbar ; B 255 -175 345 675 ; C -1 ; WX 600 ; N registered ; B 0 -18 600 580 ; C -1 ; WX 600 ; N Gbreve ; B 22 -18 594 784 ; C -1 ; WX 600 ; N Idotaccent ; B 77 0 523 761 ; C -1 ; WX 600 ; N summation ; B 15 -10 586 706 ; C -1 ; WX 600 ; N Egrave ; B 25 0 560 784 ; C -1 ; WX 600 ; N racute ; B 47 0 580 661 ; C -1 ; WX 600 ; N omacron ; B 30 -15 570 585 ; C -1 ; WX 600 ; N Zacute ; B 62 0 539 784 ; C -1 ; WX 600 ; N Zcaron ; B 62 0 539 790 ; C -1 ; WX 600 ; N greaterequal ; B 26 0 523 696 ; C -1 ; WX 600 ; N Eth ; B 30 0 594 562 ; C -1 ; WX 600 ; N Ccedilla ; B 22 -206 560 580 ; C -1 ; WX 600 ; N lcommaaccent ; B 77 -250 523 626 ; C -1 ; WX 600 ; N tcaron ; B 47 -15 532 703 ; C -1 ; WX 600 ; N eogonek ; B 40 -199 563 454 ; C -1 ; WX 600 ; N Uogonek ; B 4 -199 596 562 ; C -1 ; WX 600 ; N Aacute ; B -9 0 609 784 ; C -1 ; WX 600 ; N Adieresis ; B -9 0 609 761 ; C -1 ; WX 600 ; N egrave ; B 40 -15 563 661 ; C -1 ; WX 600 ; N zacute ; B 81 0 520 661 ; C -1 ; WX 600 ; N iogonek ; B 77 -199 523 658 ; C -1 ; WX 600 ; N Oacute ; B 22 -18 578 784 ; C -1 ; WX 600 ; N oacute ; B 30 -15 570 661 ; C -1 ; WX 600 ; N amacron ; B 35 -15 570 585 ; C -1 ; WX 600 ; N sacute ; B 68 -17 535 661 ; C -1 ; WX 600 ; N idieresis ; B 77 0 523 618 ; C -1 ; WX 600 ; N Ocircumflex ; B 22 -18 578 780 ; C -1 ; WX 600 ; N Ugrave ; B 4 -18 596 784 ; C -1 ; WX 600 ; N Delta ; B 6 0 594 688 ; C -1 ; WX 600 ; N thorn ; B -14 -142 570 626 ; C -1 ; WX 600 ; N twosuperior ; B 143 230 436 616 ; C -1 ; WX 600 ; N Odieresis ; B 22 -18 578 761 ; C -1 ; WX 600 ; N mu ; B -1 -142 569 439 ; C -1 ; WX 600 ; N igrave ; B 77 0 523 661 ; C -1 ; WX 600 ; N ohungarumlaut ; B 30 -15 668 661 ; C -1 ; WX 600 ; N Eogonek ; B 25 -199 576 562 ; C -1 ; WX 600 ; N dcroat ; B 20 -15 591 626 ; C -1 ; WX 600 ; N threequarters ; B -47 -60 648 661 ; C -1 ; WX 600 ; N Scedilla ; B 47 -206 553 582 ; C -1 ; WX 600 ; N lcaron ; B 77 0 597 626 ; C -1 ; WX 600 ; N Kcommaaccent ; B 21 -250 599 562 ; C -1 ; WX 600 ; N Lacute ; B 39 0 578 784 ; C -1 ; WX 600 ; N trademark ; B -9 230 749 562 ; C -1 ; WX 600 ; N edotaccent ; B 40 -15 563 638 ; C -1 ; WX 600 ; N Igrave ; B 77 0 523 784 ; C -1 ; WX 600 ; N Imacron ; B 77 0 523 708 ; C -1 ; WX 600 ; N Lcaron ; B 39 0 637 562 ; C -1 ; WX 600 ; N onehalf ; B -47 -60 648 661 ; C -1 ; WX 600 ; N lessequal ; B 26 0 523 696 ; C -1 ; WX 600 ; N ocircumflex ; B 30 -15 570 657 ; C -1 ; WX 600 ; N ntilde ; B 18 0 592 636 ; C -1 ; WX 600 ; N Uhungarumlaut ; B 4 -18 638 784 ; C -1 ; WX 600 ; N Eacute ; B 25 0 560 784 ; C -1 ; WX 600 ; N emacron ; B 40 -15 563 585 ; C -1 ; WX 600 ; N gbreve ; B 30 -146 580 661 ; C -1 ; WX 600 ; N onequarter ; B -56 -60 656 661 ; C -1 ; WX 600 ; N Scaron ; B 47 -22 553 790 ; C -1 ; WX 600 ; N Scommaaccent ; B 47 -250 553 582 ; C -1 ; WX 600 ; N Ohungarumlaut ; B 22 -18 628 784 ; C -1 ; WX 600 ; N degree ; B 86 243 474 616 ; C -1 ; WX 600 ; N ograve ; B 30 -15 570 661 ; C -1 ; WX 600 ; N Ccaron ; B 22 -18 560 790 ; C -1 ; WX 600 ; N ugrave ; B -1 -15 569 661 ; C -1 ; WX 600 ; N radical ; B -19 -104 473 778 ; C -1 ; WX 600 ; N Dcaron ; B 30 0 594 790 ; C -1 ; WX 600 ; N rcommaaccent ; B 47 -250 580 454 ; C -1 ; WX 600 ; N Ntilde ; B 8 -12 610 759 ; C -1 ; WX 600 ; N otilde ; B 30 -15 570 636 ; C -1 ; WX 600 ; N Rcommaaccent ; B 24 -250 599 562 ; C -1 ; WX 600 ; N Lcommaaccent ; B 39 -250 578 562 ; C -1 ; WX 600 ; N Atilde ; B -9 0 609 759 ; C -1 ; WX 600 ; N Aogonek ; B -9 -199 625 562 ; C -1 ; WX 600 ; N Aring ; B -9 0 609 801 ; C -1 ; WX 600 ; N Otilde ; B 22 -18 578 759 ; C -1 ; WX 600 ; N zdotaccent ; B 81 0 520 638 ; C -1 ; WX 600 ; N Ecaron ; B 25 0 560 790 ; C -1 ; WX 600 ; N Iogonek ; B 77 -199 523 562 ; C -1 ; WX 600 ; N kcommaaccent ; B 20 -250 585 626 ; C -1 ; WX 600 ; N minus ; B 71 203 529 313 ; C -1 ; WX 600 ; N Icircumflex ; B 77 0 523 780 ; C -1 ; WX 600 ; N ncaron ; B 18 0 592 667 ; C -1 ; WX 600 ; N tcommaaccent ; B 47 -250 532 562 ; C -1 ; WX 600 ; N logicalnot ; B 71 103 529 413 ; C -1 ; WX 600 ; N odieresis ; B 30 -15 570 638 ; C -1 ; WX 600 ; N udieresis ; B -1 -15 569 638 ; C -1 ; WX 600 ; N notequal ; B 12 -47 537 563 ; C -1 ; WX 600 ; N gcommaaccent ; B 30 -146 580 714 ; C -1 ; WX 600 ; N eth ; B 58 -27 543 626 ; C -1 ; WX 600 ; N zcaron ; B 81 0 520 667 ; C -1 ; WX 600 ; N ncommaaccent ; B 18 -250 592 454 ; C -1 ; WX 600 ; N onesuperior ; B 153 230 447 616 ; C -1 ; WX 600 ; N imacron ; B 77 0 523 585 ; C -1 ; WX 600 ; N Euro ; B 0 0 0 0 ; EndCharMetrics EndFontMetrics camlpdf-2.8.1/compressor/Courier-BoldOblique.afm000066400000000000000000000360471477056064700216520ustar00rootroot00000000000000StartFontMetrics 4.1 Comment Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. Comment Creation Date: Mon Jun 23 16:28:46 1997 Comment UniqueID 43049 Comment VMusage 17529 79244 FontName Courier-BoldOblique FullName Courier Bold Oblique FamilyName Courier Weight Bold ItalicAngle -12 IsFixedPitch true CharacterSet ExtendedRoman FontBBox -57 -250 869 801 UnderlinePosition -100 UnderlineThickness 50 Version 003.000 Notice Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. EncodingScheme AdobeStandardEncoding CapHeight 562 XHeight 439 Ascender 629 Descender -157 StdHW 84 StdVW 106 StartCharMetrics 315 C 32 ; WX 600 ; N space ; B 0 0 0 0 ; C 33 ; WX 600 ; N exclam ; B 215 -15 495 572 ; C 34 ; WX 600 ; N quotedbl ; B 211 277 585 562 ; C 35 ; WX 600 ; N numbersign ; B 88 -45 641 651 ; C 36 ; WX 600 ; N dollar ; B 87 -126 630 666 ; C 37 ; WX 600 ; N percent ; B 101 -15 625 616 ; C 38 ; WX 600 ; N ampersand ; B 61 -15 595 543 ; C 39 ; WX 600 ; N quoteright ; B 229 277 543 562 ; C 40 ; WX 600 ; N parenleft ; B 265 -102 592 616 ; C 41 ; WX 600 ; N parenright ; B 117 -102 444 616 ; C 42 ; WX 600 ; N asterisk ; B 179 219 598 601 ; C 43 ; WX 600 ; N plus ; B 114 39 596 478 ; C 44 ; WX 600 ; N comma ; B 99 -111 430 174 ; C 45 ; WX 600 ; N hyphen ; B 143 203 567 313 ; C 46 ; WX 600 ; N period ; B 206 -15 427 171 ; C 47 ; WX 600 ; N slash ; B 90 -77 626 626 ; C 48 ; WX 600 ; N zero ; B 135 -15 593 616 ; C 49 ; WX 600 ; N one ; B 93 0 562 616 ; C 50 ; WX 600 ; N two ; B 61 0 594 616 ; C 51 ; WX 600 ; N three ; B 71 -15 571 616 ; C 52 ; WX 600 ; N four ; B 81 0 559 616 ; C 53 ; WX 600 ; N five ; B 77 -15 621 601 ; C 54 ; WX 600 ; N six ; B 135 -15 652 616 ; C 55 ; WX 600 ; N seven ; B 147 0 622 601 ; C 56 ; WX 600 ; N eight ; B 115 -15 604 616 ; C 57 ; WX 600 ; N nine ; B 75 -15 592 616 ; C 58 ; WX 600 ; N colon ; B 205 -15 480 425 ; C 59 ; WX 600 ; N semicolon ; B 99 -111 481 425 ; C 60 ; WX 600 ; N less ; B 120 15 613 501 ; C 61 ; WX 600 ; N equal ; B 96 118 614 398 ; C 62 ; WX 600 ; N greater ; B 97 15 589 501 ; C 63 ; WX 600 ; N question ; B 183 -14 592 580 ; C 64 ; WX 600 ; N at ; B 65 -15 642 616 ; C 65 ; WX 600 ; N A ; B -9 0 632 562 ; C 66 ; WX 600 ; N B ; B 30 0 630 562 ; C 67 ; WX 600 ; N C ; B 74 -18 675 580 ; C 68 ; WX 600 ; N D ; B 30 0 664 562 ; C 69 ; WX 600 ; N E ; B 25 0 670 562 ; C 70 ; WX 600 ; N F ; B 39 0 684 562 ; C 71 ; WX 600 ; N G ; B 74 -18 675 580 ; C 72 ; WX 600 ; N H ; B 20 0 700 562 ; C 73 ; WX 600 ; N I ; B 77 0 643 562 ; C 74 ; WX 600 ; N J ; B 58 -18 721 562 ; C 75 ; WX 600 ; N K ; B 21 0 692 562 ; C 76 ; WX 600 ; N L ; B 39 0 636 562 ; C 77 ; WX 600 ; N M ; B -2 0 722 562 ; C 78 ; WX 600 ; N N ; B 8 -12 730 562 ; C 79 ; WX 600 ; N O ; B 74 -18 645 580 ; C 80 ; WX 600 ; N P ; B 48 0 643 562 ; C 81 ; WX 600 ; N Q ; B 83 -138 636 580 ; C 82 ; WX 600 ; N R ; B 24 0 617 562 ; C 83 ; WX 600 ; N S ; B 54 -22 673 582 ; C 84 ; WX 600 ; N T ; B 86 0 679 562 ; C 85 ; WX 600 ; N U ; B 101 -18 716 562 ; C 86 ; WX 600 ; N V ; B 84 0 733 562 ; C 87 ; WX 600 ; N W ; B 79 0 738 562 ; C 88 ; WX 600 ; N X ; B 12 0 690 562 ; C 89 ; WX 600 ; N Y ; B 109 0 709 562 ; C 90 ; WX 600 ; N Z ; B 62 0 637 562 ; C 91 ; WX 600 ; N bracketleft ; B 223 -102 606 616 ; C 92 ; WX 600 ; N backslash ; B 222 -77 496 626 ; C 93 ; WX 600 ; N bracketright ; B 103 -102 486 616 ; C 94 ; WX 600 ; N asciicircum ; B 171 250 556 616 ; C 95 ; WX 600 ; N underscore ; B -27 -125 585 -75 ; C 96 ; WX 600 ; N quoteleft ; B 297 277 487 562 ; C 97 ; WX 600 ; N a ; B 61 -15 593 454 ; C 98 ; WX 600 ; N b ; B 13 -15 636 626 ; C 99 ; WX 600 ; N c ; B 81 -15 631 459 ; C 100 ; WX 600 ; N d ; B 60 -15 645 626 ; C 101 ; WX 600 ; N e ; B 81 -15 605 454 ; C 102 ; WX 600 ; N f ; B 83 0 677 626 ; L i fi ; L l fl ; C 103 ; WX 600 ; N g ; B 40 -146 674 454 ; C 104 ; WX 600 ; N h ; B 18 0 615 626 ; C 105 ; WX 600 ; N i ; B 77 0 546 658 ; C 106 ; WX 600 ; N j ; B 36 -146 580 658 ; C 107 ; WX 600 ; N k ; B 33 0 643 626 ; C 108 ; WX 600 ; N l ; B 77 0 546 626 ; C 109 ; WX 600 ; N m ; B -22 0 649 454 ; C 110 ; WX 600 ; N n ; B 18 0 615 454 ; C 111 ; WX 600 ; N o ; B 71 -15 622 454 ; C 112 ; WX 600 ; N p ; B -32 -142 622 454 ; C 113 ; WX 600 ; N q ; B 60 -142 685 454 ; C 114 ; WX 600 ; N r ; B 47 0 655 454 ; C 115 ; WX 600 ; N s ; B 66 -17 608 459 ; C 116 ; WX 600 ; N t ; B 118 -15 567 562 ; C 117 ; WX 600 ; N u ; B 70 -15 592 439 ; C 118 ; WX 600 ; N v ; B 70 0 695 439 ; C 119 ; WX 600 ; N w ; B 53 0 712 439 ; C 120 ; WX 600 ; N x ; B 6 0 671 439 ; C 121 ; WX 600 ; N y ; B -21 -142 695 439 ; C 122 ; WX 600 ; N z ; B 81 0 614 439 ; C 123 ; WX 600 ; N braceleft ; B 203 -102 595 616 ; C 124 ; WX 600 ; N bar ; B 201 -250 505 750 ; C 125 ; WX 600 ; N braceright ; B 114 -102 506 616 ; C 126 ; WX 600 ; N asciitilde ; B 120 153 590 356 ; C 161 ; WX 600 ; N exclamdown ; B 196 -146 477 449 ; C 162 ; WX 600 ; N cent ; B 121 -49 605 614 ; C 163 ; WX 600 ; N sterling ; B 106 -28 650 611 ; C 164 ; WX 600 ; N fraction ; B 22 -60 708 661 ; C 165 ; WX 600 ; N yen ; B 98 0 710 562 ; C 166 ; WX 600 ; N florin ; B -57 -131 702 616 ; C 167 ; WX 600 ; N section ; B 74 -70 620 580 ; C 168 ; WX 600 ; N currency ; B 77 49 644 517 ; C 169 ; WX 600 ; N quotesingle ; B 303 277 493 562 ; C 170 ; WX 600 ; N quotedblleft ; B 190 277 594 562 ; C 171 ; WX 600 ; N guillemotleft ; B 62 70 639 446 ; C 172 ; WX 600 ; N guilsinglleft ; B 195 70 545 446 ; C 173 ; WX 600 ; N guilsinglright ; B 165 70 514 446 ; C 174 ; WX 600 ; N fi ; B 12 0 644 626 ; C 175 ; WX 600 ; N fl ; B 12 0 644 626 ; C 177 ; WX 600 ; N endash ; B 108 203 602 313 ; C 178 ; WX 600 ; N dagger ; B 175 -70 586 580 ; C 179 ; WX 600 ; N daggerdbl ; B 121 -70 587 580 ; C 180 ; WX 600 ; N periodcentered ; B 248 165 461 351 ; C 182 ; WX 600 ; N paragraph ; B 61 -70 700 580 ; C 183 ; WX 600 ; N bullet ; B 196 132 523 430 ; C 184 ; WX 600 ; N quotesinglbase ; B 144 -142 458 143 ; C 185 ; WX 600 ; N quotedblbase ; B 34 -142 560 143 ; C 186 ; WX 600 ; N quotedblright ; B 119 277 645 562 ; C 187 ; WX 600 ; N guillemotright ; B 71 70 647 446 ; C 188 ; WX 600 ; N ellipsis ; B 35 -15 587 116 ; C 189 ; WX 600 ; N perthousand ; B -45 -15 743 616 ; C 191 ; WX 600 ; N questiondown ; B 100 -146 509 449 ; C 193 ; WX 600 ; N grave ; B 272 508 503 661 ; C 194 ; WX 600 ; N acute ; B 312 508 609 661 ; C 195 ; WX 600 ; N circumflex ; B 212 483 607 657 ; C 196 ; WX 600 ; N tilde ; B 199 493 643 636 ; C 197 ; WX 600 ; N macron ; B 195 505 637 585 ; C 198 ; WX 600 ; N breve ; B 217 468 652 631 ; C 199 ; WX 600 ; N dotaccent ; B 348 498 493 638 ; C 200 ; WX 600 ; N dieresis ; B 246 498 595 638 ; C 202 ; WX 600 ; N ring ; B 319 481 528 678 ; C 203 ; WX 600 ; N cedilla ; B 168 -206 368 0 ; C 205 ; WX 600 ; N hungarumlaut ; B 171 488 729 661 ; C 206 ; WX 600 ; N ogonek ; B 143 -199 367 0 ; C 207 ; WX 600 ; N caron ; B 238 493 633 667 ; C 208 ; WX 600 ; N emdash ; B 33 203 677 313 ; C 225 ; WX 600 ; N AE ; B -29 0 708 562 ; C 227 ; WX 600 ; N ordfeminine ; B 188 196 526 580 ; C 232 ; WX 600 ; N Lslash ; B 39 0 636 562 ; C 233 ; WX 600 ; N Oslash ; B 48 -22 673 584 ; C 234 ; WX 600 ; N OE ; B 26 0 701 562 ; C 235 ; WX 600 ; N ordmasculine ; B 188 196 543 580 ; C 241 ; WX 600 ; N ae ; B 21 -15 652 454 ; C 245 ; WX 600 ; N dotlessi ; B 77 0 546 439 ; C 248 ; WX 600 ; N lslash ; B 77 0 587 626 ; C 249 ; WX 600 ; N oslash ; B 54 -24 638 463 ; C 250 ; WX 600 ; N oe ; B 18 -15 662 454 ; C 251 ; WX 600 ; N germandbls ; B 22 -15 629 626 ; C -1 ; WX 600 ; N Idieresis ; B 77 0 643 761 ; C -1 ; WX 600 ; N eacute ; B 81 -15 609 661 ; C -1 ; WX 600 ; N abreve ; B 61 -15 658 661 ; C -1 ; WX 600 ; N uhungarumlaut ; B 70 -15 769 661 ; C -1 ; WX 600 ; N ecaron ; B 81 -15 633 667 ; C -1 ; WX 600 ; N Ydieresis ; B 109 0 709 761 ; C -1 ; WX 600 ; N divide ; B 114 16 596 500 ; C -1 ; WX 600 ; N Yacute ; B 109 0 709 784 ; C -1 ; WX 600 ; N Acircumflex ; B -9 0 632 780 ; C -1 ; WX 600 ; N aacute ; B 61 -15 609 661 ; C -1 ; WX 600 ; N Ucircumflex ; B 101 -18 716 780 ; C -1 ; WX 600 ; N yacute ; B -21 -142 695 661 ; C -1 ; WX 600 ; N scommaaccent ; B 66 -250 608 459 ; C -1 ; WX 600 ; N ecircumflex ; B 81 -15 607 657 ; C -1 ; WX 600 ; N Uring ; B 101 -18 716 801 ; C -1 ; WX 600 ; N Udieresis ; B 101 -18 716 761 ; C -1 ; WX 600 ; N aogonek ; B 61 -199 593 454 ; C -1 ; WX 600 ; N Uacute ; B 101 -18 716 784 ; C -1 ; WX 600 ; N uogonek ; B 70 -199 592 439 ; C -1 ; WX 600 ; N Edieresis ; B 25 0 670 761 ; C -1 ; WX 600 ; N Dcroat ; B 30 0 664 562 ; C -1 ; WX 600 ; N commaaccent ; B 151 -250 385 -57 ; C -1 ; WX 600 ; N copyright ; B 53 -18 667 580 ; C -1 ; WX 600 ; N Emacron ; B 25 0 670 708 ; C -1 ; WX 600 ; N ccaron ; B 81 -15 633 667 ; C -1 ; WX 600 ; N aring ; B 61 -15 593 678 ; C -1 ; WX 600 ; N Ncommaaccent ; B 8 -250 730 562 ; C -1 ; WX 600 ; N lacute ; B 77 0 639 801 ; C -1 ; WX 600 ; N agrave ; B 61 -15 593 661 ; C -1 ; WX 600 ; N Tcommaaccent ; B 86 -250 679 562 ; C -1 ; WX 600 ; N Cacute ; B 74 -18 675 784 ; C -1 ; WX 600 ; N atilde ; B 61 -15 643 636 ; C -1 ; WX 600 ; N Edotaccent ; B 25 0 670 761 ; C -1 ; WX 600 ; N scaron ; B 66 -17 633 667 ; C -1 ; WX 600 ; N scedilla ; B 66 -206 608 459 ; C -1 ; WX 600 ; N iacute ; B 77 0 609 661 ; C -1 ; WX 600 ; N lozenge ; B 145 0 614 740 ; C -1 ; WX 600 ; N Rcaron ; B 24 0 659 790 ; C -1 ; WX 600 ; N Gcommaaccent ; B 74 -250 675 580 ; C -1 ; WX 600 ; N ucircumflex ; B 70 -15 597 657 ; C -1 ; WX 600 ; N acircumflex ; B 61 -15 607 657 ; C -1 ; WX 600 ; N Amacron ; B -9 0 633 708 ; C -1 ; WX 600 ; N rcaron ; B 47 0 655 667 ; C -1 ; WX 600 ; N ccedilla ; B 81 -206 631 459 ; C -1 ; WX 600 ; N Zdotaccent ; B 62 0 637 761 ; C -1 ; WX 600 ; N Thorn ; B 48 0 620 562 ; C -1 ; WX 600 ; N Omacron ; B 74 -18 663 708 ; C -1 ; WX 600 ; N Racute ; B 24 0 665 784 ; C -1 ; WX 600 ; N Sacute ; B 54 -22 673 784 ; C -1 ; WX 600 ; N dcaron ; B 60 -15 861 626 ; C -1 ; WX 600 ; N Umacron ; B 101 -18 716 708 ; C -1 ; WX 600 ; N uring ; B 70 -15 592 678 ; C -1 ; WX 600 ; N threesuperior ; B 193 222 526 616 ; C -1 ; WX 600 ; N Ograve ; B 74 -18 645 784 ; C -1 ; WX 600 ; N Agrave ; B -9 0 632 784 ; C -1 ; WX 600 ; N Abreve ; B -9 0 684 784 ; C -1 ; WX 600 ; N multiply ; B 104 39 606 478 ; C -1 ; WX 600 ; N uacute ; B 70 -15 599 661 ; C -1 ; WX 600 ; N Tcaron ; B 86 0 679 790 ; C -1 ; WX 600 ; N partialdiff ; B 91 -38 627 728 ; C -1 ; WX 600 ; N ydieresis ; B -21 -142 695 638 ; C -1 ; WX 600 ; N Nacute ; B 8 -12 730 784 ; C -1 ; WX 600 ; N icircumflex ; B 77 0 577 657 ; C -1 ; WX 600 ; N Ecircumflex ; B 25 0 670 780 ; C -1 ; WX 600 ; N adieresis ; B 61 -15 595 638 ; C -1 ; WX 600 ; N edieresis ; B 81 -15 605 638 ; C -1 ; WX 600 ; N cacute ; B 81 -15 649 661 ; C -1 ; WX 600 ; N nacute ; B 18 0 639 661 ; C -1 ; WX 600 ; N umacron ; B 70 -15 637 585 ; C -1 ; WX 600 ; N Ncaron ; B 8 -12 730 790 ; C -1 ; WX 600 ; N Iacute ; B 77 0 643 784 ; C -1 ; WX 600 ; N plusminus ; B 76 24 614 515 ; C -1 ; WX 600 ; N brokenbar ; B 217 -175 489 675 ; C -1 ; WX 600 ; N registered ; B 53 -18 667 580 ; C -1 ; WX 600 ; N Gbreve ; B 74 -18 684 784 ; C -1 ; WX 600 ; N Idotaccent ; B 77 0 643 761 ; C -1 ; WX 600 ; N summation ; B 15 -10 672 706 ; C -1 ; WX 600 ; N Egrave ; B 25 0 670 784 ; C -1 ; WX 600 ; N racute ; B 47 0 655 661 ; C -1 ; WX 600 ; N omacron ; B 71 -15 637 585 ; C -1 ; WX 600 ; N Zacute ; B 62 0 665 784 ; C -1 ; WX 600 ; N Zcaron ; B 62 0 659 790 ; C -1 ; WX 600 ; N greaterequal ; B 26 0 627 696 ; C -1 ; WX 600 ; N Eth ; B 30 0 664 562 ; C -1 ; WX 600 ; N Ccedilla ; B 74 -206 675 580 ; C -1 ; WX 600 ; N lcommaaccent ; B 77 -250 546 626 ; C -1 ; WX 600 ; N tcaron ; B 118 -15 627 703 ; C -1 ; WX 600 ; N eogonek ; B 81 -199 605 454 ; C -1 ; WX 600 ; N Uogonek ; B 101 -199 716 562 ; C -1 ; WX 600 ; N Aacute ; B -9 0 655 784 ; C -1 ; WX 600 ; N Adieresis ; B -9 0 632 761 ; C -1 ; WX 600 ; N egrave ; B 81 -15 605 661 ; C -1 ; WX 600 ; N zacute ; B 81 0 614 661 ; C -1 ; WX 600 ; N iogonek ; B 77 -199 546 658 ; C -1 ; WX 600 ; N Oacute ; B 74 -18 645 784 ; C -1 ; WX 600 ; N oacute ; B 71 -15 649 661 ; C -1 ; WX 600 ; N amacron ; B 61 -15 637 585 ; C -1 ; WX 600 ; N sacute ; B 66 -17 609 661 ; C -1 ; WX 600 ; N idieresis ; B 77 0 561 618 ; C -1 ; WX 600 ; N Ocircumflex ; B 74 -18 645 780 ; C -1 ; WX 600 ; N Ugrave ; B 101 -18 716 784 ; C -1 ; WX 600 ; N Delta ; B 6 0 594 688 ; C -1 ; WX 600 ; N thorn ; B -32 -142 622 626 ; C -1 ; WX 600 ; N twosuperior ; B 191 230 542 616 ; C -1 ; WX 600 ; N Odieresis ; B 74 -18 645 761 ; C -1 ; WX 600 ; N mu ; B 49 -142 592 439 ; C -1 ; WX 600 ; N igrave ; B 77 0 546 661 ; C -1 ; WX 600 ; N ohungarumlaut ; B 71 -15 809 661 ; C -1 ; WX 600 ; N Eogonek ; B 25 -199 670 562 ; C -1 ; WX 600 ; N dcroat ; B 60 -15 712 626 ; C -1 ; WX 600 ; N threequarters ; B 8 -60 699 661 ; C -1 ; WX 600 ; N Scedilla ; B 54 -206 673 582 ; C -1 ; WX 600 ; N lcaron ; B 77 0 731 626 ; C -1 ; WX 600 ; N Kcommaaccent ; B 21 -250 692 562 ; C -1 ; WX 600 ; N Lacute ; B 39 0 636 784 ; C -1 ; WX 600 ; N trademark ; B 86 230 869 562 ; C -1 ; WX 600 ; N edotaccent ; B 81 -15 605 638 ; C -1 ; WX 600 ; N Igrave ; B 77 0 643 784 ; C -1 ; WX 600 ; N Imacron ; B 77 0 663 708 ; C -1 ; WX 600 ; N Lcaron ; B 39 0 757 562 ; C -1 ; WX 600 ; N onehalf ; B 22 -60 716 661 ; C -1 ; WX 600 ; N lessequal ; B 26 0 671 696 ; C -1 ; WX 600 ; N ocircumflex ; B 71 -15 622 657 ; C -1 ; WX 600 ; N ntilde ; B 18 0 643 636 ; C -1 ; WX 600 ; N Uhungarumlaut ; B 101 -18 805 784 ; C -1 ; WX 600 ; N Eacute ; B 25 0 670 784 ; C -1 ; WX 600 ; N emacron ; B 81 -15 637 585 ; C -1 ; WX 600 ; N gbreve ; B 40 -146 674 661 ; C -1 ; WX 600 ; N onequarter ; B 13 -60 707 661 ; C -1 ; WX 600 ; N Scaron ; B 54 -22 689 790 ; C -1 ; WX 600 ; N Scommaaccent ; B 54 -250 673 582 ; C -1 ; WX 600 ; N Ohungarumlaut ; B 74 -18 795 784 ; C -1 ; WX 600 ; N degree ; B 173 243 570 616 ; C -1 ; WX 600 ; N ograve ; B 71 -15 622 661 ; C -1 ; WX 600 ; N Ccaron ; B 74 -18 689 790 ; C -1 ; WX 600 ; N ugrave ; B 70 -15 592 661 ; C -1 ; WX 600 ; N radical ; B 67 -104 635 778 ; C -1 ; WX 600 ; N Dcaron ; B 30 0 664 790 ; C -1 ; WX 600 ; N rcommaaccent ; B 47 -250 655 454 ; C -1 ; WX 600 ; N Ntilde ; B 8 -12 730 759 ; C -1 ; WX 600 ; N otilde ; B 71 -15 643 636 ; C -1 ; WX 600 ; N Rcommaaccent ; B 24 -250 617 562 ; C -1 ; WX 600 ; N Lcommaaccent ; B 39 -250 636 562 ; C -1 ; WX 600 ; N Atilde ; B -9 0 669 759 ; C -1 ; WX 600 ; N Aogonek ; B -9 -199 632 562 ; C -1 ; WX 600 ; N Aring ; B -9 0 632 801 ; C -1 ; WX 600 ; N Otilde ; B 74 -18 669 759 ; C -1 ; WX 600 ; N zdotaccent ; B 81 0 614 638 ; C -1 ; WX 600 ; N Ecaron ; B 25 0 670 790 ; C -1 ; WX 600 ; N Iogonek ; B 77 -199 643 562 ; C -1 ; WX 600 ; N kcommaaccent ; B 33 -250 643 626 ; C -1 ; WX 600 ; N minus ; B 114 203 596 313 ; C -1 ; WX 600 ; N Icircumflex ; B 77 0 643 780 ; C -1 ; WX 600 ; N ncaron ; B 18 0 633 667 ; C -1 ; WX 600 ; N tcommaaccent ; B 118 -250 567 562 ; C -1 ; WX 600 ; N logicalnot ; B 135 103 617 413 ; C -1 ; WX 600 ; N odieresis ; B 71 -15 622 638 ; C -1 ; WX 600 ; N udieresis ; B 70 -15 595 638 ; C -1 ; WX 600 ; N notequal ; B 30 -47 626 563 ; C -1 ; WX 600 ; N gcommaaccent ; B 40 -146 674 714 ; C -1 ; WX 600 ; N eth ; B 93 -27 661 626 ; C -1 ; WX 600 ; N zcaron ; B 81 0 643 667 ; C -1 ; WX 600 ; N ncommaaccent ; B 18 -250 615 454 ; C -1 ; WX 600 ; N onesuperior ; B 212 230 514 616 ; C -1 ; WX 600 ; N imacron ; B 77 0 575 585 ; C -1 ; WX 600 ; N Euro ; B 0 0 0 0 ; EndCharMetrics EndFontMetrics camlpdf-2.8.1/compressor/Courier-Oblique.afm000066400000000000000000000361211477056064700210420ustar00rootroot00000000000000StartFontMetrics 4.1 Comment Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. Comment Creation Date: Thu May 1 17:37:52 1997 Comment UniqueID 43051 Comment VMusage 16248 75829 FontName Courier-Oblique FullName Courier Oblique FamilyName Courier Weight Medium ItalicAngle -12 IsFixedPitch true CharacterSet ExtendedRoman FontBBox -27 -250 849 805 UnderlinePosition -100 UnderlineThickness 50 Version 003.000 Notice Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. EncodingScheme AdobeStandardEncoding CapHeight 562 XHeight 426 Ascender 629 Descender -157 StdHW 51 StdVW 51 StartCharMetrics 315 C 32 ; WX 600 ; N space ; B 0 0 0 0 ; C 33 ; WX 600 ; N exclam ; B 243 -15 464 572 ; C 34 ; WX 600 ; N quotedbl ; B 273 328 532 562 ; C 35 ; WX 600 ; N numbersign ; B 133 -32 596 639 ; C 36 ; WX 600 ; N dollar ; B 108 -126 596 662 ; C 37 ; WX 600 ; N percent ; B 134 -15 599 622 ; C 38 ; WX 600 ; N ampersand ; B 87 -15 580 543 ; C 39 ; WX 600 ; N quoteright ; B 283 328 495 562 ; C 40 ; WX 600 ; N parenleft ; B 313 -108 572 622 ; C 41 ; WX 600 ; N parenright ; B 137 -108 396 622 ; C 42 ; WX 600 ; N asterisk ; B 212 257 580 607 ; C 43 ; WX 600 ; N plus ; B 129 44 580 470 ; C 44 ; WX 600 ; N comma ; B 157 -112 370 122 ; C 45 ; WX 600 ; N hyphen ; B 152 231 558 285 ; C 46 ; WX 600 ; N period ; B 238 -15 382 109 ; C 47 ; WX 600 ; N slash ; B 112 -80 604 629 ; C 48 ; WX 600 ; N zero ; B 154 -15 575 622 ; C 49 ; WX 600 ; N one ; B 98 0 515 622 ; C 50 ; WX 600 ; N two ; B 70 0 568 622 ; C 51 ; WX 600 ; N three ; B 82 -15 538 622 ; C 52 ; WX 600 ; N four ; B 108 0 541 622 ; C 53 ; WX 600 ; N five ; B 99 -15 589 607 ; C 54 ; WX 600 ; N six ; B 155 -15 629 622 ; C 55 ; WX 600 ; N seven ; B 182 0 612 607 ; C 56 ; WX 600 ; N eight ; B 132 -15 588 622 ; C 57 ; WX 600 ; N nine ; B 93 -15 574 622 ; C 58 ; WX 600 ; N colon ; B 238 -15 441 385 ; C 59 ; WX 600 ; N semicolon ; B 157 -112 441 385 ; C 60 ; WX 600 ; N less ; B 96 42 610 472 ; C 61 ; WX 600 ; N equal ; B 109 138 600 376 ; C 62 ; WX 600 ; N greater ; B 85 42 599 472 ; C 63 ; WX 600 ; N question ; B 222 -15 583 572 ; C 64 ; WX 600 ; N at ; B 127 -15 582 622 ; C 65 ; WX 600 ; N A ; B 3 0 607 562 ; C 66 ; WX 600 ; N B ; B 43 0 616 562 ; C 67 ; WX 600 ; N C ; B 93 -18 655 580 ; C 68 ; WX 600 ; N D ; B 43 0 645 562 ; C 69 ; WX 600 ; N E ; B 53 0 660 562 ; C 70 ; WX 600 ; N F ; B 53 0 660 562 ; C 71 ; WX 600 ; N G ; B 83 -18 645 580 ; C 72 ; WX 600 ; N H ; B 32 0 687 562 ; C 73 ; WX 600 ; N I ; B 96 0 623 562 ; C 74 ; WX 600 ; N J ; B 52 -18 685 562 ; C 75 ; WX 600 ; N K ; B 38 0 671 562 ; C 76 ; WX 600 ; N L ; B 47 0 607 562 ; C 77 ; WX 600 ; N M ; B 4 0 715 562 ; C 78 ; WX 600 ; N N ; B 7 -13 712 562 ; C 79 ; WX 600 ; N O ; B 94 -18 625 580 ; C 80 ; WX 600 ; N P ; B 79 0 644 562 ; C 81 ; WX 600 ; N Q ; B 95 -138 625 580 ; C 82 ; WX 600 ; N R ; B 38 0 598 562 ; C 83 ; WX 600 ; N S ; B 76 -20 650 580 ; C 84 ; WX 600 ; N T ; B 108 0 665 562 ; C 85 ; WX 600 ; N U ; B 125 -18 702 562 ; C 86 ; WX 600 ; N V ; B 105 -13 723 562 ; C 87 ; WX 600 ; N W ; B 106 -13 722 562 ; C 88 ; WX 600 ; N X ; B 23 0 675 562 ; C 89 ; WX 600 ; N Y ; B 133 0 695 562 ; C 90 ; WX 600 ; N Z ; B 86 0 610 562 ; C 91 ; WX 600 ; N bracketleft ; B 246 -108 574 622 ; C 92 ; WX 600 ; N backslash ; B 249 -80 468 629 ; C 93 ; WX 600 ; N bracketright ; B 135 -108 463 622 ; C 94 ; WX 600 ; N asciicircum ; B 175 354 587 622 ; C 95 ; WX 600 ; N underscore ; B -27 -125 584 -75 ; C 96 ; WX 600 ; N quoteleft ; B 343 328 457 562 ; C 97 ; WX 600 ; N a ; B 76 -15 569 441 ; C 98 ; WX 600 ; N b ; B 29 -15 625 629 ; C 99 ; WX 600 ; N c ; B 106 -15 608 441 ; C 100 ; WX 600 ; N d ; B 85 -15 640 629 ; C 101 ; WX 600 ; N e ; B 106 -15 598 441 ; C 102 ; WX 600 ; N f ; B 114 0 662 629 ; L i fi ; L l fl ; C 103 ; WX 600 ; N g ; B 61 -157 657 441 ; C 104 ; WX 600 ; N h ; B 33 0 592 629 ; C 105 ; WX 600 ; N i ; B 95 0 515 657 ; C 106 ; WX 600 ; N j ; B 52 -157 550 657 ; C 107 ; WX 600 ; N k ; B 58 0 633 629 ; C 108 ; WX 600 ; N l ; B 95 0 515 629 ; C 109 ; WX 600 ; N m ; B -5 0 615 441 ; C 110 ; WX 600 ; N n ; B 26 0 585 441 ; C 111 ; WX 600 ; N o ; B 102 -15 588 441 ; C 112 ; WX 600 ; N p ; B -24 -157 605 441 ; C 113 ; WX 600 ; N q ; B 85 -157 682 441 ; C 114 ; WX 600 ; N r ; B 60 0 636 441 ; C 115 ; WX 600 ; N s ; B 78 -15 584 441 ; C 116 ; WX 600 ; N t ; B 167 -15 561 561 ; C 117 ; WX 600 ; N u ; B 101 -15 572 426 ; C 118 ; WX 600 ; N v ; B 90 -10 681 426 ; C 119 ; WX 600 ; N w ; B 76 -10 695 426 ; C 120 ; WX 600 ; N x ; B 20 0 655 426 ; C 121 ; WX 600 ; N y ; B -4 -157 683 426 ; C 122 ; WX 600 ; N z ; B 99 0 593 426 ; C 123 ; WX 600 ; N braceleft ; B 233 -108 569 622 ; C 124 ; WX 600 ; N bar ; B 222 -250 485 750 ; C 125 ; WX 600 ; N braceright ; B 140 -108 477 622 ; C 126 ; WX 600 ; N asciitilde ; B 116 197 600 320 ; C 161 ; WX 600 ; N exclamdown ; B 225 -157 445 430 ; C 162 ; WX 600 ; N cent ; B 151 -49 588 614 ; C 163 ; WX 600 ; N sterling ; B 124 -21 621 611 ; C 164 ; WX 600 ; N fraction ; B 84 -57 646 665 ; C 165 ; WX 600 ; N yen ; B 120 0 693 562 ; C 166 ; WX 600 ; N florin ; B -26 -143 671 622 ; C 167 ; WX 600 ; N section ; B 104 -78 590 580 ; C 168 ; WX 600 ; N currency ; B 94 58 628 506 ; C 169 ; WX 600 ; N quotesingle ; B 345 328 460 562 ; C 170 ; WX 600 ; N quotedblleft ; B 262 328 541 562 ; C 171 ; WX 600 ; N guillemotleft ; B 92 70 652 446 ; C 172 ; WX 600 ; N guilsinglleft ; B 204 70 540 446 ; C 173 ; WX 600 ; N guilsinglright ; B 170 70 506 446 ; C 174 ; WX 600 ; N fi ; B 3 0 619 629 ; C 175 ; WX 600 ; N fl ; B 3 0 619 629 ; C 177 ; WX 600 ; N endash ; B 124 231 586 285 ; C 178 ; WX 600 ; N dagger ; B 217 -78 546 580 ; C 179 ; WX 600 ; N daggerdbl ; B 163 -78 546 580 ; C 180 ; WX 600 ; N periodcentered ; B 275 189 434 327 ; C 182 ; WX 600 ; N paragraph ; B 100 -78 630 562 ; C 183 ; WX 600 ; N bullet ; B 224 130 485 383 ; C 184 ; WX 600 ; N quotesinglbase ; B 185 -134 397 100 ; C 185 ; WX 600 ; N quotedblbase ; B 115 -134 478 100 ; C 186 ; WX 600 ; N quotedblright ; B 213 328 576 562 ; C 187 ; WX 600 ; N guillemotright ; B 58 70 618 446 ; C 188 ; WX 600 ; N ellipsis ; B 46 -15 575 111 ; C 189 ; WX 600 ; N perthousand ; B 59 -15 627 622 ; C 191 ; WX 600 ; N questiondown ; B 105 -157 466 430 ; C 193 ; WX 600 ; N grave ; B 294 497 484 672 ; C 194 ; WX 600 ; N acute ; B 348 497 612 672 ; C 195 ; WX 600 ; N circumflex ; B 229 477 581 654 ; C 196 ; WX 600 ; N tilde ; B 212 489 629 606 ; C 197 ; WX 600 ; N macron ; B 232 525 600 565 ; C 198 ; WX 600 ; N breve ; B 279 501 576 609 ; C 199 ; WX 600 ; N dotaccent ; B 373 537 478 640 ; C 200 ; WX 600 ; N dieresis ; B 272 537 579 640 ; C 202 ; WX 600 ; N ring ; B 332 463 500 627 ; C 203 ; WX 600 ; N cedilla ; B 197 -151 344 10 ; C 205 ; WX 600 ; N hungarumlaut ; B 239 497 683 672 ; C 206 ; WX 600 ; N ogonek ; B 189 -172 377 4 ; C 207 ; WX 600 ; N caron ; B 262 492 614 669 ; C 208 ; WX 600 ; N emdash ; B 49 231 661 285 ; C 225 ; WX 600 ; N AE ; B 3 0 655 562 ; C 227 ; WX 600 ; N ordfeminine ; B 209 249 512 580 ; C 232 ; WX 600 ; N Lslash ; B 47 0 607 562 ; C 233 ; WX 600 ; N Oslash ; B 94 -80 625 629 ; C 234 ; WX 600 ; N OE ; B 59 0 672 562 ; C 235 ; WX 600 ; N ordmasculine ; B 210 249 535 580 ; C 241 ; WX 600 ; N ae ; B 41 -15 626 441 ; C 245 ; WX 600 ; N dotlessi ; B 95 0 515 426 ; C 248 ; WX 600 ; N lslash ; B 95 0 587 629 ; C 249 ; WX 600 ; N oslash ; B 102 -80 588 506 ; C 250 ; WX 600 ; N oe ; B 54 -15 615 441 ; C 251 ; WX 600 ; N germandbls ; B 48 -15 617 629 ; C -1 ; WX 600 ; N Idieresis ; B 96 0 623 753 ; C -1 ; WX 600 ; N eacute ; B 106 -15 612 672 ; C -1 ; WX 600 ; N abreve ; B 76 -15 576 609 ; C -1 ; WX 600 ; N uhungarumlaut ; B 101 -15 723 672 ; C -1 ; WX 600 ; N ecaron ; B 106 -15 614 669 ; C -1 ; WX 600 ; N Ydieresis ; B 133 0 695 753 ; C -1 ; WX 600 ; N divide ; B 136 48 573 467 ; C -1 ; WX 600 ; N Yacute ; B 133 0 695 805 ; C -1 ; WX 600 ; N Acircumflex ; B 3 0 607 787 ; C -1 ; WX 600 ; N aacute ; B 76 -15 612 672 ; C -1 ; WX 600 ; N Ucircumflex ; B 125 -18 702 787 ; C -1 ; WX 600 ; N yacute ; B -4 -157 683 672 ; C -1 ; WX 600 ; N scommaaccent ; B 78 -250 584 441 ; C -1 ; WX 600 ; N ecircumflex ; B 106 -15 598 654 ; C -1 ; WX 600 ; N Uring ; B 125 -18 702 760 ; C -1 ; WX 600 ; N Udieresis ; B 125 -18 702 753 ; C -1 ; WX 600 ; N aogonek ; B 76 -172 569 441 ; C -1 ; WX 600 ; N Uacute ; B 125 -18 702 805 ; C -1 ; WX 600 ; N uogonek ; B 101 -172 572 426 ; C -1 ; WX 600 ; N Edieresis ; B 53 0 660 753 ; C -1 ; WX 600 ; N Dcroat ; B 43 0 645 562 ; C -1 ; WX 600 ; N commaaccent ; B 145 -250 323 -58 ; C -1 ; WX 600 ; N copyright ; B 53 -18 667 580 ; C -1 ; WX 600 ; N Emacron ; B 53 0 660 698 ; C -1 ; WX 600 ; N ccaron ; B 106 -15 614 669 ; C -1 ; WX 600 ; N aring ; B 76 -15 569 627 ; C -1 ; WX 600 ; N Ncommaaccent ; B 7 -250 712 562 ; C -1 ; WX 600 ; N lacute ; B 95 0 640 805 ; C -1 ; WX 600 ; N agrave ; B 76 -15 569 672 ; C -1 ; WX 600 ; N Tcommaaccent ; B 108 -250 665 562 ; C -1 ; WX 600 ; N Cacute ; B 93 -18 655 805 ; C -1 ; WX 600 ; N atilde ; B 76 -15 629 606 ; C -1 ; WX 600 ; N Edotaccent ; B 53 0 660 753 ; C -1 ; WX 600 ; N scaron ; B 78 -15 614 669 ; C -1 ; WX 600 ; N scedilla ; B 78 -151 584 441 ; C -1 ; WX 600 ; N iacute ; B 95 0 612 672 ; C -1 ; WX 600 ; N lozenge ; B 94 0 519 706 ; C -1 ; WX 600 ; N Rcaron ; B 38 0 642 802 ; C -1 ; WX 600 ; N Gcommaaccent ; B 83 -250 645 580 ; C -1 ; WX 600 ; N ucircumflex ; B 101 -15 572 654 ; C -1 ; WX 600 ; N acircumflex ; B 76 -15 581 654 ; C -1 ; WX 600 ; N Amacron ; B 3 0 607 698 ; C -1 ; WX 600 ; N rcaron ; B 60 0 636 669 ; C -1 ; WX 600 ; N ccedilla ; B 106 -151 614 441 ; C -1 ; WX 600 ; N Zdotaccent ; B 86 0 610 753 ; C -1 ; WX 600 ; N Thorn ; B 79 0 606 562 ; C -1 ; WX 600 ; N Omacron ; B 94 -18 628 698 ; C -1 ; WX 600 ; N Racute ; B 38 0 670 805 ; C -1 ; WX 600 ; N Sacute ; B 76 -20 650 805 ; C -1 ; WX 600 ; N dcaron ; B 85 -15 849 629 ; C -1 ; WX 600 ; N Umacron ; B 125 -18 702 698 ; C -1 ; WX 600 ; N uring ; B 101 -15 572 627 ; C -1 ; WX 600 ; N threesuperior ; B 213 240 501 622 ; C -1 ; WX 600 ; N Ograve ; B 94 -18 625 805 ; C -1 ; WX 600 ; N Agrave ; B 3 0 607 805 ; C -1 ; WX 600 ; N Abreve ; B 3 0 607 732 ; C -1 ; WX 600 ; N multiply ; B 103 43 607 470 ; C -1 ; WX 600 ; N uacute ; B 101 -15 602 672 ; C -1 ; WX 600 ; N Tcaron ; B 108 0 665 802 ; C -1 ; WX 600 ; N partialdiff ; B 45 -38 546 710 ; C -1 ; WX 600 ; N ydieresis ; B -4 -157 683 620 ; C -1 ; WX 600 ; N Nacute ; B 7 -13 712 805 ; C -1 ; WX 600 ; N icircumflex ; B 95 0 551 654 ; C -1 ; WX 600 ; N Ecircumflex ; B 53 0 660 787 ; C -1 ; WX 600 ; N adieresis ; B 76 -15 575 620 ; C -1 ; WX 600 ; N edieresis ; B 106 -15 598 620 ; C -1 ; WX 600 ; N cacute ; B 106 -15 612 672 ; C -1 ; WX 600 ; N nacute ; B 26 0 602 672 ; C -1 ; WX 600 ; N umacron ; B 101 -15 600 565 ; C -1 ; WX 600 ; N Ncaron ; B 7 -13 712 802 ; C -1 ; WX 600 ; N Iacute ; B 96 0 640 805 ; C -1 ; WX 600 ; N plusminus ; B 96 44 594 558 ; C -1 ; WX 600 ; N brokenbar ; B 238 -175 469 675 ; C -1 ; WX 600 ; N registered ; B 53 -18 667 580 ; C -1 ; WX 600 ; N Gbreve ; B 83 -18 645 732 ; C -1 ; WX 600 ; N Idotaccent ; B 96 0 623 753 ; C -1 ; WX 600 ; N summation ; B 15 -10 670 706 ; C -1 ; WX 600 ; N Egrave ; B 53 0 660 805 ; C -1 ; WX 600 ; N racute ; B 60 0 636 672 ; C -1 ; WX 600 ; N omacron ; B 102 -15 600 565 ; C -1 ; WX 600 ; N Zacute ; B 86 0 670 805 ; C -1 ; WX 600 ; N Zcaron ; B 86 0 642 802 ; C -1 ; WX 600 ; N greaterequal ; B 98 0 594 710 ; C -1 ; WX 600 ; N Eth ; B 43 0 645 562 ; C -1 ; WX 600 ; N Ccedilla ; B 93 -151 658 580 ; C -1 ; WX 600 ; N lcommaaccent ; B 95 -250 515 629 ; C -1 ; WX 600 ; N tcaron ; B 167 -15 587 717 ; C -1 ; WX 600 ; N eogonek ; B 106 -172 598 441 ; C -1 ; WX 600 ; N Uogonek ; B 124 -172 702 562 ; C -1 ; WX 600 ; N Aacute ; B 3 0 660 805 ; C -1 ; WX 600 ; N Adieresis ; B 3 0 607 753 ; C -1 ; WX 600 ; N egrave ; B 106 -15 598 672 ; C -1 ; WX 600 ; N zacute ; B 99 0 612 672 ; C -1 ; WX 600 ; N iogonek ; B 95 -172 515 657 ; C -1 ; WX 600 ; N Oacute ; B 94 -18 640 805 ; C -1 ; WX 600 ; N oacute ; B 102 -15 612 672 ; C -1 ; WX 600 ; N amacron ; B 76 -15 600 565 ; C -1 ; WX 600 ; N sacute ; B 78 -15 612 672 ; C -1 ; WX 600 ; N idieresis ; B 95 0 545 620 ; C -1 ; WX 600 ; N Ocircumflex ; B 94 -18 625 787 ; C -1 ; WX 600 ; N Ugrave ; B 125 -18 702 805 ; C -1 ; WX 600 ; N Delta ; B 6 0 598 688 ; C -1 ; WX 600 ; N thorn ; B -24 -157 605 629 ; C -1 ; WX 600 ; N twosuperior ; B 230 249 535 622 ; C -1 ; WX 600 ; N Odieresis ; B 94 -18 625 753 ; C -1 ; WX 600 ; N mu ; B 72 -157 572 426 ; C -1 ; WX 600 ; N igrave ; B 95 0 515 672 ; C -1 ; WX 600 ; N ohungarumlaut ; B 102 -15 723 672 ; C -1 ; WX 600 ; N Eogonek ; B 53 -172 660 562 ; C -1 ; WX 600 ; N dcroat ; B 85 -15 704 629 ; C -1 ; WX 600 ; N threequarters ; B 73 -56 659 666 ; C -1 ; WX 600 ; N Scedilla ; B 76 -151 650 580 ; C -1 ; WX 600 ; N lcaron ; B 95 0 667 629 ; C -1 ; WX 600 ; N Kcommaaccent ; B 38 -250 671 562 ; C -1 ; WX 600 ; N Lacute ; B 47 0 607 805 ; C -1 ; WX 600 ; N trademark ; B 75 263 742 562 ; C -1 ; WX 600 ; N edotaccent ; B 106 -15 598 620 ; C -1 ; WX 600 ; N Igrave ; B 96 0 623 805 ; C -1 ; WX 600 ; N Imacron ; B 96 0 628 698 ; C -1 ; WX 600 ; N Lcaron ; B 47 0 632 562 ; C -1 ; WX 600 ; N onehalf ; B 65 -57 669 665 ; C -1 ; WX 600 ; N lessequal ; B 98 0 645 710 ; C -1 ; WX 600 ; N ocircumflex ; B 102 -15 588 654 ; C -1 ; WX 600 ; N ntilde ; B 26 0 629 606 ; C -1 ; WX 600 ; N Uhungarumlaut ; B 125 -18 761 805 ; C -1 ; WX 600 ; N Eacute ; B 53 0 670 805 ; C -1 ; WX 600 ; N emacron ; B 106 -15 600 565 ; C -1 ; WX 600 ; N gbreve ; B 61 -157 657 609 ; C -1 ; WX 600 ; N onequarter ; B 65 -57 674 665 ; C -1 ; WX 600 ; N Scaron ; B 76 -20 672 802 ; C -1 ; WX 600 ; N Scommaaccent ; B 76 -250 650 580 ; C -1 ; WX 600 ; N Ohungarumlaut ; B 94 -18 751 805 ; C -1 ; WX 600 ; N degree ; B 214 269 576 622 ; C -1 ; WX 600 ; N ograve ; B 102 -15 588 672 ; C -1 ; WX 600 ; N Ccaron ; B 93 -18 672 802 ; C -1 ; WX 600 ; N ugrave ; B 101 -15 572 672 ; C -1 ; WX 600 ; N radical ; B 85 -15 765 792 ; C -1 ; WX 600 ; N Dcaron ; B 43 0 645 802 ; C -1 ; WX 600 ; N rcommaaccent ; B 60 -250 636 441 ; C -1 ; WX 600 ; N Ntilde ; B 7 -13 712 729 ; C -1 ; WX 600 ; N otilde ; B 102 -15 629 606 ; C -1 ; WX 600 ; N Rcommaaccent ; B 38 -250 598 562 ; C -1 ; WX 600 ; N Lcommaaccent ; B 47 -250 607 562 ; C -1 ; WX 600 ; N Atilde ; B 3 0 655 729 ; C -1 ; WX 600 ; N Aogonek ; B 3 -172 607 562 ; C -1 ; WX 600 ; N Aring ; B 3 0 607 750 ; C -1 ; WX 600 ; N Otilde ; B 94 -18 655 729 ; C -1 ; WX 600 ; N zdotaccent ; B 99 0 593 620 ; C -1 ; WX 600 ; N Ecaron ; B 53 0 660 802 ; C -1 ; WX 600 ; N Iogonek ; B 96 -172 623 562 ; C -1 ; WX 600 ; N kcommaaccent ; B 58 -250 633 629 ; C -1 ; WX 600 ; N minus ; B 129 232 580 283 ; C -1 ; WX 600 ; N Icircumflex ; B 96 0 623 787 ; C -1 ; WX 600 ; N ncaron ; B 26 0 614 669 ; C -1 ; WX 600 ; N tcommaaccent ; B 165 -250 561 561 ; C -1 ; WX 600 ; N logicalnot ; B 155 108 591 369 ; C -1 ; WX 600 ; N odieresis ; B 102 -15 588 620 ; C -1 ; WX 600 ; N udieresis ; B 101 -15 575 620 ; C -1 ; WX 600 ; N notequal ; B 43 -16 621 529 ; C -1 ; WX 600 ; N gcommaaccent ; B 61 -157 657 708 ; C -1 ; WX 600 ; N eth ; B 102 -15 639 629 ; C -1 ; WX 600 ; N zcaron ; B 99 0 624 669 ; C -1 ; WX 600 ; N ncommaaccent ; B 26 -250 585 441 ; C -1 ; WX 600 ; N onesuperior ; B 231 249 491 622 ; C -1 ; WX 600 ; N imacron ; B 95 0 543 565 ; C -1 ; WX 600 ; N Euro ; B 0 0 0 0 ; EndCharMetrics EndFontMetrics camlpdf-2.8.1/compressor/Courier.afm000066400000000000000000000357471477056064700174610ustar00rootroot00000000000000StartFontMetrics 4.1 Comment Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. Comment Creation Date: Thu May 1 17:27:09 1997 Comment UniqueID 43050 Comment VMusage 39754 50779 FontName Courier FullName Courier FamilyName Courier Weight Medium ItalicAngle 0 IsFixedPitch true CharacterSet ExtendedRoman FontBBox -23 -250 715 805 UnderlinePosition -100 UnderlineThickness 50 Version 003.000 Notice Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved. EncodingScheme AdobeStandardEncoding CapHeight 562 XHeight 426 Ascender 629 Descender -157 StdHW 51 StdVW 51 StartCharMetrics 315 C 32 ; WX 600 ; N space ; B 0 0 0 0 ; C 33 ; WX 600 ; N exclam ; B 236 -15 364 572 ; C 34 ; WX 600 ; N quotedbl ; B 187 328 413 562 ; C 35 ; WX 600 ; N numbersign ; B 93 -32 507 639 ; C 36 ; WX 600 ; N dollar ; B 105 -126 496 662 ; C 37 ; WX 600 ; N percent ; B 81 -15 518 622 ; C 38 ; WX 600 ; N ampersand ; B 63 -15 538 543 ; C 39 ; WX 600 ; N quoteright ; B 213 328 376 562 ; C 40 ; WX 600 ; N parenleft ; B 269 -108 440 622 ; C 41 ; WX 600 ; N parenright ; B 160 -108 331 622 ; C 42 ; WX 600 ; N asterisk ; B 116 257 484 607 ; C 43 ; WX 600 ; N plus ; B 80 44 520 470 ; C 44 ; WX 600 ; N comma ; B 181 -112 344 122 ; C 45 ; WX 600 ; N hyphen ; B 103 231 497 285 ; C 46 ; WX 600 ; N period ; B 229 -15 371 109 ; C 47 ; WX 600 ; N slash ; B 125 -80 475 629 ; C 48 ; WX 600 ; N zero ; B 106 -15 494 622 ; C 49 ; WX 600 ; N one ; B 96 0 505 622 ; C 50 ; WX 600 ; N two ; B 70 0 471 622 ; C 51 ; WX 600 ; N three ; B 75 -15 466 622 ; C 52 ; WX 600 ; N four ; B 78 0 500 622 ; C 53 ; WX 600 ; N five ; B 92 -15 497 607 ; C 54 ; WX 600 ; N six ; B 111 -15 497 622 ; C 55 ; WX 600 ; N seven ; B 82 0 483 607 ; C 56 ; WX 600 ; N eight ; B 102 -15 498 622 ; C 57 ; WX 600 ; N nine ; B 96 -15 489 622 ; C 58 ; WX 600 ; N colon ; B 229 -15 371 385 ; C 59 ; WX 600 ; N semicolon ; B 181 -112 371 385 ; C 60 ; WX 600 ; N less ; B 41 42 519 472 ; C 61 ; WX 600 ; N equal ; B 80 138 520 376 ; C 62 ; WX 600 ; N greater ; B 66 42 544 472 ; C 63 ; WX 600 ; N question ; B 129 -15 492 572 ; C 64 ; WX 600 ; N at ; B 77 -15 533 622 ; C 65 ; WX 600 ; N A ; B 3 0 597 562 ; C 66 ; WX 600 ; N B ; B 43 0 559 562 ; C 67 ; WX 600 ; N C ; B 41 -18 540 580 ; C 68 ; WX 600 ; N D ; B 43 0 574 562 ; C 69 ; WX 600 ; N E ; B 53 0 550 562 ; C 70 ; WX 600 ; N F ; B 53 0 545 562 ; C 71 ; WX 600 ; N G ; B 31 -18 575 580 ; C 72 ; WX 600 ; N H ; B 32 0 568 562 ; C 73 ; WX 600 ; N I ; B 96 0 504 562 ; C 74 ; WX 600 ; N J ; B 34 -18 566 562 ; C 75 ; WX 600 ; N K ; B 38 0 582 562 ; C 76 ; WX 600 ; N L ; B 47 0 554 562 ; C 77 ; WX 600 ; N M ; B 4 0 596 562 ; C 78 ; WX 600 ; N N ; B 7 -13 593 562 ; C 79 ; WX 600 ; N O ; B 43 -18 557 580 ; C 80 ; WX 600 ; N P ; B 79 0 558 562 ; C 81 ; WX 600 ; N Q ; B 43 -138 557 580 ; C 82 ; WX 600 ; N R ; B 38 0 588 562 ; C 83 ; WX 600 ; N S ; B 72 -20 529 580 ; C 84 ; WX 600 ; N T ; B 38 0 563 562 ; C 85 ; WX 600 ; N U ; B 17 -18 583 562 ; C 86 ; WX 600 ; N V ; B -4 -13 604 562 ; C 87 ; WX 600 ; N W ; B -3 -13 603 562 ; C 88 ; WX 600 ; N X ; B 23 0 577 562 ; C 89 ; WX 600 ; N Y ; B 24 0 576 562 ; C 90 ; WX 600 ; N Z ; B 86 0 514 562 ; C 91 ; WX 600 ; N bracketleft ; B 269 -108 442 622 ; C 92 ; WX 600 ; N backslash ; B 118 -80 482 629 ; C 93 ; WX 600 ; N bracketright ; B 158 -108 331 622 ; C 94 ; WX 600 ; N asciicircum ; B 94 354 506 622 ; C 95 ; WX 600 ; N underscore ; B 0 -125 600 -75 ; C 96 ; WX 600 ; N quoteleft ; B 224 328 387 562 ; C 97 ; WX 600 ; N a ; B 53 -15 559 441 ; C 98 ; WX 600 ; N b ; B 14 -15 575 629 ; C 99 ; WX 600 ; N c ; B 66 -15 529 441 ; C 100 ; WX 600 ; N d ; B 45 -15 591 629 ; C 101 ; WX 600 ; N e ; B 66 -15 548 441 ; C 102 ; WX 600 ; N f ; B 114 0 531 629 ; L i fi ; L l fl ; C 103 ; WX 600 ; N g ; B 45 -157 566 441 ; C 104 ; WX 600 ; N h ; B 18 0 582 629 ; C 105 ; WX 600 ; N i ; B 95 0 505 657 ; C 106 ; WX 600 ; N j ; B 82 -157 410 657 ; C 107 ; WX 600 ; N k ; B 43 0 580 629 ; C 108 ; WX 600 ; N l ; B 95 0 505 629 ; C 109 ; WX 600 ; N m ; B -5 0 605 441 ; C 110 ; WX 600 ; N n ; B 26 0 575 441 ; C 111 ; WX 600 ; N o ; B 62 -15 538 441 ; C 112 ; WX 600 ; N p ; B 9 -157 555 441 ; C 113 ; WX 600 ; N q ; B 45 -157 591 441 ; C 114 ; WX 600 ; N r ; B 60 0 559 441 ; C 115 ; WX 600 ; N s ; B 80 -15 513 441 ; C 116 ; WX 600 ; N t ; B 87 -15 530 561 ; C 117 ; WX 600 ; N u ; B 21 -15 562 426 ; C 118 ; WX 600 ; N v ; B 10 -10 590 426 ; C 119 ; WX 600 ; N w ; B -4 -10 604 426 ; C 120 ; WX 600 ; N x ; B 20 0 580 426 ; C 121 ; WX 600 ; N y ; B 7 -157 592 426 ; C 122 ; WX 600 ; N z ; B 99 0 502 426 ; C 123 ; WX 600 ; N braceleft ; B 182 -108 437 622 ; C 124 ; WX 600 ; N bar ; B 275 -250 326 750 ; C 125 ; WX 600 ; N braceright ; B 163 -108 418 622 ; C 126 ; WX 600 ; N asciitilde ; B 63 197 540 320 ; C 161 ; WX 600 ; N exclamdown ; B 236 -157 364 430 ; C 162 ; WX 600 ; N cent ; B 96 -49 500 614 ; C 163 ; WX 600 ; N sterling ; B 84 -21 521 611 ; C 164 ; WX 600 ; N fraction ; B 92 -57 509 665 ; C 165 ; WX 600 ; N yen ; B 26 0 574 562 ; C 166 ; WX 600 ; N florin ; B 4 -143 539 622 ; C 167 ; WX 600 ; N section ; B 113 -78 488 580 ; C 168 ; WX 600 ; N currency ; B 73 58 527 506 ; C 169 ; WX 600 ; N quotesingle ; B 259 328 341 562 ; C 170 ; WX 600 ; N quotedblleft ; B 143 328 471 562 ; C 171 ; WX 600 ; N guillemotleft ; B 37 70 563 446 ; C 172 ; WX 600 ; N guilsinglleft ; B 149 70 451 446 ; C 173 ; WX 600 ; N guilsinglright ; B 149 70 451 446 ; C 174 ; WX 600 ; N fi ; B 3 0 597 629 ; C 175 ; WX 600 ; N fl ; B 3 0 597 629 ; C 177 ; WX 600 ; N endash ; B 75 231 525 285 ; C 178 ; WX 600 ; N dagger ; B 141 -78 459 580 ; C 179 ; WX 600 ; N daggerdbl ; B 141 -78 459 580 ; C 180 ; WX 600 ; N periodcentered ; B 222 189 378 327 ; C 182 ; WX 600 ; N paragraph ; B 50 -78 511 562 ; C 183 ; WX 600 ; N bullet ; B 172 130 428 383 ; C 184 ; WX 600 ; N quotesinglbase ; B 213 -134 376 100 ; C 185 ; WX 600 ; N quotedblbase ; B 143 -134 457 100 ; C 186 ; WX 600 ; N quotedblright ; B 143 328 457 562 ; C 187 ; WX 600 ; N guillemotright ; B 37 70 563 446 ; C 188 ; WX 600 ; N ellipsis ; B 37 -15 563 111 ; C 189 ; WX 600 ; N perthousand ; B 3 -15 600 622 ; C 191 ; WX 600 ; N questiondown ; B 108 -157 471 430 ; C 193 ; WX 600 ; N grave ; B 151 497 378 672 ; C 194 ; WX 600 ; N acute ; B 242 497 469 672 ; C 195 ; WX 600 ; N circumflex ; B 124 477 476 654 ; C 196 ; WX 600 ; N tilde ; B 105 489 503 606 ; C 197 ; WX 600 ; N macron ; B 120 525 480 565 ; C 198 ; WX 600 ; N breve ; B 153 501 447 609 ; C 199 ; WX 600 ; N dotaccent ; B 249 537 352 640 ; C 200 ; WX 600 ; N dieresis ; B 148 537 453 640 ; C 202 ; WX 600 ; N ring ; B 218 463 382 627 ; C 203 ; WX 600 ; N cedilla ; B 224 -151 362 10 ; C 205 ; WX 600 ; N hungarumlaut ; B 133 497 540 672 ; C 206 ; WX 600 ; N ogonek ; B 211 -172 407 4 ; C 207 ; WX 600 ; N caron ; B 124 492 476 669 ; C 208 ; WX 600 ; N emdash ; B 0 231 600 285 ; C 225 ; WX 600 ; N AE ; B 3 0 550 562 ; C 227 ; WX 600 ; N ordfeminine ; B 156 249 442 580 ; C 232 ; WX 600 ; N Lslash ; B 47 0 554 562 ; C 233 ; WX 600 ; N Oslash ; B 43 -80 557 629 ; C 234 ; WX 600 ; N OE ; B 7 0 567 562 ; C 235 ; WX 600 ; N ordmasculine ; B 157 249 443 580 ; C 241 ; WX 600 ; N ae ; B 19 -15 570 441 ; C 245 ; WX 600 ; N dotlessi ; B 95 0 505 426 ; C 248 ; WX 600 ; N lslash ; B 95 0 505 629 ; C 249 ; WX 600 ; N oslash ; B 62 -80 538 506 ; C 250 ; WX 600 ; N oe ; B 19 -15 559 441 ; C 251 ; WX 600 ; N germandbls ; B 48 -15 588 629 ; C -1 ; WX 600 ; N Idieresis ; B 96 0 504 753 ; C -1 ; WX 600 ; N eacute ; B 66 -15 548 672 ; C -1 ; WX 600 ; N abreve ; B 53 -15 559 609 ; C -1 ; WX 600 ; N uhungarumlaut ; B 21 -15 580 672 ; C -1 ; WX 600 ; N ecaron ; B 66 -15 548 669 ; C -1 ; WX 600 ; N Ydieresis ; B 24 0 576 753 ; C -1 ; WX 600 ; N divide ; B 87 48 513 467 ; C -1 ; WX 600 ; N Yacute ; B 24 0 576 805 ; C -1 ; WX 600 ; N Acircumflex ; B 3 0 597 787 ; C -1 ; WX 600 ; N aacute ; B 53 -15 559 672 ; C -1 ; WX 600 ; N Ucircumflex ; B 17 -18 583 787 ; C -1 ; WX 600 ; N yacute ; B 7 -157 592 672 ; C -1 ; WX 600 ; N scommaaccent ; B 80 -250 513 441 ; C -1 ; WX 600 ; N ecircumflex ; B 66 -15 548 654 ; C -1 ; WX 600 ; N Uring ; B 17 -18 583 760 ; C -1 ; WX 600 ; N Udieresis ; B 17 -18 583 753 ; C -1 ; WX 600 ; N aogonek ; B 53 -172 587 441 ; C -1 ; WX 600 ; N Uacute ; B 17 -18 583 805 ; C -1 ; WX 600 ; N uogonek ; B 21 -172 590 426 ; C -1 ; WX 600 ; N Edieresis ; B 53 0 550 753 ; C -1 ; WX 600 ; N Dcroat ; B 30 0 574 562 ; C -1 ; WX 600 ; N commaaccent ; B 198 -250 335 -58 ; C -1 ; WX 600 ; N copyright ; B 0 -18 600 580 ; C -1 ; WX 600 ; N Emacron ; B 53 0 550 698 ; C -1 ; WX 600 ; N ccaron ; B 66 -15 529 669 ; C -1 ; WX 600 ; N aring ; B 53 -15 559 627 ; C -1 ; WX 600 ; N Ncommaaccent ; B 7 -250 593 562 ; C -1 ; WX 600 ; N lacute ; B 95 0 505 805 ; C -1 ; WX 600 ; N agrave ; B 53 -15 559 672 ; C -1 ; WX 600 ; N Tcommaaccent ; B 38 -250 563 562 ; C -1 ; WX 600 ; N Cacute ; B 41 -18 540 805 ; C -1 ; WX 600 ; N atilde ; B 53 -15 559 606 ; C -1 ; WX 600 ; N Edotaccent ; B 53 0 550 753 ; C -1 ; WX 600 ; N scaron ; B 80 -15 513 669 ; C -1 ; WX 600 ; N scedilla ; B 80 -151 513 441 ; C -1 ; WX 600 ; N iacute ; B 95 0 505 672 ; C -1 ; WX 600 ; N lozenge ; B 18 0 443 706 ; C -1 ; WX 600 ; N Rcaron ; B 38 0 588 802 ; C -1 ; WX 600 ; N Gcommaaccent ; B 31 -250 575 580 ; C -1 ; WX 600 ; N ucircumflex ; B 21 -15 562 654 ; C -1 ; WX 600 ; N acircumflex ; B 53 -15 559 654 ; C -1 ; WX 600 ; N Amacron ; B 3 0 597 698 ; C -1 ; WX 600 ; N rcaron ; B 60 0 559 669 ; C -1 ; WX 600 ; N ccedilla ; B 66 -151 529 441 ; C -1 ; WX 600 ; N Zdotaccent ; B 86 0 514 753 ; C -1 ; WX 600 ; N Thorn ; B 79 0 538 562 ; C -1 ; WX 600 ; N Omacron ; B 43 -18 557 698 ; C -1 ; WX 600 ; N Racute ; B 38 0 588 805 ; C -1 ; WX 600 ; N Sacute ; B 72 -20 529 805 ; C -1 ; WX 600 ; N dcaron ; B 45 -15 715 629 ; C -1 ; WX 600 ; N Umacron ; B 17 -18 583 698 ; C -1 ; WX 600 ; N uring ; B 21 -15 562 627 ; C -1 ; WX 600 ; N threesuperior ; B 155 240 406 622 ; C -1 ; WX 600 ; N Ograve ; B 43 -18 557 805 ; C -1 ; WX 600 ; N Agrave ; B 3 0 597 805 ; C -1 ; WX 600 ; N Abreve ; B 3 0 597 732 ; C -1 ; WX 600 ; N multiply ; B 87 43 515 470 ; C -1 ; WX 600 ; N uacute ; B 21 -15 562 672 ; C -1 ; WX 600 ; N Tcaron ; B 38 0 563 802 ; C -1 ; WX 600 ; N partialdiff ; B 17 -38 459 710 ; C -1 ; WX 600 ; N ydieresis ; B 7 -157 592 620 ; C -1 ; WX 600 ; N Nacute ; B 7 -13 593 805 ; C -1 ; WX 600 ; N icircumflex ; B 94 0 505 654 ; C -1 ; WX 600 ; N Ecircumflex ; B 53 0 550 787 ; C -1 ; WX 600 ; N adieresis ; B 53 -15 559 620 ; C -1 ; WX 600 ; N edieresis ; B 66 -15 548 620 ; C -1 ; WX 600 ; N cacute ; B 66 -15 529 672 ; C -1 ; WX 600 ; N nacute ; B 26 0 575 672 ; C -1 ; WX 600 ; N umacron ; B 21 -15 562 565 ; C -1 ; WX 600 ; N Ncaron ; B 7 -13 593 802 ; C -1 ; WX 600 ; N Iacute ; B 96 0 504 805 ; C -1 ; WX 600 ; N plusminus ; B 87 44 513 558 ; C -1 ; WX 600 ; N brokenbar ; B 275 -175 326 675 ; C -1 ; WX 600 ; N registered ; B 0 -18 600 580 ; C -1 ; WX 600 ; N Gbreve ; B 31 -18 575 732 ; C -1 ; WX 600 ; N Idotaccent ; B 96 0 504 753 ; C -1 ; WX 600 ; N summation ; B 15 -10 585 706 ; C -1 ; WX 600 ; N Egrave ; B 53 0 550 805 ; C -1 ; WX 600 ; N racute ; B 60 0 559 672 ; C -1 ; WX 600 ; N omacron ; B 62 -15 538 565 ; C -1 ; WX 600 ; N Zacute ; B 86 0 514 805 ; C -1 ; WX 600 ; N Zcaron ; B 86 0 514 802 ; C -1 ; WX 600 ; N greaterequal ; B 98 0 502 710 ; C -1 ; WX 600 ; N Eth ; B 30 0 574 562 ; C -1 ; WX 600 ; N Ccedilla ; B 41 -151 540 580 ; C -1 ; WX 600 ; N lcommaaccent ; B 95 -250 505 629 ; C -1 ; WX 600 ; N tcaron ; B 87 -15 530 717 ; C -1 ; WX 600 ; N eogonek ; B 66 -172 548 441 ; C -1 ; WX 600 ; N Uogonek ; B 17 -172 583 562 ; C -1 ; WX 600 ; N Aacute ; B 3 0 597 805 ; C -1 ; WX 600 ; N Adieresis ; B 3 0 597 753 ; C -1 ; WX 600 ; N egrave ; B 66 -15 548 672 ; C -1 ; WX 600 ; N zacute ; B 99 0 502 672 ; C -1 ; WX 600 ; N iogonek ; B 95 -172 505 657 ; C -1 ; WX 600 ; N Oacute ; B 43 -18 557 805 ; C -1 ; WX 600 ; N oacute ; B 62 -15 538 672 ; C -1 ; WX 600 ; N amacron ; B 53 -15 559 565 ; C -1 ; WX 600 ; N sacute ; B 80 -15 513 672 ; C -1 ; WX 600 ; N idieresis ; B 95 0 505 620 ; C -1 ; WX 600 ; N Ocircumflex ; B 43 -18 557 787 ; C -1 ; WX 600 ; N Ugrave ; B 17 -18 583 805 ; C -1 ; WX 600 ; N Delta ; B 6 0 598 688 ; C -1 ; WX 600 ; N thorn ; B -6 -157 555 629 ; C -1 ; WX 600 ; N twosuperior ; B 177 249 424 622 ; C -1 ; WX 600 ; N Odieresis ; B 43 -18 557 753 ; C -1 ; WX 600 ; N mu ; B 21 -157 562 426 ; C -1 ; WX 600 ; N igrave ; B 95 0 505 672 ; C -1 ; WX 600 ; N ohungarumlaut ; B 62 -15 580 672 ; C -1 ; WX 600 ; N Eogonek ; B 53 -172 561 562 ; C -1 ; WX 600 ; N dcroat ; B 45 -15 591 629 ; C -1 ; WX 600 ; N threequarters ; B 8 -56 593 666 ; C -1 ; WX 600 ; N Scedilla ; B 72 -151 529 580 ; C -1 ; WX 600 ; N lcaron ; B 95 0 533 629 ; C -1 ; WX 600 ; N Kcommaaccent ; B 38 -250 582 562 ; C -1 ; WX 600 ; N Lacute ; B 47 0 554 805 ; C -1 ; WX 600 ; N trademark ; B -23 263 623 562 ; C -1 ; WX 600 ; N edotaccent ; B 66 -15 548 620 ; C -1 ; WX 600 ; N Igrave ; B 96 0 504 805 ; C -1 ; WX 600 ; N Imacron ; B 96 0 504 698 ; C -1 ; WX 600 ; N Lcaron ; B 47 0 554 562 ; C -1 ; WX 600 ; N onehalf ; B 0 -57 611 665 ; C -1 ; WX 600 ; N lessequal ; B 98 0 502 710 ; C -1 ; WX 600 ; N ocircumflex ; B 62 -15 538 654 ; C -1 ; WX 600 ; N ntilde ; B 26 0 575 606 ; C -1 ; WX 600 ; N Uhungarumlaut ; B 17 -18 590 805 ; C -1 ; WX 600 ; N Eacute ; B 53 0 550 805 ; C -1 ; WX 600 ; N emacron ; B 66 -15 548 565 ; C -1 ; WX 600 ; N gbreve ; B 45 -157 566 609 ; C -1 ; WX 600 ; N onequarter ; B 0 -57 600 665 ; C -1 ; WX 600 ; N Scaron ; B 72 -20 529 802 ; C -1 ; WX 600 ; N Scommaaccent ; B 72 -250 529 580 ; C -1 ; WX 600 ; N Ohungarumlaut ; B 43 -18 580 805 ; C -1 ; WX 600 ; N degree ; B 123 269 477 622 ; C -1 ; WX 600 ; N ograve ; B 62 -15 538 672 ; C -1 ; WX 600 ; N Ccaron ; B 41 -18 540 802 ; C -1 ; WX 600 ; N ugrave ; B 21 -15 562 672 ; C -1 ; WX 600 ; N radical ; B 3 -15 597 792 ; C -1 ; WX 600 ; N Dcaron ; B 43 0 574 802 ; C -1 ; WX 600 ; N rcommaaccent ; B 60 -250 559 441 ; C -1 ; WX 600 ; N Ntilde ; B 7 -13 593 729 ; C -1 ; WX 600 ; N otilde ; B 62 -15 538 606 ; C -1 ; WX 600 ; N Rcommaaccent ; B 38 -250 588 562 ; C -1 ; WX 600 ; N Lcommaaccent ; B 47 -250 554 562 ; C -1 ; WX 600 ; N Atilde ; B 3 0 597 729 ; C -1 ; WX 600 ; N Aogonek ; B 3 -172 608 562 ; C -1 ; WX 600 ; N Aring ; B 3 0 597 750 ; C -1 ; WX 600 ; N Otilde ; B 43 -18 557 729 ; C -1 ; WX 600 ; N zdotaccent ; B 99 0 502 620 ; C -1 ; WX 600 ; N Ecaron ; B 53 0 550 802 ; C -1 ; WX 600 ; N Iogonek ; B 96 -172 504 562 ; C -1 ; WX 600 ; N kcommaaccent ; B 43 -250 580 629 ; C -1 ; WX 600 ; N minus ; B 80 232 520 283 ; C -1 ; WX 600 ; N Icircumflex ; B 96 0 504 787 ; C -1 ; WX 600 ; N ncaron ; B 26 0 575 669 ; C -1 ; WX 600 ; N tcommaaccent ; B 87 -250 530 561 ; C -1 ; WX 600 ; N logicalnot ; B 87 108 513 369 ; C -1 ; WX 600 ; N odieresis ; B 62 -15 538 620 ; C -1 ; WX 600 ; N udieresis ; B 21 -15 562 620 ; C -1 ; WX 600 ; N notequal ; B 15 -16 540 529 ; C -1 ; WX 600 ; N gcommaaccent ; B 45 -157 566 708 ; C -1 ; WX 600 ; N eth ; B 62 -15 538 629 ; C -1 ; WX 600 ; N zcaron ; B 99 0 502 669 ; C -1 ; WX 600 ; N ncommaaccent ; B 26 -250 575 441 ; C -1 ; WX 600 ; N onesuperior ; B 172 249 428 622 ; C -1 ; WX 600 ; N imacron ; B 95 0 505 565 ; C -1 ; WX 600 ; N Euro ; B 0 0 0 0 ; EndCharMetrics EndFontMetrics camlpdf-2.8.1/compressor/Helvetica-Bold.afm000066400000000000000000002072251477056064700206230ustar00rootroot00000000000000StartFontMetrics 4.1 Comment Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved. Comment Creation Date: Thu May 1 12:43:52 1997 Comment UniqueID 43052 Comment VMusage 37169 48194 FontName Helvetica-Bold FullName Helvetica Bold FamilyName Helvetica Weight Bold ItalicAngle 0 IsFixedPitch false CharacterSet ExtendedRoman FontBBox -170 -228 1003 962 UnderlinePosition -100 UnderlineThickness 50 Version 002.000 Notice Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved.Helvetica is a trademark of Linotype-Hell AG and/or its subsidiaries. EncodingScheme AdobeStandardEncoding CapHeight 718 XHeight 532 Ascender 718 Descender -207 StdHW 118 StdVW 140 StartCharMetrics 315 C 32 ; WX 278 ; N space ; B 0 0 0 0 ; C 33 ; WX 333 ; N exclam ; B 90 0 244 718 ; C 34 ; WX 474 ; N quotedbl ; B 98 447 376 718 ; C 35 ; WX 556 ; N numbersign ; B 18 0 538 698 ; C 36 ; WX 556 ; N dollar ; B 30 -115 523 775 ; C 37 ; WX 889 ; N percent ; B 28 -19 861 710 ; C 38 ; WX 722 ; N ampersand ; B 54 -19 701 718 ; C 39 ; WX 278 ; N quoteright ; B 69 445 209 718 ; C 40 ; WX 333 ; N parenleft ; B 35 -208 314 734 ; C 41 ; WX 333 ; N parenright ; B 19 -208 298 734 ; C 42 ; WX 389 ; N asterisk ; B 27 387 362 718 ; C 43 ; WX 584 ; N plus ; B 40 0 544 506 ; C 44 ; WX 278 ; N comma ; B 64 -168 214 146 ; C 45 ; WX 333 ; N hyphen ; B 27 215 306 345 ; C 46 ; WX 278 ; N period ; B 64 0 214 146 ; C 47 ; WX 278 ; N slash ; B -33 -19 311 737 ; C 48 ; WX 556 ; N zero ; B 32 -19 524 710 ; C 49 ; WX 556 ; N one ; B 69 0 378 710 ; C 50 ; WX 556 ; N two ; B 26 0 511 710 ; C 51 ; WX 556 ; N three ; B 27 -19 516 710 ; C 52 ; WX 556 ; N four ; B 27 0 526 710 ; C 53 ; WX 556 ; N five ; B 27 -19 516 698 ; C 54 ; WX 556 ; N six ; B 31 -19 520 710 ; C 55 ; WX 556 ; N seven ; B 25 0 528 698 ; C 56 ; WX 556 ; N eight ; B 32 -19 524 710 ; C 57 ; WX 556 ; N nine ; B 30 -19 522 710 ; C 58 ; WX 333 ; N colon ; B 92 0 242 512 ; C 59 ; WX 333 ; N semicolon ; B 92 -168 242 512 ; C 60 ; WX 584 ; N less ; B 38 -8 546 514 ; C 61 ; WX 584 ; N equal ; B 40 87 544 419 ; C 62 ; WX 584 ; N greater ; B 38 -8 546 514 ; C 63 ; WX 611 ; N question ; B 60 0 556 727 ; C 64 ; WX 975 ; N at ; B 118 -19 856 737 ; C 65 ; WX 722 ; N A ; B 20 0 702 718 ; C 66 ; WX 722 ; N B ; B 76 0 669 718 ; C 67 ; WX 722 ; N C ; B 44 -19 684 737 ; C 68 ; WX 722 ; N D ; B 76 0 685 718 ; C 69 ; WX 667 ; N E ; B 76 0 621 718 ; C 70 ; WX 611 ; N F ; B 76 0 587 718 ; C 71 ; WX 778 ; N G ; B 44 -19 713 737 ; C 72 ; WX 722 ; N H ; B 71 0 651 718 ; C 73 ; WX 278 ; N I ; B 64 0 214 718 ; C 74 ; WX 556 ; N J ; B 22 -18 484 718 ; C 75 ; WX 722 ; N K ; B 87 0 722 718 ; C 76 ; WX 611 ; N L ; B 76 0 583 718 ; C 77 ; WX 833 ; N M ; B 69 0 765 718 ; C 78 ; WX 722 ; N N ; B 69 0 654 718 ; C 79 ; WX 778 ; N O ; B 44 -19 734 737 ; C 80 ; WX 667 ; N P ; B 76 0 627 718 ; C 81 ; WX 778 ; N Q ; B 44 -52 737 737 ; C 82 ; WX 722 ; N R ; B 76 0 677 718 ; C 83 ; WX 667 ; N S ; B 39 -19 629 737 ; C 84 ; WX 611 ; N T ; B 14 0 598 718 ; C 85 ; WX 722 ; N U ; B 72 -19 651 718 ; C 86 ; WX 667 ; N V ; B 19 0 648 718 ; C 87 ; WX 944 ; N W ; B 16 0 929 718 ; C 88 ; WX 667 ; N X ; B 14 0 653 718 ; C 89 ; WX 667 ; N Y ; B 15 0 653 718 ; C 90 ; WX 611 ; N Z ; B 25 0 586 718 ; C 91 ; WX 333 ; N bracketleft ; B 63 -196 309 722 ; C 92 ; WX 278 ; N backslash ; B -33 -19 311 737 ; C 93 ; WX 333 ; N bracketright ; B 24 -196 270 722 ; C 94 ; WX 584 ; N asciicircum ; B 62 323 522 698 ; C 95 ; WX 556 ; N underscore ; B 0 -125 556 -75 ; C 96 ; WX 278 ; N quoteleft ; B 69 454 209 727 ; C 97 ; WX 556 ; N a ; B 29 -14 527 546 ; C 98 ; WX 611 ; N b ; B 61 -14 578 718 ; C 99 ; WX 556 ; N c ; B 34 -14 524 546 ; C 100 ; WX 611 ; N d ; B 34 -14 551 718 ; C 101 ; WX 556 ; N e ; B 23 -14 528 546 ; C 102 ; WX 333 ; N f ; B 10 0 318 727 ; L i fi ; L l fl ; C 103 ; WX 611 ; N g ; B 40 -217 553 546 ; C 104 ; WX 611 ; N h ; B 65 0 546 718 ; C 105 ; WX 278 ; N i ; B 69 0 209 725 ; C 106 ; WX 278 ; N j ; B 3 -214 209 725 ; C 107 ; WX 556 ; N k ; B 69 0 562 718 ; C 108 ; WX 278 ; N l ; B 69 0 209 718 ; C 109 ; WX 889 ; N m ; B 64 0 826 546 ; C 110 ; WX 611 ; N n ; B 65 0 546 546 ; C 111 ; WX 611 ; N o ; B 34 -14 578 546 ; C 112 ; WX 611 ; N p ; B 62 -207 578 546 ; C 113 ; WX 611 ; N q ; B 34 -207 552 546 ; C 114 ; WX 389 ; N r ; B 64 0 373 546 ; C 115 ; WX 556 ; N s ; B 30 -14 519 546 ; C 116 ; WX 333 ; N t ; B 10 -6 309 676 ; C 117 ; WX 611 ; N u ; B 66 -14 545 532 ; C 118 ; WX 556 ; N v ; B 13 0 543 532 ; C 119 ; WX 778 ; N w ; B 10 0 769 532 ; C 120 ; WX 556 ; N x ; B 15 0 541 532 ; C 121 ; WX 556 ; N y ; B 10 -214 539 532 ; C 122 ; WX 500 ; N z ; B 20 0 480 532 ; C 123 ; WX 389 ; N braceleft ; B 48 -196 365 722 ; C 124 ; WX 280 ; N bar ; B 84 -225 196 775 ; C 125 ; WX 389 ; N braceright ; B 24 -196 341 722 ; C 126 ; WX 584 ; N asciitilde ; B 61 163 523 343 ; C 161 ; WX 333 ; N exclamdown ; B 90 -186 244 532 ; C 162 ; WX 556 ; N cent ; B 34 -118 524 628 ; C 163 ; WX 556 ; N sterling ; B 28 -16 541 718 ; C 164 ; WX 167 ; N fraction ; B -170 -19 336 710 ; C 165 ; WX 556 ; N yen ; B -9 0 565 698 ; C 166 ; WX 556 ; N florin ; B -10 -210 516 737 ; C 167 ; WX 556 ; N section ; B 34 -184 522 727 ; C 168 ; WX 556 ; N currency ; B -3 76 559 636 ; C 169 ; WX 238 ; N quotesingle ; B 70 447 168 718 ; C 170 ; WX 500 ; N quotedblleft ; B 64 454 436 727 ; C 171 ; WX 556 ; N guillemotleft ; B 88 76 468 484 ; C 172 ; WX 333 ; N guilsinglleft ; B 83 76 250 484 ; C 173 ; WX 333 ; N guilsinglright ; B 83 76 250 484 ; C 174 ; WX 611 ; N fi ; B 10 0 542 727 ; C 175 ; WX 611 ; N fl ; B 10 0 542 727 ; C 177 ; WX 556 ; N endash ; B 0 227 556 333 ; C 178 ; WX 556 ; N dagger ; B 36 -171 520 718 ; C 179 ; WX 556 ; N daggerdbl ; B 36 -171 520 718 ; C 180 ; WX 278 ; N periodcentered ; B 58 172 220 334 ; C 182 ; WX 556 ; N paragraph ; B -8 -191 539 700 ; C 183 ; WX 350 ; N bullet ; B 10 194 340 524 ; C 184 ; WX 278 ; N quotesinglbase ; B 69 -146 209 127 ; C 185 ; WX 500 ; N quotedblbase ; B 64 -146 436 127 ; C 186 ; WX 500 ; N quotedblright ; B 64 445 436 718 ; C 187 ; WX 556 ; N guillemotright ; B 88 76 468 484 ; C 188 ; WX 1000 ; N ellipsis ; B 92 0 908 146 ; C 189 ; WX 1000 ; N perthousand ; B -3 -19 1003 710 ; C 191 ; WX 611 ; N questiondown ; B 55 -195 551 532 ; C 193 ; WX 333 ; N grave ; B -23 604 225 750 ; C 194 ; WX 333 ; N acute ; B 108 604 356 750 ; C 195 ; WX 333 ; N circumflex ; B -10 604 343 750 ; C 196 ; WX 333 ; N tilde ; B -17 610 350 737 ; C 197 ; WX 333 ; N macron ; B -6 604 339 678 ; C 198 ; WX 333 ; N breve ; B -2 604 335 750 ; C 199 ; WX 333 ; N dotaccent ; B 104 614 230 729 ; C 200 ; WX 333 ; N dieresis ; B 6 614 327 729 ; C 202 ; WX 333 ; N ring ; B 59 568 275 776 ; C 203 ; WX 333 ; N cedilla ; B 6 -228 245 0 ; C 205 ; WX 333 ; N hungarumlaut ; B 9 604 486 750 ; C 206 ; WX 333 ; N ogonek ; B 71 -228 304 0 ; C 207 ; WX 333 ; N caron ; B -10 604 343 750 ; C 208 ; WX 1000 ; N emdash ; B 0 227 1000 333 ; C 225 ; WX 1000 ; N AE ; B 5 0 954 718 ; C 227 ; WX 370 ; N ordfeminine ; B 22 401 347 737 ; C 232 ; WX 611 ; N Lslash ; B -20 0 583 718 ; C 233 ; WX 778 ; N Oslash ; B 33 -27 744 745 ; C 234 ; WX 1000 ; N OE ; B 37 -19 961 737 ; C 235 ; WX 365 ; N ordmasculine ; B 6 401 360 737 ; C 241 ; WX 889 ; N ae ; B 29 -14 858 546 ; C 245 ; WX 278 ; N dotlessi ; B 69 0 209 532 ; C 248 ; WX 278 ; N lslash ; B -18 0 296 718 ; C 249 ; WX 611 ; N oslash ; B 22 -29 589 560 ; C 250 ; WX 944 ; N oe ; B 34 -14 912 546 ; C 251 ; WX 611 ; N germandbls ; B 69 -14 579 731 ; C -1 ; WX 278 ; N Idieresis ; B -21 0 300 915 ; C -1 ; WX 556 ; N eacute ; B 23 -14 528 750 ; C -1 ; WX 556 ; N abreve ; B 29 -14 527 750 ; C -1 ; WX 611 ; N uhungarumlaut ; B 66 -14 625 750 ; C -1 ; WX 556 ; N ecaron ; B 23 -14 528 750 ; C -1 ; WX 667 ; N Ydieresis ; B 15 0 653 915 ; C -1 ; WX 584 ; N divide ; B 40 -42 544 548 ; C -1 ; WX 667 ; N Yacute ; B 15 0 653 936 ; C -1 ; WX 722 ; N Acircumflex ; B 20 0 702 936 ; C -1 ; WX 556 ; N aacute ; B 29 -14 527 750 ; C -1 ; WX 722 ; N Ucircumflex ; B 72 -19 651 936 ; C -1 ; WX 556 ; N yacute ; B 10 -214 539 750 ; C -1 ; WX 556 ; N scommaaccent ; B 30 -228 519 546 ; C -1 ; WX 556 ; N ecircumflex ; B 23 -14 528 750 ; C -1 ; WX 722 ; N Uring ; B 72 -19 651 962 ; C -1 ; WX 722 ; N Udieresis ; B 72 -19 651 915 ; C -1 ; WX 556 ; N aogonek ; B 29 -224 545 546 ; C -1 ; WX 722 ; N Uacute ; B 72 -19 651 936 ; C -1 ; WX 611 ; N uogonek ; B 66 -228 545 532 ; C -1 ; WX 667 ; N Edieresis ; B 76 0 621 915 ; C -1 ; WX 722 ; N Dcroat ; B -5 0 685 718 ; C -1 ; WX 250 ; N commaaccent ; B 64 -228 199 -50 ; C -1 ; WX 737 ; N copyright ; B -11 -19 749 737 ; C -1 ; WX 667 ; N Emacron ; B 76 0 621 864 ; C -1 ; WX 556 ; N ccaron ; B 34 -14 524 750 ; C -1 ; WX 556 ; N aring ; B 29 -14 527 776 ; C -1 ; WX 722 ; N Ncommaaccent ; B 69 -228 654 718 ; C -1 ; WX 278 ; N lacute ; B 69 0 329 936 ; C -1 ; WX 556 ; N agrave ; B 29 -14 527 750 ; C -1 ; WX 611 ; N Tcommaaccent ; B 14 -228 598 718 ; C -1 ; WX 722 ; N Cacute ; B 44 -19 684 936 ; C -1 ; WX 556 ; N atilde ; B 29 -14 527 737 ; C -1 ; WX 667 ; N Edotaccent ; B 76 0 621 915 ; C -1 ; WX 556 ; N scaron ; B 30 -14 519 750 ; C -1 ; WX 556 ; N scedilla ; B 30 -228 519 546 ; C -1 ; WX 278 ; N iacute ; B 69 0 329 750 ; C -1 ; WX 494 ; N lozenge ; B 10 0 484 745 ; C -1 ; WX 722 ; N Rcaron ; B 76 0 677 936 ; C -1 ; WX 778 ; N Gcommaaccent ; B 44 -228 713 737 ; C -1 ; WX 611 ; N ucircumflex ; B 66 -14 545 750 ; C -1 ; WX 556 ; N acircumflex ; B 29 -14 527 750 ; C -1 ; WX 722 ; N Amacron ; B 20 0 702 864 ; C -1 ; WX 389 ; N rcaron ; B 18 0 373 750 ; C -1 ; WX 556 ; N ccedilla ; B 34 -228 524 546 ; C -1 ; WX 611 ; N Zdotaccent ; B 25 0 586 915 ; C -1 ; WX 667 ; N Thorn ; B 76 0 627 718 ; C -1 ; WX 778 ; N Omacron ; B 44 -19 734 864 ; C -1 ; WX 722 ; N Racute ; B 76 0 677 936 ; C -1 ; WX 667 ; N Sacute ; B 39 -19 629 936 ; C -1 ; WX 743 ; N dcaron ; B 34 -14 750 718 ; C -1 ; WX 722 ; N Umacron ; B 72 -19 651 864 ; C -1 ; WX 611 ; N uring ; B 66 -14 545 776 ; C -1 ; WX 333 ; N threesuperior ; B 8 271 326 710 ; C -1 ; WX 778 ; N Ograve ; B 44 -19 734 936 ; C -1 ; WX 722 ; N Agrave ; B 20 0 702 936 ; C -1 ; WX 722 ; N Abreve ; B 20 0 702 936 ; C -1 ; WX 584 ; N multiply ; B 40 1 545 505 ; C -1 ; WX 611 ; N uacute ; B 66 -14 545 750 ; C -1 ; WX 611 ; N Tcaron ; B 14 0 598 936 ; C -1 ; WX 494 ; N partialdiff ; B 11 -21 494 750 ; C -1 ; WX 556 ; N ydieresis ; B 10 -214 539 729 ; C -1 ; WX 722 ; N Nacute ; B 69 0 654 936 ; C -1 ; WX 278 ; N icircumflex ; B -37 0 316 750 ; C -1 ; WX 667 ; N Ecircumflex ; B 76 0 621 936 ; C -1 ; WX 556 ; N adieresis ; B 29 -14 527 729 ; C -1 ; WX 556 ; N edieresis ; B 23 -14 528 729 ; C -1 ; WX 556 ; N cacute ; B 34 -14 524 750 ; C -1 ; WX 611 ; N nacute ; B 65 0 546 750 ; C -1 ; WX 611 ; N umacron ; B 66 -14 545 678 ; C -1 ; WX 722 ; N Ncaron ; B 69 0 654 936 ; C -1 ; WX 278 ; N Iacute ; B 64 0 329 936 ; C -1 ; WX 584 ; N plusminus ; B 40 0 544 506 ; C -1 ; WX 280 ; N brokenbar ; B 84 -150 196 700 ; C -1 ; WX 737 ; N registered ; B -11 -19 748 737 ; C -1 ; WX 778 ; N Gbreve ; B 44 -19 713 936 ; C -1 ; WX 278 ; N Idotaccent ; B 64 0 214 915 ; C -1 ; WX 600 ; N summation ; B 14 -10 585 706 ; C -1 ; WX 667 ; N Egrave ; B 76 0 621 936 ; C -1 ; WX 389 ; N racute ; B 64 0 384 750 ; C -1 ; WX 611 ; N omacron ; B 34 -14 578 678 ; C -1 ; WX 611 ; N Zacute ; B 25 0 586 936 ; C -1 ; WX 611 ; N Zcaron ; B 25 0 586 936 ; C -1 ; WX 549 ; N greaterequal ; B 26 0 523 704 ; C -1 ; WX 722 ; N Eth ; B -5 0 685 718 ; C -1 ; WX 722 ; N Ccedilla ; B 44 -228 684 737 ; C -1 ; WX 278 ; N lcommaaccent ; B 69 -228 213 718 ; C -1 ; WX 389 ; N tcaron ; B 10 -6 421 878 ; C -1 ; WX 556 ; N eogonek ; B 23 -228 528 546 ; C -1 ; WX 722 ; N Uogonek ; B 72 -228 651 718 ; C -1 ; WX 722 ; N Aacute ; B 20 0 702 936 ; C -1 ; WX 722 ; N Adieresis ; B 20 0 702 915 ; C -1 ; WX 556 ; N egrave ; B 23 -14 528 750 ; C -1 ; WX 500 ; N zacute ; B 20 0 480 750 ; C -1 ; WX 278 ; N iogonek ; B 16 -224 249 725 ; C -1 ; WX 778 ; N Oacute ; B 44 -19 734 936 ; C -1 ; WX 611 ; N oacute ; B 34 -14 578 750 ; C -1 ; WX 556 ; N amacron ; B 29 -14 527 678 ; C -1 ; WX 556 ; N sacute ; B 30 -14 519 750 ; C -1 ; WX 278 ; N idieresis ; B -21 0 300 729 ; C -1 ; WX 778 ; N Ocircumflex ; B 44 -19 734 936 ; C -1 ; WX 722 ; N Ugrave ; B 72 -19 651 936 ; C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ; C -1 ; WX 611 ; N thorn ; B 62 -208 578 718 ; C -1 ; WX 333 ; N twosuperior ; B 9 283 324 710 ; C -1 ; WX 778 ; N Odieresis ; B 44 -19 734 915 ; C -1 ; WX 611 ; N mu ; B 66 -207 545 532 ; C -1 ; WX 278 ; N igrave ; B -50 0 209 750 ; C -1 ; WX 611 ; N ohungarumlaut ; B 34 -14 625 750 ; C -1 ; WX 667 ; N Eogonek ; B 76 -224 639 718 ; C -1 ; WX 611 ; N dcroat ; B 34 -14 650 718 ; C -1 ; WX 834 ; N threequarters ; B 16 -19 799 710 ; C -1 ; WX 667 ; N Scedilla ; B 39 -228 629 737 ; C -1 ; WX 400 ; N lcaron ; B 69 0 408 718 ; C -1 ; WX 722 ; N Kcommaaccent ; B 87 -228 722 718 ; C -1 ; WX 611 ; N Lacute ; B 76 0 583 936 ; C -1 ; WX 1000 ; N trademark ; B 44 306 956 718 ; C -1 ; WX 556 ; N edotaccent ; B 23 -14 528 729 ; C -1 ; WX 278 ; N Igrave ; B -50 0 214 936 ; C -1 ; WX 278 ; N Imacron ; B -33 0 312 864 ; C -1 ; WX 611 ; N Lcaron ; B 76 0 583 718 ; C -1 ; WX 834 ; N onehalf ; B 26 -19 794 710 ; C -1 ; WX 549 ; N lessequal ; B 29 0 526 704 ; C -1 ; WX 611 ; N ocircumflex ; B 34 -14 578 750 ; C -1 ; WX 611 ; N ntilde ; B 65 0 546 737 ; C -1 ; WX 722 ; N Uhungarumlaut ; B 72 -19 681 936 ; C -1 ; WX 667 ; N Eacute ; B 76 0 621 936 ; C -1 ; WX 556 ; N emacron ; B 23 -14 528 678 ; C -1 ; WX 611 ; N gbreve ; B 40 -217 553 750 ; C -1 ; WX 834 ; N onequarter ; B 26 -19 766 710 ; C -1 ; WX 667 ; N Scaron ; B 39 -19 629 936 ; C -1 ; WX 667 ; N Scommaaccent ; B 39 -228 629 737 ; C -1 ; WX 778 ; N Ohungarumlaut ; B 44 -19 734 936 ; C -1 ; WX 400 ; N degree ; B 57 426 343 712 ; C -1 ; WX 611 ; N ograve ; B 34 -14 578 750 ; C -1 ; WX 722 ; N Ccaron ; B 44 -19 684 936 ; C -1 ; WX 611 ; N ugrave ; B 66 -14 545 750 ; C -1 ; WX 549 ; N radical ; B 10 -46 512 850 ; C -1 ; WX 722 ; N Dcaron ; B 76 0 685 936 ; C -1 ; WX 389 ; N rcommaaccent ; B 64 -228 373 546 ; C -1 ; WX 722 ; N Ntilde ; B 69 0 654 923 ; C -1 ; WX 611 ; N otilde ; B 34 -14 578 737 ; C -1 ; WX 722 ; N Rcommaaccent ; B 76 -228 677 718 ; C -1 ; WX 611 ; N Lcommaaccent ; B 76 -228 583 718 ; C -1 ; WX 722 ; N Atilde ; B 20 0 702 923 ; C -1 ; WX 722 ; N Aogonek ; B 20 -224 742 718 ; C -1 ; WX 722 ; N Aring ; B 20 0 702 962 ; C -1 ; WX 778 ; N Otilde ; B 44 -19 734 923 ; C -1 ; WX 500 ; N zdotaccent ; B 20 0 480 729 ; C -1 ; WX 667 ; N Ecaron ; B 76 0 621 936 ; C -1 ; WX 278 ; N Iogonek ; B -11 -228 222 718 ; C -1 ; WX 556 ; N kcommaaccent ; B 69 -228 562 718 ; C -1 ; WX 584 ; N minus ; B 40 197 544 309 ; C -1 ; WX 278 ; N Icircumflex ; B -37 0 316 936 ; C -1 ; WX 611 ; N ncaron ; B 65 0 546 750 ; C -1 ; WX 333 ; N tcommaaccent ; B 10 -228 309 676 ; C -1 ; WX 584 ; N logicalnot ; B 40 108 544 419 ; C -1 ; WX 611 ; N odieresis ; B 34 -14 578 729 ; C -1 ; WX 611 ; N udieresis ; B 66 -14 545 729 ; C -1 ; WX 549 ; N notequal ; B 15 -49 540 570 ; C -1 ; WX 611 ; N gcommaaccent ; B 40 -217 553 850 ; C -1 ; WX 611 ; N eth ; B 34 -14 578 737 ; C -1 ; WX 500 ; N zcaron ; B 20 0 480 750 ; C -1 ; WX 611 ; N ncommaaccent ; B 65 -228 546 546 ; C -1 ; WX 333 ; N onesuperior ; B 26 283 237 710 ; C -1 ; WX 278 ; N imacron ; B -8 0 285 678 ; C -1 ; WX 556 ; N Euro ; B 0 0 0 0 ; EndCharMetrics StartKernData StartKernPairs 2481 KPX A C -40 KPX A Cacute -40 KPX A Ccaron -40 KPX A Ccedilla -40 KPX A G -50 KPX A Gbreve -50 KPX A Gcommaaccent -50 KPX A O -40 KPX A Oacute -40 KPX A Ocircumflex -40 KPX A Odieresis -40 KPX A Ograve -40 KPX A Ohungarumlaut -40 KPX A Omacron -40 KPX A Oslash -40 KPX A Otilde -40 KPX A Q -40 KPX A T -90 KPX A Tcaron -90 KPX A Tcommaaccent -90 KPX A U -50 KPX A Uacute -50 KPX A Ucircumflex -50 KPX A Udieresis -50 KPX A Ugrave -50 KPX A Uhungarumlaut -50 KPX A Umacron -50 KPX A Uogonek -50 KPX A Uring -50 KPX A V -80 KPX A W -60 KPX A Y -110 KPX A Yacute -110 KPX A Ydieresis -110 KPX A u -30 KPX A uacute -30 KPX A ucircumflex -30 KPX A udieresis -30 KPX A ugrave -30 KPX A uhungarumlaut -30 KPX A umacron -30 KPX A uogonek -30 KPX A uring -30 KPX A v -40 KPX A w -30 KPX A y -30 KPX A yacute -30 KPX A ydieresis -30 KPX Aacute C -40 KPX Aacute Cacute -40 KPX Aacute Ccaron -40 KPX Aacute Ccedilla -40 KPX Aacute G -50 KPX Aacute Gbreve -50 KPX Aacute Gcommaaccent -50 KPX Aacute O -40 KPX Aacute Oacute -40 KPX Aacute Ocircumflex -40 KPX Aacute Odieresis -40 KPX Aacute Ograve -40 KPX Aacute Ohungarumlaut -40 KPX Aacute Omacron -40 KPX Aacute Oslash -40 KPX Aacute Otilde -40 KPX Aacute Q -40 KPX Aacute T -90 KPX Aacute Tcaron -90 KPX Aacute Tcommaaccent -90 KPX Aacute U -50 KPX Aacute Uacute -50 KPX Aacute Ucircumflex -50 KPX Aacute Udieresis -50 KPX Aacute Ugrave -50 KPX Aacute Uhungarumlaut -50 KPX Aacute Umacron -50 KPX Aacute Uogonek -50 KPX Aacute Uring -50 KPX Aacute V -80 KPX Aacute W -60 KPX Aacute Y -110 KPX Aacute Yacute -110 KPX Aacute Ydieresis -110 KPX Aacute u -30 KPX Aacute uacute -30 KPX Aacute ucircumflex -30 KPX Aacute udieresis -30 KPX Aacute ugrave -30 KPX Aacute uhungarumlaut -30 KPX Aacute umacron -30 KPX Aacute uogonek -30 KPX Aacute uring -30 KPX Aacute v -40 KPX Aacute w -30 KPX Aacute y -30 KPX Aacute yacute -30 KPX Aacute ydieresis -30 KPX Abreve C -40 KPX Abreve Cacute -40 KPX Abreve Ccaron -40 KPX Abreve Ccedilla -40 KPX Abreve G -50 KPX Abreve Gbreve -50 KPX Abreve Gcommaaccent -50 KPX Abreve O -40 KPX Abreve Oacute -40 KPX Abreve Ocircumflex -40 KPX Abreve Odieresis -40 KPX Abreve Ograve -40 KPX Abreve Ohungarumlaut -40 KPX Abreve Omacron -40 KPX Abreve Oslash -40 KPX Abreve Otilde -40 KPX Abreve Q -40 KPX Abreve T -90 KPX Abreve Tcaron -90 KPX Abreve Tcommaaccent -90 KPX Abreve U -50 KPX Abreve Uacute -50 KPX Abreve Ucircumflex -50 KPX Abreve Udieresis -50 KPX Abreve Ugrave -50 KPX Abreve Uhungarumlaut -50 KPX Abreve Umacron -50 KPX Abreve Uogonek -50 KPX Abreve Uring -50 KPX Abreve V -80 KPX Abreve W -60 KPX Abreve Y -110 KPX Abreve Yacute -110 KPX Abreve Ydieresis -110 KPX Abreve u -30 KPX Abreve uacute -30 KPX Abreve ucircumflex -30 KPX Abreve udieresis -30 KPX Abreve ugrave -30 KPX Abreve uhungarumlaut -30 KPX Abreve umacron -30 KPX Abreve uogonek -30 KPX Abreve uring -30 KPX Abreve v -40 KPX Abreve w -30 KPX Abreve y -30 KPX Abreve yacute -30 KPX Abreve ydieresis -30 KPX Acircumflex C -40 KPX Acircumflex Cacute -40 KPX Acircumflex Ccaron -40 KPX Acircumflex Ccedilla -40 KPX Acircumflex G -50 KPX Acircumflex Gbreve -50 KPX Acircumflex Gcommaaccent -50 KPX Acircumflex O -40 KPX Acircumflex Oacute -40 KPX Acircumflex Ocircumflex -40 KPX Acircumflex Odieresis -40 KPX Acircumflex Ograve -40 KPX Acircumflex Ohungarumlaut -40 KPX Acircumflex Omacron -40 KPX Acircumflex Oslash -40 KPX Acircumflex Otilde -40 KPX Acircumflex Q -40 KPX Acircumflex T -90 KPX Acircumflex Tcaron -90 KPX Acircumflex Tcommaaccent -90 KPX Acircumflex U -50 KPX Acircumflex Uacute -50 KPX Acircumflex Ucircumflex -50 KPX Acircumflex Udieresis -50 KPX Acircumflex Ugrave -50 KPX Acircumflex Uhungarumlaut -50 KPX Acircumflex Umacron -50 KPX Acircumflex Uogonek -50 KPX Acircumflex Uring -50 KPX Acircumflex V -80 KPX Acircumflex W -60 KPX Acircumflex Y -110 KPX Acircumflex Yacute -110 KPX Acircumflex Ydieresis -110 KPX Acircumflex u -30 KPX Acircumflex uacute -30 KPX Acircumflex ucircumflex -30 KPX Acircumflex udieresis -30 KPX Acircumflex ugrave -30 KPX Acircumflex uhungarumlaut -30 KPX Acircumflex umacron -30 KPX Acircumflex uogonek -30 KPX Acircumflex uring -30 KPX Acircumflex v -40 KPX Acircumflex w -30 KPX Acircumflex y -30 KPX Acircumflex yacute -30 KPX Acircumflex ydieresis -30 KPX Adieresis C -40 KPX Adieresis Cacute -40 KPX Adieresis Ccaron -40 KPX Adieresis Ccedilla -40 KPX Adieresis G -50 KPX Adieresis Gbreve -50 KPX Adieresis Gcommaaccent -50 KPX Adieresis O -40 KPX Adieresis Oacute -40 KPX Adieresis Ocircumflex -40 KPX Adieresis Odieresis -40 KPX Adieresis Ograve -40 KPX Adieresis Ohungarumlaut -40 KPX Adieresis Omacron -40 KPX Adieresis Oslash -40 KPX Adieresis Otilde -40 KPX Adieresis Q -40 KPX Adieresis T -90 KPX Adieresis Tcaron -90 KPX Adieresis Tcommaaccent -90 KPX Adieresis U -50 KPX Adieresis Uacute -50 KPX Adieresis Ucircumflex -50 KPX Adieresis Udieresis -50 KPX Adieresis Ugrave -50 KPX Adieresis Uhungarumlaut -50 KPX Adieresis Umacron -50 KPX Adieresis Uogonek -50 KPX Adieresis Uring -50 KPX Adieresis V -80 KPX Adieresis W -60 KPX Adieresis Y -110 KPX Adieresis Yacute -110 KPX Adieresis Ydieresis -110 KPX Adieresis u -30 KPX Adieresis uacute -30 KPX Adieresis ucircumflex -30 KPX Adieresis udieresis -30 KPX Adieresis ugrave -30 KPX Adieresis uhungarumlaut -30 KPX Adieresis umacron -30 KPX Adieresis uogonek -30 KPX Adieresis uring -30 KPX Adieresis v -40 KPX Adieresis w -30 KPX Adieresis y -30 KPX Adieresis yacute -30 KPX Adieresis ydieresis -30 KPX Agrave C -40 KPX Agrave Cacute -40 KPX Agrave Ccaron -40 KPX Agrave Ccedilla -40 KPX Agrave G -50 KPX Agrave Gbreve -50 KPX Agrave Gcommaaccent -50 KPX Agrave O -40 KPX Agrave Oacute -40 KPX Agrave Ocircumflex -40 KPX Agrave Odieresis -40 KPX Agrave Ograve -40 KPX Agrave Ohungarumlaut -40 KPX Agrave Omacron -40 KPX Agrave Oslash -40 KPX Agrave Otilde -40 KPX Agrave Q -40 KPX Agrave T -90 KPX Agrave Tcaron -90 KPX Agrave Tcommaaccent -90 KPX Agrave U -50 KPX Agrave Uacute -50 KPX Agrave Ucircumflex -50 KPX Agrave Udieresis -50 KPX Agrave Ugrave -50 KPX Agrave Uhungarumlaut -50 KPX Agrave Umacron -50 KPX Agrave Uogonek -50 KPX Agrave Uring -50 KPX Agrave V -80 KPX Agrave W -60 KPX Agrave Y -110 KPX Agrave Yacute -110 KPX Agrave Ydieresis -110 KPX Agrave u -30 KPX Agrave uacute -30 KPX Agrave ucircumflex -30 KPX Agrave udieresis -30 KPX Agrave ugrave -30 KPX Agrave uhungarumlaut -30 KPX Agrave umacron -30 KPX Agrave uogonek -30 KPX Agrave uring -30 KPX Agrave v -40 KPX Agrave w -30 KPX Agrave y -30 KPX Agrave yacute -30 KPX Agrave ydieresis -30 KPX Amacron C -40 KPX Amacron Cacute -40 KPX Amacron Ccaron -40 KPX Amacron Ccedilla -40 KPX Amacron G -50 KPX Amacron Gbreve -50 KPX Amacron Gcommaaccent -50 KPX Amacron O -40 KPX Amacron Oacute -40 KPX Amacron Ocircumflex -40 KPX Amacron Odieresis -40 KPX Amacron Ograve -40 KPX Amacron Ohungarumlaut -40 KPX Amacron Omacron -40 KPX Amacron Oslash -40 KPX Amacron Otilde -40 KPX Amacron Q -40 KPX Amacron T -90 KPX Amacron Tcaron -90 KPX Amacron Tcommaaccent -90 KPX Amacron U -50 KPX Amacron Uacute -50 KPX Amacron Ucircumflex -50 KPX Amacron Udieresis -50 KPX Amacron Ugrave -50 KPX Amacron Uhungarumlaut -50 KPX Amacron Umacron -50 KPX Amacron Uogonek -50 KPX Amacron Uring -50 KPX Amacron V -80 KPX Amacron W -60 KPX Amacron Y -110 KPX Amacron Yacute -110 KPX Amacron Ydieresis -110 KPX Amacron u -30 KPX Amacron uacute -30 KPX Amacron ucircumflex -30 KPX Amacron udieresis -30 KPX Amacron ugrave -30 KPX Amacron uhungarumlaut -30 KPX Amacron umacron -30 KPX Amacron uogonek -30 KPX Amacron uring -30 KPX Amacron v -40 KPX Amacron w -30 KPX Amacron y -30 KPX Amacron yacute -30 KPX Amacron ydieresis -30 KPX Aogonek C -40 KPX Aogonek Cacute -40 KPX Aogonek Ccaron -40 KPX Aogonek Ccedilla -40 KPX Aogonek G -50 KPX Aogonek Gbreve -50 KPX Aogonek Gcommaaccent -50 KPX Aogonek O -40 KPX Aogonek Oacute -40 KPX Aogonek Ocircumflex -40 KPX Aogonek Odieresis -40 KPX Aogonek Ograve -40 KPX Aogonek Ohungarumlaut -40 KPX Aogonek Omacron -40 KPX Aogonek Oslash -40 KPX Aogonek Otilde -40 KPX Aogonek Q -40 KPX Aogonek T -90 KPX Aogonek Tcaron -90 KPX Aogonek Tcommaaccent -90 KPX Aogonek U -50 KPX Aogonek Uacute -50 KPX Aogonek Ucircumflex -50 KPX Aogonek Udieresis -50 KPX Aogonek Ugrave -50 KPX Aogonek Uhungarumlaut -50 KPX Aogonek Umacron -50 KPX Aogonek Uogonek -50 KPX Aogonek Uring -50 KPX Aogonek V -80 KPX Aogonek W -60 KPX Aogonek Y -110 KPX Aogonek Yacute -110 KPX Aogonek Ydieresis -110 KPX Aogonek u -30 KPX Aogonek uacute -30 KPX Aogonek ucircumflex -30 KPX Aogonek udieresis -30 KPX Aogonek ugrave -30 KPX Aogonek uhungarumlaut -30 KPX Aogonek umacron -30 KPX Aogonek uogonek -30 KPX Aogonek uring -30 KPX Aogonek v -40 KPX Aogonek w -30 KPX Aogonek y -30 KPX Aogonek yacute -30 KPX Aogonek ydieresis -30 KPX Aring C -40 KPX Aring Cacute -40 KPX Aring Ccaron -40 KPX Aring Ccedilla -40 KPX Aring G -50 KPX Aring Gbreve -50 KPX Aring Gcommaaccent -50 KPX Aring O -40 KPX Aring Oacute -40 KPX Aring Ocircumflex -40 KPX Aring Odieresis -40 KPX Aring Ograve -40 KPX Aring Ohungarumlaut -40 KPX Aring Omacron -40 KPX Aring Oslash -40 KPX Aring Otilde -40 KPX Aring Q -40 KPX Aring T -90 KPX Aring Tcaron -90 KPX Aring Tcommaaccent -90 KPX Aring U -50 KPX Aring Uacute -50 KPX Aring Ucircumflex -50 KPX Aring Udieresis -50 KPX Aring Ugrave -50 KPX Aring Uhungarumlaut -50 KPX Aring Umacron -50 KPX Aring Uogonek -50 KPX Aring Uring -50 KPX Aring V -80 KPX Aring W -60 KPX Aring Y -110 KPX Aring Yacute -110 KPX Aring Ydieresis -110 KPX Aring u -30 KPX Aring uacute -30 KPX Aring ucircumflex -30 KPX Aring udieresis -30 KPX Aring ugrave -30 KPX Aring uhungarumlaut -30 KPX Aring umacron -30 KPX Aring uogonek -30 KPX Aring uring -30 KPX Aring v -40 KPX Aring w -30 KPX Aring y -30 KPX Aring yacute -30 KPX Aring ydieresis -30 KPX Atilde C -40 KPX Atilde Cacute -40 KPX Atilde Ccaron -40 KPX Atilde Ccedilla -40 KPX Atilde G -50 KPX Atilde Gbreve -50 KPX Atilde Gcommaaccent -50 KPX Atilde O -40 KPX Atilde Oacute -40 KPX Atilde Ocircumflex -40 KPX Atilde Odieresis -40 KPX Atilde Ograve -40 KPX Atilde Ohungarumlaut -40 KPX Atilde Omacron -40 KPX Atilde Oslash -40 KPX Atilde Otilde -40 KPX Atilde Q -40 KPX Atilde T -90 KPX Atilde Tcaron -90 KPX Atilde Tcommaaccent -90 KPX Atilde U -50 KPX Atilde Uacute -50 KPX Atilde Ucircumflex -50 KPX Atilde Udieresis -50 KPX Atilde Ugrave -50 KPX Atilde Uhungarumlaut -50 KPX Atilde Umacron -50 KPX Atilde Uogonek -50 KPX Atilde Uring -50 KPX Atilde V -80 KPX Atilde W -60 KPX Atilde Y -110 KPX Atilde Yacute -110 KPX Atilde Ydieresis -110 KPX Atilde u -30 KPX Atilde uacute -30 KPX Atilde ucircumflex -30 KPX Atilde udieresis -30 KPX Atilde ugrave -30 KPX Atilde uhungarumlaut -30 KPX Atilde umacron -30 KPX Atilde uogonek -30 KPX Atilde uring -30 KPX Atilde v -40 KPX Atilde w -30 KPX Atilde y -30 KPX Atilde yacute -30 KPX Atilde ydieresis -30 KPX B A -30 KPX B Aacute -30 KPX B Abreve -30 KPX B Acircumflex -30 KPX B Adieresis -30 KPX B Agrave -30 KPX B Amacron -30 KPX B Aogonek -30 KPX B Aring -30 KPX B Atilde -30 KPX B U -10 KPX B Uacute -10 KPX B Ucircumflex -10 KPX B Udieresis -10 KPX B Ugrave -10 KPX B Uhungarumlaut -10 KPX B Umacron -10 KPX B Uogonek -10 KPX B Uring -10 KPX D A -40 KPX D Aacute -40 KPX D Abreve -40 KPX D Acircumflex -40 KPX D Adieresis -40 KPX D Agrave -40 KPX D Amacron -40 KPX D Aogonek -40 KPX D Aring -40 KPX D Atilde -40 KPX D V -40 KPX D W -40 KPX D Y -70 KPX D Yacute -70 KPX D Ydieresis -70 KPX D comma -30 KPX D period -30 KPX Dcaron A -40 KPX Dcaron Aacute -40 KPX Dcaron Abreve -40 KPX Dcaron Acircumflex -40 KPX Dcaron Adieresis -40 KPX Dcaron Agrave -40 KPX Dcaron Amacron -40 KPX Dcaron Aogonek -40 KPX Dcaron Aring -40 KPX Dcaron Atilde -40 KPX Dcaron V -40 KPX Dcaron W -40 KPX Dcaron Y -70 KPX Dcaron Yacute -70 KPX Dcaron Ydieresis -70 KPX Dcaron comma -30 KPX Dcaron period -30 KPX Dcroat A -40 KPX Dcroat Aacute -40 KPX Dcroat Abreve -40 KPX Dcroat Acircumflex -40 KPX Dcroat Adieresis -40 KPX Dcroat Agrave -40 KPX Dcroat Amacron -40 KPX Dcroat Aogonek -40 KPX Dcroat Aring -40 KPX Dcroat Atilde -40 KPX Dcroat V -40 KPX Dcroat W -40 KPX Dcroat Y -70 KPX Dcroat Yacute -70 KPX Dcroat Ydieresis -70 KPX Dcroat comma -30 KPX Dcroat period -30 KPX F A -80 KPX F Aacute -80 KPX F Abreve -80 KPX F Acircumflex -80 KPX F Adieresis -80 KPX F Agrave -80 KPX F Amacron -80 KPX F Aogonek -80 KPX F Aring -80 KPX F Atilde -80 KPX F a -20 KPX F aacute -20 KPX F abreve -20 KPX F acircumflex -20 KPX F adieresis -20 KPX F agrave -20 KPX F amacron -20 KPX F aogonek -20 KPX F aring -20 KPX F atilde -20 KPX F comma -100 KPX F period -100 KPX J A -20 KPX J Aacute -20 KPX J Abreve -20 KPX J Acircumflex -20 KPX J Adieresis -20 KPX J Agrave -20 KPX J Amacron -20 KPX J Aogonek -20 KPX J Aring -20 KPX J Atilde -20 KPX J comma -20 KPX J period -20 KPX J u -20 KPX J uacute -20 KPX J ucircumflex -20 KPX J udieresis -20 KPX J ugrave -20 KPX J uhungarumlaut -20 KPX J umacron -20 KPX J uogonek -20 KPX J uring -20 KPX K O -30 KPX K Oacute -30 KPX K Ocircumflex -30 KPX K Odieresis -30 KPX K Ograve -30 KPX K Ohungarumlaut -30 KPX K Omacron -30 KPX K Oslash -30 KPX K Otilde -30 KPX K e -15 KPX K eacute -15 KPX K ecaron -15 KPX K ecircumflex -15 KPX K edieresis -15 KPX K edotaccent -15 KPX K egrave -15 KPX K emacron -15 KPX K eogonek -15 KPX K o -35 KPX K oacute -35 KPX K ocircumflex -35 KPX K odieresis -35 KPX K ograve -35 KPX K ohungarumlaut -35 KPX K omacron -35 KPX K oslash -35 KPX K otilde -35 KPX K u -30 KPX K uacute -30 KPX K ucircumflex -30 KPX K udieresis -30 KPX K ugrave -30 KPX K uhungarumlaut -30 KPX K umacron -30 KPX K uogonek -30 KPX K uring -30 KPX K y -40 KPX K yacute -40 KPX K ydieresis -40 KPX Kcommaaccent O -30 KPX Kcommaaccent Oacute -30 KPX Kcommaaccent Ocircumflex -30 KPX Kcommaaccent Odieresis -30 KPX Kcommaaccent Ograve -30 KPX Kcommaaccent Ohungarumlaut -30 KPX Kcommaaccent Omacron -30 KPX Kcommaaccent Oslash -30 KPX Kcommaaccent Otilde -30 KPX Kcommaaccent e -15 KPX Kcommaaccent eacute -15 KPX Kcommaaccent ecaron -15 KPX Kcommaaccent ecircumflex -15 KPX Kcommaaccent edieresis -15 KPX Kcommaaccent edotaccent -15 KPX Kcommaaccent egrave -15 KPX Kcommaaccent emacron -15 KPX Kcommaaccent eogonek -15 KPX Kcommaaccent o -35 KPX Kcommaaccent oacute -35 KPX Kcommaaccent ocircumflex -35 KPX Kcommaaccent odieresis -35 KPX Kcommaaccent ograve -35 KPX Kcommaaccent ohungarumlaut -35 KPX Kcommaaccent omacron -35 KPX Kcommaaccent oslash -35 KPX Kcommaaccent otilde -35 KPX Kcommaaccent u -30 KPX Kcommaaccent uacute -30 KPX Kcommaaccent ucircumflex -30 KPX Kcommaaccent udieresis -30 KPX Kcommaaccent ugrave -30 KPX Kcommaaccent uhungarumlaut -30 KPX Kcommaaccent umacron -30 KPX Kcommaaccent uogonek -30 KPX Kcommaaccent uring -30 KPX Kcommaaccent y -40 KPX Kcommaaccent yacute -40 KPX Kcommaaccent ydieresis -40 KPX L T -90 KPX L Tcaron -90 KPX L Tcommaaccent -90 KPX L V -110 KPX L W -80 KPX L Y -120 KPX L Yacute -120 KPX L Ydieresis -120 KPX L quotedblright -140 KPX L quoteright -140 KPX L y -30 KPX L yacute -30 KPX L ydieresis -30 KPX Lacute T -90 KPX Lacute Tcaron -90 KPX Lacute Tcommaaccent -90 KPX Lacute V -110 KPX Lacute W -80 KPX Lacute Y -120 KPX Lacute Yacute -120 KPX Lacute Ydieresis -120 KPX Lacute quotedblright -140 KPX Lacute quoteright -140 KPX Lacute y -30 KPX Lacute yacute -30 KPX Lacute ydieresis -30 KPX Lcommaaccent T -90 KPX Lcommaaccent Tcaron -90 KPX Lcommaaccent Tcommaaccent -90 KPX Lcommaaccent V -110 KPX Lcommaaccent W -80 KPX Lcommaaccent Y -120 KPX Lcommaaccent Yacute -120 KPX Lcommaaccent Ydieresis -120 KPX Lcommaaccent quotedblright -140 KPX Lcommaaccent quoteright -140 KPX Lcommaaccent y -30 KPX Lcommaaccent yacute -30 KPX Lcommaaccent ydieresis -30 KPX Lslash T -90 KPX Lslash Tcaron -90 KPX Lslash Tcommaaccent -90 KPX Lslash V -110 KPX Lslash W -80 KPX Lslash Y -120 KPX Lslash Yacute -120 KPX Lslash Ydieresis -120 KPX Lslash quotedblright -140 KPX Lslash quoteright -140 KPX Lslash y -30 KPX Lslash yacute -30 KPX Lslash ydieresis -30 KPX O A -50 KPX O Aacute -50 KPX O Abreve -50 KPX O Acircumflex -50 KPX O Adieresis -50 KPX O Agrave -50 KPX O Amacron -50 KPX O Aogonek -50 KPX O Aring -50 KPX O Atilde -50 KPX O T -40 KPX O Tcaron -40 KPX O Tcommaaccent -40 KPX O V -50 KPX O W -50 KPX O X -50 KPX O Y -70 KPX O Yacute -70 KPX O Ydieresis -70 KPX O comma -40 KPX O period -40 KPX Oacute A -50 KPX Oacute Aacute -50 KPX Oacute Abreve -50 KPX Oacute Acircumflex -50 KPX Oacute Adieresis -50 KPX Oacute Agrave -50 KPX Oacute Amacron -50 KPX Oacute Aogonek -50 KPX Oacute Aring -50 KPX Oacute Atilde -50 KPX Oacute T -40 KPX Oacute Tcaron -40 KPX Oacute Tcommaaccent -40 KPX Oacute V -50 KPX Oacute W -50 KPX Oacute X -50 KPX Oacute Y -70 KPX Oacute Yacute -70 KPX Oacute Ydieresis -70 KPX Oacute comma -40 KPX Oacute period -40 KPX Ocircumflex A -50 KPX Ocircumflex Aacute -50 KPX Ocircumflex Abreve -50 KPX Ocircumflex Acircumflex -50 KPX Ocircumflex Adieresis -50 KPX Ocircumflex Agrave -50 KPX Ocircumflex Amacron -50 KPX Ocircumflex Aogonek -50 KPX Ocircumflex Aring -50 KPX Ocircumflex Atilde -50 KPX Ocircumflex T -40 KPX Ocircumflex Tcaron -40 KPX Ocircumflex Tcommaaccent -40 KPX Ocircumflex V -50 KPX Ocircumflex W -50 KPX Ocircumflex X -50 KPX Ocircumflex Y -70 KPX Ocircumflex Yacute -70 KPX Ocircumflex Ydieresis -70 KPX Ocircumflex comma -40 KPX Ocircumflex period -40 KPX Odieresis A -50 KPX Odieresis Aacute -50 KPX Odieresis Abreve -50 KPX Odieresis Acircumflex -50 KPX Odieresis Adieresis -50 KPX Odieresis Agrave -50 KPX Odieresis Amacron -50 KPX Odieresis Aogonek -50 KPX Odieresis Aring -50 KPX Odieresis Atilde -50 KPX Odieresis T -40 KPX Odieresis Tcaron -40 KPX Odieresis Tcommaaccent -40 KPX Odieresis V -50 KPX Odieresis W -50 KPX Odieresis X -50 KPX Odieresis Y -70 KPX Odieresis Yacute -70 KPX Odieresis Ydieresis -70 KPX Odieresis comma -40 KPX Odieresis period -40 KPX Ograve A -50 KPX Ograve Aacute -50 KPX Ograve Abreve -50 KPX Ograve Acircumflex -50 KPX Ograve Adieresis -50 KPX Ograve Agrave -50 KPX Ograve Amacron -50 KPX Ograve Aogonek -50 KPX Ograve Aring -50 KPX Ograve Atilde -50 KPX Ograve T -40 KPX Ograve Tcaron -40 KPX Ograve Tcommaaccent -40 KPX Ograve V -50 KPX Ograve W -50 KPX Ograve X -50 KPX Ograve Y -70 KPX Ograve Yacute -70 KPX Ograve Ydieresis -70 KPX Ograve comma -40 KPX Ograve period -40 KPX Ohungarumlaut A -50 KPX Ohungarumlaut Aacute -50 KPX Ohungarumlaut Abreve -50 KPX Ohungarumlaut Acircumflex -50 KPX Ohungarumlaut Adieresis -50 KPX Ohungarumlaut Agrave -50 KPX Ohungarumlaut Amacron -50 KPX Ohungarumlaut Aogonek -50 KPX Ohungarumlaut Aring -50 KPX Ohungarumlaut Atilde -50 KPX Ohungarumlaut T -40 KPX Ohungarumlaut Tcaron -40 KPX Ohungarumlaut Tcommaaccent -40 KPX Ohungarumlaut V -50 KPX Ohungarumlaut W -50 KPX Ohungarumlaut X -50 KPX Ohungarumlaut Y -70 KPX Ohungarumlaut Yacute -70 KPX Ohungarumlaut Ydieresis -70 KPX Ohungarumlaut comma -40 KPX Ohungarumlaut period -40 KPX Omacron A -50 KPX Omacron Aacute -50 KPX Omacron Abreve -50 KPX Omacron Acircumflex -50 KPX Omacron Adieresis -50 KPX Omacron Agrave -50 KPX Omacron Amacron -50 KPX Omacron Aogonek -50 KPX Omacron Aring -50 KPX Omacron Atilde -50 KPX Omacron T -40 KPX Omacron Tcaron -40 KPX Omacron Tcommaaccent -40 KPX Omacron V -50 KPX Omacron W -50 KPX Omacron X -50 KPX Omacron Y -70 KPX Omacron Yacute -70 KPX Omacron Ydieresis -70 KPX Omacron comma -40 KPX Omacron period -40 KPX Oslash A -50 KPX Oslash Aacute -50 KPX Oslash Abreve -50 KPX Oslash Acircumflex -50 KPX Oslash Adieresis -50 KPX Oslash Agrave -50 KPX Oslash Amacron -50 KPX Oslash Aogonek -50 KPX Oslash Aring -50 KPX Oslash Atilde -50 KPX Oslash T -40 KPX Oslash Tcaron -40 KPX Oslash Tcommaaccent -40 KPX Oslash V -50 KPX Oslash W -50 KPX Oslash X -50 KPX Oslash Y -70 KPX Oslash Yacute -70 KPX Oslash Ydieresis -70 KPX Oslash comma -40 KPX Oslash period -40 KPX Otilde A -50 KPX Otilde Aacute -50 KPX Otilde Abreve -50 KPX Otilde Acircumflex -50 KPX Otilde Adieresis -50 KPX Otilde Agrave -50 KPX Otilde Amacron -50 KPX Otilde Aogonek -50 KPX Otilde Aring -50 KPX Otilde Atilde -50 KPX Otilde T -40 KPX Otilde Tcaron -40 KPX Otilde Tcommaaccent -40 KPX Otilde V -50 KPX Otilde W -50 KPX Otilde X -50 KPX Otilde Y -70 KPX Otilde Yacute -70 KPX Otilde Ydieresis -70 KPX Otilde comma -40 KPX Otilde period -40 KPX P A -100 KPX P Aacute -100 KPX P Abreve -100 KPX P Acircumflex -100 KPX P Adieresis -100 KPX P Agrave -100 KPX P Amacron -100 KPX P Aogonek -100 KPX P Aring -100 KPX P Atilde -100 KPX P a -30 KPX P aacute -30 KPX P abreve -30 KPX P acircumflex -30 KPX P adieresis -30 KPX P agrave -30 KPX P amacron -30 KPX P aogonek -30 KPX P aring -30 KPX P atilde -30 KPX P comma -120 KPX P e -30 KPX P eacute -30 KPX P ecaron -30 KPX P ecircumflex -30 KPX P edieresis -30 KPX P edotaccent -30 KPX P egrave -30 KPX P emacron -30 KPX P eogonek -30 KPX P o -40 KPX P oacute -40 KPX P ocircumflex -40 KPX P odieresis -40 KPX P ograve -40 KPX P ohungarumlaut -40 KPX P omacron -40 KPX P oslash -40 KPX P otilde -40 KPX P period -120 KPX Q U -10 KPX Q Uacute -10 KPX Q Ucircumflex -10 KPX Q Udieresis -10 KPX Q Ugrave -10 KPX Q Uhungarumlaut -10 KPX Q Umacron -10 KPX Q Uogonek -10 KPX Q Uring -10 KPX Q comma 20 KPX Q period 20 KPX R O -20 KPX R Oacute -20 KPX R Ocircumflex -20 KPX R Odieresis -20 KPX R Ograve -20 KPX R Ohungarumlaut -20 KPX R Omacron -20 KPX R Oslash -20 KPX R Otilde -20 KPX R T -20 KPX R Tcaron -20 KPX R Tcommaaccent -20 KPX R U -20 KPX R Uacute -20 KPX R Ucircumflex -20 KPX R Udieresis -20 KPX R Ugrave -20 KPX R Uhungarumlaut -20 KPX R Umacron -20 KPX R Uogonek -20 KPX R Uring -20 KPX R V -50 KPX R W -40 KPX R Y -50 KPX R Yacute -50 KPX R Ydieresis -50 KPX Racute O -20 KPX Racute Oacute -20 KPX Racute Ocircumflex -20 KPX Racute Odieresis -20 KPX Racute Ograve -20 KPX Racute Ohungarumlaut -20 KPX Racute Omacron -20 KPX Racute Oslash -20 KPX Racute Otilde -20 KPX Racute T -20 KPX Racute Tcaron -20 KPX Racute Tcommaaccent -20 KPX Racute U -20 KPX Racute Uacute -20 KPX Racute Ucircumflex -20 KPX Racute Udieresis -20 KPX Racute Ugrave -20 KPX Racute Uhungarumlaut -20 KPX Racute Umacron -20 KPX Racute Uogonek -20 KPX Racute Uring -20 KPX Racute V -50 KPX Racute W -40 KPX Racute Y -50 KPX Racute Yacute -50 KPX Racute Ydieresis -50 KPX Rcaron O -20 KPX Rcaron Oacute -20 KPX Rcaron Ocircumflex -20 KPX Rcaron Odieresis -20 KPX Rcaron Ograve -20 KPX Rcaron Ohungarumlaut -20 KPX Rcaron Omacron -20 KPX Rcaron Oslash -20 KPX Rcaron Otilde -20 KPX Rcaron T -20 KPX Rcaron Tcaron -20 KPX Rcaron Tcommaaccent -20 KPX Rcaron U -20 KPX Rcaron Uacute -20 KPX Rcaron Ucircumflex -20 KPX Rcaron Udieresis -20 KPX Rcaron Ugrave -20 KPX Rcaron Uhungarumlaut -20 KPX Rcaron Umacron -20 KPX Rcaron Uogonek -20 KPX Rcaron Uring -20 KPX Rcaron V -50 KPX Rcaron W -40 KPX Rcaron Y -50 KPX Rcaron Yacute -50 KPX Rcaron Ydieresis -50 KPX Rcommaaccent O -20 KPX Rcommaaccent Oacute -20 KPX Rcommaaccent Ocircumflex -20 KPX Rcommaaccent Odieresis -20 KPX Rcommaaccent Ograve -20 KPX Rcommaaccent Ohungarumlaut -20 KPX Rcommaaccent Omacron -20 KPX Rcommaaccent Oslash -20 KPX Rcommaaccent Otilde -20 KPX Rcommaaccent T -20 KPX Rcommaaccent Tcaron -20 KPX Rcommaaccent Tcommaaccent -20 KPX Rcommaaccent U -20 KPX Rcommaaccent Uacute -20 KPX Rcommaaccent Ucircumflex -20 KPX Rcommaaccent Udieresis -20 KPX Rcommaaccent Ugrave -20 KPX Rcommaaccent Uhungarumlaut -20 KPX Rcommaaccent Umacron -20 KPX Rcommaaccent Uogonek -20 KPX Rcommaaccent Uring -20 KPX Rcommaaccent V -50 KPX Rcommaaccent W -40 KPX Rcommaaccent Y -50 KPX Rcommaaccent Yacute -50 KPX Rcommaaccent Ydieresis -50 KPX T A -90 KPX T Aacute -90 KPX T Abreve -90 KPX T Acircumflex -90 KPX T Adieresis -90 KPX T Agrave -90 KPX T Amacron -90 KPX T Aogonek -90 KPX T Aring -90 KPX T Atilde -90 KPX T O -40 KPX T Oacute -40 KPX T Ocircumflex -40 KPX T Odieresis -40 KPX T Ograve -40 KPX T Ohungarumlaut -40 KPX T Omacron -40 KPX T Oslash -40 KPX T Otilde -40 KPX T a -80 KPX T aacute -80 KPX T abreve -80 KPX T acircumflex -80 KPX T adieresis -80 KPX T agrave -80 KPX T amacron -80 KPX T aogonek -80 KPX T aring -80 KPX T atilde -80 KPX T colon -40 KPX T comma -80 KPX T e -60 KPX T eacute -60 KPX T ecaron -60 KPX T ecircumflex -60 KPX T edieresis -60 KPX T edotaccent -60 KPX T egrave -60 KPX T emacron -60 KPX T eogonek -60 KPX T hyphen -120 KPX T o -80 KPX T oacute -80 KPX T ocircumflex -80 KPX T odieresis -80 KPX T ograve -80 KPX T ohungarumlaut -80 KPX T omacron -80 KPX T oslash -80 KPX T otilde -80 KPX T period -80 KPX T r -80 KPX T racute -80 KPX T rcommaaccent -80 KPX T semicolon -40 KPX T u -90 KPX T uacute -90 KPX T ucircumflex -90 KPX T udieresis -90 KPX T ugrave -90 KPX T uhungarumlaut -90 KPX T umacron -90 KPX T uogonek -90 KPX T uring -90 KPX T w -60 KPX T y -60 KPX T yacute -60 KPX T ydieresis -60 KPX Tcaron A -90 KPX Tcaron Aacute -90 KPX Tcaron Abreve -90 KPX Tcaron Acircumflex -90 KPX Tcaron Adieresis -90 KPX Tcaron Agrave -90 KPX Tcaron Amacron -90 KPX Tcaron Aogonek -90 KPX Tcaron Aring -90 KPX Tcaron Atilde -90 KPX Tcaron O -40 KPX Tcaron Oacute -40 KPX Tcaron Ocircumflex -40 KPX Tcaron Odieresis -40 KPX Tcaron Ograve -40 KPX Tcaron Ohungarumlaut -40 KPX Tcaron Omacron -40 KPX Tcaron Oslash -40 KPX Tcaron Otilde -40 KPX Tcaron a -80 KPX Tcaron aacute -80 KPX Tcaron abreve -80 KPX Tcaron acircumflex -80 KPX Tcaron adieresis -80 KPX Tcaron agrave -80 KPX Tcaron amacron -80 KPX Tcaron aogonek -80 KPX Tcaron aring -80 KPX Tcaron atilde -80 KPX Tcaron colon -40 KPX Tcaron comma -80 KPX Tcaron e -60 KPX Tcaron eacute -60 KPX Tcaron ecaron -60 KPX Tcaron ecircumflex -60 KPX Tcaron edieresis -60 KPX Tcaron edotaccent -60 KPX Tcaron egrave -60 KPX Tcaron emacron -60 KPX Tcaron eogonek -60 KPX Tcaron hyphen -120 KPX Tcaron o -80 KPX Tcaron oacute -80 KPX Tcaron ocircumflex -80 KPX Tcaron odieresis -80 KPX Tcaron ograve -80 KPX Tcaron ohungarumlaut -80 KPX Tcaron omacron -80 KPX Tcaron oslash -80 KPX Tcaron otilde -80 KPX Tcaron period -80 KPX Tcaron r -80 KPX Tcaron racute -80 KPX Tcaron rcommaaccent -80 KPX Tcaron semicolon -40 KPX Tcaron u -90 KPX Tcaron uacute -90 KPX Tcaron ucircumflex -90 KPX Tcaron udieresis -90 KPX Tcaron ugrave -90 KPX Tcaron uhungarumlaut -90 KPX Tcaron umacron -90 KPX Tcaron uogonek -90 KPX Tcaron uring -90 KPX Tcaron w -60 KPX Tcaron y -60 KPX Tcaron yacute -60 KPX Tcaron ydieresis -60 KPX Tcommaaccent A -90 KPX Tcommaaccent Aacute -90 KPX Tcommaaccent Abreve -90 KPX Tcommaaccent Acircumflex -90 KPX Tcommaaccent Adieresis -90 KPX Tcommaaccent Agrave -90 KPX Tcommaaccent Amacron -90 KPX Tcommaaccent Aogonek -90 KPX Tcommaaccent Aring -90 KPX Tcommaaccent Atilde -90 KPX Tcommaaccent O -40 KPX Tcommaaccent Oacute -40 KPX Tcommaaccent Ocircumflex -40 KPX Tcommaaccent Odieresis -40 KPX Tcommaaccent Ograve -40 KPX Tcommaaccent Ohungarumlaut -40 KPX Tcommaaccent Omacron -40 KPX Tcommaaccent Oslash -40 KPX Tcommaaccent Otilde -40 KPX Tcommaaccent a -80 KPX Tcommaaccent aacute -80 KPX Tcommaaccent abreve -80 KPX Tcommaaccent acircumflex -80 KPX Tcommaaccent adieresis -80 KPX Tcommaaccent agrave -80 KPX Tcommaaccent amacron -80 KPX Tcommaaccent aogonek -80 KPX Tcommaaccent aring -80 KPX Tcommaaccent atilde -80 KPX Tcommaaccent colon -40 KPX Tcommaaccent comma -80 KPX Tcommaaccent e -60 KPX Tcommaaccent eacute -60 KPX Tcommaaccent ecaron -60 KPX Tcommaaccent ecircumflex -60 KPX Tcommaaccent edieresis -60 KPX Tcommaaccent edotaccent -60 KPX Tcommaaccent egrave -60 KPX Tcommaaccent emacron -60 KPX Tcommaaccent eogonek -60 KPX Tcommaaccent hyphen -120 KPX Tcommaaccent o -80 KPX Tcommaaccent oacute -80 KPX Tcommaaccent ocircumflex -80 KPX Tcommaaccent odieresis -80 KPX Tcommaaccent ograve -80 KPX Tcommaaccent ohungarumlaut -80 KPX Tcommaaccent omacron -80 KPX Tcommaaccent oslash -80 KPX Tcommaaccent otilde -80 KPX Tcommaaccent period -80 KPX Tcommaaccent r -80 KPX Tcommaaccent racute -80 KPX Tcommaaccent rcommaaccent -80 KPX Tcommaaccent semicolon -40 KPX Tcommaaccent u -90 KPX Tcommaaccent uacute -90 KPX Tcommaaccent ucircumflex -90 KPX Tcommaaccent udieresis -90 KPX Tcommaaccent ugrave -90 KPX Tcommaaccent uhungarumlaut -90 KPX Tcommaaccent umacron -90 KPX Tcommaaccent uogonek -90 KPX Tcommaaccent uring -90 KPX Tcommaaccent w -60 KPX Tcommaaccent y -60 KPX Tcommaaccent yacute -60 KPX Tcommaaccent ydieresis -60 KPX U A -50 KPX U Aacute -50 KPX U Abreve -50 KPX U Acircumflex -50 KPX U Adieresis -50 KPX U Agrave -50 KPX U Amacron -50 KPX U Aogonek -50 KPX U Aring -50 KPX U Atilde -50 KPX U comma -30 KPX U period -30 KPX Uacute A -50 KPX Uacute Aacute -50 KPX Uacute Abreve -50 KPX Uacute Acircumflex -50 KPX Uacute Adieresis -50 KPX Uacute Agrave -50 KPX Uacute Amacron -50 KPX Uacute Aogonek -50 KPX Uacute Aring -50 KPX Uacute Atilde -50 KPX Uacute comma -30 KPX Uacute period -30 KPX Ucircumflex A -50 KPX Ucircumflex Aacute -50 KPX Ucircumflex Abreve -50 KPX Ucircumflex Acircumflex -50 KPX Ucircumflex Adieresis -50 KPX Ucircumflex Agrave -50 KPX Ucircumflex Amacron -50 KPX Ucircumflex Aogonek -50 KPX Ucircumflex Aring -50 KPX Ucircumflex Atilde -50 KPX Ucircumflex comma -30 KPX Ucircumflex period -30 KPX Udieresis A -50 KPX Udieresis Aacute -50 KPX Udieresis Abreve -50 KPX Udieresis Acircumflex -50 KPX Udieresis Adieresis -50 KPX Udieresis Agrave -50 KPX Udieresis Amacron -50 KPX Udieresis Aogonek -50 KPX Udieresis Aring -50 KPX Udieresis Atilde -50 KPX Udieresis comma -30 KPX Udieresis period -30 KPX Ugrave A -50 KPX Ugrave Aacute -50 KPX Ugrave Abreve -50 KPX Ugrave Acircumflex -50 KPX Ugrave Adieresis -50 KPX Ugrave Agrave -50 KPX Ugrave Amacron -50 KPX Ugrave Aogonek -50 KPX Ugrave Aring -50 KPX Ugrave Atilde -50 KPX Ugrave comma -30 KPX Ugrave period -30 KPX Uhungarumlaut A -50 KPX Uhungarumlaut Aacute -50 KPX Uhungarumlaut Abreve -50 KPX Uhungarumlaut Acircumflex -50 KPX Uhungarumlaut Adieresis -50 KPX Uhungarumlaut Agrave -50 KPX Uhungarumlaut Amacron -50 KPX Uhungarumlaut Aogonek -50 KPX Uhungarumlaut Aring -50 KPX Uhungarumlaut Atilde -50 KPX Uhungarumlaut comma -30 KPX Uhungarumlaut period -30 KPX Umacron A -50 KPX Umacron Aacute -50 KPX Umacron Abreve -50 KPX Umacron Acircumflex -50 KPX Umacron Adieresis -50 KPX Umacron Agrave -50 KPX Umacron Amacron -50 KPX Umacron Aogonek -50 KPX Umacron Aring -50 KPX Umacron Atilde -50 KPX Umacron comma -30 KPX Umacron period -30 KPX Uogonek A -50 KPX Uogonek Aacute -50 KPX Uogonek Abreve -50 KPX Uogonek Acircumflex -50 KPX Uogonek Adieresis -50 KPX Uogonek Agrave -50 KPX Uogonek Amacron -50 KPX Uogonek Aogonek -50 KPX Uogonek Aring -50 KPX Uogonek Atilde -50 KPX Uogonek comma -30 KPX Uogonek period -30 KPX Uring A -50 KPX Uring Aacute -50 KPX Uring Abreve -50 KPX Uring Acircumflex -50 KPX Uring Adieresis -50 KPX Uring Agrave -50 KPX Uring Amacron -50 KPX Uring Aogonek -50 KPX Uring Aring -50 KPX Uring Atilde -50 KPX Uring comma -30 KPX Uring period -30 KPX V A -80 KPX V Aacute -80 KPX V Abreve -80 KPX V Acircumflex -80 KPX V Adieresis -80 KPX V Agrave -80 KPX V Amacron -80 KPX V Aogonek -80 KPX V Aring -80 KPX V Atilde -80 KPX V G -50 KPX V Gbreve -50 KPX V Gcommaaccent -50 KPX V O -50 KPX V Oacute -50 KPX V Ocircumflex -50 KPX V Odieresis -50 KPX V Ograve -50 KPX V Ohungarumlaut -50 KPX V Omacron -50 KPX V Oslash -50 KPX V Otilde -50 KPX V a -60 KPX V aacute -60 KPX V abreve -60 KPX V acircumflex -60 KPX V adieresis -60 KPX V agrave -60 KPX V amacron -60 KPX V aogonek -60 KPX V aring -60 KPX V atilde -60 KPX V colon -40 KPX V comma -120 KPX V e -50 KPX V eacute -50 KPX V ecaron -50 KPX V ecircumflex -50 KPX V edieresis -50 KPX V edotaccent -50 KPX V egrave -50 KPX V emacron -50 KPX V eogonek -50 KPX V hyphen -80 KPX V o -90 KPX V oacute -90 KPX V ocircumflex -90 KPX V odieresis -90 KPX V ograve -90 KPX V ohungarumlaut -90 KPX V omacron -90 KPX V oslash -90 KPX V otilde -90 KPX V period -120 KPX V semicolon -40 KPX V u -60 KPX V uacute -60 KPX V ucircumflex -60 KPX V udieresis -60 KPX V ugrave -60 KPX V uhungarumlaut -60 KPX V umacron -60 KPX V uogonek -60 KPX V uring -60 KPX W A -60 KPX W Aacute -60 KPX W Abreve -60 KPX W Acircumflex -60 KPX W Adieresis -60 KPX W Agrave -60 KPX W Amacron -60 KPX W Aogonek -60 KPX W Aring -60 KPX W Atilde -60 KPX W O -20 KPX W Oacute -20 KPX W Ocircumflex -20 KPX W Odieresis -20 KPX W Ograve -20 KPX W Ohungarumlaut -20 KPX W Omacron -20 KPX W Oslash -20 KPX W Otilde -20 KPX W a -40 KPX W aacute -40 KPX W abreve -40 KPX W acircumflex -40 KPX W adieresis -40 KPX W agrave -40 KPX W amacron -40 KPX W aogonek -40 KPX W aring -40 KPX W atilde -40 KPX W colon -10 KPX W comma -80 KPX W e -35 KPX W eacute -35 KPX W ecaron -35 KPX W ecircumflex -35 KPX W edieresis -35 KPX W edotaccent -35 KPX W egrave -35 KPX W emacron -35 KPX W eogonek -35 KPX W hyphen -40 KPX W o -60 KPX W oacute -60 KPX W ocircumflex -60 KPX W odieresis -60 KPX W ograve -60 KPX W ohungarumlaut -60 KPX W omacron -60 KPX W oslash -60 KPX W otilde -60 KPX W period -80 KPX W semicolon -10 KPX W u -45 KPX W uacute -45 KPX W ucircumflex -45 KPX W udieresis -45 KPX W ugrave -45 KPX W uhungarumlaut -45 KPX W umacron -45 KPX W uogonek -45 KPX W uring -45 KPX W y -20 KPX W yacute -20 KPX W ydieresis -20 KPX Y A -110 KPX Y Aacute -110 KPX Y Abreve -110 KPX Y Acircumflex -110 KPX Y Adieresis -110 KPX Y Agrave -110 KPX Y Amacron -110 KPX Y Aogonek -110 KPX Y Aring -110 KPX Y Atilde -110 KPX Y O -70 KPX Y Oacute -70 KPX Y Ocircumflex -70 KPX Y Odieresis -70 KPX Y Ograve -70 KPX Y Ohungarumlaut -70 KPX Y Omacron -70 KPX Y Oslash -70 KPX Y Otilde -70 KPX Y a -90 KPX Y aacute -90 KPX Y abreve -90 KPX Y acircumflex -90 KPX Y adieresis -90 KPX Y agrave -90 KPX Y amacron -90 KPX Y aogonek -90 KPX Y aring -90 KPX Y atilde -90 KPX Y colon -50 KPX Y comma -100 KPX Y e -80 KPX Y eacute -80 KPX Y ecaron -80 KPX Y ecircumflex -80 KPX Y edieresis -80 KPX Y edotaccent -80 KPX Y egrave -80 KPX Y emacron -80 KPX Y eogonek -80 KPX Y o -100 KPX Y oacute -100 KPX Y ocircumflex -100 KPX Y odieresis -100 KPX Y ograve -100 KPX Y ohungarumlaut -100 KPX Y omacron -100 KPX Y oslash -100 KPX Y otilde -100 KPX Y period -100 KPX Y semicolon -50 KPX Y u -100 KPX Y uacute -100 KPX Y ucircumflex -100 KPX Y udieresis -100 KPX Y ugrave -100 KPX Y uhungarumlaut -100 KPX Y umacron -100 KPX Y uogonek -100 KPX Y uring -100 KPX Yacute A -110 KPX Yacute Aacute -110 KPX Yacute Abreve -110 KPX Yacute Acircumflex -110 KPX Yacute Adieresis -110 KPX Yacute Agrave -110 KPX Yacute Amacron -110 KPX Yacute Aogonek -110 KPX Yacute Aring -110 KPX Yacute Atilde -110 KPX Yacute O -70 KPX Yacute Oacute -70 KPX Yacute Ocircumflex -70 KPX Yacute Odieresis -70 KPX Yacute Ograve -70 KPX Yacute Ohungarumlaut -70 KPX Yacute Omacron -70 KPX Yacute Oslash -70 KPX Yacute Otilde -70 KPX Yacute a -90 KPX Yacute aacute -90 KPX Yacute abreve -90 KPX Yacute acircumflex -90 KPX Yacute adieresis -90 KPX Yacute agrave -90 KPX Yacute amacron -90 KPX Yacute aogonek -90 KPX Yacute aring -90 KPX Yacute atilde -90 KPX Yacute colon -50 KPX Yacute comma -100 KPX Yacute e -80 KPX Yacute eacute -80 KPX Yacute ecaron -80 KPX Yacute ecircumflex -80 KPX Yacute edieresis -80 KPX Yacute edotaccent -80 KPX Yacute egrave -80 KPX Yacute emacron -80 KPX Yacute eogonek -80 KPX Yacute o -100 KPX Yacute oacute -100 KPX Yacute ocircumflex -100 KPX Yacute odieresis -100 KPX Yacute ograve -100 KPX Yacute ohungarumlaut -100 KPX Yacute omacron -100 KPX Yacute oslash -100 KPX Yacute otilde -100 KPX Yacute period -100 KPX Yacute semicolon -50 KPX Yacute u -100 KPX Yacute uacute -100 KPX Yacute ucircumflex -100 KPX Yacute udieresis -100 KPX Yacute ugrave -100 KPX Yacute uhungarumlaut -100 KPX Yacute umacron -100 KPX Yacute uogonek -100 KPX Yacute uring -100 KPX Ydieresis A -110 KPX Ydieresis Aacute -110 KPX Ydieresis Abreve -110 KPX Ydieresis Acircumflex -110 KPX Ydieresis Adieresis -110 KPX Ydieresis Agrave -110 KPX Ydieresis Amacron -110 KPX Ydieresis Aogonek -110 KPX Ydieresis Aring -110 KPX Ydieresis Atilde -110 KPX Ydieresis O -70 KPX Ydieresis Oacute -70 KPX Ydieresis Ocircumflex -70 KPX Ydieresis Odieresis -70 KPX Ydieresis Ograve -70 KPX Ydieresis Ohungarumlaut -70 KPX Ydieresis Omacron -70 KPX Ydieresis Oslash -70 KPX Ydieresis Otilde -70 KPX Ydieresis a -90 KPX Ydieresis aacute -90 KPX Ydieresis abreve -90 KPX Ydieresis acircumflex -90 KPX Ydieresis adieresis -90 KPX Ydieresis agrave -90 KPX Ydieresis amacron -90 KPX Ydieresis aogonek -90 KPX Ydieresis aring -90 KPX Ydieresis atilde -90 KPX Ydieresis colon -50 KPX Ydieresis comma -100 KPX Ydieresis e -80 KPX Ydieresis eacute -80 KPX Ydieresis ecaron -80 KPX Ydieresis ecircumflex -80 KPX Ydieresis edieresis -80 KPX Ydieresis edotaccent -80 KPX Ydieresis egrave -80 KPX Ydieresis emacron -80 KPX Ydieresis eogonek -80 KPX Ydieresis o -100 KPX Ydieresis oacute -100 KPX Ydieresis ocircumflex -100 KPX Ydieresis odieresis -100 KPX Ydieresis ograve -100 KPX Ydieresis ohungarumlaut -100 KPX Ydieresis omacron -100 KPX Ydieresis oslash -100 KPX Ydieresis otilde -100 KPX Ydieresis period -100 KPX Ydieresis semicolon -50 KPX Ydieresis u -100 KPX Ydieresis uacute -100 KPX Ydieresis ucircumflex -100 KPX Ydieresis udieresis -100 KPX Ydieresis ugrave -100 KPX Ydieresis uhungarumlaut -100 KPX Ydieresis umacron -100 KPX Ydieresis uogonek -100 KPX Ydieresis uring -100 KPX a g -10 KPX a gbreve -10 KPX a gcommaaccent -10 KPX a v -15 KPX a w -15 KPX a y -20 KPX a yacute -20 KPX a ydieresis -20 KPX aacute g -10 KPX aacute gbreve -10 KPX aacute gcommaaccent -10 KPX aacute v -15 KPX aacute w -15 KPX aacute y -20 KPX aacute yacute -20 KPX aacute ydieresis -20 KPX abreve g -10 KPX abreve gbreve -10 KPX abreve gcommaaccent -10 KPX abreve v -15 KPX abreve w -15 KPX abreve y -20 KPX abreve yacute -20 KPX abreve ydieresis -20 KPX acircumflex g -10 KPX acircumflex gbreve -10 KPX acircumflex gcommaaccent -10 KPX acircumflex v -15 KPX acircumflex w -15 KPX acircumflex y -20 KPX acircumflex yacute -20 KPX acircumflex ydieresis -20 KPX adieresis g -10 KPX adieresis gbreve -10 KPX adieresis gcommaaccent -10 KPX adieresis v -15 KPX adieresis w -15 KPX adieresis y -20 KPX adieresis yacute -20 KPX adieresis ydieresis -20 KPX agrave g -10 KPX agrave gbreve -10 KPX agrave gcommaaccent -10 KPX agrave v -15 KPX agrave w -15 KPX agrave y -20 KPX agrave yacute -20 KPX agrave ydieresis -20 KPX amacron g -10 KPX amacron gbreve -10 KPX amacron gcommaaccent -10 KPX amacron v -15 KPX amacron w -15 KPX amacron y -20 KPX amacron yacute -20 KPX amacron ydieresis -20 KPX aogonek g -10 KPX aogonek gbreve -10 KPX aogonek gcommaaccent -10 KPX aogonek v -15 KPX aogonek w -15 KPX aogonek y -20 KPX aogonek yacute -20 KPX aogonek ydieresis -20 KPX aring g -10 KPX aring gbreve -10 KPX aring gcommaaccent -10 KPX aring v -15 KPX aring w -15 KPX aring y -20 KPX aring yacute -20 KPX aring ydieresis -20 KPX atilde g -10 KPX atilde gbreve -10 KPX atilde gcommaaccent -10 KPX atilde v -15 KPX atilde w -15 KPX atilde y -20 KPX atilde yacute -20 KPX atilde ydieresis -20 KPX b l -10 KPX b lacute -10 KPX b lcommaaccent -10 KPX b lslash -10 KPX b u -20 KPX b uacute -20 KPX b ucircumflex -20 KPX b udieresis -20 KPX b ugrave -20 KPX b uhungarumlaut -20 KPX b umacron -20 KPX b uogonek -20 KPX b uring -20 KPX b v -20 KPX b y -20 KPX b yacute -20 KPX b ydieresis -20 KPX c h -10 KPX c k -20 KPX c kcommaaccent -20 KPX c l -20 KPX c lacute -20 KPX c lcommaaccent -20 KPX c lslash -20 KPX c y -10 KPX c yacute -10 KPX c ydieresis -10 KPX cacute h -10 KPX cacute k -20 KPX cacute kcommaaccent -20 KPX cacute l -20 KPX cacute lacute -20 KPX cacute lcommaaccent -20 KPX cacute lslash -20 KPX cacute y -10 KPX cacute yacute -10 KPX cacute ydieresis -10 KPX ccaron h -10 KPX ccaron k -20 KPX ccaron kcommaaccent -20 KPX ccaron l -20 KPX ccaron lacute -20 KPX ccaron lcommaaccent -20 KPX ccaron lslash -20 KPX ccaron y -10 KPX ccaron yacute -10 KPX ccaron ydieresis -10 KPX ccedilla h -10 KPX ccedilla k -20 KPX ccedilla kcommaaccent -20 KPX ccedilla l -20 KPX ccedilla lacute -20 KPX ccedilla lcommaaccent -20 KPX ccedilla lslash -20 KPX ccedilla y -10 KPX ccedilla yacute -10 KPX ccedilla ydieresis -10 KPX colon space -40 KPX comma quotedblright -120 KPX comma quoteright -120 KPX comma space -40 KPX d d -10 KPX d dcroat -10 KPX d v -15 KPX d w -15 KPX d y -15 KPX d yacute -15 KPX d ydieresis -15 KPX dcroat d -10 KPX dcroat dcroat -10 KPX dcroat v -15 KPX dcroat w -15 KPX dcroat y -15 KPX dcroat yacute -15 KPX dcroat ydieresis -15 KPX e comma 10 KPX e period 20 KPX e v -15 KPX e w -15 KPX e x -15 KPX e y -15 KPX e yacute -15 KPX e ydieresis -15 KPX eacute comma 10 KPX eacute period 20 KPX eacute v -15 KPX eacute w -15 KPX eacute x -15 KPX eacute y -15 KPX eacute yacute -15 KPX eacute ydieresis -15 KPX ecaron comma 10 KPX ecaron period 20 KPX ecaron v -15 KPX ecaron w -15 KPX ecaron x -15 KPX ecaron y -15 KPX ecaron yacute -15 KPX ecaron ydieresis -15 KPX ecircumflex comma 10 KPX ecircumflex period 20 KPX ecircumflex v -15 KPX ecircumflex w -15 KPX ecircumflex x -15 KPX ecircumflex y -15 KPX ecircumflex yacute -15 KPX ecircumflex ydieresis -15 KPX edieresis comma 10 KPX edieresis period 20 KPX edieresis v -15 KPX edieresis w -15 KPX edieresis x -15 KPX edieresis y -15 KPX edieresis yacute -15 KPX edieresis ydieresis -15 KPX edotaccent comma 10 KPX edotaccent period 20 KPX edotaccent v -15 KPX edotaccent w -15 KPX edotaccent x -15 KPX edotaccent y -15 KPX edotaccent yacute -15 KPX edotaccent ydieresis -15 KPX egrave comma 10 KPX egrave period 20 KPX egrave v -15 KPX egrave w -15 KPX egrave x -15 KPX egrave y -15 KPX egrave yacute -15 KPX egrave ydieresis -15 KPX emacron comma 10 KPX emacron period 20 KPX emacron v -15 KPX emacron w -15 KPX emacron x -15 KPX emacron y -15 KPX emacron yacute -15 KPX emacron ydieresis -15 KPX eogonek comma 10 KPX eogonek period 20 KPX eogonek v -15 KPX eogonek w -15 KPX eogonek x -15 KPX eogonek y -15 KPX eogonek yacute -15 KPX eogonek ydieresis -15 KPX f comma -10 KPX f e -10 KPX f eacute -10 KPX f ecaron -10 KPX f ecircumflex -10 KPX f edieresis -10 KPX f edotaccent -10 KPX f egrave -10 KPX f emacron -10 KPX f eogonek -10 KPX f o -20 KPX f oacute -20 KPX f ocircumflex -20 KPX f odieresis -20 KPX f ograve -20 KPX f ohungarumlaut -20 KPX f omacron -20 KPX f oslash -20 KPX f otilde -20 KPX f period -10 KPX f quotedblright 30 KPX f quoteright 30 KPX g e 10 KPX g eacute 10 KPX g ecaron 10 KPX g ecircumflex 10 KPX g edieresis 10 KPX g edotaccent 10 KPX g egrave 10 KPX g emacron 10 KPX g eogonek 10 KPX g g -10 KPX g gbreve -10 KPX g gcommaaccent -10 KPX gbreve e 10 KPX gbreve eacute 10 KPX gbreve ecaron 10 KPX gbreve ecircumflex 10 KPX gbreve edieresis 10 KPX gbreve edotaccent 10 KPX gbreve egrave 10 KPX gbreve emacron 10 KPX gbreve eogonek 10 KPX gbreve g -10 KPX gbreve gbreve -10 KPX gbreve gcommaaccent -10 KPX gcommaaccent e 10 KPX gcommaaccent eacute 10 KPX gcommaaccent ecaron 10 KPX gcommaaccent ecircumflex 10 KPX gcommaaccent edieresis 10 KPX gcommaaccent edotaccent 10 KPX gcommaaccent egrave 10 KPX gcommaaccent emacron 10 KPX gcommaaccent eogonek 10 KPX gcommaaccent g -10 KPX gcommaaccent gbreve -10 KPX gcommaaccent gcommaaccent -10 KPX h y -20 KPX h yacute -20 KPX h ydieresis -20 KPX k o -15 KPX k oacute -15 KPX k ocircumflex -15 KPX k odieresis -15 KPX k ograve -15 KPX k ohungarumlaut -15 KPX k omacron -15 KPX k oslash -15 KPX k otilde -15 KPX kcommaaccent o -15 KPX kcommaaccent oacute -15 KPX kcommaaccent ocircumflex -15 KPX kcommaaccent odieresis -15 KPX kcommaaccent ograve -15 KPX kcommaaccent ohungarumlaut -15 KPX kcommaaccent omacron -15 KPX kcommaaccent oslash -15 KPX kcommaaccent otilde -15 KPX l w -15 KPX l y -15 KPX l yacute -15 KPX l ydieresis -15 KPX lacute w -15 KPX lacute y -15 KPX lacute yacute -15 KPX lacute ydieresis -15 KPX lcommaaccent w -15 KPX lcommaaccent y -15 KPX lcommaaccent yacute -15 KPX lcommaaccent ydieresis -15 KPX lslash w -15 KPX lslash y -15 KPX lslash yacute -15 KPX lslash ydieresis -15 KPX m u -20 KPX m uacute -20 KPX m ucircumflex -20 KPX m udieresis -20 KPX m ugrave -20 KPX m uhungarumlaut -20 KPX m umacron -20 KPX m uogonek -20 KPX m uring -20 KPX m y -30 KPX m yacute -30 KPX m ydieresis -30 KPX n u -10 KPX n uacute -10 KPX n ucircumflex -10 KPX n udieresis -10 KPX n ugrave -10 KPX n uhungarumlaut -10 KPX n umacron -10 KPX n uogonek -10 KPX n uring -10 KPX n v -40 KPX n y -20 KPX n yacute -20 KPX n ydieresis -20 KPX nacute u -10 KPX nacute uacute -10 KPX nacute ucircumflex -10 KPX nacute udieresis -10 KPX nacute ugrave -10 KPX nacute uhungarumlaut -10 KPX nacute umacron -10 KPX nacute uogonek -10 KPX nacute uring -10 KPX nacute v -40 KPX nacute y -20 KPX nacute yacute -20 KPX nacute ydieresis -20 KPX ncaron u -10 KPX ncaron uacute -10 KPX ncaron ucircumflex -10 KPX ncaron udieresis -10 KPX ncaron ugrave -10 KPX ncaron uhungarumlaut -10 KPX ncaron umacron -10 KPX ncaron uogonek -10 KPX ncaron uring -10 KPX ncaron v -40 KPX ncaron y -20 KPX ncaron yacute -20 KPX ncaron ydieresis -20 KPX ncommaaccent u -10 KPX ncommaaccent uacute -10 KPX ncommaaccent ucircumflex -10 KPX ncommaaccent udieresis -10 KPX ncommaaccent ugrave -10 KPX ncommaaccent uhungarumlaut -10 KPX ncommaaccent umacron -10 KPX ncommaaccent uogonek -10 KPX ncommaaccent uring -10 KPX ncommaaccent v -40 KPX ncommaaccent y -20 KPX ncommaaccent yacute -20 KPX ncommaaccent ydieresis -20 KPX ntilde u -10 KPX ntilde uacute -10 KPX ntilde ucircumflex -10 KPX ntilde udieresis -10 KPX ntilde ugrave -10 KPX ntilde uhungarumlaut -10 KPX ntilde umacron -10 KPX ntilde uogonek -10 KPX ntilde uring -10 KPX ntilde v -40 KPX ntilde y -20 KPX ntilde yacute -20 KPX ntilde ydieresis -20 KPX o v -20 KPX o w -15 KPX o x -30 KPX o y -20 KPX o yacute -20 KPX o ydieresis -20 KPX oacute v -20 KPX oacute w -15 KPX oacute x -30 KPX oacute y -20 KPX oacute yacute -20 KPX oacute ydieresis -20 KPX ocircumflex v -20 KPX ocircumflex w -15 KPX ocircumflex x -30 KPX ocircumflex y -20 KPX ocircumflex yacute -20 KPX ocircumflex ydieresis -20 KPX odieresis v -20 KPX odieresis w -15 KPX odieresis x -30 KPX odieresis y -20 KPX odieresis yacute -20 KPX odieresis ydieresis -20 KPX ograve v -20 KPX ograve w -15 KPX ograve x -30 KPX ograve y -20 KPX ograve yacute -20 KPX ograve ydieresis -20 KPX ohungarumlaut v -20 KPX ohungarumlaut w -15 KPX ohungarumlaut x -30 KPX ohungarumlaut y -20 KPX ohungarumlaut yacute -20 KPX ohungarumlaut ydieresis -20 KPX omacron v -20 KPX omacron w -15 KPX omacron x -30 KPX omacron y -20 KPX omacron yacute -20 KPX omacron ydieresis -20 KPX oslash v -20 KPX oslash w -15 KPX oslash x -30 KPX oslash y -20 KPX oslash yacute -20 KPX oslash ydieresis -20 KPX otilde v -20 KPX otilde w -15 KPX otilde x -30 KPX otilde y -20 KPX otilde yacute -20 KPX otilde ydieresis -20 KPX p y -15 KPX p yacute -15 KPX p ydieresis -15 KPX period quotedblright -120 KPX period quoteright -120 KPX period space -40 KPX quotedblright space -80 KPX quoteleft quoteleft -46 KPX quoteright d -80 KPX quoteright dcroat -80 KPX quoteright l -20 KPX quoteright lacute -20 KPX quoteright lcommaaccent -20 KPX quoteright lslash -20 KPX quoteright quoteright -46 KPX quoteright r -40 KPX quoteright racute -40 KPX quoteright rcaron -40 KPX quoteright rcommaaccent -40 KPX quoteright s -60 KPX quoteright sacute -60 KPX quoteright scaron -60 KPX quoteright scedilla -60 KPX quoteright scommaaccent -60 KPX quoteright space -80 KPX quoteright v -20 KPX r c -20 KPX r cacute -20 KPX r ccaron -20 KPX r ccedilla -20 KPX r comma -60 KPX r d -20 KPX r dcroat -20 KPX r g -15 KPX r gbreve -15 KPX r gcommaaccent -15 KPX r hyphen -20 KPX r o -20 KPX r oacute -20 KPX r ocircumflex -20 KPX r odieresis -20 KPX r ograve -20 KPX r ohungarumlaut -20 KPX r omacron -20 KPX r oslash -20 KPX r otilde -20 KPX r period -60 KPX r q -20 KPX r s -15 KPX r sacute -15 KPX r scaron -15 KPX r scedilla -15 KPX r scommaaccent -15 KPX r t 20 KPX r tcommaaccent 20 KPX r v 10 KPX r y 10 KPX r yacute 10 KPX r ydieresis 10 KPX racute c -20 KPX racute cacute -20 KPX racute ccaron -20 KPX racute ccedilla -20 KPX racute comma -60 KPX racute d -20 KPX racute dcroat -20 KPX racute g -15 KPX racute gbreve -15 KPX racute gcommaaccent -15 KPX racute hyphen -20 KPX racute o -20 KPX racute oacute -20 KPX racute ocircumflex -20 KPX racute odieresis -20 KPX racute ograve -20 KPX racute ohungarumlaut -20 KPX racute omacron -20 KPX racute oslash -20 KPX racute otilde -20 KPX racute period -60 KPX racute q -20 KPX racute s -15 KPX racute sacute -15 KPX racute scaron -15 KPX racute scedilla -15 KPX racute scommaaccent -15 KPX racute t 20 KPX racute tcommaaccent 20 KPX racute v 10 KPX racute y 10 KPX racute yacute 10 KPX racute ydieresis 10 KPX rcaron c -20 KPX rcaron cacute -20 KPX rcaron ccaron -20 KPX rcaron ccedilla -20 KPX rcaron comma -60 KPX rcaron d -20 KPX rcaron dcroat -20 KPX rcaron g -15 KPX rcaron gbreve -15 KPX rcaron gcommaaccent -15 KPX rcaron hyphen -20 KPX rcaron o -20 KPX rcaron oacute -20 KPX rcaron ocircumflex -20 KPX rcaron odieresis -20 KPX rcaron ograve -20 KPX rcaron ohungarumlaut -20 KPX rcaron omacron -20 KPX rcaron oslash -20 KPX rcaron otilde -20 KPX rcaron period -60 KPX rcaron q -20 KPX rcaron s -15 KPX rcaron sacute -15 KPX rcaron scaron -15 KPX rcaron scedilla -15 KPX rcaron scommaaccent -15 KPX rcaron t 20 KPX rcaron tcommaaccent 20 KPX rcaron v 10 KPX rcaron y 10 KPX rcaron yacute 10 KPX rcaron ydieresis 10 KPX rcommaaccent c -20 KPX rcommaaccent cacute -20 KPX rcommaaccent ccaron -20 KPX rcommaaccent ccedilla -20 KPX rcommaaccent comma -60 KPX rcommaaccent d -20 KPX rcommaaccent dcroat -20 KPX rcommaaccent g -15 KPX rcommaaccent gbreve -15 KPX rcommaaccent gcommaaccent -15 KPX rcommaaccent hyphen -20 KPX rcommaaccent o -20 KPX rcommaaccent oacute -20 KPX rcommaaccent ocircumflex -20 KPX rcommaaccent odieresis -20 KPX rcommaaccent ograve -20 KPX rcommaaccent ohungarumlaut -20 KPX rcommaaccent omacron -20 KPX rcommaaccent oslash -20 KPX rcommaaccent otilde -20 KPX rcommaaccent period -60 KPX rcommaaccent q -20 KPX rcommaaccent s -15 KPX rcommaaccent sacute -15 KPX rcommaaccent scaron -15 KPX rcommaaccent scedilla -15 KPX rcommaaccent scommaaccent -15 KPX rcommaaccent t 20 KPX rcommaaccent tcommaaccent 20 KPX rcommaaccent v 10 KPX rcommaaccent y 10 KPX rcommaaccent yacute 10 KPX rcommaaccent ydieresis 10 KPX s w -15 KPX sacute w -15 KPX scaron w -15 KPX scedilla w -15 KPX scommaaccent w -15 KPX semicolon space -40 KPX space T -100 KPX space Tcaron -100 KPX space Tcommaaccent -100 KPX space V -80 KPX space W -80 KPX space Y -120 KPX space Yacute -120 KPX space Ydieresis -120 KPX space quotedblleft -80 KPX space quoteleft -60 KPX v a -20 KPX v aacute -20 KPX v abreve -20 KPX v acircumflex -20 KPX v adieresis -20 KPX v agrave -20 KPX v amacron -20 KPX v aogonek -20 KPX v aring -20 KPX v atilde -20 KPX v comma -80 KPX v o -30 KPX v oacute -30 KPX v ocircumflex -30 KPX v odieresis -30 KPX v ograve -30 KPX v ohungarumlaut -30 KPX v omacron -30 KPX v oslash -30 KPX v otilde -30 KPX v period -80 KPX w comma -40 KPX w o -20 KPX w oacute -20 KPX w ocircumflex -20 KPX w odieresis -20 KPX w ograve -20 KPX w ohungarumlaut -20 KPX w omacron -20 KPX w oslash -20 KPX w otilde -20 KPX w period -40 KPX x e -10 KPX x eacute -10 KPX x ecaron -10 KPX x ecircumflex -10 KPX x edieresis -10 KPX x edotaccent -10 KPX x egrave -10 KPX x emacron -10 KPX x eogonek -10 KPX y a -30 KPX y aacute -30 KPX y abreve -30 KPX y acircumflex -30 KPX y adieresis -30 KPX y agrave -30 KPX y amacron -30 KPX y aogonek -30 KPX y aring -30 KPX y atilde -30 KPX y comma -80 KPX y e -10 KPX y eacute -10 KPX y ecaron -10 KPX y ecircumflex -10 KPX y edieresis -10 KPX y edotaccent -10 KPX y egrave -10 KPX y emacron -10 KPX y eogonek -10 KPX y o -25 KPX y oacute -25 KPX y ocircumflex -25 KPX y odieresis -25 KPX y ograve -25 KPX y ohungarumlaut -25 KPX y omacron -25 KPX y oslash -25 KPX y otilde -25 KPX y period -80 KPX yacute a -30 KPX yacute aacute -30 KPX yacute abreve -30 KPX yacute acircumflex -30 KPX yacute adieresis -30 KPX yacute agrave -30 KPX yacute amacron -30 KPX yacute aogonek -30 KPX yacute aring -30 KPX yacute atilde -30 KPX yacute comma -80 KPX yacute e -10 KPX yacute eacute -10 KPX yacute ecaron -10 KPX yacute ecircumflex -10 KPX yacute edieresis -10 KPX yacute edotaccent -10 KPX yacute egrave -10 KPX yacute emacron -10 KPX yacute eogonek -10 KPX yacute o -25 KPX yacute oacute -25 KPX yacute ocircumflex -25 KPX yacute odieresis -25 KPX yacute ograve -25 KPX yacute ohungarumlaut -25 KPX yacute omacron -25 KPX yacute oslash -25 KPX yacute otilde -25 KPX yacute period -80 KPX ydieresis a -30 KPX ydieresis aacute -30 KPX ydieresis abreve -30 KPX ydieresis acircumflex -30 KPX ydieresis adieresis -30 KPX ydieresis agrave -30 KPX ydieresis amacron -30 KPX ydieresis aogonek -30 KPX ydieresis aring -30 KPX ydieresis atilde -30 KPX ydieresis comma -80 KPX ydieresis e -10 KPX ydieresis eacute -10 KPX ydieresis ecaron -10 KPX ydieresis ecircumflex -10 KPX ydieresis edieresis -10 KPX ydieresis edotaccent -10 KPX ydieresis egrave -10 KPX ydieresis emacron -10 KPX ydieresis eogonek -10 KPX ydieresis o -25 KPX ydieresis oacute -25 KPX ydieresis ocircumflex -25 KPX ydieresis odieresis -25 KPX ydieresis ograve -25 KPX ydieresis ohungarumlaut -25 KPX ydieresis omacron -25 KPX ydieresis oslash -25 KPX ydieresis otilde -25 KPX ydieresis period -80 KPX z e 10 KPX z eacute 10 KPX z ecaron 10 KPX z ecircumflex 10 KPX z edieresis 10 KPX z edotaccent 10 KPX z egrave 10 KPX z emacron 10 KPX z eogonek 10 KPX zacute e 10 KPX zacute eacute 10 KPX zacute ecaron 10 KPX zacute ecircumflex 10 KPX zacute edieresis 10 KPX zacute edotaccent 10 KPX zacute egrave 10 KPX zacute emacron 10 KPX zacute eogonek 10 KPX zcaron e 10 KPX zcaron eacute 10 KPX zcaron ecaron 10 KPX zcaron ecircumflex 10 KPX zcaron edieresis 10 KPX zcaron edotaccent 10 KPX zcaron egrave 10 KPX zcaron emacron 10 KPX zcaron eogonek 10 KPX zdotaccent e 10 KPX zdotaccent eacute 10 KPX zdotaccent ecaron 10 KPX zdotaccent ecircumflex 10 KPX zdotaccent edieresis 10 KPX zdotaccent edotaccent 10 KPX zdotaccent egrave 10 KPX zdotaccent emacron 10 KPX zdotaccent eogonek 10 EndKernPairs EndKernData EndFontMetrics camlpdf-2.8.1/compressor/Helvetica-BoldOblique.afm000066400000000000000000002073651477056064700221510ustar00rootroot00000000000000StartFontMetrics 4.1 Comment Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved. Comment Creation Date: Thu May 1 12:45:12 1997 Comment UniqueID 43053 Comment VMusage 14482 68586 FontName Helvetica-BoldOblique FullName Helvetica Bold Oblique FamilyName Helvetica Weight Bold ItalicAngle -12 IsFixedPitch false CharacterSet ExtendedRoman FontBBox -174 -228 1114 962 UnderlinePosition -100 UnderlineThickness 50 Version 002.000 Notice Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved.Helvetica is a trademark of Linotype-Hell AG and/or its subsidiaries. EncodingScheme AdobeStandardEncoding CapHeight 718 XHeight 532 Ascender 718 Descender -207 StdHW 118 StdVW 140 StartCharMetrics 315 C 32 ; WX 278 ; N space ; B 0 0 0 0 ; C 33 ; WX 333 ; N exclam ; B 94 0 397 718 ; C 34 ; WX 474 ; N quotedbl ; B 193 447 529 718 ; C 35 ; WX 556 ; N numbersign ; B 60 0 644 698 ; C 36 ; WX 556 ; N dollar ; B 67 -115 622 775 ; C 37 ; WX 889 ; N percent ; B 136 -19 901 710 ; C 38 ; WX 722 ; N ampersand ; B 89 -19 732 718 ; C 39 ; WX 278 ; N quoteright ; B 167 445 362 718 ; C 40 ; WX 333 ; N parenleft ; B 76 -208 470 734 ; C 41 ; WX 333 ; N parenright ; B -25 -208 369 734 ; C 42 ; WX 389 ; N asterisk ; B 146 387 481 718 ; C 43 ; WX 584 ; N plus ; B 82 0 610 506 ; C 44 ; WX 278 ; N comma ; B 28 -168 245 146 ; C 45 ; WX 333 ; N hyphen ; B 73 215 379 345 ; C 46 ; WX 278 ; N period ; B 64 0 245 146 ; C 47 ; WX 278 ; N slash ; B -37 -19 468 737 ; C 48 ; WX 556 ; N zero ; B 86 -19 617 710 ; C 49 ; WX 556 ; N one ; B 173 0 529 710 ; C 50 ; WX 556 ; N two ; B 26 0 619 710 ; C 51 ; WX 556 ; N three ; B 65 -19 608 710 ; C 52 ; WX 556 ; N four ; B 60 0 598 710 ; C 53 ; WX 556 ; N five ; B 64 -19 636 698 ; C 54 ; WX 556 ; N six ; B 85 -19 619 710 ; C 55 ; WX 556 ; N seven ; B 125 0 676 698 ; C 56 ; WX 556 ; N eight ; B 69 -19 616 710 ; C 57 ; WX 556 ; N nine ; B 78 -19 615 710 ; C 58 ; WX 333 ; N colon ; B 92 0 351 512 ; C 59 ; WX 333 ; N semicolon ; B 56 -168 351 512 ; C 60 ; WX 584 ; N less ; B 82 -8 655 514 ; C 61 ; WX 584 ; N equal ; B 58 87 633 419 ; C 62 ; WX 584 ; N greater ; B 36 -8 609 514 ; C 63 ; WX 611 ; N question ; B 165 0 671 727 ; C 64 ; WX 975 ; N at ; B 186 -19 954 737 ; C 65 ; WX 722 ; N A ; B 20 0 702 718 ; C 66 ; WX 722 ; N B ; B 76 0 764 718 ; C 67 ; WX 722 ; N C ; B 107 -19 789 737 ; C 68 ; WX 722 ; N D ; B 76 0 777 718 ; C 69 ; WX 667 ; N E ; B 76 0 757 718 ; C 70 ; WX 611 ; N F ; B 76 0 740 718 ; C 71 ; WX 778 ; N G ; B 108 -19 817 737 ; C 72 ; WX 722 ; N H ; B 71 0 804 718 ; C 73 ; WX 278 ; N I ; B 64 0 367 718 ; C 74 ; WX 556 ; N J ; B 60 -18 637 718 ; C 75 ; WX 722 ; N K ; B 87 0 858 718 ; C 76 ; WX 611 ; N L ; B 76 0 611 718 ; C 77 ; WX 833 ; N M ; B 69 0 918 718 ; C 78 ; WX 722 ; N N ; B 69 0 807 718 ; C 79 ; WX 778 ; N O ; B 107 -19 823 737 ; C 80 ; WX 667 ; N P ; B 76 0 738 718 ; C 81 ; WX 778 ; N Q ; B 107 -52 823 737 ; C 82 ; WX 722 ; N R ; B 76 0 778 718 ; C 83 ; WX 667 ; N S ; B 81 -19 718 737 ; C 84 ; WX 611 ; N T ; B 140 0 751 718 ; C 85 ; WX 722 ; N U ; B 116 -19 804 718 ; C 86 ; WX 667 ; N V ; B 172 0 801 718 ; C 87 ; WX 944 ; N W ; B 169 0 1082 718 ; C 88 ; WX 667 ; N X ; B 14 0 791 718 ; C 89 ; WX 667 ; N Y ; B 168 0 806 718 ; C 90 ; WX 611 ; N Z ; B 25 0 737 718 ; C 91 ; WX 333 ; N bracketleft ; B 21 -196 462 722 ; C 92 ; WX 278 ; N backslash ; B 124 -19 307 737 ; C 93 ; WX 333 ; N bracketright ; B -18 -196 423 722 ; C 94 ; WX 584 ; N asciicircum ; B 131 323 591 698 ; C 95 ; WX 556 ; N underscore ; B -27 -125 540 -75 ; C 96 ; WX 278 ; N quoteleft ; B 165 454 361 727 ; C 97 ; WX 556 ; N a ; B 55 -14 583 546 ; C 98 ; WX 611 ; N b ; B 61 -14 645 718 ; C 99 ; WX 556 ; N c ; B 79 -14 599 546 ; C 100 ; WX 611 ; N d ; B 82 -14 704 718 ; C 101 ; WX 556 ; N e ; B 70 -14 593 546 ; C 102 ; WX 333 ; N f ; B 87 0 469 727 ; L i fi ; L l fl ; C 103 ; WX 611 ; N g ; B 38 -217 666 546 ; C 104 ; WX 611 ; N h ; B 65 0 629 718 ; C 105 ; WX 278 ; N i ; B 69 0 363 725 ; C 106 ; WX 278 ; N j ; B -42 -214 363 725 ; C 107 ; WX 556 ; N k ; B 69 0 670 718 ; C 108 ; WX 278 ; N l ; B 69 0 362 718 ; C 109 ; WX 889 ; N m ; B 64 0 909 546 ; C 110 ; WX 611 ; N n ; B 65 0 629 546 ; C 111 ; WX 611 ; N o ; B 82 -14 643 546 ; C 112 ; WX 611 ; N p ; B 18 -207 645 546 ; C 113 ; WX 611 ; N q ; B 80 -207 665 546 ; C 114 ; WX 389 ; N r ; B 64 0 489 546 ; C 115 ; WX 556 ; N s ; B 63 -14 584 546 ; C 116 ; WX 333 ; N t ; B 100 -6 422 676 ; C 117 ; WX 611 ; N u ; B 98 -14 658 532 ; C 118 ; WX 556 ; N v ; B 126 0 656 532 ; C 119 ; WX 778 ; N w ; B 123 0 882 532 ; C 120 ; WX 556 ; N x ; B 15 0 648 532 ; C 121 ; WX 556 ; N y ; B 42 -214 652 532 ; C 122 ; WX 500 ; N z ; B 20 0 583 532 ; C 123 ; WX 389 ; N braceleft ; B 94 -196 518 722 ; C 124 ; WX 280 ; N bar ; B 36 -225 361 775 ; C 125 ; WX 389 ; N braceright ; B -18 -196 407 722 ; C 126 ; WX 584 ; N asciitilde ; B 115 163 577 343 ; C 161 ; WX 333 ; N exclamdown ; B 50 -186 353 532 ; C 162 ; WX 556 ; N cent ; B 79 -118 599 628 ; C 163 ; WX 556 ; N sterling ; B 50 -16 635 718 ; C 164 ; WX 167 ; N fraction ; B -174 -19 487 710 ; C 165 ; WX 556 ; N yen ; B 60 0 713 698 ; C 166 ; WX 556 ; N florin ; B -50 -210 669 737 ; C 167 ; WX 556 ; N section ; B 61 -184 598 727 ; C 168 ; WX 556 ; N currency ; B 27 76 680 636 ; C 169 ; WX 238 ; N quotesingle ; B 165 447 321 718 ; C 170 ; WX 500 ; N quotedblleft ; B 160 454 588 727 ; C 171 ; WX 556 ; N guillemotleft ; B 135 76 571 484 ; C 172 ; WX 333 ; N guilsinglleft ; B 130 76 353 484 ; C 173 ; WX 333 ; N guilsinglright ; B 99 76 322 484 ; C 174 ; WX 611 ; N fi ; B 87 0 696 727 ; C 175 ; WX 611 ; N fl ; B 87 0 695 727 ; C 177 ; WX 556 ; N endash ; B 48 227 627 333 ; C 178 ; WX 556 ; N dagger ; B 118 -171 626 718 ; C 179 ; WX 556 ; N daggerdbl ; B 46 -171 628 718 ; C 180 ; WX 278 ; N periodcentered ; B 110 172 276 334 ; C 182 ; WX 556 ; N paragraph ; B 98 -191 688 700 ; C 183 ; WX 350 ; N bullet ; B 83 194 420 524 ; C 184 ; WX 278 ; N quotesinglbase ; B 41 -146 236 127 ; C 185 ; WX 500 ; N quotedblbase ; B 36 -146 463 127 ; C 186 ; WX 500 ; N quotedblright ; B 162 445 589 718 ; C 187 ; WX 556 ; N guillemotright ; B 104 76 540 484 ; C 188 ; WX 1000 ; N ellipsis ; B 92 0 939 146 ; C 189 ; WX 1000 ; N perthousand ; B 76 -19 1038 710 ; C 191 ; WX 611 ; N questiondown ; B 53 -195 559 532 ; C 193 ; WX 333 ; N grave ; B 136 604 353 750 ; C 194 ; WX 333 ; N acute ; B 236 604 515 750 ; C 195 ; WX 333 ; N circumflex ; B 118 604 471 750 ; C 196 ; WX 333 ; N tilde ; B 113 610 507 737 ; C 197 ; WX 333 ; N macron ; B 122 604 483 678 ; C 198 ; WX 333 ; N breve ; B 156 604 494 750 ; C 199 ; WX 333 ; N dotaccent ; B 235 614 385 729 ; C 200 ; WX 333 ; N dieresis ; B 137 614 482 729 ; C 202 ; WX 333 ; N ring ; B 200 568 420 776 ; C 203 ; WX 333 ; N cedilla ; B -37 -228 220 0 ; C 205 ; WX 333 ; N hungarumlaut ; B 137 604 645 750 ; C 206 ; WX 333 ; N ogonek ; B 41 -228 264 0 ; C 207 ; WX 333 ; N caron ; B 149 604 502 750 ; C 208 ; WX 1000 ; N emdash ; B 48 227 1071 333 ; C 225 ; WX 1000 ; N AE ; B 5 0 1100 718 ; C 227 ; WX 370 ; N ordfeminine ; B 125 401 465 737 ; C 232 ; WX 611 ; N Lslash ; B 34 0 611 718 ; C 233 ; WX 778 ; N Oslash ; B 35 -27 894 745 ; C 234 ; WX 1000 ; N OE ; B 99 -19 1114 737 ; C 235 ; WX 365 ; N ordmasculine ; B 123 401 485 737 ; C 241 ; WX 889 ; N ae ; B 56 -14 923 546 ; C 245 ; WX 278 ; N dotlessi ; B 69 0 322 532 ; C 248 ; WX 278 ; N lslash ; B 40 0 407 718 ; C 249 ; WX 611 ; N oslash ; B 22 -29 701 560 ; C 250 ; WX 944 ; N oe ; B 82 -14 977 546 ; C 251 ; WX 611 ; N germandbls ; B 69 -14 657 731 ; C -1 ; WX 278 ; N Idieresis ; B 64 0 494 915 ; C -1 ; WX 556 ; N eacute ; B 70 -14 627 750 ; C -1 ; WX 556 ; N abreve ; B 55 -14 606 750 ; C -1 ; WX 611 ; N uhungarumlaut ; B 98 -14 784 750 ; C -1 ; WX 556 ; N ecaron ; B 70 -14 614 750 ; C -1 ; WX 667 ; N Ydieresis ; B 168 0 806 915 ; C -1 ; WX 584 ; N divide ; B 82 -42 610 548 ; C -1 ; WX 667 ; N Yacute ; B 168 0 806 936 ; C -1 ; WX 722 ; N Acircumflex ; B 20 0 706 936 ; C -1 ; WX 556 ; N aacute ; B 55 -14 627 750 ; C -1 ; WX 722 ; N Ucircumflex ; B 116 -19 804 936 ; C -1 ; WX 556 ; N yacute ; B 42 -214 652 750 ; C -1 ; WX 556 ; N scommaaccent ; B 63 -228 584 546 ; C -1 ; WX 556 ; N ecircumflex ; B 70 -14 593 750 ; C -1 ; WX 722 ; N Uring ; B 116 -19 804 962 ; C -1 ; WX 722 ; N Udieresis ; B 116 -19 804 915 ; C -1 ; WX 556 ; N aogonek ; B 55 -224 583 546 ; C -1 ; WX 722 ; N Uacute ; B 116 -19 804 936 ; C -1 ; WX 611 ; N uogonek ; B 98 -228 658 532 ; C -1 ; WX 667 ; N Edieresis ; B 76 0 757 915 ; C -1 ; WX 722 ; N Dcroat ; B 62 0 777 718 ; C -1 ; WX 250 ; N commaaccent ; B 16 -228 188 -50 ; C -1 ; WX 737 ; N copyright ; B 56 -19 835 737 ; C -1 ; WX 667 ; N Emacron ; B 76 0 757 864 ; C -1 ; WX 556 ; N ccaron ; B 79 -14 614 750 ; C -1 ; WX 556 ; N aring ; B 55 -14 583 776 ; C -1 ; WX 722 ; N Ncommaaccent ; B 69 -228 807 718 ; C -1 ; WX 278 ; N lacute ; B 69 0 528 936 ; C -1 ; WX 556 ; N agrave ; B 55 -14 583 750 ; C -1 ; WX 611 ; N Tcommaaccent ; B 140 -228 751 718 ; C -1 ; WX 722 ; N Cacute ; B 107 -19 789 936 ; C -1 ; WX 556 ; N atilde ; B 55 -14 619 737 ; C -1 ; WX 667 ; N Edotaccent ; B 76 0 757 915 ; C -1 ; WX 556 ; N scaron ; B 63 -14 614 750 ; C -1 ; WX 556 ; N scedilla ; B 63 -228 584 546 ; C -1 ; WX 278 ; N iacute ; B 69 0 488 750 ; C -1 ; WX 494 ; N lozenge ; B 90 0 564 745 ; C -1 ; WX 722 ; N Rcaron ; B 76 0 778 936 ; C -1 ; WX 778 ; N Gcommaaccent ; B 108 -228 817 737 ; C -1 ; WX 611 ; N ucircumflex ; B 98 -14 658 750 ; C -1 ; WX 556 ; N acircumflex ; B 55 -14 583 750 ; C -1 ; WX 722 ; N Amacron ; B 20 0 718 864 ; C -1 ; WX 389 ; N rcaron ; B 64 0 530 750 ; C -1 ; WX 556 ; N ccedilla ; B 79 -228 599 546 ; C -1 ; WX 611 ; N Zdotaccent ; B 25 0 737 915 ; C -1 ; WX 667 ; N Thorn ; B 76 0 716 718 ; C -1 ; WX 778 ; N Omacron ; B 107 -19 823 864 ; C -1 ; WX 722 ; N Racute ; B 76 0 778 936 ; C -1 ; WX 667 ; N Sacute ; B 81 -19 722 936 ; C -1 ; WX 743 ; N dcaron ; B 82 -14 903 718 ; C -1 ; WX 722 ; N Umacron ; B 116 -19 804 864 ; C -1 ; WX 611 ; N uring ; B 98 -14 658 776 ; C -1 ; WX 333 ; N threesuperior ; B 91 271 441 710 ; C -1 ; WX 778 ; N Ograve ; B 107 -19 823 936 ; C -1 ; WX 722 ; N Agrave ; B 20 0 702 936 ; C -1 ; WX 722 ; N Abreve ; B 20 0 729 936 ; C -1 ; WX 584 ; N multiply ; B 57 1 635 505 ; C -1 ; WX 611 ; N uacute ; B 98 -14 658 750 ; C -1 ; WX 611 ; N Tcaron ; B 140 0 751 936 ; C -1 ; WX 494 ; N partialdiff ; B 43 -21 585 750 ; C -1 ; WX 556 ; N ydieresis ; B 42 -214 652 729 ; C -1 ; WX 722 ; N Nacute ; B 69 0 807 936 ; C -1 ; WX 278 ; N icircumflex ; B 69 0 444 750 ; C -1 ; WX 667 ; N Ecircumflex ; B 76 0 757 936 ; C -1 ; WX 556 ; N adieresis ; B 55 -14 594 729 ; C -1 ; WX 556 ; N edieresis ; B 70 -14 594 729 ; C -1 ; WX 556 ; N cacute ; B 79 -14 627 750 ; C -1 ; WX 611 ; N nacute ; B 65 0 654 750 ; C -1 ; WX 611 ; N umacron ; B 98 -14 658 678 ; C -1 ; WX 722 ; N Ncaron ; B 69 0 807 936 ; C -1 ; WX 278 ; N Iacute ; B 64 0 528 936 ; C -1 ; WX 584 ; N plusminus ; B 40 0 625 506 ; C -1 ; WX 280 ; N brokenbar ; B 52 -150 345 700 ; C -1 ; WX 737 ; N registered ; B 55 -19 834 737 ; C -1 ; WX 778 ; N Gbreve ; B 108 -19 817 936 ; C -1 ; WX 278 ; N Idotaccent ; B 64 0 397 915 ; C -1 ; WX 600 ; N summation ; B 14 -10 670 706 ; C -1 ; WX 667 ; N Egrave ; B 76 0 757 936 ; C -1 ; WX 389 ; N racute ; B 64 0 543 750 ; C -1 ; WX 611 ; N omacron ; B 82 -14 643 678 ; C -1 ; WX 611 ; N Zacute ; B 25 0 737 936 ; C -1 ; WX 611 ; N Zcaron ; B 25 0 737 936 ; C -1 ; WX 549 ; N greaterequal ; B 26 0 629 704 ; C -1 ; WX 722 ; N Eth ; B 62 0 777 718 ; C -1 ; WX 722 ; N Ccedilla ; B 107 -228 789 737 ; C -1 ; WX 278 ; N lcommaaccent ; B 30 -228 362 718 ; C -1 ; WX 389 ; N tcaron ; B 100 -6 608 878 ; C -1 ; WX 556 ; N eogonek ; B 70 -228 593 546 ; C -1 ; WX 722 ; N Uogonek ; B 116 -228 804 718 ; C -1 ; WX 722 ; N Aacute ; B 20 0 750 936 ; C -1 ; WX 722 ; N Adieresis ; B 20 0 716 915 ; C -1 ; WX 556 ; N egrave ; B 70 -14 593 750 ; C -1 ; WX 500 ; N zacute ; B 20 0 599 750 ; C -1 ; WX 278 ; N iogonek ; B -14 -224 363 725 ; C -1 ; WX 778 ; N Oacute ; B 107 -19 823 936 ; C -1 ; WX 611 ; N oacute ; B 82 -14 654 750 ; C -1 ; WX 556 ; N amacron ; B 55 -14 595 678 ; C -1 ; WX 556 ; N sacute ; B 63 -14 627 750 ; C -1 ; WX 278 ; N idieresis ; B 69 0 455 729 ; C -1 ; WX 778 ; N Ocircumflex ; B 107 -19 823 936 ; C -1 ; WX 722 ; N Ugrave ; B 116 -19 804 936 ; C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ; C -1 ; WX 611 ; N thorn ; B 18 -208 645 718 ; C -1 ; WX 333 ; N twosuperior ; B 69 283 449 710 ; C -1 ; WX 778 ; N Odieresis ; B 107 -19 823 915 ; C -1 ; WX 611 ; N mu ; B 22 -207 658 532 ; C -1 ; WX 278 ; N igrave ; B 69 0 326 750 ; C -1 ; WX 611 ; N ohungarumlaut ; B 82 -14 784 750 ; C -1 ; WX 667 ; N Eogonek ; B 76 -224 757 718 ; C -1 ; WX 611 ; N dcroat ; B 82 -14 789 718 ; C -1 ; WX 834 ; N threequarters ; B 99 -19 839 710 ; C -1 ; WX 667 ; N Scedilla ; B 81 -228 718 737 ; C -1 ; WX 400 ; N lcaron ; B 69 0 561 718 ; C -1 ; WX 722 ; N Kcommaaccent ; B 87 -228 858 718 ; C -1 ; WX 611 ; N Lacute ; B 76 0 611 936 ; C -1 ; WX 1000 ; N trademark ; B 179 306 1109 718 ; C -1 ; WX 556 ; N edotaccent ; B 70 -14 593 729 ; C -1 ; WX 278 ; N Igrave ; B 64 0 367 936 ; C -1 ; WX 278 ; N Imacron ; B 64 0 496 864 ; C -1 ; WX 611 ; N Lcaron ; B 76 0 643 718 ; C -1 ; WX 834 ; N onehalf ; B 132 -19 858 710 ; C -1 ; WX 549 ; N lessequal ; B 29 0 676 704 ; C -1 ; WX 611 ; N ocircumflex ; B 82 -14 643 750 ; C -1 ; WX 611 ; N ntilde ; B 65 0 646 737 ; C -1 ; WX 722 ; N Uhungarumlaut ; B 116 -19 880 936 ; C -1 ; WX 667 ; N Eacute ; B 76 0 757 936 ; C -1 ; WX 556 ; N emacron ; B 70 -14 595 678 ; C -1 ; WX 611 ; N gbreve ; B 38 -217 666 750 ; C -1 ; WX 834 ; N onequarter ; B 132 -19 806 710 ; C -1 ; WX 667 ; N Scaron ; B 81 -19 718 936 ; C -1 ; WX 667 ; N Scommaaccent ; B 81 -228 718 737 ; C -1 ; WX 778 ; N Ohungarumlaut ; B 107 -19 908 936 ; C -1 ; WX 400 ; N degree ; B 175 426 467 712 ; C -1 ; WX 611 ; N ograve ; B 82 -14 643 750 ; C -1 ; WX 722 ; N Ccaron ; B 107 -19 789 936 ; C -1 ; WX 611 ; N ugrave ; B 98 -14 658 750 ; C -1 ; WX 549 ; N radical ; B 112 -46 689 850 ; C -1 ; WX 722 ; N Dcaron ; B 76 0 777 936 ; C -1 ; WX 389 ; N rcommaaccent ; B 26 -228 489 546 ; C -1 ; WX 722 ; N Ntilde ; B 69 0 807 923 ; C -1 ; WX 611 ; N otilde ; B 82 -14 646 737 ; C -1 ; WX 722 ; N Rcommaaccent ; B 76 -228 778 718 ; C -1 ; WX 611 ; N Lcommaaccent ; B 76 -228 611 718 ; C -1 ; WX 722 ; N Atilde ; B 20 0 741 923 ; C -1 ; WX 722 ; N Aogonek ; B 20 -224 702 718 ; C -1 ; WX 722 ; N Aring ; B 20 0 702 962 ; C -1 ; WX 778 ; N Otilde ; B 107 -19 823 923 ; C -1 ; WX 500 ; N zdotaccent ; B 20 0 583 729 ; C -1 ; WX 667 ; N Ecaron ; B 76 0 757 936 ; C -1 ; WX 278 ; N Iogonek ; B -41 -228 367 718 ; C -1 ; WX 556 ; N kcommaaccent ; B 69 -228 670 718 ; C -1 ; WX 584 ; N minus ; B 82 197 610 309 ; C -1 ; WX 278 ; N Icircumflex ; B 64 0 484 936 ; C -1 ; WX 611 ; N ncaron ; B 65 0 641 750 ; C -1 ; WX 333 ; N tcommaaccent ; B 58 -228 422 676 ; C -1 ; WX 584 ; N logicalnot ; B 105 108 633 419 ; C -1 ; WX 611 ; N odieresis ; B 82 -14 643 729 ; C -1 ; WX 611 ; N udieresis ; B 98 -14 658 729 ; C -1 ; WX 549 ; N notequal ; B 32 -49 630 570 ; C -1 ; WX 611 ; N gcommaaccent ; B 38 -217 666 850 ; C -1 ; WX 611 ; N eth ; B 82 -14 670 737 ; C -1 ; WX 500 ; N zcaron ; B 20 0 586 750 ; C -1 ; WX 611 ; N ncommaaccent ; B 65 -228 629 546 ; C -1 ; WX 333 ; N onesuperior ; B 148 283 388 710 ; C -1 ; WX 278 ; N imacron ; B 69 0 429 678 ; C -1 ; WX 556 ; N Euro ; B 0 0 0 0 ; EndCharMetrics StartKernData StartKernPairs 2481 KPX A C -40 KPX A Cacute -40 KPX A Ccaron -40 KPX A Ccedilla -40 KPX A G -50 KPX A Gbreve -50 KPX A Gcommaaccent -50 KPX A O -40 KPX A Oacute -40 KPX A Ocircumflex -40 KPX A Odieresis -40 KPX A Ograve -40 KPX A Ohungarumlaut -40 KPX A Omacron -40 KPX A Oslash -40 KPX A Otilde -40 KPX A Q -40 KPX A T -90 KPX A Tcaron -90 KPX A Tcommaaccent -90 KPX A U -50 KPX A Uacute -50 KPX A Ucircumflex -50 KPX A Udieresis -50 KPX A Ugrave -50 KPX A Uhungarumlaut -50 KPX A Umacron -50 KPX A Uogonek -50 KPX A Uring -50 KPX A V -80 KPX A W -60 KPX A Y -110 KPX A Yacute -110 KPX A Ydieresis -110 KPX A u -30 KPX A uacute -30 KPX A ucircumflex -30 KPX A udieresis -30 KPX A ugrave -30 KPX A uhungarumlaut -30 KPX A umacron -30 KPX A uogonek -30 KPX A uring -30 KPX A v -40 KPX A w -30 KPX A y -30 KPX A yacute -30 KPX A ydieresis -30 KPX Aacute C -40 KPX Aacute Cacute -40 KPX Aacute Ccaron -40 KPX Aacute Ccedilla -40 KPX Aacute G -50 KPX Aacute Gbreve -50 KPX Aacute Gcommaaccent -50 KPX Aacute O -40 KPX Aacute Oacute -40 KPX Aacute Ocircumflex -40 KPX Aacute Odieresis -40 KPX Aacute Ograve -40 KPX Aacute Ohungarumlaut -40 KPX Aacute Omacron -40 KPX Aacute Oslash -40 KPX Aacute Otilde -40 KPX Aacute Q -40 KPX Aacute T -90 KPX Aacute Tcaron -90 KPX Aacute Tcommaaccent -90 KPX Aacute U -50 KPX Aacute Uacute -50 KPX Aacute Ucircumflex -50 KPX Aacute Udieresis -50 KPX Aacute Ugrave -50 KPX Aacute Uhungarumlaut -50 KPX Aacute Umacron -50 KPX Aacute Uogonek -50 KPX Aacute Uring -50 KPX Aacute V -80 KPX Aacute W -60 KPX Aacute Y -110 KPX Aacute Yacute -110 KPX Aacute Ydieresis -110 KPX Aacute u -30 KPX Aacute uacute -30 KPX Aacute ucircumflex -30 KPX Aacute udieresis -30 KPX Aacute ugrave -30 KPX Aacute uhungarumlaut -30 KPX Aacute umacron -30 KPX Aacute uogonek -30 KPX Aacute uring -30 KPX Aacute v -40 KPX Aacute w -30 KPX Aacute y -30 KPX Aacute yacute -30 KPX Aacute ydieresis -30 KPX Abreve C -40 KPX Abreve Cacute -40 KPX Abreve Ccaron -40 KPX Abreve Ccedilla -40 KPX Abreve G -50 KPX Abreve Gbreve -50 KPX Abreve Gcommaaccent -50 KPX Abreve O -40 KPX Abreve Oacute -40 KPX Abreve Ocircumflex -40 KPX Abreve Odieresis -40 KPX Abreve Ograve -40 KPX Abreve Ohungarumlaut -40 KPX Abreve Omacron -40 KPX Abreve Oslash -40 KPX Abreve Otilde -40 KPX Abreve Q -40 KPX Abreve T -90 KPX Abreve Tcaron -90 KPX Abreve Tcommaaccent -90 KPX Abreve U -50 KPX Abreve Uacute -50 KPX Abreve Ucircumflex -50 KPX Abreve Udieresis -50 KPX Abreve Ugrave -50 KPX Abreve Uhungarumlaut -50 KPX Abreve Umacron -50 KPX Abreve Uogonek -50 KPX Abreve Uring -50 KPX Abreve V -80 KPX Abreve W -60 KPX Abreve Y -110 KPX Abreve Yacute -110 KPX Abreve Ydieresis -110 KPX Abreve u -30 KPX Abreve uacute -30 KPX Abreve ucircumflex -30 KPX Abreve udieresis -30 KPX Abreve ugrave -30 KPX Abreve uhungarumlaut -30 KPX Abreve umacron -30 KPX Abreve uogonek -30 KPX Abreve uring -30 KPX Abreve v -40 KPX Abreve w -30 KPX Abreve y -30 KPX Abreve yacute -30 KPX Abreve ydieresis -30 KPX Acircumflex C -40 KPX Acircumflex Cacute -40 KPX Acircumflex Ccaron -40 KPX Acircumflex Ccedilla -40 KPX Acircumflex G -50 KPX Acircumflex Gbreve -50 KPX Acircumflex Gcommaaccent -50 KPX Acircumflex O -40 KPX Acircumflex Oacute -40 KPX Acircumflex Ocircumflex -40 KPX Acircumflex Odieresis -40 KPX Acircumflex Ograve -40 KPX Acircumflex Ohungarumlaut -40 KPX Acircumflex Omacron -40 KPX Acircumflex Oslash -40 KPX Acircumflex Otilde -40 KPX Acircumflex Q -40 KPX Acircumflex T -90 KPX Acircumflex Tcaron -90 KPX Acircumflex Tcommaaccent -90 KPX Acircumflex U -50 KPX Acircumflex Uacute -50 KPX Acircumflex Ucircumflex -50 KPX Acircumflex Udieresis -50 KPX Acircumflex Ugrave -50 KPX Acircumflex Uhungarumlaut -50 KPX Acircumflex Umacron -50 KPX Acircumflex Uogonek -50 KPX Acircumflex Uring -50 KPX Acircumflex V -80 KPX Acircumflex W -60 KPX Acircumflex Y -110 KPX Acircumflex Yacute -110 KPX Acircumflex Ydieresis -110 KPX Acircumflex u -30 KPX Acircumflex uacute -30 KPX Acircumflex ucircumflex -30 KPX Acircumflex udieresis -30 KPX Acircumflex ugrave -30 KPX Acircumflex uhungarumlaut -30 KPX Acircumflex umacron -30 KPX Acircumflex uogonek -30 KPX Acircumflex uring -30 KPX Acircumflex v -40 KPX Acircumflex w -30 KPX Acircumflex y -30 KPX Acircumflex yacute -30 KPX Acircumflex ydieresis -30 KPX Adieresis C -40 KPX Adieresis Cacute -40 KPX Adieresis Ccaron -40 KPX Adieresis Ccedilla -40 KPX Adieresis G -50 KPX Adieresis Gbreve -50 KPX Adieresis Gcommaaccent -50 KPX Adieresis O -40 KPX Adieresis Oacute -40 KPX Adieresis Ocircumflex -40 KPX Adieresis Odieresis -40 KPX Adieresis Ograve -40 KPX Adieresis Ohungarumlaut -40 KPX Adieresis Omacron -40 KPX Adieresis Oslash -40 KPX Adieresis Otilde -40 KPX Adieresis Q -40 KPX Adieresis T -90 KPX Adieresis Tcaron -90 KPX Adieresis Tcommaaccent -90 KPX Adieresis U -50 KPX Adieresis Uacute -50 KPX Adieresis Ucircumflex -50 KPX Adieresis Udieresis -50 KPX Adieresis Ugrave -50 KPX Adieresis Uhungarumlaut -50 KPX Adieresis Umacron -50 KPX Adieresis Uogonek -50 KPX Adieresis Uring -50 KPX Adieresis V -80 KPX Adieresis W -60 KPX Adieresis Y -110 KPX Adieresis Yacute -110 KPX Adieresis Ydieresis -110 KPX Adieresis u -30 KPX Adieresis uacute -30 KPX Adieresis ucircumflex -30 KPX Adieresis udieresis -30 KPX Adieresis ugrave -30 KPX Adieresis uhungarumlaut -30 KPX Adieresis umacron -30 KPX Adieresis uogonek -30 KPX Adieresis uring -30 KPX Adieresis v -40 KPX Adieresis w -30 KPX Adieresis y -30 KPX Adieresis yacute -30 KPX Adieresis ydieresis -30 KPX Agrave C -40 KPX Agrave Cacute -40 KPX Agrave Ccaron -40 KPX Agrave Ccedilla -40 KPX Agrave G -50 KPX Agrave Gbreve -50 KPX Agrave Gcommaaccent -50 KPX Agrave O -40 KPX Agrave Oacute -40 KPX Agrave Ocircumflex -40 KPX Agrave Odieresis -40 KPX Agrave Ograve -40 KPX Agrave Ohungarumlaut -40 KPX Agrave Omacron -40 KPX Agrave Oslash -40 KPX Agrave Otilde -40 KPX Agrave Q -40 KPX Agrave T -90 KPX Agrave Tcaron -90 KPX Agrave Tcommaaccent -90 KPX Agrave U -50 KPX Agrave Uacute -50 KPX Agrave Ucircumflex -50 KPX Agrave Udieresis -50 KPX Agrave Ugrave -50 KPX Agrave Uhungarumlaut -50 KPX Agrave Umacron -50 KPX Agrave Uogonek -50 KPX Agrave Uring -50 KPX Agrave V -80 KPX Agrave W -60 KPX Agrave Y -110 KPX Agrave Yacute -110 KPX Agrave Ydieresis -110 KPX Agrave u -30 KPX Agrave uacute -30 KPX Agrave ucircumflex -30 KPX Agrave udieresis -30 KPX Agrave ugrave -30 KPX Agrave uhungarumlaut -30 KPX Agrave umacron -30 KPX Agrave uogonek -30 KPX Agrave uring -30 KPX Agrave v -40 KPX Agrave w -30 KPX Agrave y -30 KPX Agrave yacute -30 KPX Agrave ydieresis -30 KPX Amacron C -40 KPX Amacron Cacute -40 KPX Amacron Ccaron -40 KPX Amacron Ccedilla -40 KPX Amacron G -50 KPX Amacron Gbreve -50 KPX Amacron Gcommaaccent -50 KPX Amacron O -40 KPX Amacron Oacute -40 KPX Amacron Ocircumflex -40 KPX Amacron Odieresis -40 KPX Amacron Ograve -40 KPX Amacron Ohungarumlaut -40 KPX Amacron Omacron -40 KPX Amacron Oslash -40 KPX Amacron Otilde -40 KPX Amacron Q -40 KPX Amacron T -90 KPX Amacron Tcaron -90 KPX Amacron Tcommaaccent -90 KPX Amacron U -50 KPX Amacron Uacute -50 KPX Amacron Ucircumflex -50 KPX Amacron Udieresis -50 KPX Amacron Ugrave -50 KPX Amacron Uhungarumlaut -50 KPX Amacron Umacron -50 KPX Amacron Uogonek -50 KPX Amacron Uring -50 KPX Amacron V -80 KPX Amacron W -60 KPX Amacron Y -110 KPX Amacron Yacute -110 KPX Amacron Ydieresis -110 KPX Amacron u -30 KPX Amacron uacute -30 KPX Amacron ucircumflex -30 KPX Amacron udieresis -30 KPX Amacron ugrave -30 KPX Amacron uhungarumlaut -30 KPX Amacron umacron -30 KPX Amacron uogonek -30 KPX Amacron uring -30 KPX Amacron v -40 KPX Amacron w -30 KPX Amacron y -30 KPX Amacron yacute -30 KPX Amacron ydieresis -30 KPX Aogonek C -40 KPX Aogonek Cacute -40 KPX Aogonek Ccaron -40 KPX Aogonek Ccedilla -40 KPX Aogonek G -50 KPX Aogonek Gbreve -50 KPX Aogonek Gcommaaccent -50 KPX Aogonek O -40 KPX Aogonek Oacute -40 KPX Aogonek Ocircumflex -40 KPX Aogonek Odieresis -40 KPX Aogonek Ograve -40 KPX Aogonek Ohungarumlaut -40 KPX Aogonek Omacron -40 KPX Aogonek Oslash -40 KPX Aogonek Otilde -40 KPX Aogonek Q -40 KPX Aogonek T -90 KPX Aogonek Tcaron -90 KPX Aogonek Tcommaaccent -90 KPX Aogonek U -50 KPX Aogonek Uacute -50 KPX Aogonek Ucircumflex -50 KPX Aogonek Udieresis -50 KPX Aogonek Ugrave -50 KPX Aogonek Uhungarumlaut -50 KPX Aogonek Umacron -50 KPX Aogonek Uogonek -50 KPX Aogonek Uring -50 KPX Aogonek V -80 KPX Aogonek W -60 KPX Aogonek Y -110 KPX Aogonek Yacute -110 KPX Aogonek Ydieresis -110 KPX Aogonek u -30 KPX Aogonek uacute -30 KPX Aogonek ucircumflex -30 KPX Aogonek udieresis -30 KPX Aogonek ugrave -30 KPX Aogonek uhungarumlaut -30 KPX Aogonek umacron -30 KPX Aogonek uogonek -30 KPX Aogonek uring -30 KPX Aogonek v -40 KPX Aogonek w -30 KPX Aogonek y -30 KPX Aogonek yacute -30 KPX Aogonek ydieresis -30 KPX Aring C -40 KPX Aring Cacute -40 KPX Aring Ccaron -40 KPX Aring Ccedilla -40 KPX Aring G -50 KPX Aring Gbreve -50 KPX Aring Gcommaaccent -50 KPX Aring O -40 KPX Aring Oacute -40 KPX Aring Ocircumflex -40 KPX Aring Odieresis -40 KPX Aring Ograve -40 KPX Aring Ohungarumlaut -40 KPX Aring Omacron -40 KPX Aring Oslash -40 KPX Aring Otilde -40 KPX Aring Q -40 KPX Aring T -90 KPX Aring Tcaron -90 KPX Aring Tcommaaccent -90 KPX Aring U -50 KPX Aring Uacute -50 KPX Aring Ucircumflex -50 KPX Aring Udieresis -50 KPX Aring Ugrave -50 KPX Aring Uhungarumlaut -50 KPX Aring Umacron -50 KPX Aring Uogonek -50 KPX Aring Uring -50 KPX Aring V -80 KPX Aring W -60 KPX Aring Y -110 KPX Aring Yacute -110 KPX Aring Ydieresis -110 KPX Aring u -30 KPX Aring uacute -30 KPX Aring ucircumflex -30 KPX Aring udieresis -30 KPX Aring ugrave -30 KPX Aring uhungarumlaut -30 KPX Aring umacron -30 KPX Aring uogonek -30 KPX Aring uring -30 KPX Aring v -40 KPX Aring w -30 KPX Aring y -30 KPX Aring yacute -30 KPX Aring ydieresis -30 KPX Atilde C -40 KPX Atilde Cacute -40 KPX Atilde Ccaron -40 KPX Atilde Ccedilla -40 KPX Atilde G -50 KPX Atilde Gbreve -50 KPX Atilde Gcommaaccent -50 KPX Atilde O -40 KPX Atilde Oacute -40 KPX Atilde Ocircumflex -40 KPX Atilde Odieresis -40 KPX Atilde Ograve -40 KPX Atilde Ohungarumlaut -40 KPX Atilde Omacron -40 KPX Atilde Oslash -40 KPX Atilde Otilde -40 KPX Atilde Q -40 KPX Atilde T -90 KPX Atilde Tcaron -90 KPX Atilde Tcommaaccent -90 KPX Atilde U -50 KPX Atilde Uacute -50 KPX Atilde Ucircumflex -50 KPX Atilde Udieresis -50 KPX Atilde Ugrave -50 KPX Atilde Uhungarumlaut -50 KPX Atilde Umacron -50 KPX Atilde Uogonek -50 KPX Atilde Uring -50 KPX Atilde V -80 KPX Atilde W -60 KPX Atilde Y -110 KPX Atilde Yacute -110 KPX Atilde Ydieresis -110 KPX Atilde u -30 KPX Atilde uacute -30 KPX Atilde ucircumflex -30 KPX Atilde udieresis -30 KPX Atilde ugrave -30 KPX Atilde uhungarumlaut -30 KPX Atilde umacron -30 KPX Atilde uogonek -30 KPX Atilde uring -30 KPX Atilde v -40 KPX Atilde w -30 KPX Atilde y -30 KPX Atilde yacute -30 KPX Atilde ydieresis -30 KPX B A -30 KPX B Aacute -30 KPX B Abreve -30 KPX B Acircumflex -30 KPX B Adieresis -30 KPX B Agrave -30 KPX B Amacron -30 KPX B Aogonek -30 KPX B Aring -30 KPX B Atilde -30 KPX B U -10 KPX B Uacute -10 KPX B Ucircumflex -10 KPX B Udieresis -10 KPX B Ugrave -10 KPX B Uhungarumlaut -10 KPX B Umacron -10 KPX B Uogonek -10 KPX B Uring -10 KPX D A -40 KPX D Aacute -40 KPX D Abreve -40 KPX D Acircumflex -40 KPX D Adieresis -40 KPX D Agrave -40 KPX D Amacron -40 KPX D Aogonek -40 KPX D Aring -40 KPX D Atilde -40 KPX D V -40 KPX D W -40 KPX D Y -70 KPX D Yacute -70 KPX D Ydieresis -70 KPX D comma -30 KPX D period -30 KPX Dcaron A -40 KPX Dcaron Aacute -40 KPX Dcaron Abreve -40 KPX Dcaron Acircumflex -40 KPX Dcaron Adieresis -40 KPX Dcaron Agrave -40 KPX Dcaron Amacron -40 KPX Dcaron Aogonek -40 KPX Dcaron Aring -40 KPX Dcaron Atilde -40 KPX Dcaron V -40 KPX Dcaron W -40 KPX Dcaron Y -70 KPX Dcaron Yacute -70 KPX Dcaron Ydieresis -70 KPX Dcaron comma -30 KPX Dcaron period -30 KPX Dcroat A -40 KPX Dcroat Aacute -40 KPX Dcroat Abreve -40 KPX Dcroat Acircumflex -40 KPX Dcroat Adieresis -40 KPX Dcroat Agrave -40 KPX Dcroat Amacron -40 KPX Dcroat Aogonek -40 KPX Dcroat Aring -40 KPX Dcroat Atilde -40 KPX Dcroat V -40 KPX Dcroat W -40 KPX Dcroat Y -70 KPX Dcroat Yacute -70 KPX Dcroat Ydieresis -70 KPX Dcroat comma -30 KPX Dcroat period -30 KPX F A -80 KPX F Aacute -80 KPX F Abreve -80 KPX F Acircumflex -80 KPX F Adieresis -80 KPX F Agrave -80 KPX F Amacron -80 KPX F Aogonek -80 KPX F Aring -80 KPX F Atilde -80 KPX F a -20 KPX F aacute -20 KPX F abreve -20 KPX F acircumflex -20 KPX F adieresis -20 KPX F agrave -20 KPX F amacron -20 KPX F aogonek -20 KPX F aring -20 KPX F atilde -20 KPX F comma -100 KPX F period -100 KPX J A -20 KPX J Aacute -20 KPX J Abreve -20 KPX J Acircumflex -20 KPX J Adieresis -20 KPX J Agrave -20 KPX J Amacron -20 KPX J Aogonek -20 KPX J Aring -20 KPX J Atilde -20 KPX J comma -20 KPX J period -20 KPX J u -20 KPX J uacute -20 KPX J ucircumflex -20 KPX J udieresis -20 KPX J ugrave -20 KPX J uhungarumlaut -20 KPX J umacron -20 KPX J uogonek -20 KPX J uring -20 KPX K O -30 KPX K Oacute -30 KPX K Ocircumflex -30 KPX K Odieresis -30 KPX K Ograve -30 KPX K Ohungarumlaut -30 KPX K Omacron -30 KPX K Oslash -30 KPX K Otilde -30 KPX K e -15 KPX K eacute -15 KPX K ecaron -15 KPX K ecircumflex -15 KPX K edieresis -15 KPX K edotaccent -15 KPX K egrave -15 KPX K emacron -15 KPX K eogonek -15 KPX K o -35 KPX K oacute -35 KPX K ocircumflex -35 KPX K odieresis -35 KPX K ograve -35 KPX K ohungarumlaut -35 KPX K omacron -35 KPX K oslash -35 KPX K otilde -35 KPX K u -30 KPX K uacute -30 KPX K ucircumflex -30 KPX K udieresis -30 KPX K ugrave -30 KPX K uhungarumlaut -30 KPX K umacron -30 KPX K uogonek -30 KPX K uring -30 KPX K y -40 KPX K yacute -40 KPX K ydieresis -40 KPX Kcommaaccent O -30 KPX Kcommaaccent Oacute -30 KPX Kcommaaccent Ocircumflex -30 KPX Kcommaaccent Odieresis -30 KPX Kcommaaccent Ograve -30 KPX Kcommaaccent Ohungarumlaut -30 KPX Kcommaaccent Omacron -30 KPX Kcommaaccent Oslash -30 KPX Kcommaaccent Otilde -30 KPX Kcommaaccent e -15 KPX Kcommaaccent eacute -15 KPX Kcommaaccent ecaron -15 KPX Kcommaaccent ecircumflex -15 KPX Kcommaaccent edieresis -15 KPX Kcommaaccent edotaccent -15 KPX Kcommaaccent egrave -15 KPX Kcommaaccent emacron -15 KPX Kcommaaccent eogonek -15 KPX Kcommaaccent o -35 KPX Kcommaaccent oacute -35 KPX Kcommaaccent ocircumflex -35 KPX Kcommaaccent odieresis -35 KPX Kcommaaccent ograve -35 KPX Kcommaaccent ohungarumlaut -35 KPX Kcommaaccent omacron -35 KPX Kcommaaccent oslash -35 KPX Kcommaaccent otilde -35 KPX Kcommaaccent u -30 KPX Kcommaaccent uacute -30 KPX Kcommaaccent ucircumflex -30 KPX Kcommaaccent udieresis -30 KPX Kcommaaccent ugrave -30 KPX Kcommaaccent uhungarumlaut -30 KPX Kcommaaccent umacron -30 KPX Kcommaaccent uogonek -30 KPX Kcommaaccent uring -30 KPX Kcommaaccent y -40 KPX Kcommaaccent yacute -40 KPX Kcommaaccent ydieresis -40 KPX L T -90 KPX L Tcaron -90 KPX L Tcommaaccent -90 KPX L V -110 KPX L W -80 KPX L Y -120 KPX L Yacute -120 KPX L Ydieresis -120 KPX L quotedblright -140 KPX L quoteright -140 KPX L y -30 KPX L yacute -30 KPX L ydieresis -30 KPX Lacute T -90 KPX Lacute Tcaron -90 KPX Lacute Tcommaaccent -90 KPX Lacute V -110 KPX Lacute W -80 KPX Lacute Y -120 KPX Lacute Yacute -120 KPX Lacute Ydieresis -120 KPX Lacute quotedblright -140 KPX Lacute quoteright -140 KPX Lacute y -30 KPX Lacute yacute -30 KPX Lacute ydieresis -30 KPX Lcommaaccent T -90 KPX Lcommaaccent Tcaron -90 KPX Lcommaaccent Tcommaaccent -90 KPX Lcommaaccent V -110 KPX Lcommaaccent W -80 KPX Lcommaaccent Y -120 KPX Lcommaaccent Yacute -120 KPX Lcommaaccent Ydieresis -120 KPX Lcommaaccent quotedblright -140 KPX Lcommaaccent quoteright -140 KPX Lcommaaccent y -30 KPX Lcommaaccent yacute -30 KPX Lcommaaccent ydieresis -30 KPX Lslash T -90 KPX Lslash Tcaron -90 KPX Lslash Tcommaaccent -90 KPX Lslash V -110 KPX Lslash W -80 KPX Lslash Y -120 KPX Lslash Yacute -120 KPX Lslash Ydieresis -120 KPX Lslash quotedblright -140 KPX Lslash quoteright -140 KPX Lslash y -30 KPX Lslash yacute -30 KPX Lslash ydieresis -30 KPX O A -50 KPX O Aacute -50 KPX O Abreve -50 KPX O Acircumflex -50 KPX O Adieresis -50 KPX O Agrave -50 KPX O Amacron -50 KPX O Aogonek -50 KPX O Aring -50 KPX O Atilde -50 KPX O T -40 KPX O Tcaron -40 KPX O Tcommaaccent -40 KPX O V -50 KPX O W -50 KPX O X -50 KPX O Y -70 KPX O Yacute -70 KPX O Ydieresis -70 KPX O comma -40 KPX O period -40 KPX Oacute A -50 KPX Oacute Aacute -50 KPX Oacute Abreve -50 KPX Oacute Acircumflex -50 KPX Oacute Adieresis -50 KPX Oacute Agrave -50 KPX Oacute Amacron -50 KPX Oacute Aogonek -50 KPX Oacute Aring -50 KPX Oacute Atilde -50 KPX Oacute T -40 KPX Oacute Tcaron -40 KPX Oacute Tcommaaccent -40 KPX Oacute V -50 KPX Oacute W -50 KPX Oacute X -50 KPX Oacute Y -70 KPX Oacute Yacute -70 KPX Oacute Ydieresis -70 KPX Oacute comma -40 KPX Oacute period -40 KPX Ocircumflex A -50 KPX Ocircumflex Aacute -50 KPX Ocircumflex Abreve -50 KPX Ocircumflex Acircumflex -50 KPX Ocircumflex Adieresis -50 KPX Ocircumflex Agrave -50 KPX Ocircumflex Amacron -50 KPX Ocircumflex Aogonek -50 KPX Ocircumflex Aring -50 KPX Ocircumflex Atilde -50 KPX Ocircumflex T -40 KPX Ocircumflex Tcaron -40 KPX Ocircumflex Tcommaaccent -40 KPX Ocircumflex V -50 KPX Ocircumflex W -50 KPX Ocircumflex X -50 KPX Ocircumflex Y -70 KPX Ocircumflex Yacute -70 KPX Ocircumflex Ydieresis -70 KPX Ocircumflex comma -40 KPX Ocircumflex period -40 KPX Odieresis A -50 KPX Odieresis Aacute -50 KPX Odieresis Abreve -50 KPX Odieresis Acircumflex -50 KPX Odieresis Adieresis -50 KPX Odieresis Agrave -50 KPX Odieresis Amacron -50 KPX Odieresis Aogonek -50 KPX Odieresis Aring -50 KPX Odieresis Atilde -50 KPX Odieresis T -40 KPX Odieresis Tcaron -40 KPX Odieresis Tcommaaccent -40 KPX Odieresis V -50 KPX Odieresis W -50 KPX Odieresis X -50 KPX Odieresis Y -70 KPX Odieresis Yacute -70 KPX Odieresis Ydieresis -70 KPX Odieresis comma -40 KPX Odieresis period -40 KPX Ograve A -50 KPX Ograve Aacute -50 KPX Ograve Abreve -50 KPX Ograve Acircumflex -50 KPX Ograve Adieresis -50 KPX Ograve Agrave -50 KPX Ograve Amacron -50 KPX Ograve Aogonek -50 KPX Ograve Aring -50 KPX Ograve Atilde -50 KPX Ograve T -40 KPX Ograve Tcaron -40 KPX Ograve Tcommaaccent -40 KPX Ograve V -50 KPX Ograve W -50 KPX Ograve X -50 KPX Ograve Y -70 KPX Ograve Yacute -70 KPX Ograve Ydieresis -70 KPX Ograve comma -40 KPX Ograve period -40 KPX Ohungarumlaut A -50 KPX Ohungarumlaut Aacute -50 KPX Ohungarumlaut Abreve -50 KPX Ohungarumlaut Acircumflex -50 KPX Ohungarumlaut Adieresis -50 KPX Ohungarumlaut Agrave -50 KPX Ohungarumlaut Amacron -50 KPX Ohungarumlaut Aogonek -50 KPX Ohungarumlaut Aring -50 KPX Ohungarumlaut Atilde -50 KPX Ohungarumlaut T -40 KPX Ohungarumlaut Tcaron -40 KPX Ohungarumlaut Tcommaaccent -40 KPX Ohungarumlaut V -50 KPX Ohungarumlaut W -50 KPX Ohungarumlaut X -50 KPX Ohungarumlaut Y -70 KPX Ohungarumlaut Yacute -70 KPX Ohungarumlaut Ydieresis -70 KPX Ohungarumlaut comma -40 KPX Ohungarumlaut period -40 KPX Omacron A -50 KPX Omacron Aacute -50 KPX Omacron Abreve -50 KPX Omacron Acircumflex -50 KPX Omacron Adieresis -50 KPX Omacron Agrave -50 KPX Omacron Amacron -50 KPX Omacron Aogonek -50 KPX Omacron Aring -50 KPX Omacron Atilde -50 KPX Omacron T -40 KPX Omacron Tcaron -40 KPX Omacron Tcommaaccent -40 KPX Omacron V -50 KPX Omacron W -50 KPX Omacron X -50 KPX Omacron Y -70 KPX Omacron Yacute -70 KPX Omacron Ydieresis -70 KPX Omacron comma -40 KPX Omacron period -40 KPX Oslash A -50 KPX Oslash Aacute -50 KPX Oslash Abreve -50 KPX Oslash Acircumflex -50 KPX Oslash Adieresis -50 KPX Oslash Agrave -50 KPX Oslash Amacron -50 KPX Oslash Aogonek -50 KPX Oslash Aring -50 KPX Oslash Atilde -50 KPX Oslash T -40 KPX Oslash Tcaron -40 KPX Oslash Tcommaaccent -40 KPX Oslash V -50 KPX Oslash W -50 KPX Oslash X -50 KPX Oslash Y -70 KPX Oslash Yacute -70 KPX Oslash Ydieresis -70 KPX Oslash comma -40 KPX Oslash period -40 KPX Otilde A -50 KPX Otilde Aacute -50 KPX Otilde Abreve -50 KPX Otilde Acircumflex -50 KPX Otilde Adieresis -50 KPX Otilde Agrave -50 KPX Otilde Amacron -50 KPX Otilde Aogonek -50 KPX Otilde Aring -50 KPX Otilde Atilde -50 KPX Otilde T -40 KPX Otilde Tcaron -40 KPX Otilde Tcommaaccent -40 KPX Otilde V -50 KPX Otilde W -50 KPX Otilde X -50 KPX Otilde Y -70 KPX Otilde Yacute -70 KPX Otilde Ydieresis -70 KPX Otilde comma -40 KPX Otilde period -40 KPX P A -100 KPX P Aacute -100 KPX P Abreve -100 KPX P Acircumflex -100 KPX P Adieresis -100 KPX P Agrave -100 KPX P Amacron -100 KPX P Aogonek -100 KPX P Aring -100 KPX P Atilde -100 KPX P a -30 KPX P aacute -30 KPX P abreve -30 KPX P acircumflex -30 KPX P adieresis -30 KPX P agrave -30 KPX P amacron -30 KPX P aogonek -30 KPX P aring -30 KPX P atilde -30 KPX P comma -120 KPX P e -30 KPX P eacute -30 KPX P ecaron -30 KPX P ecircumflex -30 KPX P edieresis -30 KPX P edotaccent -30 KPX P egrave -30 KPX P emacron -30 KPX P eogonek -30 KPX P o -40 KPX P oacute -40 KPX P ocircumflex -40 KPX P odieresis -40 KPX P ograve -40 KPX P ohungarumlaut -40 KPX P omacron -40 KPX P oslash -40 KPX P otilde -40 KPX P period -120 KPX Q U -10 KPX Q Uacute -10 KPX Q Ucircumflex -10 KPX Q Udieresis -10 KPX Q Ugrave -10 KPX Q Uhungarumlaut -10 KPX Q Umacron -10 KPX Q Uogonek -10 KPX Q Uring -10 KPX Q comma 20 KPX Q period 20 KPX R O -20 KPX R Oacute -20 KPX R Ocircumflex -20 KPX R Odieresis -20 KPX R Ograve -20 KPX R Ohungarumlaut -20 KPX R Omacron -20 KPX R Oslash -20 KPX R Otilde -20 KPX R T -20 KPX R Tcaron -20 KPX R Tcommaaccent -20 KPX R U -20 KPX R Uacute -20 KPX R Ucircumflex -20 KPX R Udieresis -20 KPX R Ugrave -20 KPX R Uhungarumlaut -20 KPX R Umacron -20 KPX R Uogonek -20 KPX R Uring -20 KPX R V -50 KPX R W -40 KPX R Y -50 KPX R Yacute -50 KPX R Ydieresis -50 KPX Racute O -20 KPX Racute Oacute -20 KPX Racute Ocircumflex -20 KPX Racute Odieresis -20 KPX Racute Ograve -20 KPX Racute Ohungarumlaut -20 KPX Racute Omacron -20 KPX Racute Oslash -20 KPX Racute Otilde -20 KPX Racute T -20 KPX Racute Tcaron -20 KPX Racute Tcommaaccent -20 KPX Racute U -20 KPX Racute Uacute -20 KPX Racute Ucircumflex -20 KPX Racute Udieresis -20 KPX Racute Ugrave -20 KPX Racute Uhungarumlaut -20 KPX Racute Umacron -20 KPX Racute Uogonek -20 KPX Racute Uring -20 KPX Racute V -50 KPX Racute W -40 KPX Racute Y -50 KPX Racute Yacute -50 KPX Racute Ydieresis -50 KPX Rcaron O -20 KPX Rcaron Oacute -20 KPX Rcaron Ocircumflex -20 KPX Rcaron Odieresis -20 KPX Rcaron Ograve -20 KPX Rcaron Ohungarumlaut -20 KPX Rcaron Omacron -20 KPX Rcaron Oslash -20 KPX Rcaron Otilde -20 KPX Rcaron T -20 KPX Rcaron Tcaron -20 KPX Rcaron Tcommaaccent -20 KPX Rcaron U -20 KPX Rcaron Uacute -20 KPX Rcaron Ucircumflex -20 KPX Rcaron Udieresis -20 KPX Rcaron Ugrave -20 KPX Rcaron Uhungarumlaut -20 KPX Rcaron Umacron -20 KPX Rcaron Uogonek -20 KPX Rcaron Uring -20 KPX Rcaron V -50 KPX Rcaron W -40 KPX Rcaron Y -50 KPX Rcaron Yacute -50 KPX Rcaron Ydieresis -50 KPX Rcommaaccent O -20 KPX Rcommaaccent Oacute -20 KPX Rcommaaccent Ocircumflex -20 KPX Rcommaaccent Odieresis -20 KPX Rcommaaccent Ograve -20 KPX Rcommaaccent Ohungarumlaut -20 KPX Rcommaaccent Omacron -20 KPX Rcommaaccent Oslash -20 KPX Rcommaaccent Otilde -20 KPX Rcommaaccent T -20 KPX Rcommaaccent Tcaron -20 KPX Rcommaaccent Tcommaaccent -20 KPX Rcommaaccent U -20 KPX Rcommaaccent Uacute -20 KPX Rcommaaccent Ucircumflex -20 KPX Rcommaaccent Udieresis -20 KPX Rcommaaccent Ugrave -20 KPX Rcommaaccent Uhungarumlaut -20 KPX Rcommaaccent Umacron -20 KPX Rcommaaccent Uogonek -20 KPX Rcommaaccent Uring -20 KPX Rcommaaccent V -50 KPX Rcommaaccent W -40 KPX Rcommaaccent Y -50 KPX Rcommaaccent Yacute -50 KPX Rcommaaccent Ydieresis -50 KPX T A -90 KPX T Aacute -90 KPX T Abreve -90 KPX T Acircumflex -90 KPX T Adieresis -90 KPX T Agrave -90 KPX T Amacron -90 KPX T Aogonek -90 KPX T Aring -90 KPX T Atilde -90 KPX T O -40 KPX T Oacute -40 KPX T Ocircumflex -40 KPX T Odieresis -40 KPX T Ograve -40 KPX T Ohungarumlaut -40 KPX T Omacron -40 KPX T Oslash -40 KPX T Otilde -40 KPX T a -80 KPX T aacute -80 KPX T abreve -80 KPX T acircumflex -80 KPX T adieresis -80 KPX T agrave -80 KPX T amacron -80 KPX T aogonek -80 KPX T aring -80 KPX T atilde -80 KPX T colon -40 KPX T comma -80 KPX T e -60 KPX T eacute -60 KPX T ecaron -60 KPX T ecircumflex -60 KPX T edieresis -60 KPX T edotaccent -60 KPX T egrave -60 KPX T emacron -60 KPX T eogonek -60 KPX T hyphen -120 KPX T o -80 KPX T oacute -80 KPX T ocircumflex -80 KPX T odieresis -80 KPX T ograve -80 KPX T ohungarumlaut -80 KPX T omacron -80 KPX T oslash -80 KPX T otilde -80 KPX T period -80 KPX T r -80 KPX T racute -80 KPX T rcommaaccent -80 KPX T semicolon -40 KPX T u -90 KPX T uacute -90 KPX T ucircumflex -90 KPX T udieresis -90 KPX T ugrave -90 KPX T uhungarumlaut -90 KPX T umacron -90 KPX T uogonek -90 KPX T uring -90 KPX T w -60 KPX T y -60 KPX T yacute -60 KPX T ydieresis -60 KPX Tcaron A -90 KPX Tcaron Aacute -90 KPX Tcaron Abreve -90 KPX Tcaron Acircumflex -90 KPX Tcaron Adieresis -90 KPX Tcaron Agrave -90 KPX Tcaron Amacron -90 KPX Tcaron Aogonek -90 KPX Tcaron Aring -90 KPX Tcaron Atilde -90 KPX Tcaron O -40 KPX Tcaron Oacute -40 KPX Tcaron Ocircumflex -40 KPX Tcaron Odieresis -40 KPX Tcaron Ograve -40 KPX Tcaron Ohungarumlaut -40 KPX Tcaron Omacron -40 KPX Tcaron Oslash -40 KPX Tcaron Otilde -40 KPX Tcaron a -80 KPX Tcaron aacute -80 KPX Tcaron abreve -80 KPX Tcaron acircumflex -80 KPX Tcaron adieresis -80 KPX Tcaron agrave -80 KPX Tcaron amacron -80 KPX Tcaron aogonek -80 KPX Tcaron aring -80 KPX Tcaron atilde -80 KPX Tcaron colon -40 KPX Tcaron comma -80 KPX Tcaron e -60 KPX Tcaron eacute -60 KPX Tcaron ecaron -60 KPX Tcaron ecircumflex -60 KPX Tcaron edieresis -60 KPX Tcaron edotaccent -60 KPX Tcaron egrave -60 KPX Tcaron emacron -60 KPX Tcaron eogonek -60 KPX Tcaron hyphen -120 KPX Tcaron o -80 KPX Tcaron oacute -80 KPX Tcaron ocircumflex -80 KPX Tcaron odieresis -80 KPX Tcaron ograve -80 KPX Tcaron ohungarumlaut -80 KPX Tcaron omacron -80 KPX Tcaron oslash -80 KPX Tcaron otilde -80 KPX Tcaron period -80 KPX Tcaron r -80 KPX Tcaron racute -80 KPX Tcaron rcommaaccent -80 KPX Tcaron semicolon -40 KPX Tcaron u -90 KPX Tcaron uacute -90 KPX Tcaron ucircumflex -90 KPX Tcaron udieresis -90 KPX Tcaron ugrave -90 KPX Tcaron uhungarumlaut -90 KPX Tcaron umacron -90 KPX Tcaron uogonek -90 KPX Tcaron uring -90 KPX Tcaron w -60 KPX Tcaron y -60 KPX Tcaron yacute -60 KPX Tcaron ydieresis -60 KPX Tcommaaccent A -90 KPX Tcommaaccent Aacute -90 KPX Tcommaaccent Abreve -90 KPX Tcommaaccent Acircumflex -90 KPX Tcommaaccent Adieresis -90 KPX Tcommaaccent Agrave -90 KPX Tcommaaccent Amacron -90 KPX Tcommaaccent Aogonek -90 KPX Tcommaaccent Aring -90 KPX Tcommaaccent Atilde -90 KPX Tcommaaccent O -40 KPX Tcommaaccent Oacute -40 KPX Tcommaaccent Ocircumflex -40 KPX Tcommaaccent Odieresis -40 KPX Tcommaaccent Ograve -40 KPX Tcommaaccent Ohungarumlaut -40 KPX Tcommaaccent Omacron -40 KPX Tcommaaccent Oslash -40 KPX Tcommaaccent Otilde -40 KPX Tcommaaccent a -80 KPX Tcommaaccent aacute -80 KPX Tcommaaccent abreve -80 KPX Tcommaaccent acircumflex -80 KPX Tcommaaccent adieresis -80 KPX Tcommaaccent agrave -80 KPX Tcommaaccent amacron -80 KPX Tcommaaccent aogonek -80 KPX Tcommaaccent aring -80 KPX Tcommaaccent atilde -80 KPX Tcommaaccent colon -40 KPX Tcommaaccent comma -80 KPX Tcommaaccent e -60 KPX Tcommaaccent eacute -60 KPX Tcommaaccent ecaron -60 KPX Tcommaaccent ecircumflex -60 KPX Tcommaaccent edieresis -60 KPX Tcommaaccent edotaccent -60 KPX Tcommaaccent egrave -60 KPX Tcommaaccent emacron -60 KPX Tcommaaccent eogonek -60 KPX Tcommaaccent hyphen -120 KPX Tcommaaccent o -80 KPX Tcommaaccent oacute -80 KPX Tcommaaccent ocircumflex -80 KPX Tcommaaccent odieresis -80 KPX Tcommaaccent ograve -80 KPX Tcommaaccent ohungarumlaut -80 KPX Tcommaaccent omacron -80 KPX Tcommaaccent oslash -80 KPX Tcommaaccent otilde -80 KPX Tcommaaccent period -80 KPX Tcommaaccent r -80 KPX Tcommaaccent racute -80 KPX Tcommaaccent rcommaaccent -80 KPX Tcommaaccent semicolon -40 KPX Tcommaaccent u -90 KPX Tcommaaccent uacute -90 KPX Tcommaaccent ucircumflex -90 KPX Tcommaaccent udieresis -90 KPX Tcommaaccent ugrave -90 KPX Tcommaaccent uhungarumlaut -90 KPX Tcommaaccent umacron -90 KPX Tcommaaccent uogonek -90 KPX Tcommaaccent uring -90 KPX Tcommaaccent w -60 KPX Tcommaaccent y -60 KPX Tcommaaccent yacute -60 KPX Tcommaaccent ydieresis -60 KPX U A -50 KPX U Aacute -50 KPX U Abreve -50 KPX U Acircumflex -50 KPX U Adieresis -50 KPX U Agrave -50 KPX U Amacron -50 KPX U Aogonek -50 KPX U Aring -50 KPX U Atilde -50 KPX U comma -30 KPX U period -30 KPX Uacute A -50 KPX Uacute Aacute -50 KPX Uacute Abreve -50 KPX Uacute Acircumflex -50 KPX Uacute Adieresis -50 KPX Uacute Agrave -50 KPX Uacute Amacron -50 KPX Uacute Aogonek -50 KPX Uacute Aring -50 KPX Uacute Atilde -50 KPX Uacute comma -30 KPX Uacute period -30 KPX Ucircumflex A -50 KPX Ucircumflex Aacute -50 KPX Ucircumflex Abreve -50 KPX Ucircumflex Acircumflex -50 KPX Ucircumflex Adieresis -50 KPX Ucircumflex Agrave -50 KPX Ucircumflex Amacron -50 KPX Ucircumflex Aogonek -50 KPX Ucircumflex Aring -50 KPX Ucircumflex Atilde -50 KPX Ucircumflex comma -30 KPX Ucircumflex period -30 KPX Udieresis A -50 KPX Udieresis Aacute -50 KPX Udieresis Abreve -50 KPX Udieresis Acircumflex -50 KPX Udieresis Adieresis -50 KPX Udieresis Agrave -50 KPX Udieresis Amacron -50 KPX Udieresis Aogonek -50 KPX Udieresis Aring -50 KPX Udieresis Atilde -50 KPX Udieresis comma -30 KPX Udieresis period -30 KPX Ugrave A -50 KPX Ugrave Aacute -50 KPX Ugrave Abreve -50 KPX Ugrave Acircumflex -50 KPX Ugrave Adieresis -50 KPX Ugrave Agrave -50 KPX Ugrave Amacron -50 KPX Ugrave Aogonek -50 KPX Ugrave Aring -50 KPX Ugrave Atilde -50 KPX Ugrave comma -30 KPX Ugrave period -30 KPX Uhungarumlaut A -50 KPX Uhungarumlaut Aacute -50 KPX Uhungarumlaut Abreve -50 KPX Uhungarumlaut Acircumflex -50 KPX Uhungarumlaut Adieresis -50 KPX Uhungarumlaut Agrave -50 KPX Uhungarumlaut Amacron -50 KPX Uhungarumlaut Aogonek -50 KPX Uhungarumlaut Aring -50 KPX Uhungarumlaut Atilde -50 KPX Uhungarumlaut comma -30 KPX Uhungarumlaut period -30 KPX Umacron A -50 KPX Umacron Aacute -50 KPX Umacron Abreve -50 KPX Umacron Acircumflex -50 KPX Umacron Adieresis -50 KPX Umacron Agrave -50 KPX Umacron Amacron -50 KPX Umacron Aogonek -50 KPX Umacron Aring -50 KPX Umacron Atilde -50 KPX Umacron comma -30 KPX Umacron period -30 KPX Uogonek A -50 KPX Uogonek Aacute -50 KPX Uogonek Abreve -50 KPX Uogonek Acircumflex -50 KPX Uogonek Adieresis -50 KPX Uogonek Agrave -50 KPX Uogonek Amacron -50 KPX Uogonek Aogonek -50 KPX Uogonek Aring -50 KPX Uogonek Atilde -50 KPX Uogonek comma -30 KPX Uogonek period -30 KPX Uring A -50 KPX Uring Aacute -50 KPX Uring Abreve -50 KPX Uring Acircumflex -50 KPX Uring Adieresis -50 KPX Uring Agrave -50 KPX Uring Amacron -50 KPX Uring Aogonek -50 KPX Uring Aring -50 KPX Uring Atilde -50 KPX Uring comma -30 KPX Uring period -30 KPX V A -80 KPX V Aacute -80 KPX V Abreve -80 KPX V Acircumflex -80 KPX V Adieresis -80 KPX V Agrave -80 KPX V Amacron -80 KPX V Aogonek -80 KPX V Aring -80 KPX V Atilde -80 KPX V G -50 KPX V Gbreve -50 KPX V Gcommaaccent -50 KPX V O -50 KPX V Oacute -50 KPX V Ocircumflex -50 KPX V Odieresis -50 KPX V Ograve -50 KPX V Ohungarumlaut -50 KPX V Omacron -50 KPX V Oslash -50 KPX V Otilde -50 KPX V a -60 KPX V aacute -60 KPX V abreve -60 KPX V acircumflex -60 KPX V adieresis -60 KPX V agrave -60 KPX V amacron -60 KPX V aogonek -60 KPX V aring -60 KPX V atilde -60 KPX V colon -40 KPX V comma -120 KPX V e -50 KPX V eacute -50 KPX V ecaron -50 KPX V ecircumflex -50 KPX V edieresis -50 KPX V edotaccent -50 KPX V egrave -50 KPX V emacron -50 KPX V eogonek -50 KPX V hyphen -80 KPX V o -90 KPX V oacute -90 KPX V ocircumflex -90 KPX V odieresis -90 KPX V ograve -90 KPX V ohungarumlaut -90 KPX V omacron -90 KPX V oslash -90 KPX V otilde -90 KPX V period -120 KPX V semicolon -40 KPX V u -60 KPX V uacute -60 KPX V ucircumflex -60 KPX V udieresis -60 KPX V ugrave -60 KPX V uhungarumlaut -60 KPX V umacron -60 KPX V uogonek -60 KPX V uring -60 KPX W A -60 KPX W Aacute -60 KPX W Abreve -60 KPX W Acircumflex -60 KPX W Adieresis -60 KPX W Agrave -60 KPX W Amacron -60 KPX W Aogonek -60 KPX W Aring -60 KPX W Atilde -60 KPX W O -20 KPX W Oacute -20 KPX W Ocircumflex -20 KPX W Odieresis -20 KPX W Ograve -20 KPX W Ohungarumlaut -20 KPX W Omacron -20 KPX W Oslash -20 KPX W Otilde -20 KPX W a -40 KPX W aacute -40 KPX W abreve -40 KPX W acircumflex -40 KPX W adieresis -40 KPX W agrave -40 KPX W amacron -40 KPX W aogonek -40 KPX W aring -40 KPX W atilde -40 KPX W colon -10 KPX W comma -80 KPX W e -35 KPX W eacute -35 KPX W ecaron -35 KPX W ecircumflex -35 KPX W edieresis -35 KPX W edotaccent -35 KPX W egrave -35 KPX W emacron -35 KPX W eogonek -35 KPX W hyphen -40 KPX W o -60 KPX W oacute -60 KPX W ocircumflex -60 KPX W odieresis -60 KPX W ograve -60 KPX W ohungarumlaut -60 KPX W omacron -60 KPX W oslash -60 KPX W otilde -60 KPX W period -80 KPX W semicolon -10 KPX W u -45 KPX W uacute -45 KPX W ucircumflex -45 KPX W udieresis -45 KPX W ugrave -45 KPX W uhungarumlaut -45 KPX W umacron -45 KPX W uogonek -45 KPX W uring -45 KPX W y -20 KPX W yacute -20 KPX W ydieresis -20 KPX Y A -110 KPX Y Aacute -110 KPX Y Abreve -110 KPX Y Acircumflex -110 KPX Y Adieresis -110 KPX Y Agrave -110 KPX Y Amacron -110 KPX Y Aogonek -110 KPX Y Aring -110 KPX Y Atilde -110 KPX Y O -70 KPX Y Oacute -70 KPX Y Ocircumflex -70 KPX Y Odieresis -70 KPX Y Ograve -70 KPX Y Ohungarumlaut -70 KPX Y Omacron -70 KPX Y Oslash -70 KPX Y Otilde -70 KPX Y a -90 KPX Y aacute -90 KPX Y abreve -90 KPX Y acircumflex -90 KPX Y adieresis -90 KPX Y agrave -90 KPX Y amacron -90 KPX Y aogonek -90 KPX Y aring -90 KPX Y atilde -90 KPX Y colon -50 KPX Y comma -100 KPX Y e -80 KPX Y eacute -80 KPX Y ecaron -80 KPX Y ecircumflex -80 KPX Y edieresis -80 KPX Y edotaccent -80 KPX Y egrave -80 KPX Y emacron -80 KPX Y eogonek -80 KPX Y o -100 KPX Y oacute -100 KPX Y ocircumflex -100 KPX Y odieresis -100 KPX Y ograve -100 KPX Y ohungarumlaut -100 KPX Y omacron -100 KPX Y oslash -100 KPX Y otilde -100 KPX Y period -100 KPX Y semicolon -50 KPX Y u -100 KPX Y uacute -100 KPX Y ucircumflex -100 KPX Y udieresis -100 KPX Y ugrave -100 KPX Y uhungarumlaut -100 KPX Y umacron -100 KPX Y uogonek -100 KPX Y uring -100 KPX Yacute A -110 KPX Yacute Aacute -110 KPX Yacute Abreve -110 KPX Yacute Acircumflex -110 KPX Yacute Adieresis -110 KPX Yacute Agrave -110 KPX Yacute Amacron -110 KPX Yacute Aogonek -110 KPX Yacute Aring -110 KPX Yacute Atilde -110 KPX Yacute O -70 KPX Yacute Oacute -70 KPX Yacute Ocircumflex -70 KPX Yacute Odieresis -70 KPX Yacute Ograve -70 KPX Yacute Ohungarumlaut -70 KPX Yacute Omacron -70 KPX Yacute Oslash -70 KPX Yacute Otilde -70 KPX Yacute a -90 KPX Yacute aacute -90 KPX Yacute abreve -90 KPX Yacute acircumflex -90 KPX Yacute adieresis -90 KPX Yacute agrave -90 KPX Yacute amacron -90 KPX Yacute aogonek -90 KPX Yacute aring -90 KPX Yacute atilde -90 KPX Yacute colon -50 KPX Yacute comma -100 KPX Yacute e -80 KPX Yacute eacute -80 KPX Yacute ecaron -80 KPX Yacute ecircumflex -80 KPX Yacute edieresis -80 KPX Yacute edotaccent -80 KPX Yacute egrave -80 KPX Yacute emacron -80 KPX Yacute eogonek -80 KPX Yacute o -100 KPX Yacute oacute -100 KPX Yacute ocircumflex -100 KPX Yacute odieresis -100 KPX Yacute ograve -100 KPX Yacute ohungarumlaut -100 KPX Yacute omacron -100 KPX Yacute oslash -100 KPX Yacute otilde -100 KPX Yacute period -100 KPX Yacute semicolon -50 KPX Yacute u -100 KPX Yacute uacute -100 KPX Yacute ucircumflex -100 KPX Yacute udieresis -100 KPX Yacute ugrave -100 KPX Yacute uhungarumlaut -100 KPX Yacute umacron -100 KPX Yacute uogonek -100 KPX Yacute uring -100 KPX Ydieresis A -110 KPX Ydieresis Aacute -110 KPX Ydieresis Abreve -110 KPX Ydieresis Acircumflex -110 KPX Ydieresis Adieresis -110 KPX Ydieresis Agrave -110 KPX Ydieresis Amacron -110 KPX Ydieresis Aogonek -110 KPX Ydieresis Aring -110 KPX Ydieresis Atilde -110 KPX Ydieresis O -70 KPX Ydieresis Oacute -70 KPX Ydieresis Ocircumflex -70 KPX Ydieresis Odieresis -70 KPX Ydieresis Ograve -70 KPX Ydieresis Ohungarumlaut -70 KPX Ydieresis Omacron -70 KPX Ydieresis Oslash -70 KPX Ydieresis Otilde -70 KPX Ydieresis a -90 KPX Ydieresis aacute -90 KPX Ydieresis abreve -90 KPX Ydieresis acircumflex -90 KPX Ydieresis adieresis -90 KPX Ydieresis agrave -90 KPX Ydieresis amacron -90 KPX Ydieresis aogonek -90 KPX Ydieresis aring -90 KPX Ydieresis atilde -90 KPX Ydieresis colon -50 KPX Ydieresis comma -100 KPX Ydieresis e -80 KPX Ydieresis eacute -80 KPX Ydieresis ecaron -80 KPX Ydieresis ecircumflex -80 KPX Ydieresis edieresis -80 KPX Ydieresis edotaccent -80 KPX Ydieresis egrave -80 KPX Ydieresis emacron -80 KPX Ydieresis eogonek -80 KPX Ydieresis o -100 KPX Ydieresis oacute -100 KPX Ydieresis ocircumflex -100 KPX Ydieresis odieresis -100 KPX Ydieresis ograve -100 KPX Ydieresis ohungarumlaut -100 KPX Ydieresis omacron -100 KPX Ydieresis oslash -100 KPX Ydieresis otilde -100 KPX Ydieresis period -100 KPX Ydieresis semicolon -50 KPX Ydieresis u -100 KPX Ydieresis uacute -100 KPX Ydieresis ucircumflex -100 KPX Ydieresis udieresis -100 KPX Ydieresis ugrave -100 KPX Ydieresis uhungarumlaut -100 KPX Ydieresis umacron -100 KPX Ydieresis uogonek -100 KPX Ydieresis uring -100 KPX a g -10 KPX a gbreve -10 KPX a gcommaaccent -10 KPX a v -15 KPX a w -15 KPX a y -20 KPX a yacute -20 KPX a ydieresis -20 KPX aacute g -10 KPX aacute gbreve -10 KPX aacute gcommaaccent -10 KPX aacute v -15 KPX aacute w -15 KPX aacute y -20 KPX aacute yacute -20 KPX aacute ydieresis -20 KPX abreve g -10 KPX abreve gbreve -10 KPX abreve gcommaaccent -10 KPX abreve v -15 KPX abreve w -15 KPX abreve y -20 KPX abreve yacute -20 KPX abreve ydieresis -20 KPX acircumflex g -10 KPX acircumflex gbreve -10 KPX acircumflex gcommaaccent -10 KPX acircumflex v -15 KPX acircumflex w -15 KPX acircumflex y -20 KPX acircumflex yacute -20 KPX acircumflex ydieresis -20 KPX adieresis g -10 KPX adieresis gbreve -10 KPX adieresis gcommaaccent -10 KPX adieresis v -15 KPX adieresis w -15 KPX adieresis y -20 KPX adieresis yacute -20 KPX adieresis ydieresis -20 KPX agrave g -10 KPX agrave gbreve -10 KPX agrave gcommaaccent -10 KPX agrave v -15 KPX agrave w -15 KPX agrave y -20 KPX agrave yacute -20 KPX agrave ydieresis -20 KPX amacron g -10 KPX amacron gbreve -10 KPX amacron gcommaaccent -10 KPX amacron v -15 KPX amacron w -15 KPX amacron y -20 KPX amacron yacute -20 KPX amacron ydieresis -20 KPX aogonek g -10 KPX aogonek gbreve -10 KPX aogonek gcommaaccent -10 KPX aogonek v -15 KPX aogonek w -15 KPX aogonek y -20 KPX aogonek yacute -20 KPX aogonek ydieresis -20 KPX aring g -10 KPX aring gbreve -10 KPX aring gcommaaccent -10 KPX aring v -15 KPX aring w -15 KPX aring y -20 KPX aring yacute -20 KPX aring ydieresis -20 KPX atilde g -10 KPX atilde gbreve -10 KPX atilde gcommaaccent -10 KPX atilde v -15 KPX atilde w -15 KPX atilde y -20 KPX atilde yacute -20 KPX atilde ydieresis -20 KPX b l -10 KPX b lacute -10 KPX b lcommaaccent -10 KPX b lslash -10 KPX b u -20 KPX b uacute -20 KPX b ucircumflex -20 KPX b udieresis -20 KPX b ugrave -20 KPX b uhungarumlaut -20 KPX b umacron -20 KPX b uogonek -20 KPX b uring -20 KPX b v -20 KPX b y -20 KPX b yacute -20 KPX b ydieresis -20 KPX c h -10 KPX c k -20 KPX c kcommaaccent -20 KPX c l -20 KPX c lacute -20 KPX c lcommaaccent -20 KPX c lslash -20 KPX c y -10 KPX c yacute -10 KPX c ydieresis -10 KPX cacute h -10 KPX cacute k -20 KPX cacute kcommaaccent -20 KPX cacute l -20 KPX cacute lacute -20 KPX cacute lcommaaccent -20 KPX cacute lslash -20 KPX cacute y -10 KPX cacute yacute -10 KPX cacute ydieresis -10 KPX ccaron h -10 KPX ccaron k -20 KPX ccaron kcommaaccent -20 KPX ccaron l -20 KPX ccaron lacute -20 KPX ccaron lcommaaccent -20 KPX ccaron lslash -20 KPX ccaron y -10 KPX ccaron yacute -10 KPX ccaron ydieresis -10 KPX ccedilla h -10 KPX ccedilla k -20 KPX ccedilla kcommaaccent -20 KPX ccedilla l -20 KPX ccedilla lacute -20 KPX ccedilla lcommaaccent -20 KPX ccedilla lslash -20 KPX ccedilla y -10 KPX ccedilla yacute -10 KPX ccedilla ydieresis -10 KPX colon space -40 KPX comma quotedblright -120 KPX comma quoteright -120 KPX comma space -40 KPX d d -10 KPX d dcroat -10 KPX d v -15 KPX d w -15 KPX d y -15 KPX d yacute -15 KPX d ydieresis -15 KPX dcroat d -10 KPX dcroat dcroat -10 KPX dcroat v -15 KPX dcroat w -15 KPX dcroat y -15 KPX dcroat yacute -15 KPX dcroat ydieresis -15 KPX e comma 10 KPX e period 20 KPX e v -15 KPX e w -15 KPX e x -15 KPX e y -15 KPX e yacute -15 KPX e ydieresis -15 KPX eacute comma 10 KPX eacute period 20 KPX eacute v -15 KPX eacute w -15 KPX eacute x -15 KPX eacute y -15 KPX eacute yacute -15 KPX eacute ydieresis -15 KPX ecaron comma 10 KPX ecaron period 20 KPX ecaron v -15 KPX ecaron w -15 KPX ecaron x -15 KPX ecaron y -15 KPX ecaron yacute -15 KPX ecaron ydieresis -15 KPX ecircumflex comma 10 KPX ecircumflex period 20 KPX ecircumflex v -15 KPX ecircumflex w -15 KPX ecircumflex x -15 KPX ecircumflex y -15 KPX ecircumflex yacute -15 KPX ecircumflex ydieresis -15 KPX edieresis comma 10 KPX edieresis period 20 KPX edieresis v -15 KPX edieresis w -15 KPX edieresis x -15 KPX edieresis y -15 KPX edieresis yacute -15 KPX edieresis ydieresis -15 KPX edotaccent comma 10 KPX edotaccent period 20 KPX edotaccent v -15 KPX edotaccent w -15 KPX edotaccent x -15 KPX edotaccent y -15 KPX edotaccent yacute -15 KPX edotaccent ydieresis -15 KPX egrave comma 10 KPX egrave period 20 KPX egrave v -15 KPX egrave w -15 KPX egrave x -15 KPX egrave y -15 KPX egrave yacute -15 KPX egrave ydieresis -15 KPX emacron comma 10 KPX emacron period 20 KPX emacron v -15 KPX emacron w -15 KPX emacron x -15 KPX emacron y -15 KPX emacron yacute -15 KPX emacron ydieresis -15 KPX eogonek comma 10 KPX eogonek period 20 KPX eogonek v -15 KPX eogonek w -15 KPX eogonek x -15 KPX eogonek y -15 KPX eogonek yacute -15 KPX eogonek ydieresis -15 KPX f comma -10 KPX f e -10 KPX f eacute -10 KPX f ecaron -10 KPX f ecircumflex -10 KPX f edieresis -10 KPX f edotaccent -10 KPX f egrave -10 KPX f emacron -10 KPX f eogonek -10 KPX f o -20 KPX f oacute -20 KPX f ocircumflex -20 KPX f odieresis -20 KPX f ograve -20 KPX f ohungarumlaut -20 KPX f omacron -20 KPX f oslash -20 KPX f otilde -20 KPX f period -10 KPX f quotedblright 30 KPX f quoteright 30 KPX g e 10 KPX g eacute 10 KPX g ecaron 10 KPX g ecircumflex 10 KPX g edieresis 10 KPX g edotaccent 10 KPX g egrave 10 KPX g emacron 10 KPX g eogonek 10 KPX g g -10 KPX g gbreve -10 KPX g gcommaaccent -10 KPX gbreve e 10 KPX gbreve eacute 10 KPX gbreve ecaron 10 KPX gbreve ecircumflex 10 KPX gbreve edieresis 10 KPX gbreve edotaccent 10 KPX gbreve egrave 10 KPX gbreve emacron 10 KPX gbreve eogonek 10 KPX gbreve g -10 KPX gbreve gbreve -10 KPX gbreve gcommaaccent -10 KPX gcommaaccent e 10 KPX gcommaaccent eacute 10 KPX gcommaaccent ecaron 10 KPX gcommaaccent ecircumflex 10 KPX gcommaaccent edieresis 10 KPX gcommaaccent edotaccent 10 KPX gcommaaccent egrave 10 KPX gcommaaccent emacron 10 KPX gcommaaccent eogonek 10 KPX gcommaaccent g -10 KPX gcommaaccent gbreve -10 KPX gcommaaccent gcommaaccent -10 KPX h y -20 KPX h yacute -20 KPX h ydieresis -20 KPX k o -15 KPX k oacute -15 KPX k ocircumflex -15 KPX k odieresis -15 KPX k ograve -15 KPX k ohungarumlaut -15 KPX k omacron -15 KPX k oslash -15 KPX k otilde -15 KPX kcommaaccent o -15 KPX kcommaaccent oacute -15 KPX kcommaaccent ocircumflex -15 KPX kcommaaccent odieresis -15 KPX kcommaaccent ograve -15 KPX kcommaaccent ohungarumlaut -15 KPX kcommaaccent omacron -15 KPX kcommaaccent oslash -15 KPX kcommaaccent otilde -15 KPX l w -15 KPX l y -15 KPX l yacute -15 KPX l ydieresis -15 KPX lacute w -15 KPX lacute y -15 KPX lacute yacute -15 KPX lacute ydieresis -15 KPX lcommaaccent w -15 KPX lcommaaccent y -15 KPX lcommaaccent yacute -15 KPX lcommaaccent ydieresis -15 KPX lslash w -15 KPX lslash y -15 KPX lslash yacute -15 KPX lslash ydieresis -15 KPX m u -20 KPX m uacute -20 KPX m ucircumflex -20 KPX m udieresis -20 KPX m ugrave -20 KPX m uhungarumlaut -20 KPX m umacron -20 KPX m uogonek -20 KPX m uring -20 KPX m y -30 KPX m yacute -30 KPX m ydieresis -30 KPX n u -10 KPX n uacute -10 KPX n ucircumflex -10 KPX n udieresis -10 KPX n ugrave -10 KPX n uhungarumlaut -10 KPX n umacron -10 KPX n uogonek -10 KPX n uring -10 KPX n v -40 KPX n y -20 KPX n yacute -20 KPX n ydieresis -20 KPX nacute u -10 KPX nacute uacute -10 KPX nacute ucircumflex -10 KPX nacute udieresis -10 KPX nacute ugrave -10 KPX nacute uhungarumlaut -10 KPX nacute umacron -10 KPX nacute uogonek -10 KPX nacute uring -10 KPX nacute v -40 KPX nacute y -20 KPX nacute yacute -20 KPX nacute ydieresis -20 KPX ncaron u -10 KPX ncaron uacute -10 KPX ncaron ucircumflex -10 KPX ncaron udieresis -10 KPX ncaron ugrave -10 KPX ncaron uhungarumlaut -10 KPX ncaron umacron -10 KPX ncaron uogonek -10 KPX ncaron uring -10 KPX ncaron v -40 KPX ncaron y -20 KPX ncaron yacute -20 KPX ncaron ydieresis -20 KPX ncommaaccent u -10 KPX ncommaaccent uacute -10 KPX ncommaaccent ucircumflex -10 KPX ncommaaccent udieresis -10 KPX ncommaaccent ugrave -10 KPX ncommaaccent uhungarumlaut -10 KPX ncommaaccent umacron -10 KPX ncommaaccent uogonek -10 KPX ncommaaccent uring -10 KPX ncommaaccent v -40 KPX ncommaaccent y -20 KPX ncommaaccent yacute -20 KPX ncommaaccent ydieresis -20 KPX ntilde u -10 KPX ntilde uacute -10 KPX ntilde ucircumflex -10 KPX ntilde udieresis -10 KPX ntilde ugrave -10 KPX ntilde uhungarumlaut -10 KPX ntilde umacron -10 KPX ntilde uogonek -10 KPX ntilde uring -10 KPX ntilde v -40 KPX ntilde y -20 KPX ntilde yacute -20 KPX ntilde ydieresis -20 KPX o v -20 KPX o w -15 KPX o x -30 KPX o y -20 KPX o yacute -20 KPX o ydieresis -20 KPX oacute v -20 KPX oacute w -15 KPX oacute x -30 KPX oacute y -20 KPX oacute yacute -20 KPX oacute ydieresis -20 KPX ocircumflex v -20 KPX ocircumflex w -15 KPX ocircumflex x -30 KPX ocircumflex y -20 KPX ocircumflex yacute -20 KPX ocircumflex ydieresis -20 KPX odieresis v -20 KPX odieresis w -15 KPX odieresis x -30 KPX odieresis y -20 KPX odieresis yacute -20 KPX odieresis ydieresis -20 KPX ograve v -20 KPX ograve w -15 KPX ograve x -30 KPX ograve y -20 KPX ograve yacute -20 KPX ograve ydieresis -20 KPX ohungarumlaut v -20 KPX ohungarumlaut w -15 KPX ohungarumlaut x -30 KPX ohungarumlaut y -20 KPX ohungarumlaut yacute -20 KPX ohungarumlaut ydieresis -20 KPX omacron v -20 KPX omacron w -15 KPX omacron x -30 KPX omacron y -20 KPX omacron yacute -20 KPX omacron ydieresis -20 KPX oslash v -20 KPX oslash w -15 KPX oslash x -30 KPX oslash y -20 KPX oslash yacute -20 KPX oslash ydieresis -20 KPX otilde v -20 KPX otilde w -15 KPX otilde x -30 KPX otilde y -20 KPX otilde yacute -20 KPX otilde ydieresis -20 KPX p y -15 KPX p yacute -15 KPX p ydieresis -15 KPX period quotedblright -120 KPX period quoteright -120 KPX period space -40 KPX quotedblright space -80 KPX quoteleft quoteleft -46 KPX quoteright d -80 KPX quoteright dcroat -80 KPX quoteright l -20 KPX quoteright lacute -20 KPX quoteright lcommaaccent -20 KPX quoteright lslash -20 KPX quoteright quoteright -46 KPX quoteright r -40 KPX quoteright racute -40 KPX quoteright rcaron -40 KPX quoteright rcommaaccent -40 KPX quoteright s -60 KPX quoteright sacute -60 KPX quoteright scaron -60 KPX quoteright scedilla -60 KPX quoteright scommaaccent -60 KPX quoteright space -80 KPX quoteright v -20 KPX r c -20 KPX r cacute -20 KPX r ccaron -20 KPX r ccedilla -20 KPX r comma -60 KPX r d -20 KPX r dcroat -20 KPX r g -15 KPX r gbreve -15 KPX r gcommaaccent -15 KPX r hyphen -20 KPX r o -20 KPX r oacute -20 KPX r ocircumflex -20 KPX r odieresis -20 KPX r ograve -20 KPX r ohungarumlaut -20 KPX r omacron -20 KPX r oslash -20 KPX r otilde -20 KPX r period -60 KPX r q -20 KPX r s -15 KPX r sacute -15 KPX r scaron -15 KPX r scedilla -15 KPX r scommaaccent -15 KPX r t 20 KPX r tcommaaccent 20 KPX r v 10 KPX r y 10 KPX r yacute 10 KPX r ydieresis 10 KPX racute c -20 KPX racute cacute -20 KPX racute ccaron -20 KPX racute ccedilla -20 KPX racute comma -60 KPX racute d -20 KPX racute dcroat -20 KPX racute g -15 KPX racute gbreve -15 KPX racute gcommaaccent -15 KPX racute hyphen -20 KPX racute o -20 KPX racute oacute -20 KPX racute ocircumflex -20 KPX racute odieresis -20 KPX racute ograve -20 KPX racute ohungarumlaut -20 KPX racute omacron -20 KPX racute oslash -20 KPX racute otilde -20 KPX racute period -60 KPX racute q -20 KPX racute s -15 KPX racute sacute -15 KPX racute scaron -15 KPX racute scedilla -15 KPX racute scommaaccent -15 KPX racute t 20 KPX racute tcommaaccent 20 KPX racute v 10 KPX racute y 10 KPX racute yacute 10 KPX racute ydieresis 10 KPX rcaron c -20 KPX rcaron cacute -20 KPX rcaron ccaron -20 KPX rcaron ccedilla -20 KPX rcaron comma -60 KPX rcaron d -20 KPX rcaron dcroat -20 KPX rcaron g -15 KPX rcaron gbreve -15 KPX rcaron gcommaaccent -15 KPX rcaron hyphen -20 KPX rcaron o -20 KPX rcaron oacute -20 KPX rcaron ocircumflex -20 KPX rcaron odieresis -20 KPX rcaron ograve -20 KPX rcaron ohungarumlaut -20 KPX rcaron omacron -20 KPX rcaron oslash -20 KPX rcaron otilde -20 KPX rcaron period -60 KPX rcaron q -20 KPX rcaron s -15 KPX rcaron sacute -15 KPX rcaron scaron -15 KPX rcaron scedilla -15 KPX rcaron scommaaccent -15 KPX rcaron t 20 KPX rcaron tcommaaccent 20 KPX rcaron v 10 KPX rcaron y 10 KPX rcaron yacute 10 KPX rcaron ydieresis 10 KPX rcommaaccent c -20 KPX rcommaaccent cacute -20 KPX rcommaaccent ccaron -20 KPX rcommaaccent ccedilla -20 KPX rcommaaccent comma -60 KPX rcommaaccent d -20 KPX rcommaaccent dcroat -20 KPX rcommaaccent g -15 KPX rcommaaccent gbreve -15 KPX rcommaaccent gcommaaccent -15 KPX rcommaaccent hyphen -20 KPX rcommaaccent o -20 KPX rcommaaccent oacute -20 KPX rcommaaccent ocircumflex -20 KPX rcommaaccent odieresis -20 KPX rcommaaccent ograve -20 KPX rcommaaccent ohungarumlaut -20 KPX rcommaaccent omacron -20 KPX rcommaaccent oslash -20 KPX rcommaaccent otilde -20 KPX rcommaaccent period -60 KPX rcommaaccent q -20 KPX rcommaaccent s -15 KPX rcommaaccent sacute -15 KPX rcommaaccent scaron -15 KPX rcommaaccent scedilla -15 KPX rcommaaccent scommaaccent -15 KPX rcommaaccent t 20 KPX rcommaaccent tcommaaccent 20 KPX rcommaaccent v 10 KPX rcommaaccent y 10 KPX rcommaaccent yacute 10 KPX rcommaaccent ydieresis 10 KPX s w -15 KPX sacute w -15 KPX scaron w -15 KPX scedilla w -15 KPX scommaaccent w -15 KPX semicolon space -40 KPX space T -100 KPX space Tcaron -100 KPX space Tcommaaccent -100 KPX space V -80 KPX space W -80 KPX space Y -120 KPX space Yacute -120 KPX space Ydieresis -120 KPX space quotedblleft -80 KPX space quoteleft -60 KPX v a -20 KPX v aacute -20 KPX v abreve -20 KPX v acircumflex -20 KPX v adieresis -20 KPX v agrave -20 KPX v amacron -20 KPX v aogonek -20 KPX v aring -20 KPX v atilde -20 KPX v comma -80 KPX v o -30 KPX v oacute -30 KPX v ocircumflex -30 KPX v odieresis -30 KPX v ograve -30 KPX v ohungarumlaut -30 KPX v omacron -30 KPX v oslash -30 KPX v otilde -30 KPX v period -80 KPX w comma -40 KPX w o -20 KPX w oacute -20 KPX w ocircumflex -20 KPX w odieresis -20 KPX w ograve -20 KPX w ohungarumlaut -20 KPX w omacron -20 KPX w oslash -20 KPX w otilde -20 KPX w period -40 KPX x e -10 KPX x eacute -10 KPX x ecaron -10 KPX x ecircumflex -10 KPX x edieresis -10 KPX x edotaccent -10 KPX x egrave -10 KPX x emacron -10 KPX x eogonek -10 KPX y a -30 KPX y aacute -30 KPX y abreve -30 KPX y acircumflex -30 KPX y adieresis -30 KPX y agrave -30 KPX y amacron -30 KPX y aogonek -30 KPX y aring -30 KPX y atilde -30 KPX y comma -80 KPX y e -10 KPX y eacute -10 KPX y ecaron -10 KPX y ecircumflex -10 KPX y edieresis -10 KPX y edotaccent -10 KPX y egrave -10 KPX y emacron -10 KPX y eogonek -10 KPX y o -25 KPX y oacute -25 KPX y ocircumflex -25 KPX y odieresis -25 KPX y ograve -25 KPX y ohungarumlaut -25 KPX y omacron -25 KPX y oslash -25 KPX y otilde -25 KPX y period -80 KPX yacute a -30 KPX yacute aacute -30 KPX yacute abreve -30 KPX yacute acircumflex -30 KPX yacute adieresis -30 KPX yacute agrave -30 KPX yacute amacron -30 KPX yacute aogonek -30 KPX yacute aring -30 KPX yacute atilde -30 KPX yacute comma -80 KPX yacute e -10 KPX yacute eacute -10 KPX yacute ecaron -10 KPX yacute ecircumflex -10 KPX yacute edieresis -10 KPX yacute edotaccent -10 KPX yacute egrave -10 KPX yacute emacron -10 KPX yacute eogonek -10 KPX yacute o -25 KPX yacute oacute -25 KPX yacute ocircumflex -25 KPX yacute odieresis -25 KPX yacute ograve -25 KPX yacute ohungarumlaut -25 KPX yacute omacron -25 KPX yacute oslash -25 KPX yacute otilde -25 KPX yacute period -80 KPX ydieresis a -30 KPX ydieresis aacute -30 KPX ydieresis abreve -30 KPX ydieresis acircumflex -30 KPX ydieresis adieresis -30 KPX ydieresis agrave -30 KPX ydieresis amacron -30 KPX ydieresis aogonek -30 KPX ydieresis aring -30 KPX ydieresis atilde -30 KPX ydieresis comma -80 KPX ydieresis e -10 KPX ydieresis eacute -10 KPX ydieresis ecaron -10 KPX ydieresis ecircumflex -10 KPX ydieresis edieresis -10 KPX ydieresis edotaccent -10 KPX ydieresis egrave -10 KPX ydieresis emacron -10 KPX ydieresis eogonek -10 KPX ydieresis o -25 KPX ydieresis oacute -25 KPX ydieresis ocircumflex -25 KPX ydieresis odieresis -25 KPX ydieresis ograve -25 KPX ydieresis ohungarumlaut -25 KPX ydieresis omacron -25 KPX ydieresis oslash -25 KPX ydieresis otilde -25 KPX ydieresis period -80 KPX z e 10 KPX z eacute 10 KPX z ecaron 10 KPX z ecircumflex 10 KPX z edieresis 10 KPX z edotaccent 10 KPX z egrave 10 KPX z emacron 10 KPX z eogonek 10 KPX zacute e 10 KPX zacute eacute 10 KPX zacute ecaron 10 KPX zacute ecircumflex 10 KPX zacute edieresis 10 KPX zacute edotaccent 10 KPX zacute egrave 10 KPX zacute emacron 10 KPX zacute eogonek 10 KPX zcaron e 10 KPX zcaron eacute 10 KPX zcaron ecaron 10 KPX zcaron ecircumflex 10 KPX zcaron edieresis 10 KPX zcaron edotaccent 10 KPX zcaron egrave 10 KPX zcaron emacron 10 KPX zcaron eogonek 10 KPX zdotaccent e 10 KPX zdotaccent eacute 10 KPX zdotaccent ecaron 10 KPX zdotaccent ecircumflex 10 KPX zdotaccent edieresis 10 KPX zdotaccent edotaccent 10 KPX zdotaccent egrave 10 KPX zdotaccent emacron 10 KPX zdotaccent eogonek 10 EndKernPairs EndKernData EndFontMetrics camlpdf-2.8.1/compressor/Helvetica-Oblique.afm000066400000000000000000002212301477056064700213330ustar00rootroot00000000000000StartFontMetrics 4.1 Comment Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved. Comment Creation Date: Thu May 1 12:44:31 1997 Comment UniqueID 43055 Comment VMusage 14960 69346 FontName Helvetica-Oblique FullName Helvetica Oblique FamilyName Helvetica Weight Medium ItalicAngle -12 IsFixedPitch false CharacterSet ExtendedRoman FontBBox -170 -225 1116 931 UnderlinePosition -100 UnderlineThickness 50 Version 002.000 Notice Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved.Helvetica is a trademark of Linotype-Hell AG and/or its subsidiaries. EncodingScheme AdobeStandardEncoding CapHeight 718 XHeight 523 Ascender 718 Descender -207 StdHW 76 StdVW 88 StartCharMetrics 315 C 32 ; WX 278 ; N space ; B 0 0 0 0 ; C 33 ; WX 278 ; N exclam ; B 90 0 340 718 ; C 34 ; WX 355 ; N quotedbl ; B 168 463 438 718 ; C 35 ; WX 556 ; N numbersign ; B 73 0 631 688 ; C 36 ; WX 556 ; N dollar ; B 69 -115 617 775 ; C 37 ; WX 889 ; N percent ; B 147 -19 889 703 ; C 38 ; WX 667 ; N ampersand ; B 77 -15 647 718 ; C 39 ; WX 222 ; N quoteright ; B 151 463 310 718 ; C 40 ; WX 333 ; N parenleft ; B 108 -207 454 733 ; C 41 ; WX 333 ; N parenright ; B -9 -207 337 733 ; C 42 ; WX 389 ; N asterisk ; B 165 431 475 718 ; C 43 ; WX 584 ; N plus ; B 85 0 606 505 ; C 44 ; WX 278 ; N comma ; B 56 -147 214 106 ; C 45 ; WX 333 ; N hyphen ; B 93 232 357 322 ; C 46 ; WX 278 ; N period ; B 87 0 214 106 ; C 47 ; WX 278 ; N slash ; B -21 -19 452 737 ; C 48 ; WX 556 ; N zero ; B 93 -19 608 703 ; C 49 ; WX 556 ; N one ; B 207 0 508 703 ; C 50 ; WX 556 ; N two ; B 26 0 617 703 ; C 51 ; WX 556 ; N three ; B 75 -19 610 703 ; C 52 ; WX 556 ; N four ; B 61 0 576 703 ; C 53 ; WX 556 ; N five ; B 68 -19 621 688 ; C 54 ; WX 556 ; N six ; B 91 -19 615 703 ; C 55 ; WX 556 ; N seven ; B 137 0 669 688 ; C 56 ; WX 556 ; N eight ; B 74 -19 607 703 ; C 57 ; WX 556 ; N nine ; B 82 -19 609 703 ; C 58 ; WX 278 ; N colon ; B 87 0 301 516 ; C 59 ; WX 278 ; N semicolon ; B 56 -147 301 516 ; C 60 ; WX 584 ; N less ; B 94 11 641 495 ; C 61 ; WX 584 ; N equal ; B 63 115 628 390 ; C 62 ; WX 584 ; N greater ; B 50 11 597 495 ; C 63 ; WX 556 ; N question ; B 161 0 610 727 ; C 64 ; WX 1015 ; N at ; B 215 -19 965 737 ; C 65 ; WX 667 ; N A ; B 14 0 654 718 ; C 66 ; WX 667 ; N B ; B 74 0 712 718 ; C 67 ; WX 722 ; N C ; B 108 -19 782 737 ; C 68 ; WX 722 ; N D ; B 81 0 764 718 ; C 69 ; WX 667 ; N E ; B 86 0 762 718 ; C 70 ; WX 611 ; N F ; B 86 0 736 718 ; C 71 ; WX 778 ; N G ; B 111 -19 799 737 ; C 72 ; WX 722 ; N H ; B 77 0 799 718 ; C 73 ; WX 278 ; N I ; B 91 0 341 718 ; C 74 ; WX 500 ; N J ; B 47 -19 581 718 ; C 75 ; WX 667 ; N K ; B 76 0 808 718 ; C 76 ; WX 556 ; N L ; B 76 0 555 718 ; C 77 ; WX 833 ; N M ; B 73 0 914 718 ; C 78 ; WX 722 ; N N ; B 76 0 799 718 ; C 79 ; WX 778 ; N O ; B 105 -19 826 737 ; C 80 ; WX 667 ; N P ; B 86 0 737 718 ; C 81 ; WX 778 ; N Q ; B 105 -56 826 737 ; C 82 ; WX 722 ; N R ; B 88 0 773 718 ; C 83 ; WX 667 ; N S ; B 90 -19 713 737 ; C 84 ; WX 611 ; N T ; B 148 0 750 718 ; C 85 ; WX 722 ; N U ; B 123 -19 797 718 ; C 86 ; WX 667 ; N V ; B 173 0 800 718 ; C 87 ; WX 944 ; N W ; B 169 0 1081 718 ; C 88 ; WX 667 ; N X ; B 19 0 790 718 ; C 89 ; WX 667 ; N Y ; B 167 0 806 718 ; C 90 ; WX 611 ; N Z ; B 23 0 741 718 ; C 91 ; WX 278 ; N bracketleft ; B 21 -196 403 722 ; C 92 ; WX 278 ; N backslash ; B 140 -19 291 737 ; C 93 ; WX 278 ; N bracketright ; B -14 -196 368 722 ; C 94 ; WX 469 ; N asciicircum ; B 42 264 539 688 ; C 95 ; WX 556 ; N underscore ; B -27 -125 540 -75 ; C 96 ; WX 222 ; N quoteleft ; B 165 470 323 725 ; C 97 ; WX 556 ; N a ; B 61 -15 559 538 ; C 98 ; WX 556 ; N b ; B 58 -15 584 718 ; C 99 ; WX 500 ; N c ; B 74 -15 553 538 ; C 100 ; WX 556 ; N d ; B 84 -15 652 718 ; C 101 ; WX 556 ; N e ; B 84 -15 578 538 ; C 102 ; WX 278 ; N f ; B 86 0 416 728 ; L i fi ; L l fl ; C 103 ; WX 556 ; N g ; B 42 -220 610 538 ; C 104 ; WX 556 ; N h ; B 65 0 573 718 ; C 105 ; WX 222 ; N i ; B 67 0 308 718 ; C 106 ; WX 222 ; N j ; B -60 -210 308 718 ; C 107 ; WX 500 ; N k ; B 67 0 600 718 ; C 108 ; WX 222 ; N l ; B 67 0 308 718 ; C 109 ; WX 833 ; N m ; B 65 0 852 538 ; C 110 ; WX 556 ; N n ; B 65 0 573 538 ; C 111 ; WX 556 ; N o ; B 83 -14 585 538 ; C 112 ; WX 556 ; N p ; B 14 -207 584 538 ; C 113 ; WX 556 ; N q ; B 84 -207 605 538 ; C 114 ; WX 333 ; N r ; B 77 0 446 538 ; C 115 ; WX 500 ; N s ; B 63 -15 529 538 ; C 116 ; WX 278 ; N t ; B 102 -7 368 669 ; C 117 ; WX 556 ; N u ; B 94 -15 600 523 ; C 118 ; WX 500 ; N v ; B 119 0 603 523 ; C 119 ; WX 722 ; N w ; B 125 0 820 523 ; C 120 ; WX 500 ; N x ; B 11 0 594 523 ; C 121 ; WX 500 ; N y ; B 15 -214 600 523 ; C 122 ; WX 500 ; N z ; B 31 0 571 523 ; C 123 ; WX 334 ; N braceleft ; B 92 -196 445 722 ; C 124 ; WX 260 ; N bar ; B 46 -225 332 775 ; C 125 ; WX 334 ; N braceright ; B 0 -196 354 722 ; C 126 ; WX 584 ; N asciitilde ; B 111 180 580 326 ; C 161 ; WX 333 ; N exclamdown ; B 77 -195 326 523 ; C 162 ; WX 556 ; N cent ; B 95 -115 584 623 ; C 163 ; WX 556 ; N sterling ; B 49 -16 634 718 ; C 164 ; WX 167 ; N fraction ; B -170 -19 482 703 ; C 165 ; WX 556 ; N yen ; B 81 0 699 688 ; C 166 ; WX 556 ; N florin ; B -52 -207 654 737 ; C 167 ; WX 556 ; N section ; B 76 -191 584 737 ; C 168 ; WX 556 ; N currency ; B 60 99 646 603 ; C 169 ; WX 191 ; N quotesingle ; B 157 463 285 718 ; C 170 ; WX 333 ; N quotedblleft ; B 138 470 461 725 ; C 171 ; WX 556 ; N guillemotleft ; B 146 108 554 446 ; C 172 ; WX 333 ; N guilsinglleft ; B 137 108 340 446 ; C 173 ; WX 333 ; N guilsinglright ; B 111 108 314 446 ; C 174 ; WX 500 ; N fi ; B 86 0 587 728 ; C 175 ; WX 500 ; N fl ; B 86 0 585 728 ; C 177 ; WX 556 ; N endash ; B 51 240 623 313 ; C 178 ; WX 556 ; N dagger ; B 135 -159 622 718 ; C 179 ; WX 556 ; N daggerdbl ; B 52 -159 623 718 ; C 180 ; WX 278 ; N periodcentered ; B 129 190 257 315 ; C 182 ; WX 537 ; N paragraph ; B 126 -173 650 718 ; C 183 ; WX 350 ; N bullet ; B 91 202 413 517 ; C 184 ; WX 222 ; N quotesinglbase ; B 21 -149 180 106 ; C 185 ; WX 333 ; N quotedblbase ; B -6 -149 318 106 ; C 186 ; WX 333 ; N quotedblright ; B 124 463 448 718 ; C 187 ; WX 556 ; N guillemotright ; B 120 108 528 446 ; C 188 ; WX 1000 ; N ellipsis ; B 115 0 908 106 ; C 189 ; WX 1000 ; N perthousand ; B 88 -19 1029 703 ; C 191 ; WX 611 ; N questiondown ; B 85 -201 534 525 ; C 193 ; WX 333 ; N grave ; B 170 593 337 734 ; C 194 ; WX 333 ; N acute ; B 248 593 475 734 ; C 195 ; WX 333 ; N circumflex ; B 147 593 438 734 ; C 196 ; WX 333 ; N tilde ; B 125 606 490 722 ; C 197 ; WX 333 ; N macron ; B 143 627 468 684 ; C 198 ; WX 333 ; N breve ; B 167 595 476 731 ; C 199 ; WX 333 ; N dotaccent ; B 249 604 362 706 ; C 200 ; WX 333 ; N dieresis ; B 168 604 443 706 ; C 202 ; WX 333 ; N ring ; B 214 572 402 756 ; C 203 ; WX 333 ; N cedilla ; B 2 -225 232 0 ; C 205 ; WX 333 ; N hungarumlaut ; B 157 593 565 734 ; C 206 ; WX 333 ; N ogonek ; B 43 -225 249 0 ; C 207 ; WX 333 ; N caron ; B 177 593 468 734 ; C 208 ; WX 1000 ; N emdash ; B 51 240 1067 313 ; C 225 ; WX 1000 ; N AE ; B 8 0 1097 718 ; C 227 ; WX 370 ; N ordfeminine ; B 127 405 449 737 ; C 232 ; WX 556 ; N Lslash ; B 41 0 555 718 ; C 233 ; WX 778 ; N Oslash ; B 43 -19 890 737 ; C 234 ; WX 1000 ; N OE ; B 98 -19 1116 737 ; C 235 ; WX 365 ; N ordmasculine ; B 141 405 468 737 ; C 241 ; WX 889 ; N ae ; B 61 -15 909 538 ; C 245 ; WX 278 ; N dotlessi ; B 95 0 294 523 ; C 248 ; WX 222 ; N lslash ; B 41 0 347 718 ; C 249 ; WX 611 ; N oslash ; B 29 -22 647 545 ; C 250 ; WX 944 ; N oe ; B 83 -15 964 538 ; C 251 ; WX 611 ; N germandbls ; B 67 -15 658 728 ; C -1 ; WX 278 ; N Idieresis ; B 91 0 458 901 ; C -1 ; WX 556 ; N eacute ; B 84 -15 587 734 ; C -1 ; WX 556 ; N abreve ; B 61 -15 578 731 ; C -1 ; WX 556 ; N uhungarumlaut ; B 94 -15 677 734 ; C -1 ; WX 556 ; N ecaron ; B 84 -15 580 734 ; C -1 ; WX 667 ; N Ydieresis ; B 167 0 806 901 ; C -1 ; WX 584 ; N divide ; B 85 -19 606 524 ; C -1 ; WX 667 ; N Yacute ; B 167 0 806 929 ; C -1 ; WX 667 ; N Acircumflex ; B 14 0 654 929 ; C -1 ; WX 556 ; N aacute ; B 61 -15 587 734 ; C -1 ; WX 722 ; N Ucircumflex ; B 123 -19 797 929 ; C -1 ; WX 500 ; N yacute ; B 15 -214 600 734 ; C -1 ; WX 500 ; N scommaaccent ; B 63 -225 529 538 ; C -1 ; WX 556 ; N ecircumflex ; B 84 -15 578 734 ; C -1 ; WX 722 ; N Uring ; B 123 -19 797 931 ; C -1 ; WX 722 ; N Udieresis ; B 123 -19 797 901 ; C -1 ; WX 556 ; N aogonek ; B 61 -220 559 538 ; C -1 ; WX 722 ; N Uacute ; B 123 -19 797 929 ; C -1 ; WX 556 ; N uogonek ; B 94 -225 600 523 ; C -1 ; WX 667 ; N Edieresis ; B 86 0 762 901 ; C -1 ; WX 722 ; N Dcroat ; B 69 0 764 718 ; C -1 ; WX 250 ; N commaaccent ; B 39 -225 172 -40 ; C -1 ; WX 737 ; N copyright ; B 54 -19 837 737 ; C -1 ; WX 667 ; N Emacron ; B 86 0 762 879 ; C -1 ; WX 500 ; N ccaron ; B 74 -15 553 734 ; C -1 ; WX 556 ; N aring ; B 61 -15 559 756 ; C -1 ; WX 722 ; N Ncommaaccent ; B 76 -225 799 718 ; C -1 ; WX 222 ; N lacute ; B 67 0 461 929 ; C -1 ; WX 556 ; N agrave ; B 61 -15 559 734 ; C -1 ; WX 611 ; N Tcommaaccent ; B 148 -225 750 718 ; C -1 ; WX 722 ; N Cacute ; B 108 -19 782 929 ; C -1 ; WX 556 ; N atilde ; B 61 -15 592 722 ; C -1 ; WX 667 ; N Edotaccent ; B 86 0 762 901 ; C -1 ; WX 500 ; N scaron ; B 63 -15 552 734 ; C -1 ; WX 500 ; N scedilla ; B 63 -225 529 538 ; C -1 ; WX 278 ; N iacute ; B 95 0 448 734 ; C -1 ; WX 471 ; N lozenge ; B 88 0 540 728 ; C -1 ; WX 722 ; N Rcaron ; B 88 0 773 929 ; C -1 ; WX 778 ; N Gcommaaccent ; B 111 -225 799 737 ; C -1 ; WX 556 ; N ucircumflex ; B 94 -15 600 734 ; C -1 ; WX 556 ; N acircumflex ; B 61 -15 559 734 ; C -1 ; WX 667 ; N Amacron ; B 14 0 677 879 ; C -1 ; WX 333 ; N rcaron ; B 77 0 508 734 ; C -1 ; WX 500 ; N ccedilla ; B 74 -225 553 538 ; C -1 ; WX 611 ; N Zdotaccent ; B 23 0 741 901 ; C -1 ; WX 667 ; N Thorn ; B 86 0 712 718 ; C -1 ; WX 778 ; N Omacron ; B 105 -19 826 879 ; C -1 ; WX 722 ; N Racute ; B 88 0 773 929 ; C -1 ; WX 667 ; N Sacute ; B 90 -19 713 929 ; C -1 ; WX 643 ; N dcaron ; B 84 -15 808 718 ; C -1 ; WX 722 ; N Umacron ; B 123 -19 797 879 ; C -1 ; WX 556 ; N uring ; B 94 -15 600 756 ; C -1 ; WX 333 ; N threesuperior ; B 90 270 436 703 ; C -1 ; WX 778 ; N Ograve ; B 105 -19 826 929 ; C -1 ; WX 667 ; N Agrave ; B 14 0 654 929 ; C -1 ; WX 667 ; N Abreve ; B 14 0 685 926 ; C -1 ; WX 584 ; N multiply ; B 50 0 642 506 ; C -1 ; WX 556 ; N uacute ; B 94 -15 600 734 ; C -1 ; WX 611 ; N Tcaron ; B 148 0 750 929 ; C -1 ; WX 476 ; N partialdiff ; B 41 -38 550 714 ; C -1 ; WX 500 ; N ydieresis ; B 15 -214 600 706 ; C -1 ; WX 722 ; N Nacute ; B 76 0 799 929 ; C -1 ; WX 278 ; N icircumflex ; B 95 0 411 734 ; C -1 ; WX 667 ; N Ecircumflex ; B 86 0 762 929 ; C -1 ; WX 556 ; N adieresis ; B 61 -15 559 706 ; C -1 ; WX 556 ; N edieresis ; B 84 -15 578 706 ; C -1 ; WX 500 ; N cacute ; B 74 -15 559 734 ; C -1 ; WX 556 ; N nacute ; B 65 0 587 734 ; C -1 ; WX 556 ; N umacron ; B 94 -15 600 684 ; C -1 ; WX 722 ; N Ncaron ; B 76 0 799 929 ; C -1 ; WX 278 ; N Iacute ; B 91 0 489 929 ; C -1 ; WX 584 ; N plusminus ; B 39 0 618 506 ; C -1 ; WX 260 ; N brokenbar ; B 62 -150 316 700 ; C -1 ; WX 737 ; N registered ; B 54 -19 837 737 ; C -1 ; WX 778 ; N Gbreve ; B 111 -19 799 926 ; C -1 ; WX 278 ; N Idotaccent ; B 91 0 377 901 ; C -1 ; WX 600 ; N summation ; B 15 -10 671 706 ; C -1 ; WX 667 ; N Egrave ; B 86 0 762 929 ; C -1 ; WX 333 ; N racute ; B 77 0 475 734 ; C -1 ; WX 556 ; N omacron ; B 83 -14 585 684 ; C -1 ; WX 611 ; N Zacute ; B 23 0 741 929 ; C -1 ; WX 611 ; N Zcaron ; B 23 0 741 929 ; C -1 ; WX 549 ; N greaterequal ; B 26 0 620 674 ; C -1 ; WX 722 ; N Eth ; B 69 0 764 718 ; C -1 ; WX 722 ; N Ccedilla ; B 108 -225 782 737 ; C -1 ; WX 222 ; N lcommaaccent ; B 25 -225 308 718 ; C -1 ; WX 317 ; N tcaron ; B 102 -7 501 808 ; C -1 ; WX 556 ; N eogonek ; B 84 -225 578 538 ; C -1 ; WX 722 ; N Uogonek ; B 123 -225 797 718 ; C -1 ; WX 667 ; N Aacute ; B 14 0 683 929 ; C -1 ; WX 667 ; N Adieresis ; B 14 0 654 901 ; C -1 ; WX 556 ; N egrave ; B 84 -15 578 734 ; C -1 ; WX 500 ; N zacute ; B 31 0 571 734 ; C -1 ; WX 222 ; N iogonek ; B -61 -225 308 718 ; C -1 ; WX 778 ; N Oacute ; B 105 -19 826 929 ; C -1 ; WX 556 ; N oacute ; B 83 -14 587 734 ; C -1 ; WX 556 ; N amacron ; B 61 -15 580 684 ; C -1 ; WX 500 ; N sacute ; B 63 -15 559 734 ; C -1 ; WX 278 ; N idieresis ; B 95 0 416 706 ; C -1 ; WX 778 ; N Ocircumflex ; B 105 -19 826 929 ; C -1 ; WX 722 ; N Ugrave ; B 123 -19 797 929 ; C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ; C -1 ; WX 556 ; N thorn ; B 14 -207 584 718 ; C -1 ; WX 333 ; N twosuperior ; B 64 281 449 703 ; C -1 ; WX 778 ; N Odieresis ; B 105 -19 826 901 ; C -1 ; WX 556 ; N mu ; B 24 -207 600 523 ; C -1 ; WX 278 ; N igrave ; B 95 0 310 734 ; C -1 ; WX 556 ; N ohungarumlaut ; B 83 -14 677 734 ; C -1 ; WX 667 ; N Eogonek ; B 86 -220 762 718 ; C -1 ; WX 556 ; N dcroat ; B 84 -15 689 718 ; C -1 ; WX 834 ; N threequarters ; B 130 -19 861 703 ; C -1 ; WX 667 ; N Scedilla ; B 90 -225 713 737 ; C -1 ; WX 299 ; N lcaron ; B 67 0 464 718 ; C -1 ; WX 667 ; N Kcommaaccent ; B 76 -225 808 718 ; C -1 ; WX 556 ; N Lacute ; B 76 0 555 929 ; C -1 ; WX 1000 ; N trademark ; B 186 306 1056 718 ; C -1 ; WX 556 ; N edotaccent ; B 84 -15 578 706 ; C -1 ; WX 278 ; N Igrave ; B 91 0 351 929 ; C -1 ; WX 278 ; N Imacron ; B 91 0 483 879 ; C -1 ; WX 556 ; N Lcaron ; B 76 0 570 718 ; C -1 ; WX 834 ; N onehalf ; B 114 -19 839 703 ; C -1 ; WX 549 ; N lessequal ; B 26 0 666 674 ; C -1 ; WX 556 ; N ocircumflex ; B 83 -14 585 734 ; C -1 ; WX 556 ; N ntilde ; B 65 0 592 722 ; C -1 ; WX 722 ; N Uhungarumlaut ; B 123 -19 801 929 ; C -1 ; WX 667 ; N Eacute ; B 86 0 762 929 ; C -1 ; WX 556 ; N emacron ; B 84 -15 580 684 ; C -1 ; WX 556 ; N gbreve ; B 42 -220 610 731 ; C -1 ; WX 834 ; N onequarter ; B 150 -19 802 703 ; C -1 ; WX 667 ; N Scaron ; B 90 -19 713 929 ; C -1 ; WX 667 ; N Scommaaccent ; B 90 -225 713 737 ; C -1 ; WX 778 ; N Ohungarumlaut ; B 105 -19 829 929 ; C -1 ; WX 400 ; N degree ; B 169 411 468 703 ; C -1 ; WX 556 ; N ograve ; B 83 -14 585 734 ; C -1 ; WX 722 ; N Ccaron ; B 108 -19 782 929 ; C -1 ; WX 556 ; N ugrave ; B 94 -15 600 734 ; C -1 ; WX 453 ; N radical ; B 79 -80 617 762 ; C -1 ; WX 722 ; N Dcaron ; B 81 0 764 929 ; C -1 ; WX 333 ; N rcommaaccent ; B 30 -225 446 538 ; C -1 ; WX 722 ; N Ntilde ; B 76 0 799 917 ; C -1 ; WX 556 ; N otilde ; B 83 -14 602 722 ; C -1 ; WX 722 ; N Rcommaaccent ; B 88 -225 773 718 ; C -1 ; WX 556 ; N Lcommaaccent ; B 76 -225 555 718 ; C -1 ; WX 667 ; N Atilde ; B 14 0 699 917 ; C -1 ; WX 667 ; N Aogonek ; B 14 -225 654 718 ; C -1 ; WX 667 ; N Aring ; B 14 0 654 931 ; C -1 ; WX 778 ; N Otilde ; B 105 -19 826 917 ; C -1 ; WX 500 ; N zdotaccent ; B 31 0 571 706 ; C -1 ; WX 667 ; N Ecaron ; B 86 0 762 929 ; C -1 ; WX 278 ; N Iogonek ; B -33 -225 341 718 ; C -1 ; WX 500 ; N kcommaaccent ; B 67 -225 600 718 ; C -1 ; WX 584 ; N minus ; B 85 216 606 289 ; C -1 ; WX 278 ; N Icircumflex ; B 91 0 452 929 ; C -1 ; WX 556 ; N ncaron ; B 65 0 580 734 ; C -1 ; WX 278 ; N tcommaaccent ; B 63 -225 368 669 ; C -1 ; WX 584 ; N logicalnot ; B 106 108 628 390 ; C -1 ; WX 556 ; N odieresis ; B 83 -14 585 706 ; C -1 ; WX 556 ; N udieresis ; B 94 -15 600 706 ; C -1 ; WX 549 ; N notequal ; B 34 -35 623 551 ; C -1 ; WX 556 ; N gcommaaccent ; B 42 -220 610 822 ; C -1 ; WX 556 ; N eth ; B 81 -15 617 737 ; C -1 ; WX 500 ; N zcaron ; B 31 0 571 734 ; C -1 ; WX 556 ; N ncommaaccent ; B 65 -225 573 538 ; C -1 ; WX 333 ; N onesuperior ; B 166 281 371 703 ; C -1 ; WX 278 ; N imacron ; B 95 0 417 684 ; C -1 ; WX 556 ; N Euro ; B 0 0 0 0 ; EndCharMetrics StartKernData StartKernPairs 2705 KPX A C -30 KPX A Cacute -30 KPX A Ccaron -30 KPX A Ccedilla -30 KPX A G -30 KPX A Gbreve -30 KPX A Gcommaaccent -30 KPX A O -30 KPX A Oacute -30 KPX A Ocircumflex -30 KPX A Odieresis -30 KPX A Ograve -30 KPX A Ohungarumlaut -30 KPX A Omacron -30 KPX A Oslash -30 KPX A Otilde -30 KPX A Q -30 KPX A T -120 KPX A Tcaron -120 KPX A Tcommaaccent -120 KPX A U -50 KPX A Uacute -50 KPX A Ucircumflex -50 KPX A Udieresis -50 KPX A Ugrave -50 KPX A Uhungarumlaut -50 KPX A Umacron -50 KPX A Uogonek -50 KPX A Uring -50 KPX A V -70 KPX A W -50 KPX A Y -100 KPX A Yacute -100 KPX A Ydieresis -100 KPX A u -30 KPX A uacute -30 KPX A ucircumflex -30 KPX A udieresis -30 KPX A ugrave -30 KPX A uhungarumlaut -30 KPX A umacron -30 KPX A uogonek -30 KPX A uring -30 KPX A v -40 KPX A w -40 KPX A y -40 KPX A yacute -40 KPX A ydieresis -40 KPX Aacute C -30 KPX Aacute Cacute -30 KPX Aacute Ccaron -30 KPX Aacute Ccedilla -30 KPX Aacute G -30 KPX Aacute Gbreve -30 KPX Aacute Gcommaaccent -30 KPX Aacute O -30 KPX Aacute Oacute -30 KPX Aacute Ocircumflex -30 KPX Aacute Odieresis -30 KPX Aacute Ograve -30 KPX Aacute Ohungarumlaut -30 KPX Aacute Omacron -30 KPX Aacute Oslash -30 KPX Aacute Otilde -30 KPX Aacute Q -30 KPX Aacute T -120 KPX Aacute Tcaron -120 KPX Aacute Tcommaaccent -120 KPX Aacute U -50 KPX Aacute Uacute -50 KPX Aacute Ucircumflex -50 KPX Aacute Udieresis -50 KPX Aacute Ugrave -50 KPX Aacute Uhungarumlaut -50 KPX Aacute Umacron -50 KPX Aacute Uogonek -50 KPX Aacute Uring -50 KPX Aacute V -70 KPX Aacute W -50 KPX Aacute Y -100 KPX Aacute Yacute -100 KPX Aacute Ydieresis -100 KPX Aacute u -30 KPX Aacute uacute -30 KPX Aacute ucircumflex -30 KPX Aacute udieresis -30 KPX Aacute ugrave -30 KPX Aacute uhungarumlaut -30 KPX Aacute umacron -30 KPX Aacute uogonek -30 KPX Aacute uring -30 KPX Aacute v -40 KPX Aacute w -40 KPX Aacute y -40 KPX Aacute yacute -40 KPX Aacute ydieresis -40 KPX Abreve C -30 KPX Abreve Cacute -30 KPX Abreve Ccaron -30 KPX Abreve Ccedilla -30 KPX Abreve G -30 KPX Abreve Gbreve -30 KPX Abreve Gcommaaccent -30 KPX Abreve O -30 KPX Abreve Oacute -30 KPX Abreve Ocircumflex -30 KPX Abreve Odieresis -30 KPX Abreve Ograve -30 KPX Abreve Ohungarumlaut -30 KPX Abreve Omacron -30 KPX Abreve Oslash -30 KPX Abreve Otilde -30 KPX Abreve Q -30 KPX Abreve T -120 KPX Abreve Tcaron -120 KPX Abreve Tcommaaccent -120 KPX Abreve U -50 KPX Abreve Uacute -50 KPX Abreve Ucircumflex -50 KPX Abreve Udieresis -50 KPX Abreve Ugrave -50 KPX Abreve Uhungarumlaut -50 KPX Abreve Umacron -50 KPX Abreve Uogonek -50 KPX Abreve Uring -50 KPX Abreve V -70 KPX Abreve W -50 KPX Abreve Y -100 KPX Abreve Yacute -100 KPX Abreve Ydieresis -100 KPX Abreve u -30 KPX Abreve uacute -30 KPX Abreve ucircumflex -30 KPX Abreve udieresis -30 KPX Abreve ugrave -30 KPX Abreve uhungarumlaut -30 KPX Abreve umacron -30 KPX Abreve uogonek -30 KPX Abreve uring -30 KPX Abreve v -40 KPX Abreve w -40 KPX Abreve y -40 KPX Abreve yacute -40 KPX Abreve ydieresis -40 KPX Acircumflex C -30 KPX Acircumflex Cacute -30 KPX Acircumflex Ccaron -30 KPX Acircumflex Ccedilla -30 KPX Acircumflex G -30 KPX Acircumflex Gbreve -30 KPX Acircumflex Gcommaaccent -30 KPX Acircumflex O -30 KPX Acircumflex Oacute -30 KPX Acircumflex Ocircumflex -30 KPX Acircumflex Odieresis -30 KPX Acircumflex Ograve -30 KPX Acircumflex Ohungarumlaut -30 KPX Acircumflex Omacron -30 KPX Acircumflex Oslash -30 KPX Acircumflex Otilde -30 KPX Acircumflex Q -30 KPX Acircumflex T -120 KPX Acircumflex Tcaron -120 KPX Acircumflex Tcommaaccent -120 KPX Acircumflex U -50 KPX Acircumflex Uacute -50 KPX Acircumflex Ucircumflex -50 KPX Acircumflex Udieresis -50 KPX Acircumflex Ugrave -50 KPX Acircumflex Uhungarumlaut -50 KPX Acircumflex Umacron -50 KPX Acircumflex Uogonek -50 KPX Acircumflex Uring -50 KPX Acircumflex V -70 KPX Acircumflex W -50 KPX Acircumflex Y -100 KPX Acircumflex Yacute -100 KPX Acircumflex Ydieresis -100 KPX Acircumflex u -30 KPX Acircumflex uacute -30 KPX Acircumflex ucircumflex -30 KPX Acircumflex udieresis -30 KPX Acircumflex ugrave -30 KPX Acircumflex uhungarumlaut -30 KPX Acircumflex umacron -30 KPX Acircumflex uogonek -30 KPX Acircumflex uring -30 KPX Acircumflex v -40 KPX Acircumflex w -40 KPX Acircumflex y -40 KPX Acircumflex yacute -40 KPX Acircumflex ydieresis -40 KPX Adieresis C -30 KPX Adieresis Cacute -30 KPX Adieresis Ccaron -30 KPX Adieresis Ccedilla -30 KPX Adieresis G -30 KPX Adieresis Gbreve -30 KPX Adieresis Gcommaaccent -30 KPX Adieresis O -30 KPX Adieresis Oacute -30 KPX Adieresis Ocircumflex -30 KPX Adieresis Odieresis -30 KPX Adieresis Ograve -30 KPX Adieresis Ohungarumlaut -30 KPX Adieresis Omacron -30 KPX Adieresis Oslash -30 KPX Adieresis Otilde -30 KPX Adieresis Q -30 KPX Adieresis T -120 KPX Adieresis Tcaron -120 KPX Adieresis Tcommaaccent -120 KPX Adieresis U -50 KPX Adieresis Uacute -50 KPX Adieresis Ucircumflex -50 KPX Adieresis Udieresis -50 KPX Adieresis Ugrave -50 KPX Adieresis Uhungarumlaut -50 KPX Adieresis Umacron -50 KPX Adieresis Uogonek -50 KPX Adieresis Uring -50 KPX Adieresis V -70 KPX Adieresis W -50 KPX Adieresis Y -100 KPX Adieresis Yacute -100 KPX Adieresis Ydieresis -100 KPX Adieresis u -30 KPX Adieresis uacute -30 KPX Adieresis ucircumflex -30 KPX Adieresis udieresis -30 KPX Adieresis ugrave -30 KPX Adieresis uhungarumlaut -30 KPX Adieresis umacron -30 KPX Adieresis uogonek -30 KPX Adieresis uring -30 KPX Adieresis v -40 KPX Adieresis w -40 KPX Adieresis y -40 KPX Adieresis yacute -40 KPX Adieresis ydieresis -40 KPX Agrave C -30 KPX Agrave Cacute -30 KPX Agrave Ccaron -30 KPX Agrave Ccedilla -30 KPX Agrave G -30 KPX Agrave Gbreve -30 KPX Agrave Gcommaaccent -30 KPX Agrave O -30 KPX Agrave Oacute -30 KPX Agrave Ocircumflex -30 KPX Agrave Odieresis -30 KPX Agrave Ograve -30 KPX Agrave Ohungarumlaut -30 KPX Agrave Omacron -30 KPX Agrave Oslash -30 KPX Agrave Otilde -30 KPX Agrave Q -30 KPX Agrave T -120 KPX Agrave Tcaron -120 KPX Agrave Tcommaaccent -120 KPX Agrave U -50 KPX Agrave Uacute -50 KPX Agrave Ucircumflex -50 KPX Agrave Udieresis -50 KPX Agrave Ugrave -50 KPX Agrave Uhungarumlaut -50 KPX Agrave Umacron -50 KPX Agrave Uogonek -50 KPX Agrave Uring -50 KPX Agrave V -70 KPX Agrave W -50 KPX Agrave Y -100 KPX Agrave Yacute -100 KPX Agrave Ydieresis -100 KPX Agrave u -30 KPX Agrave uacute -30 KPX Agrave ucircumflex -30 KPX Agrave udieresis -30 KPX Agrave ugrave -30 KPX Agrave uhungarumlaut -30 KPX Agrave umacron -30 KPX Agrave uogonek -30 KPX Agrave uring -30 KPX Agrave v -40 KPX Agrave w -40 KPX Agrave y -40 KPX Agrave yacute -40 KPX Agrave ydieresis -40 KPX Amacron C -30 KPX Amacron Cacute -30 KPX Amacron Ccaron -30 KPX Amacron Ccedilla -30 KPX Amacron G -30 KPX Amacron Gbreve -30 KPX Amacron Gcommaaccent -30 KPX Amacron O -30 KPX Amacron Oacute -30 KPX Amacron Ocircumflex -30 KPX Amacron Odieresis -30 KPX Amacron Ograve -30 KPX Amacron Ohungarumlaut -30 KPX Amacron Omacron -30 KPX Amacron Oslash -30 KPX Amacron Otilde -30 KPX Amacron Q -30 KPX Amacron T -120 KPX Amacron Tcaron -120 KPX Amacron Tcommaaccent -120 KPX Amacron U -50 KPX Amacron Uacute -50 KPX Amacron Ucircumflex -50 KPX Amacron Udieresis -50 KPX Amacron Ugrave -50 KPX Amacron Uhungarumlaut -50 KPX Amacron Umacron -50 KPX Amacron Uogonek -50 KPX Amacron Uring -50 KPX Amacron V -70 KPX Amacron W -50 KPX Amacron Y -100 KPX Amacron Yacute -100 KPX Amacron Ydieresis -100 KPX Amacron u -30 KPX Amacron uacute -30 KPX Amacron ucircumflex -30 KPX Amacron udieresis -30 KPX Amacron ugrave -30 KPX Amacron uhungarumlaut -30 KPX Amacron umacron -30 KPX Amacron uogonek -30 KPX Amacron uring -30 KPX Amacron v -40 KPX Amacron w -40 KPX Amacron y -40 KPX Amacron yacute -40 KPX Amacron ydieresis -40 KPX Aogonek C -30 KPX Aogonek Cacute -30 KPX Aogonek Ccaron -30 KPX Aogonek Ccedilla -30 KPX Aogonek G -30 KPX Aogonek Gbreve -30 KPX Aogonek Gcommaaccent -30 KPX Aogonek O -30 KPX Aogonek Oacute -30 KPX Aogonek Ocircumflex -30 KPX Aogonek Odieresis -30 KPX Aogonek Ograve -30 KPX Aogonek Ohungarumlaut -30 KPX Aogonek Omacron -30 KPX Aogonek Oslash -30 KPX Aogonek Otilde -30 KPX Aogonek Q -30 KPX Aogonek T -120 KPX Aogonek Tcaron -120 KPX Aogonek Tcommaaccent -120 KPX Aogonek U -50 KPX Aogonek Uacute -50 KPX Aogonek Ucircumflex -50 KPX Aogonek Udieresis -50 KPX Aogonek Ugrave -50 KPX Aogonek Uhungarumlaut -50 KPX Aogonek Umacron -50 KPX Aogonek Uogonek -50 KPX Aogonek Uring -50 KPX Aogonek V -70 KPX Aogonek W -50 KPX Aogonek Y -100 KPX Aogonek Yacute -100 KPX Aogonek Ydieresis -100 KPX Aogonek u -30 KPX Aogonek uacute -30 KPX Aogonek ucircumflex -30 KPX Aogonek udieresis -30 KPX Aogonek ugrave -30 KPX Aogonek uhungarumlaut -30 KPX Aogonek umacron -30 KPX Aogonek uogonek -30 KPX Aogonek uring -30 KPX Aogonek v -40 KPX Aogonek w -40 KPX Aogonek y -40 KPX Aogonek yacute -40 KPX Aogonek ydieresis -40 KPX Aring C -30 KPX Aring Cacute -30 KPX Aring Ccaron -30 KPX Aring Ccedilla -30 KPX Aring G -30 KPX Aring Gbreve -30 KPX Aring Gcommaaccent -30 KPX Aring O -30 KPX Aring Oacute -30 KPX Aring Ocircumflex -30 KPX Aring Odieresis -30 KPX Aring Ograve -30 KPX Aring Ohungarumlaut -30 KPX Aring Omacron -30 KPX Aring Oslash -30 KPX Aring Otilde -30 KPX Aring Q -30 KPX Aring T -120 KPX Aring Tcaron -120 KPX Aring Tcommaaccent -120 KPX Aring U -50 KPX Aring Uacute -50 KPX Aring Ucircumflex -50 KPX Aring Udieresis -50 KPX Aring Ugrave -50 KPX Aring Uhungarumlaut -50 KPX Aring Umacron -50 KPX Aring Uogonek -50 KPX Aring Uring -50 KPX Aring V -70 KPX Aring W -50 KPX Aring Y -100 KPX Aring Yacute -100 KPX Aring Ydieresis -100 KPX Aring u -30 KPX Aring uacute -30 KPX Aring ucircumflex -30 KPX Aring udieresis -30 KPX Aring ugrave -30 KPX Aring uhungarumlaut -30 KPX Aring umacron -30 KPX Aring uogonek -30 KPX Aring uring -30 KPX Aring v -40 KPX Aring w -40 KPX Aring y -40 KPX Aring yacute -40 KPX Aring ydieresis -40 KPX Atilde C -30 KPX Atilde Cacute -30 KPX Atilde Ccaron -30 KPX Atilde Ccedilla -30 KPX Atilde G -30 KPX Atilde Gbreve -30 KPX Atilde Gcommaaccent -30 KPX Atilde O -30 KPX Atilde Oacute -30 KPX Atilde Ocircumflex -30 KPX Atilde Odieresis -30 KPX Atilde Ograve -30 KPX Atilde Ohungarumlaut -30 KPX Atilde Omacron -30 KPX Atilde Oslash -30 KPX Atilde Otilde -30 KPX Atilde Q -30 KPX Atilde T -120 KPX Atilde Tcaron -120 KPX Atilde Tcommaaccent -120 KPX Atilde U -50 KPX Atilde Uacute -50 KPX Atilde Ucircumflex -50 KPX Atilde Udieresis -50 KPX Atilde Ugrave -50 KPX Atilde Uhungarumlaut -50 KPX Atilde Umacron -50 KPX Atilde Uogonek -50 KPX Atilde Uring -50 KPX Atilde V -70 KPX Atilde W -50 KPX Atilde Y -100 KPX Atilde Yacute -100 KPX Atilde Ydieresis -100 KPX Atilde u -30 KPX Atilde uacute -30 KPX Atilde ucircumflex -30 KPX Atilde udieresis -30 KPX Atilde ugrave -30 KPX Atilde uhungarumlaut -30 KPX Atilde umacron -30 KPX Atilde uogonek -30 KPX Atilde uring -30 KPX Atilde v -40 KPX Atilde w -40 KPX Atilde y -40 KPX Atilde yacute -40 KPX Atilde ydieresis -40 KPX B U -10 KPX B Uacute -10 KPX B Ucircumflex -10 KPX B Udieresis -10 KPX B Ugrave -10 KPX B Uhungarumlaut -10 KPX B Umacron -10 KPX B Uogonek -10 KPX B Uring -10 KPX B comma -20 KPX B period -20 KPX C comma -30 KPX C period -30 KPX Cacute comma -30 KPX Cacute period -30 KPX Ccaron comma -30 KPX Ccaron period -30 KPX Ccedilla comma -30 KPX Ccedilla period -30 KPX D A -40 KPX D Aacute -40 KPX D Abreve -40 KPX D Acircumflex -40 KPX D Adieresis -40 KPX D Agrave -40 KPX D Amacron -40 KPX D Aogonek -40 KPX D Aring -40 KPX D Atilde -40 KPX D V -70 KPX D W -40 KPX D Y -90 KPX D Yacute -90 KPX D Ydieresis -90 KPX D comma -70 KPX D period -70 KPX Dcaron A -40 KPX Dcaron Aacute -40 KPX Dcaron Abreve -40 KPX Dcaron Acircumflex -40 KPX Dcaron Adieresis -40 KPX Dcaron Agrave -40 KPX Dcaron Amacron -40 KPX Dcaron Aogonek -40 KPX Dcaron Aring -40 KPX Dcaron Atilde -40 KPX Dcaron V -70 KPX Dcaron W -40 KPX Dcaron Y -90 KPX Dcaron Yacute -90 KPX Dcaron Ydieresis -90 KPX Dcaron comma -70 KPX Dcaron period -70 KPX Dcroat A -40 KPX Dcroat Aacute -40 KPX Dcroat Abreve -40 KPX Dcroat Acircumflex -40 KPX Dcroat Adieresis -40 KPX Dcroat Agrave -40 KPX Dcroat Amacron -40 KPX Dcroat Aogonek -40 KPX Dcroat Aring -40 KPX Dcroat Atilde -40 KPX Dcroat V -70 KPX Dcroat W -40 KPX Dcroat Y -90 KPX Dcroat Yacute -90 KPX Dcroat Ydieresis -90 KPX Dcroat comma -70 KPX Dcroat period -70 KPX F A -80 KPX F Aacute -80 KPX F Abreve -80 KPX F Acircumflex -80 KPX F Adieresis -80 KPX F Agrave -80 KPX F Amacron -80 KPX F Aogonek -80 KPX F Aring -80 KPX F Atilde -80 KPX F a -50 KPX F aacute -50 KPX F abreve -50 KPX F acircumflex -50 KPX F adieresis -50 KPX F agrave -50 KPX F amacron -50 KPX F aogonek -50 KPX F aring -50 KPX F atilde -50 KPX F comma -150 KPX F e -30 KPX F eacute -30 KPX F ecaron -30 KPX F ecircumflex -30 KPX F edieresis -30 KPX F edotaccent -30 KPX F egrave -30 KPX F emacron -30 KPX F eogonek -30 KPX F o -30 KPX F oacute -30 KPX F ocircumflex -30 KPX F odieresis -30 KPX F ograve -30 KPX F ohungarumlaut -30 KPX F omacron -30 KPX F oslash -30 KPX F otilde -30 KPX F period -150 KPX F r -45 KPX F racute -45 KPX F rcaron -45 KPX F rcommaaccent -45 KPX J A -20 KPX J Aacute -20 KPX J Abreve -20 KPX J Acircumflex -20 KPX J Adieresis -20 KPX J Agrave -20 KPX J Amacron -20 KPX J Aogonek -20 KPX J Aring -20 KPX J Atilde -20 KPX J a -20 KPX J aacute -20 KPX J abreve -20 KPX J acircumflex -20 KPX J adieresis -20 KPX J agrave -20 KPX J amacron -20 KPX J aogonek -20 KPX J aring -20 KPX J atilde -20 KPX J comma -30 KPX J period -30 KPX J u -20 KPX J uacute -20 KPX J ucircumflex -20 KPX J udieresis -20 KPX J ugrave -20 KPX J uhungarumlaut -20 KPX J umacron -20 KPX J uogonek -20 KPX J uring -20 KPX K O -50 KPX K Oacute -50 KPX K Ocircumflex -50 KPX K Odieresis -50 KPX K Ograve -50 KPX K Ohungarumlaut -50 KPX K Omacron -50 KPX K Oslash -50 KPX K Otilde -50 KPX K e -40 KPX K eacute -40 KPX K ecaron -40 KPX K ecircumflex -40 KPX K edieresis -40 KPX K edotaccent -40 KPX K egrave -40 KPX K emacron -40 KPX K eogonek -40 KPX K o -40 KPX K oacute -40 KPX K ocircumflex -40 KPX K odieresis -40 KPX K ograve -40 KPX K ohungarumlaut -40 KPX K omacron -40 KPX K oslash -40 KPX K otilde -40 KPX K u -30 KPX K uacute -30 KPX K ucircumflex -30 KPX K udieresis -30 KPX K ugrave -30 KPX K uhungarumlaut -30 KPX K umacron -30 KPX K uogonek -30 KPX K uring -30 KPX K y -50 KPX K yacute -50 KPX K ydieresis -50 KPX Kcommaaccent O -50 KPX Kcommaaccent Oacute -50 KPX Kcommaaccent Ocircumflex -50 KPX Kcommaaccent Odieresis -50 KPX Kcommaaccent Ograve -50 KPX Kcommaaccent Ohungarumlaut -50 KPX Kcommaaccent Omacron -50 KPX Kcommaaccent Oslash -50 KPX Kcommaaccent Otilde -50 KPX Kcommaaccent e -40 KPX Kcommaaccent eacute -40 KPX Kcommaaccent ecaron -40 KPX Kcommaaccent ecircumflex -40 KPX Kcommaaccent edieresis -40 KPX Kcommaaccent edotaccent -40 KPX Kcommaaccent egrave -40 KPX Kcommaaccent emacron -40 KPX Kcommaaccent eogonek -40 KPX Kcommaaccent o -40 KPX Kcommaaccent oacute -40 KPX Kcommaaccent ocircumflex -40 KPX Kcommaaccent odieresis -40 KPX Kcommaaccent ograve -40 KPX Kcommaaccent ohungarumlaut -40 KPX Kcommaaccent omacron -40 KPX Kcommaaccent oslash -40 KPX Kcommaaccent otilde -40 KPX Kcommaaccent u -30 KPX Kcommaaccent uacute -30 KPX Kcommaaccent ucircumflex -30 KPX Kcommaaccent udieresis -30 KPX Kcommaaccent ugrave -30 KPX Kcommaaccent uhungarumlaut -30 KPX Kcommaaccent umacron -30 KPX Kcommaaccent uogonek -30 KPX Kcommaaccent uring -30 KPX Kcommaaccent y -50 KPX Kcommaaccent yacute -50 KPX Kcommaaccent ydieresis -50 KPX L T -110 KPX L Tcaron -110 KPX L Tcommaaccent -110 KPX L V -110 KPX L W -70 KPX L Y -140 KPX L Yacute -140 KPX L Ydieresis -140 KPX L quotedblright -140 KPX L quoteright -160 KPX L y -30 KPX L yacute -30 KPX L ydieresis -30 KPX Lacute T -110 KPX Lacute Tcaron -110 KPX Lacute Tcommaaccent -110 KPX Lacute V -110 KPX Lacute W -70 KPX Lacute Y -140 KPX Lacute Yacute -140 KPX Lacute Ydieresis -140 KPX Lacute quotedblright -140 KPX Lacute quoteright -160 KPX Lacute y -30 KPX Lacute yacute -30 KPX Lacute ydieresis -30 KPX Lcaron T -110 KPX Lcaron Tcaron -110 KPX Lcaron Tcommaaccent -110 KPX Lcaron V -110 KPX Lcaron W -70 KPX Lcaron Y -140 KPX Lcaron Yacute -140 KPX Lcaron Ydieresis -140 KPX Lcaron quotedblright -140 KPX Lcaron quoteright -160 KPX Lcaron y -30 KPX Lcaron yacute -30 KPX Lcaron ydieresis -30 KPX Lcommaaccent T -110 KPX Lcommaaccent Tcaron -110 KPX Lcommaaccent Tcommaaccent -110 KPX Lcommaaccent V -110 KPX Lcommaaccent W -70 KPX Lcommaaccent Y -140 KPX Lcommaaccent Yacute -140 KPX Lcommaaccent Ydieresis -140 KPX Lcommaaccent quotedblright -140 KPX Lcommaaccent quoteright -160 KPX Lcommaaccent y -30 KPX Lcommaaccent yacute -30 KPX Lcommaaccent ydieresis -30 KPX Lslash T -110 KPX Lslash Tcaron -110 KPX Lslash Tcommaaccent -110 KPX Lslash V -110 KPX Lslash W -70 KPX Lslash Y -140 KPX Lslash Yacute -140 KPX Lslash Ydieresis -140 KPX Lslash quotedblright -140 KPX Lslash quoteright -160 KPX Lslash y -30 KPX Lslash yacute -30 KPX Lslash ydieresis -30 KPX O A -20 KPX O Aacute -20 KPX O Abreve -20 KPX O Acircumflex -20 KPX O Adieresis -20 KPX O Agrave -20 KPX O Amacron -20 KPX O Aogonek -20 KPX O Aring -20 KPX O Atilde -20 KPX O T -40 KPX O Tcaron -40 KPX O Tcommaaccent -40 KPX O V -50 KPX O W -30 KPX O X -60 KPX O Y -70 KPX O Yacute -70 KPX O Ydieresis -70 KPX O comma -40 KPX O period -40 KPX Oacute A -20 KPX Oacute Aacute -20 KPX Oacute Abreve -20 KPX Oacute Acircumflex -20 KPX Oacute Adieresis -20 KPX Oacute Agrave -20 KPX Oacute Amacron -20 KPX Oacute Aogonek -20 KPX Oacute Aring -20 KPX Oacute Atilde -20 KPX Oacute T -40 KPX Oacute Tcaron -40 KPX Oacute Tcommaaccent -40 KPX Oacute V -50 KPX Oacute W -30 KPX Oacute X -60 KPX Oacute Y -70 KPX Oacute Yacute -70 KPX Oacute Ydieresis -70 KPX Oacute comma -40 KPX Oacute period -40 KPX Ocircumflex A -20 KPX Ocircumflex Aacute -20 KPX Ocircumflex Abreve -20 KPX Ocircumflex Acircumflex -20 KPX Ocircumflex Adieresis -20 KPX Ocircumflex Agrave -20 KPX Ocircumflex Amacron -20 KPX Ocircumflex Aogonek -20 KPX Ocircumflex Aring -20 KPX Ocircumflex Atilde -20 KPX Ocircumflex T -40 KPX Ocircumflex Tcaron -40 KPX Ocircumflex Tcommaaccent -40 KPX Ocircumflex V -50 KPX Ocircumflex W -30 KPX Ocircumflex X -60 KPX Ocircumflex Y -70 KPX Ocircumflex Yacute -70 KPX Ocircumflex Ydieresis -70 KPX Ocircumflex comma -40 KPX Ocircumflex period -40 KPX Odieresis A -20 KPX Odieresis Aacute -20 KPX Odieresis Abreve -20 KPX Odieresis Acircumflex -20 KPX Odieresis Adieresis -20 KPX Odieresis Agrave -20 KPX Odieresis Amacron -20 KPX Odieresis Aogonek -20 KPX Odieresis Aring -20 KPX Odieresis Atilde -20 KPX Odieresis T -40 KPX Odieresis Tcaron -40 KPX Odieresis Tcommaaccent -40 KPX Odieresis V -50 KPX Odieresis W -30 KPX Odieresis X -60 KPX Odieresis Y -70 KPX Odieresis Yacute -70 KPX Odieresis Ydieresis -70 KPX Odieresis comma -40 KPX Odieresis period -40 KPX Ograve A -20 KPX Ograve Aacute -20 KPX Ograve Abreve -20 KPX Ograve Acircumflex -20 KPX Ograve Adieresis -20 KPX Ograve Agrave -20 KPX Ograve Amacron -20 KPX Ograve Aogonek -20 KPX Ograve Aring -20 KPX Ograve Atilde -20 KPX Ograve T -40 KPX Ograve Tcaron -40 KPX Ograve Tcommaaccent -40 KPX Ograve V -50 KPX Ograve W -30 KPX Ograve X -60 KPX Ograve Y -70 KPX Ograve Yacute -70 KPX Ograve Ydieresis -70 KPX Ograve comma -40 KPX Ograve period -40 KPX Ohungarumlaut A -20 KPX Ohungarumlaut Aacute -20 KPX Ohungarumlaut Abreve -20 KPX Ohungarumlaut Acircumflex -20 KPX Ohungarumlaut Adieresis -20 KPX Ohungarumlaut Agrave -20 KPX Ohungarumlaut Amacron -20 KPX Ohungarumlaut Aogonek -20 KPX Ohungarumlaut Aring -20 KPX Ohungarumlaut Atilde -20 KPX Ohungarumlaut T -40 KPX Ohungarumlaut Tcaron -40 KPX Ohungarumlaut Tcommaaccent -40 KPX Ohungarumlaut V -50 KPX Ohungarumlaut W -30 KPX Ohungarumlaut X -60 KPX Ohungarumlaut Y -70 KPX Ohungarumlaut Yacute -70 KPX Ohungarumlaut Ydieresis -70 KPX Ohungarumlaut comma -40 KPX Ohungarumlaut period -40 KPX Omacron A -20 KPX Omacron Aacute -20 KPX Omacron Abreve -20 KPX Omacron Acircumflex -20 KPX Omacron Adieresis -20 KPX Omacron Agrave -20 KPX Omacron Amacron -20 KPX Omacron Aogonek -20 KPX Omacron Aring -20 KPX Omacron Atilde -20 KPX Omacron T -40 KPX Omacron Tcaron -40 KPX Omacron Tcommaaccent -40 KPX Omacron V -50 KPX Omacron W -30 KPX Omacron X -60 KPX Omacron Y -70 KPX Omacron Yacute -70 KPX Omacron Ydieresis -70 KPX Omacron comma -40 KPX Omacron period -40 KPX Oslash A -20 KPX Oslash Aacute -20 KPX Oslash Abreve -20 KPX Oslash Acircumflex -20 KPX Oslash Adieresis -20 KPX Oslash Agrave -20 KPX Oslash Amacron -20 KPX Oslash Aogonek -20 KPX Oslash Aring -20 KPX Oslash Atilde -20 KPX Oslash T -40 KPX Oslash Tcaron -40 KPX Oslash Tcommaaccent -40 KPX Oslash V -50 KPX Oslash W -30 KPX Oslash X -60 KPX Oslash Y -70 KPX Oslash Yacute -70 KPX Oslash Ydieresis -70 KPX Oslash comma -40 KPX Oslash period -40 KPX Otilde A -20 KPX Otilde Aacute -20 KPX Otilde Abreve -20 KPX Otilde Acircumflex -20 KPX Otilde Adieresis -20 KPX Otilde Agrave -20 KPX Otilde Amacron -20 KPX Otilde Aogonek -20 KPX Otilde Aring -20 KPX Otilde Atilde -20 KPX Otilde T -40 KPX Otilde Tcaron -40 KPX Otilde Tcommaaccent -40 KPX Otilde V -50 KPX Otilde W -30 KPX Otilde X -60 KPX Otilde Y -70 KPX Otilde Yacute -70 KPX Otilde Ydieresis -70 KPX Otilde comma -40 KPX Otilde period -40 KPX P A -120 KPX P Aacute -120 KPX P Abreve -120 KPX P Acircumflex -120 KPX P Adieresis -120 KPX P Agrave -120 KPX P Amacron -120 KPX P Aogonek -120 KPX P Aring -120 KPX P Atilde -120 KPX P a -40 KPX P aacute -40 KPX P abreve -40 KPX P acircumflex -40 KPX P adieresis -40 KPX P agrave -40 KPX P amacron -40 KPX P aogonek -40 KPX P aring -40 KPX P atilde -40 KPX P comma -180 KPX P e -50 KPX P eacute -50 KPX P ecaron -50 KPX P ecircumflex -50 KPX P edieresis -50 KPX P edotaccent -50 KPX P egrave -50 KPX P emacron -50 KPX P eogonek -50 KPX P o -50 KPX P oacute -50 KPX P ocircumflex -50 KPX P odieresis -50 KPX P ograve -50 KPX P ohungarumlaut -50 KPX P omacron -50 KPX P oslash -50 KPX P otilde -50 KPX P period -180 KPX Q U -10 KPX Q Uacute -10 KPX Q Ucircumflex -10 KPX Q Udieresis -10 KPX Q Ugrave -10 KPX Q Uhungarumlaut -10 KPX Q Umacron -10 KPX Q Uogonek -10 KPX Q Uring -10 KPX R O -20 KPX R Oacute -20 KPX R Ocircumflex -20 KPX R Odieresis -20 KPX R Ograve -20 KPX R Ohungarumlaut -20 KPX R Omacron -20 KPX R Oslash -20 KPX R Otilde -20 KPX R T -30 KPX R Tcaron -30 KPX R Tcommaaccent -30 KPX R U -40 KPX R Uacute -40 KPX R Ucircumflex -40 KPX R Udieresis -40 KPX R Ugrave -40 KPX R Uhungarumlaut -40 KPX R Umacron -40 KPX R Uogonek -40 KPX R Uring -40 KPX R V -50 KPX R W -30 KPX R Y -50 KPX R Yacute -50 KPX R Ydieresis -50 KPX Racute O -20 KPX Racute Oacute -20 KPX Racute Ocircumflex -20 KPX Racute Odieresis -20 KPX Racute Ograve -20 KPX Racute Ohungarumlaut -20 KPX Racute Omacron -20 KPX Racute Oslash -20 KPX Racute Otilde -20 KPX Racute T -30 KPX Racute Tcaron -30 KPX Racute Tcommaaccent -30 KPX Racute U -40 KPX Racute Uacute -40 KPX Racute Ucircumflex -40 KPX Racute Udieresis -40 KPX Racute Ugrave -40 KPX Racute Uhungarumlaut -40 KPX Racute Umacron -40 KPX Racute Uogonek -40 KPX Racute Uring -40 KPX Racute V -50 KPX Racute W -30 KPX Racute Y -50 KPX Racute Yacute -50 KPX Racute Ydieresis -50 KPX Rcaron O -20 KPX Rcaron Oacute -20 KPX Rcaron Ocircumflex -20 KPX Rcaron Odieresis -20 KPX Rcaron Ograve -20 KPX Rcaron Ohungarumlaut -20 KPX Rcaron Omacron -20 KPX Rcaron Oslash -20 KPX Rcaron Otilde -20 KPX Rcaron T -30 KPX Rcaron Tcaron -30 KPX Rcaron Tcommaaccent -30 KPX Rcaron U -40 KPX Rcaron Uacute -40 KPX Rcaron Ucircumflex -40 KPX Rcaron Udieresis -40 KPX Rcaron Ugrave -40 KPX Rcaron Uhungarumlaut -40 KPX Rcaron Umacron -40 KPX Rcaron Uogonek -40 KPX Rcaron Uring -40 KPX Rcaron V -50 KPX Rcaron W -30 KPX Rcaron Y -50 KPX Rcaron Yacute -50 KPX Rcaron Ydieresis -50 KPX Rcommaaccent O -20 KPX Rcommaaccent Oacute -20 KPX Rcommaaccent Ocircumflex -20 KPX Rcommaaccent Odieresis -20 KPX Rcommaaccent Ograve -20 KPX Rcommaaccent Ohungarumlaut -20 KPX Rcommaaccent Omacron -20 KPX Rcommaaccent Oslash -20 KPX Rcommaaccent Otilde -20 KPX Rcommaaccent T -30 KPX Rcommaaccent Tcaron -30 KPX Rcommaaccent Tcommaaccent -30 KPX Rcommaaccent U -40 KPX Rcommaaccent Uacute -40 KPX Rcommaaccent Ucircumflex -40 KPX Rcommaaccent Udieresis -40 KPX Rcommaaccent Ugrave -40 KPX Rcommaaccent Uhungarumlaut -40 KPX Rcommaaccent Umacron -40 KPX Rcommaaccent Uogonek -40 KPX Rcommaaccent Uring -40 KPX Rcommaaccent V -50 KPX Rcommaaccent W -30 KPX Rcommaaccent Y -50 KPX Rcommaaccent Yacute -50 KPX Rcommaaccent Ydieresis -50 KPX S comma -20 KPX S period -20 KPX Sacute comma -20 KPX Sacute period -20 KPX Scaron comma -20 KPX Scaron period -20 KPX Scedilla comma -20 KPX Scedilla period -20 KPX Scommaaccent comma -20 KPX Scommaaccent period -20 KPX T A -120 KPX T Aacute -120 KPX T Abreve -120 KPX T Acircumflex -120 KPX T Adieresis -120 KPX T Agrave -120 KPX T Amacron -120 KPX T Aogonek -120 KPX T Aring -120 KPX T Atilde -120 KPX T O -40 KPX T Oacute -40 KPX T Ocircumflex -40 KPX T Odieresis -40 KPX T Ograve -40 KPX T Ohungarumlaut -40 KPX T Omacron -40 KPX T Oslash -40 KPX T Otilde -40 KPX T a -120 KPX T aacute -120 KPX T abreve -60 KPX T acircumflex -120 KPX T adieresis -120 KPX T agrave -120 KPX T amacron -60 KPX T aogonek -120 KPX T aring -120 KPX T atilde -60 KPX T colon -20 KPX T comma -120 KPX T e -120 KPX T eacute -120 KPX T ecaron -120 KPX T ecircumflex -120 KPX T edieresis -120 KPX T edotaccent -120 KPX T egrave -60 KPX T emacron -60 KPX T eogonek -120 KPX T hyphen -140 KPX T o -120 KPX T oacute -120 KPX T ocircumflex -120 KPX T odieresis -120 KPX T ograve -120 KPX T ohungarumlaut -120 KPX T omacron -60 KPX T oslash -120 KPX T otilde -60 KPX T period -120 KPX T r -120 KPX T racute -120 KPX T rcaron -120 KPX T rcommaaccent -120 KPX T semicolon -20 KPX T u -120 KPX T uacute -120 KPX T ucircumflex -120 KPX T udieresis -120 KPX T ugrave -120 KPX T uhungarumlaut -120 KPX T umacron -60 KPX T uogonek -120 KPX T uring -120 KPX T w -120 KPX T y -120 KPX T yacute -120 KPX T ydieresis -60 KPX Tcaron A -120 KPX Tcaron Aacute -120 KPX Tcaron Abreve -120 KPX Tcaron Acircumflex -120 KPX Tcaron Adieresis -120 KPX Tcaron Agrave -120 KPX Tcaron Amacron -120 KPX Tcaron Aogonek -120 KPX Tcaron Aring -120 KPX Tcaron Atilde -120 KPX Tcaron O -40 KPX Tcaron Oacute -40 KPX Tcaron Ocircumflex -40 KPX Tcaron Odieresis -40 KPX Tcaron Ograve -40 KPX Tcaron Ohungarumlaut -40 KPX Tcaron Omacron -40 KPX Tcaron Oslash -40 KPX Tcaron Otilde -40 KPX Tcaron a -120 KPX Tcaron aacute -120 KPX Tcaron abreve -60 KPX Tcaron acircumflex -120 KPX Tcaron adieresis -120 KPX Tcaron agrave -120 KPX Tcaron amacron -60 KPX Tcaron aogonek -120 KPX Tcaron aring -120 KPX Tcaron atilde -60 KPX Tcaron colon -20 KPX Tcaron comma -120 KPX Tcaron e -120 KPX Tcaron eacute -120 KPX Tcaron ecaron -120 KPX Tcaron ecircumflex -120 KPX Tcaron edieresis -120 KPX Tcaron edotaccent -120 KPX Tcaron egrave -60 KPX Tcaron emacron -60 KPX Tcaron eogonek -120 KPX Tcaron hyphen -140 KPX Tcaron o -120 KPX Tcaron oacute -120 KPX Tcaron ocircumflex -120 KPX Tcaron odieresis -120 KPX Tcaron ograve -120 KPX Tcaron ohungarumlaut -120 KPX Tcaron omacron -60 KPX Tcaron oslash -120 KPX Tcaron otilde -60 KPX Tcaron period -120 KPX Tcaron r -120 KPX Tcaron racute -120 KPX Tcaron rcaron -120 KPX Tcaron rcommaaccent -120 KPX Tcaron semicolon -20 KPX Tcaron u -120 KPX Tcaron uacute -120 KPX Tcaron ucircumflex -120 KPX Tcaron udieresis -120 KPX Tcaron ugrave -120 KPX Tcaron uhungarumlaut -120 KPX Tcaron umacron -60 KPX Tcaron uogonek -120 KPX Tcaron uring -120 KPX Tcaron w -120 KPX Tcaron y -120 KPX Tcaron yacute -120 KPX Tcaron ydieresis -60 KPX Tcommaaccent A -120 KPX Tcommaaccent Aacute -120 KPX Tcommaaccent Abreve -120 KPX Tcommaaccent Acircumflex -120 KPX Tcommaaccent Adieresis -120 KPX Tcommaaccent Agrave -120 KPX Tcommaaccent Amacron -120 KPX Tcommaaccent Aogonek -120 KPX Tcommaaccent Aring -120 KPX Tcommaaccent Atilde -120 KPX Tcommaaccent O -40 KPX Tcommaaccent Oacute -40 KPX Tcommaaccent Ocircumflex -40 KPX Tcommaaccent Odieresis -40 KPX Tcommaaccent Ograve -40 KPX Tcommaaccent Ohungarumlaut -40 KPX Tcommaaccent Omacron -40 KPX Tcommaaccent Oslash -40 KPX Tcommaaccent Otilde -40 KPX Tcommaaccent a -120 KPX Tcommaaccent aacute -120 KPX Tcommaaccent abreve -60 KPX Tcommaaccent acircumflex -120 KPX Tcommaaccent adieresis -120 KPX Tcommaaccent agrave -120 KPX Tcommaaccent amacron -60 KPX Tcommaaccent aogonek -120 KPX Tcommaaccent aring -120 KPX Tcommaaccent atilde -60 KPX Tcommaaccent colon -20 KPX Tcommaaccent comma -120 KPX Tcommaaccent e -120 KPX Tcommaaccent eacute -120 KPX Tcommaaccent ecaron -120 KPX Tcommaaccent ecircumflex -120 KPX Tcommaaccent edieresis -120 KPX Tcommaaccent edotaccent -120 KPX Tcommaaccent egrave -60 KPX Tcommaaccent emacron -60 KPX Tcommaaccent eogonek -120 KPX Tcommaaccent hyphen -140 KPX Tcommaaccent o -120 KPX Tcommaaccent oacute -120 KPX Tcommaaccent ocircumflex -120 KPX Tcommaaccent odieresis -120 KPX Tcommaaccent ograve -120 KPX Tcommaaccent ohungarumlaut -120 KPX Tcommaaccent omacron -60 KPX Tcommaaccent oslash -120 KPX Tcommaaccent otilde -60 KPX Tcommaaccent period -120 KPX Tcommaaccent r -120 KPX Tcommaaccent racute -120 KPX Tcommaaccent rcaron -120 KPX Tcommaaccent rcommaaccent -120 KPX Tcommaaccent semicolon -20 KPX Tcommaaccent u -120 KPX Tcommaaccent uacute -120 KPX Tcommaaccent ucircumflex -120 KPX Tcommaaccent udieresis -120 KPX Tcommaaccent ugrave -120 KPX Tcommaaccent uhungarumlaut -120 KPX Tcommaaccent umacron -60 KPX Tcommaaccent uogonek -120 KPX Tcommaaccent uring -120 KPX Tcommaaccent w -120 KPX Tcommaaccent y -120 KPX Tcommaaccent yacute -120 KPX Tcommaaccent ydieresis -60 KPX U A -40 KPX U Aacute -40 KPX U Abreve -40 KPX U Acircumflex -40 KPX U Adieresis -40 KPX U Agrave -40 KPX U Amacron -40 KPX U Aogonek -40 KPX U Aring -40 KPX U Atilde -40 KPX U comma -40 KPX U period -40 KPX Uacute A -40 KPX Uacute Aacute -40 KPX Uacute Abreve -40 KPX Uacute Acircumflex -40 KPX Uacute Adieresis -40 KPX Uacute Agrave -40 KPX Uacute Amacron -40 KPX Uacute Aogonek -40 KPX Uacute Aring -40 KPX Uacute Atilde -40 KPX Uacute comma -40 KPX Uacute period -40 KPX Ucircumflex A -40 KPX Ucircumflex Aacute -40 KPX Ucircumflex Abreve -40 KPX Ucircumflex Acircumflex -40 KPX Ucircumflex Adieresis -40 KPX Ucircumflex Agrave -40 KPX Ucircumflex Amacron -40 KPX Ucircumflex Aogonek -40 KPX Ucircumflex Aring -40 KPX Ucircumflex Atilde -40 KPX Ucircumflex comma -40 KPX Ucircumflex period -40 KPX Udieresis A -40 KPX Udieresis Aacute -40 KPX Udieresis Abreve -40 KPX Udieresis Acircumflex -40 KPX Udieresis Adieresis -40 KPX Udieresis Agrave -40 KPX Udieresis Amacron -40 KPX Udieresis Aogonek -40 KPX Udieresis Aring -40 KPX Udieresis Atilde -40 KPX Udieresis comma -40 KPX Udieresis period -40 KPX Ugrave A -40 KPX Ugrave Aacute -40 KPX Ugrave Abreve -40 KPX Ugrave Acircumflex -40 KPX Ugrave Adieresis -40 KPX Ugrave Agrave -40 KPX Ugrave Amacron -40 KPX Ugrave Aogonek -40 KPX Ugrave Aring -40 KPX Ugrave Atilde -40 KPX Ugrave comma -40 KPX Ugrave period -40 KPX Uhungarumlaut A -40 KPX Uhungarumlaut Aacute -40 KPX Uhungarumlaut Abreve -40 KPX Uhungarumlaut Acircumflex -40 KPX Uhungarumlaut Adieresis -40 KPX Uhungarumlaut Agrave -40 KPX Uhungarumlaut Amacron -40 KPX Uhungarumlaut Aogonek -40 KPX Uhungarumlaut Aring -40 KPX Uhungarumlaut Atilde -40 KPX Uhungarumlaut comma -40 KPX Uhungarumlaut period -40 KPX Umacron A -40 KPX Umacron Aacute -40 KPX Umacron Abreve -40 KPX Umacron Acircumflex -40 KPX Umacron Adieresis -40 KPX Umacron Agrave -40 KPX Umacron Amacron -40 KPX Umacron Aogonek -40 KPX Umacron Aring -40 KPX Umacron Atilde -40 KPX Umacron comma -40 KPX Umacron period -40 KPX Uogonek A -40 KPX Uogonek Aacute -40 KPX Uogonek Abreve -40 KPX Uogonek Acircumflex -40 KPX Uogonek Adieresis -40 KPX Uogonek Agrave -40 KPX Uogonek Amacron -40 KPX Uogonek Aogonek -40 KPX Uogonek Aring -40 KPX Uogonek Atilde -40 KPX Uogonek comma -40 KPX Uogonek period -40 KPX Uring A -40 KPX Uring Aacute -40 KPX Uring Abreve -40 KPX Uring Acircumflex -40 KPX Uring Adieresis -40 KPX Uring Agrave -40 KPX Uring Amacron -40 KPX Uring Aogonek -40 KPX Uring Aring -40 KPX Uring Atilde -40 KPX Uring comma -40 KPX Uring period -40 KPX V A -80 KPX V Aacute -80 KPX V Abreve -80 KPX V Acircumflex -80 KPX V Adieresis -80 KPX V Agrave -80 KPX V Amacron -80 KPX V Aogonek -80 KPX V Aring -80 KPX V Atilde -80 KPX V G -40 KPX V Gbreve -40 KPX V Gcommaaccent -40 KPX V O -40 KPX V Oacute -40 KPX V Ocircumflex -40 KPX V Odieresis -40 KPX V Ograve -40 KPX V Ohungarumlaut -40 KPX V Omacron -40 KPX V Oslash -40 KPX V Otilde -40 KPX V a -70 KPX V aacute -70 KPX V abreve -70 KPX V acircumflex -70 KPX V adieresis -70 KPX V agrave -70 KPX V amacron -70 KPX V aogonek -70 KPX V aring -70 KPX V atilde -70 KPX V colon -40 KPX V comma -125 KPX V e -80 KPX V eacute -80 KPX V ecaron -80 KPX V ecircumflex -80 KPX V edieresis -80 KPX V edotaccent -80 KPX V egrave -80 KPX V emacron -80 KPX V eogonek -80 KPX V hyphen -80 KPX V o -80 KPX V oacute -80 KPX V ocircumflex -80 KPX V odieresis -80 KPX V ograve -80 KPX V ohungarumlaut -80 KPX V omacron -80 KPX V oslash -80 KPX V otilde -80 KPX V period -125 KPX V semicolon -40 KPX V u -70 KPX V uacute -70 KPX V ucircumflex -70 KPX V udieresis -70 KPX V ugrave -70 KPX V uhungarumlaut -70 KPX V umacron -70 KPX V uogonek -70 KPX V uring -70 KPX W A -50 KPX W Aacute -50 KPX W Abreve -50 KPX W Acircumflex -50 KPX W Adieresis -50 KPX W Agrave -50 KPX W Amacron -50 KPX W Aogonek -50 KPX W Aring -50 KPX W Atilde -50 KPX W O -20 KPX W Oacute -20 KPX W Ocircumflex -20 KPX W Odieresis -20 KPX W Ograve -20 KPX W Ohungarumlaut -20 KPX W Omacron -20 KPX W Oslash -20 KPX W Otilde -20 KPX W a -40 KPX W aacute -40 KPX W abreve -40 KPX W acircumflex -40 KPX W adieresis -40 KPX W agrave -40 KPX W amacron -40 KPX W aogonek -40 KPX W aring -40 KPX W atilde -40 KPX W comma -80 KPX W e -30 KPX W eacute -30 KPX W ecaron -30 KPX W ecircumflex -30 KPX W edieresis -30 KPX W edotaccent -30 KPX W egrave -30 KPX W emacron -30 KPX W eogonek -30 KPX W hyphen -40 KPX W o -30 KPX W oacute -30 KPX W ocircumflex -30 KPX W odieresis -30 KPX W ograve -30 KPX W ohungarumlaut -30 KPX W omacron -30 KPX W oslash -30 KPX W otilde -30 KPX W period -80 KPX W u -30 KPX W uacute -30 KPX W ucircumflex -30 KPX W udieresis -30 KPX W ugrave -30 KPX W uhungarumlaut -30 KPX W umacron -30 KPX W uogonek -30 KPX W uring -30 KPX W y -20 KPX W yacute -20 KPX W ydieresis -20 KPX Y A -110 KPX Y Aacute -110 KPX Y Abreve -110 KPX Y Acircumflex -110 KPX Y Adieresis -110 KPX Y Agrave -110 KPX Y Amacron -110 KPX Y Aogonek -110 KPX Y Aring -110 KPX Y Atilde -110 KPX Y O -85 KPX Y Oacute -85 KPX Y Ocircumflex -85 KPX Y Odieresis -85 KPX Y Ograve -85 KPX Y Ohungarumlaut -85 KPX Y Omacron -85 KPX Y Oslash -85 KPX Y Otilde -85 KPX Y a -140 KPX Y aacute -140 KPX Y abreve -70 KPX Y acircumflex -140 KPX Y adieresis -140 KPX Y agrave -140 KPX Y amacron -70 KPX Y aogonek -140 KPX Y aring -140 KPX Y atilde -140 KPX Y colon -60 KPX Y comma -140 KPX Y e -140 KPX Y eacute -140 KPX Y ecaron -140 KPX Y ecircumflex -140 KPX Y edieresis -140 KPX Y edotaccent -140 KPX Y egrave -140 KPX Y emacron -70 KPX Y eogonek -140 KPX Y hyphen -140 KPX Y i -20 KPX Y iacute -20 KPX Y iogonek -20 KPX Y o -140 KPX Y oacute -140 KPX Y ocircumflex -140 KPX Y odieresis -140 KPX Y ograve -140 KPX Y ohungarumlaut -140 KPX Y omacron -140 KPX Y oslash -140 KPX Y otilde -140 KPX Y period -140 KPX Y semicolon -60 KPX Y u -110 KPX Y uacute -110 KPX Y ucircumflex -110 KPX Y udieresis -110 KPX Y ugrave -110 KPX Y uhungarumlaut -110 KPX Y umacron -110 KPX Y uogonek -110 KPX Y uring -110 KPX Yacute A -110 KPX Yacute Aacute -110 KPX Yacute Abreve -110 KPX Yacute Acircumflex -110 KPX Yacute Adieresis -110 KPX Yacute Agrave -110 KPX Yacute Amacron -110 KPX Yacute Aogonek -110 KPX Yacute Aring -110 KPX Yacute Atilde -110 KPX Yacute O -85 KPX Yacute Oacute -85 KPX Yacute Ocircumflex -85 KPX Yacute Odieresis -85 KPX Yacute Ograve -85 KPX Yacute Ohungarumlaut -85 KPX Yacute Omacron -85 KPX Yacute Oslash -85 KPX Yacute Otilde -85 KPX Yacute a -140 KPX Yacute aacute -140 KPX Yacute abreve -70 KPX Yacute acircumflex -140 KPX Yacute adieresis -140 KPX Yacute agrave -140 KPX Yacute amacron -70 KPX Yacute aogonek -140 KPX Yacute aring -140 KPX Yacute atilde -70 KPX Yacute colon -60 KPX Yacute comma -140 KPX Yacute e -140 KPX Yacute eacute -140 KPX Yacute ecaron -140 KPX Yacute ecircumflex -140 KPX Yacute edieresis -140 KPX Yacute edotaccent -140 KPX Yacute egrave -140 KPX Yacute emacron -70 KPX Yacute eogonek -140 KPX Yacute hyphen -140 KPX Yacute i -20 KPX Yacute iacute -20 KPX Yacute iogonek -20 KPX Yacute o -140 KPX Yacute oacute -140 KPX Yacute ocircumflex -140 KPX Yacute odieresis -140 KPX Yacute ograve -140 KPX Yacute ohungarumlaut -140 KPX Yacute omacron -70 KPX Yacute oslash -140 KPX Yacute otilde -140 KPX Yacute period -140 KPX Yacute semicolon -60 KPX Yacute u -110 KPX Yacute uacute -110 KPX Yacute ucircumflex -110 KPX Yacute udieresis -110 KPX Yacute ugrave -110 KPX Yacute uhungarumlaut -110 KPX Yacute umacron -110 KPX Yacute uogonek -110 KPX Yacute uring -110 KPX Ydieresis A -110 KPX Ydieresis Aacute -110 KPX Ydieresis Abreve -110 KPX Ydieresis Acircumflex -110 KPX Ydieresis Adieresis -110 KPX Ydieresis Agrave -110 KPX Ydieresis Amacron -110 KPX Ydieresis Aogonek -110 KPX Ydieresis Aring -110 KPX Ydieresis Atilde -110 KPX Ydieresis O -85 KPX Ydieresis Oacute -85 KPX Ydieresis Ocircumflex -85 KPX Ydieresis Odieresis -85 KPX Ydieresis Ograve -85 KPX Ydieresis Ohungarumlaut -85 KPX Ydieresis Omacron -85 KPX Ydieresis Oslash -85 KPX Ydieresis Otilde -85 KPX Ydieresis a -140 KPX Ydieresis aacute -140 KPX Ydieresis abreve -70 KPX Ydieresis acircumflex -140 KPX Ydieresis adieresis -140 KPX Ydieresis agrave -140 KPX Ydieresis amacron -70 KPX Ydieresis aogonek -140 KPX Ydieresis aring -140 KPX Ydieresis atilde -70 KPX Ydieresis colon -60 KPX Ydieresis comma -140 KPX Ydieresis e -140 KPX Ydieresis eacute -140 KPX Ydieresis ecaron -140 KPX Ydieresis ecircumflex -140 KPX Ydieresis edieresis -140 KPX Ydieresis edotaccent -140 KPX Ydieresis egrave -140 KPX Ydieresis emacron -70 KPX Ydieresis eogonek -140 KPX Ydieresis hyphen -140 KPX Ydieresis i -20 KPX Ydieresis iacute -20 KPX Ydieresis iogonek -20 KPX Ydieresis o -140 KPX Ydieresis oacute -140 KPX Ydieresis ocircumflex -140 KPX Ydieresis odieresis -140 KPX Ydieresis ograve -140 KPX Ydieresis ohungarumlaut -140 KPX Ydieresis omacron -140 KPX Ydieresis oslash -140 KPX Ydieresis otilde -140 KPX Ydieresis period -140 KPX Ydieresis semicolon -60 KPX Ydieresis u -110 KPX Ydieresis uacute -110 KPX Ydieresis ucircumflex -110 KPX Ydieresis udieresis -110 KPX Ydieresis ugrave -110 KPX Ydieresis uhungarumlaut -110 KPX Ydieresis umacron -110 KPX Ydieresis uogonek -110 KPX Ydieresis uring -110 KPX a v -20 KPX a w -20 KPX a y -30 KPX a yacute -30 KPX a ydieresis -30 KPX aacute v -20 KPX aacute w -20 KPX aacute y -30 KPX aacute yacute -30 KPX aacute ydieresis -30 KPX abreve v -20 KPX abreve w -20 KPX abreve y -30 KPX abreve yacute -30 KPX abreve ydieresis -30 KPX acircumflex v -20 KPX acircumflex w -20 KPX acircumflex y -30 KPX acircumflex yacute -30 KPX acircumflex ydieresis -30 KPX adieresis v -20 KPX adieresis w -20 KPX adieresis y -30 KPX adieresis yacute -30 KPX adieresis ydieresis -30 KPX agrave v -20 KPX agrave w -20 KPX agrave y -30 KPX agrave yacute -30 KPX agrave ydieresis -30 KPX amacron v -20 KPX amacron w -20 KPX amacron y -30 KPX amacron yacute -30 KPX amacron ydieresis -30 KPX aogonek v -20 KPX aogonek w -20 KPX aogonek y -30 KPX aogonek yacute -30 KPX aogonek ydieresis -30 KPX aring v -20 KPX aring w -20 KPX aring y -30 KPX aring yacute -30 KPX aring ydieresis -30 KPX atilde v -20 KPX atilde w -20 KPX atilde y -30 KPX atilde yacute -30 KPX atilde ydieresis -30 KPX b b -10 KPX b comma -40 KPX b l -20 KPX b lacute -20 KPX b lcommaaccent -20 KPX b lslash -20 KPX b period -40 KPX b u -20 KPX b uacute -20 KPX b ucircumflex -20 KPX b udieresis -20 KPX b ugrave -20 KPX b uhungarumlaut -20 KPX b umacron -20 KPX b uogonek -20 KPX b uring -20 KPX b v -20 KPX b y -20 KPX b yacute -20 KPX b ydieresis -20 KPX c comma -15 KPX c k -20 KPX c kcommaaccent -20 KPX cacute comma -15 KPX cacute k -20 KPX cacute kcommaaccent -20 KPX ccaron comma -15 KPX ccaron k -20 KPX ccaron kcommaaccent -20 KPX ccedilla comma -15 KPX ccedilla k -20 KPX ccedilla kcommaaccent -20 KPX colon space -50 KPX comma quotedblright -100 KPX comma quoteright -100 KPX e comma -15 KPX e period -15 KPX e v -30 KPX e w -20 KPX e x -30 KPX e y -20 KPX e yacute -20 KPX e ydieresis -20 KPX eacute comma -15 KPX eacute period -15 KPX eacute v -30 KPX eacute w -20 KPX eacute x -30 KPX eacute y -20 KPX eacute yacute -20 KPX eacute ydieresis -20 KPX ecaron comma -15 KPX ecaron period -15 KPX ecaron v -30 KPX ecaron w -20 KPX ecaron x -30 KPX ecaron y -20 KPX ecaron yacute -20 KPX ecaron ydieresis -20 KPX ecircumflex comma -15 KPX ecircumflex period -15 KPX ecircumflex v -30 KPX ecircumflex w -20 KPX ecircumflex x -30 KPX ecircumflex y -20 KPX ecircumflex yacute -20 KPX ecircumflex ydieresis -20 KPX edieresis comma -15 KPX edieresis period -15 KPX edieresis v -30 KPX edieresis w -20 KPX edieresis x -30 KPX edieresis y -20 KPX edieresis yacute -20 KPX edieresis ydieresis -20 KPX edotaccent comma -15 KPX edotaccent period -15 KPX edotaccent v -30 KPX edotaccent w -20 KPX edotaccent x -30 KPX edotaccent y -20 KPX edotaccent yacute -20 KPX edotaccent ydieresis -20 KPX egrave comma -15 KPX egrave period -15 KPX egrave v -30 KPX egrave w -20 KPX egrave x -30 KPX egrave y -20 KPX egrave yacute -20 KPX egrave ydieresis -20 KPX emacron comma -15 KPX emacron period -15 KPX emacron v -30 KPX emacron w -20 KPX emacron x -30 KPX emacron y -20 KPX emacron yacute -20 KPX emacron ydieresis -20 KPX eogonek comma -15 KPX eogonek period -15 KPX eogonek v -30 KPX eogonek w -20 KPX eogonek x -30 KPX eogonek y -20 KPX eogonek yacute -20 KPX eogonek ydieresis -20 KPX f a -30 KPX f aacute -30 KPX f abreve -30 KPX f acircumflex -30 KPX f adieresis -30 KPX f agrave -30 KPX f amacron -30 KPX f aogonek -30 KPX f aring -30 KPX f atilde -30 KPX f comma -30 KPX f dotlessi -28 KPX f e -30 KPX f eacute -30 KPX f ecaron -30 KPX f ecircumflex -30 KPX f edieresis -30 KPX f edotaccent -30 KPX f egrave -30 KPX f emacron -30 KPX f eogonek -30 KPX f o -30 KPX f oacute -30 KPX f ocircumflex -30 KPX f odieresis -30 KPX f ograve -30 KPX f ohungarumlaut -30 KPX f omacron -30 KPX f oslash -30 KPX f otilde -30 KPX f period -30 KPX f quotedblright 60 KPX f quoteright 50 KPX g r -10 KPX g racute -10 KPX g rcaron -10 KPX g rcommaaccent -10 KPX gbreve r -10 KPX gbreve racute -10 KPX gbreve rcaron -10 KPX gbreve rcommaaccent -10 KPX gcommaaccent r -10 KPX gcommaaccent racute -10 KPX gcommaaccent rcaron -10 KPX gcommaaccent rcommaaccent -10 KPX h y -30 KPX h yacute -30 KPX h ydieresis -30 KPX k e -20 KPX k eacute -20 KPX k ecaron -20 KPX k ecircumflex -20 KPX k edieresis -20 KPX k edotaccent -20 KPX k egrave -20 KPX k emacron -20 KPX k eogonek -20 KPX k o -20 KPX k oacute -20 KPX k ocircumflex -20 KPX k odieresis -20 KPX k ograve -20 KPX k ohungarumlaut -20 KPX k omacron -20 KPX k oslash -20 KPX k otilde -20 KPX kcommaaccent e -20 KPX kcommaaccent eacute -20 KPX kcommaaccent ecaron -20 KPX kcommaaccent ecircumflex -20 KPX kcommaaccent edieresis -20 KPX kcommaaccent edotaccent -20 KPX kcommaaccent egrave -20 KPX kcommaaccent emacron -20 KPX kcommaaccent eogonek -20 KPX kcommaaccent o -20 KPX kcommaaccent oacute -20 KPX kcommaaccent ocircumflex -20 KPX kcommaaccent odieresis -20 KPX kcommaaccent ograve -20 KPX kcommaaccent ohungarumlaut -20 KPX kcommaaccent omacron -20 KPX kcommaaccent oslash -20 KPX kcommaaccent otilde -20 KPX m u -10 KPX m uacute -10 KPX m ucircumflex -10 KPX m udieresis -10 KPX m ugrave -10 KPX m uhungarumlaut -10 KPX m umacron -10 KPX m uogonek -10 KPX m uring -10 KPX m y -15 KPX m yacute -15 KPX m ydieresis -15 KPX n u -10 KPX n uacute -10 KPX n ucircumflex -10 KPX n udieresis -10 KPX n ugrave -10 KPX n uhungarumlaut -10 KPX n umacron -10 KPX n uogonek -10 KPX n uring -10 KPX n v -20 KPX n y -15 KPX n yacute -15 KPX n ydieresis -15 KPX nacute u -10 KPX nacute uacute -10 KPX nacute ucircumflex -10 KPX nacute udieresis -10 KPX nacute ugrave -10 KPX nacute uhungarumlaut -10 KPX nacute umacron -10 KPX nacute uogonek -10 KPX nacute uring -10 KPX nacute v -20 KPX nacute y -15 KPX nacute yacute -15 KPX nacute ydieresis -15 KPX ncaron u -10 KPX ncaron uacute -10 KPX ncaron ucircumflex -10 KPX ncaron udieresis -10 KPX ncaron ugrave -10 KPX ncaron uhungarumlaut -10 KPX ncaron umacron -10 KPX ncaron uogonek -10 KPX ncaron uring -10 KPX ncaron v -20 KPX ncaron y -15 KPX ncaron yacute -15 KPX ncaron ydieresis -15 KPX ncommaaccent u -10 KPX ncommaaccent uacute -10 KPX ncommaaccent ucircumflex -10 KPX ncommaaccent udieresis -10 KPX ncommaaccent ugrave -10 KPX ncommaaccent uhungarumlaut -10 KPX ncommaaccent umacron -10 KPX ncommaaccent uogonek -10 KPX ncommaaccent uring -10 KPX ncommaaccent v -20 KPX ncommaaccent y -15 KPX ncommaaccent yacute -15 KPX ncommaaccent ydieresis -15 KPX ntilde u -10 KPX ntilde uacute -10 KPX ntilde ucircumflex -10 KPX ntilde udieresis -10 KPX ntilde ugrave -10 KPX ntilde uhungarumlaut -10 KPX ntilde umacron -10 KPX ntilde uogonek -10 KPX ntilde uring -10 KPX ntilde v -20 KPX ntilde y -15 KPX ntilde yacute -15 KPX ntilde ydieresis -15 KPX o comma -40 KPX o period -40 KPX o v -15 KPX o w -15 KPX o x -30 KPX o y -30 KPX o yacute -30 KPX o ydieresis -30 KPX oacute comma -40 KPX oacute period -40 KPX oacute v -15 KPX oacute w -15 KPX oacute x -30 KPX oacute y -30 KPX oacute yacute -30 KPX oacute ydieresis -30 KPX ocircumflex comma -40 KPX ocircumflex period -40 KPX ocircumflex v -15 KPX ocircumflex w -15 KPX ocircumflex x -30 KPX ocircumflex y -30 KPX ocircumflex yacute -30 KPX ocircumflex ydieresis -30 KPX odieresis comma -40 KPX odieresis period -40 KPX odieresis v -15 KPX odieresis w -15 KPX odieresis x -30 KPX odieresis y -30 KPX odieresis yacute -30 KPX odieresis ydieresis -30 KPX ograve comma -40 KPX ograve period -40 KPX ograve v -15 KPX ograve w -15 KPX ograve x -30 KPX ograve y -30 KPX ograve yacute -30 KPX ograve ydieresis -30 KPX ohungarumlaut comma -40 KPX ohungarumlaut period -40 KPX ohungarumlaut v -15 KPX ohungarumlaut w -15 KPX ohungarumlaut x -30 KPX ohungarumlaut y -30 KPX ohungarumlaut yacute -30 KPX ohungarumlaut ydieresis -30 KPX omacron comma -40 KPX omacron period -40 KPX omacron v -15 KPX omacron w -15 KPX omacron x -30 KPX omacron y -30 KPX omacron yacute -30 KPX omacron ydieresis -30 KPX oslash a -55 KPX oslash aacute -55 KPX oslash abreve -55 KPX oslash acircumflex -55 KPX oslash adieresis -55 KPX oslash agrave -55 KPX oslash amacron -55 KPX oslash aogonek -55 KPX oslash aring -55 KPX oslash atilde -55 KPX oslash b -55 KPX oslash c -55 KPX oslash cacute -55 KPX oslash ccaron -55 KPX oslash ccedilla -55 KPX oslash comma -95 KPX oslash d -55 KPX oslash dcroat -55 KPX oslash e -55 KPX oslash eacute -55 KPX oslash ecaron -55 KPX oslash ecircumflex -55 KPX oslash edieresis -55 KPX oslash edotaccent -55 KPX oslash egrave -55 KPX oslash emacron -55 KPX oslash eogonek -55 KPX oslash f -55 KPX oslash g -55 KPX oslash gbreve -55 KPX oslash gcommaaccent -55 KPX oslash h -55 KPX oslash i -55 KPX oslash iacute -55 KPX oslash icircumflex -55 KPX oslash idieresis -55 KPX oslash igrave -55 KPX oslash imacron -55 KPX oslash iogonek -55 KPX oslash j -55 KPX oslash k -55 KPX oslash kcommaaccent -55 KPX oslash l -55 KPX oslash lacute -55 KPX oslash lcommaaccent -55 KPX oslash lslash -55 KPX oslash m -55 KPX oslash n -55 KPX oslash nacute -55 KPX oslash ncaron -55 KPX oslash ncommaaccent -55 KPX oslash ntilde -55 KPX oslash o -55 KPX oslash oacute -55 KPX oslash ocircumflex -55 KPX oslash odieresis -55 KPX oslash ograve -55 KPX oslash ohungarumlaut -55 KPX oslash omacron -55 KPX oslash oslash -55 KPX oslash otilde -55 KPX oslash p -55 KPX oslash period -95 KPX oslash q -55 KPX oslash r -55 KPX oslash racute -55 KPX oslash rcaron -55 KPX oslash rcommaaccent -55 KPX oslash s -55 KPX oslash sacute -55 KPX oslash scaron -55 KPX oslash scedilla -55 KPX oslash scommaaccent -55 KPX oslash t -55 KPX oslash tcommaaccent -55 KPX oslash u -55 KPX oslash uacute -55 KPX oslash ucircumflex -55 KPX oslash udieresis -55 KPX oslash ugrave -55 KPX oslash uhungarumlaut -55 KPX oslash umacron -55 KPX oslash uogonek -55 KPX oslash uring -55 KPX oslash v -70 KPX oslash w -70 KPX oslash x -85 KPX oslash y -70 KPX oslash yacute -70 KPX oslash ydieresis -70 KPX oslash z -55 KPX oslash zacute -55 KPX oslash zcaron -55 KPX oslash zdotaccent -55 KPX otilde comma -40 KPX otilde period -40 KPX otilde v -15 KPX otilde w -15 KPX otilde x -30 KPX otilde y -30 KPX otilde yacute -30 KPX otilde ydieresis -30 KPX p comma -35 KPX p period -35 KPX p y -30 KPX p yacute -30 KPX p ydieresis -30 KPX period quotedblright -100 KPX period quoteright -100 KPX period space -60 KPX quotedblright space -40 KPX quoteleft quoteleft -57 KPX quoteright d -50 KPX quoteright dcroat -50 KPX quoteright quoteright -57 KPX quoteright r -50 KPX quoteright racute -50 KPX quoteright rcaron -50 KPX quoteright rcommaaccent -50 KPX quoteright s -50 KPX quoteright sacute -50 KPX quoteright scaron -50 KPX quoteright scedilla -50 KPX quoteright scommaaccent -50 KPX quoteright space -70 KPX r a -10 KPX r aacute -10 KPX r abreve -10 KPX r acircumflex -10 KPX r adieresis -10 KPX r agrave -10 KPX r amacron -10 KPX r aogonek -10 KPX r aring -10 KPX r atilde -10 KPX r colon 30 KPX r comma -50 KPX r i 15 KPX r iacute 15 KPX r icircumflex 15 KPX r idieresis 15 KPX r igrave 15 KPX r imacron 15 KPX r iogonek 15 KPX r k 15 KPX r kcommaaccent 15 KPX r l 15 KPX r lacute 15 KPX r lcommaaccent 15 KPX r lslash 15 KPX r m 25 KPX r n 25 KPX r nacute 25 KPX r ncaron 25 KPX r ncommaaccent 25 KPX r ntilde 25 KPX r p 30 KPX r period -50 KPX r semicolon 30 KPX r t 40 KPX r tcommaaccent 40 KPX r u 15 KPX r uacute 15 KPX r ucircumflex 15 KPX r udieresis 15 KPX r ugrave 15 KPX r uhungarumlaut 15 KPX r umacron 15 KPX r uogonek 15 KPX r uring 15 KPX r v 30 KPX r y 30 KPX r yacute 30 KPX r ydieresis 30 KPX racute a -10 KPX racute aacute -10 KPX racute abreve -10 KPX racute acircumflex -10 KPX racute adieresis -10 KPX racute agrave -10 KPX racute amacron -10 KPX racute aogonek -10 KPX racute aring -10 KPX racute atilde -10 KPX racute colon 30 KPX racute comma -50 KPX racute i 15 KPX racute iacute 15 KPX racute icircumflex 15 KPX racute idieresis 15 KPX racute igrave 15 KPX racute imacron 15 KPX racute iogonek 15 KPX racute k 15 KPX racute kcommaaccent 15 KPX racute l 15 KPX racute lacute 15 KPX racute lcommaaccent 15 KPX racute lslash 15 KPX racute m 25 KPX racute n 25 KPX racute nacute 25 KPX racute ncaron 25 KPX racute ncommaaccent 25 KPX racute ntilde 25 KPX racute p 30 KPX racute period -50 KPX racute semicolon 30 KPX racute t 40 KPX racute tcommaaccent 40 KPX racute u 15 KPX racute uacute 15 KPX racute ucircumflex 15 KPX racute udieresis 15 KPX racute ugrave 15 KPX racute uhungarumlaut 15 KPX racute umacron 15 KPX racute uogonek 15 KPX racute uring 15 KPX racute v 30 KPX racute y 30 KPX racute yacute 30 KPX racute ydieresis 30 KPX rcaron a -10 KPX rcaron aacute -10 KPX rcaron abreve -10 KPX rcaron acircumflex -10 KPX rcaron adieresis -10 KPX rcaron agrave -10 KPX rcaron amacron -10 KPX rcaron aogonek -10 KPX rcaron aring -10 KPX rcaron atilde -10 KPX rcaron colon 30 KPX rcaron comma -50 KPX rcaron i 15 KPX rcaron iacute 15 KPX rcaron icircumflex 15 KPX rcaron idieresis 15 KPX rcaron igrave 15 KPX rcaron imacron 15 KPX rcaron iogonek 15 KPX rcaron k 15 KPX rcaron kcommaaccent 15 KPX rcaron l 15 KPX rcaron lacute 15 KPX rcaron lcommaaccent 15 KPX rcaron lslash 15 KPX rcaron m 25 KPX rcaron n 25 KPX rcaron nacute 25 KPX rcaron ncaron 25 KPX rcaron ncommaaccent 25 KPX rcaron ntilde 25 KPX rcaron p 30 KPX rcaron period -50 KPX rcaron semicolon 30 KPX rcaron t 40 KPX rcaron tcommaaccent 40 KPX rcaron u 15 KPX rcaron uacute 15 KPX rcaron ucircumflex 15 KPX rcaron udieresis 15 KPX rcaron ugrave 15 KPX rcaron uhungarumlaut 15 KPX rcaron umacron 15 KPX rcaron uogonek 15 KPX rcaron uring 15 KPX rcaron v 30 KPX rcaron y 30 KPX rcaron yacute 30 KPX rcaron ydieresis 30 KPX rcommaaccent a -10 KPX rcommaaccent aacute -10 KPX rcommaaccent abreve -10 KPX rcommaaccent acircumflex -10 KPX rcommaaccent adieresis -10 KPX rcommaaccent agrave -10 KPX rcommaaccent amacron -10 KPX rcommaaccent aogonek -10 KPX rcommaaccent aring -10 KPX rcommaaccent atilde -10 KPX rcommaaccent colon 30 KPX rcommaaccent comma -50 KPX rcommaaccent i 15 KPX rcommaaccent iacute 15 KPX rcommaaccent icircumflex 15 KPX rcommaaccent idieresis 15 KPX rcommaaccent igrave 15 KPX rcommaaccent imacron 15 KPX rcommaaccent iogonek 15 KPX rcommaaccent k 15 KPX rcommaaccent kcommaaccent 15 KPX rcommaaccent l 15 KPX rcommaaccent lacute 15 KPX rcommaaccent lcommaaccent 15 KPX rcommaaccent lslash 15 KPX rcommaaccent m 25 KPX rcommaaccent n 25 KPX rcommaaccent nacute 25 KPX rcommaaccent ncaron 25 KPX rcommaaccent ncommaaccent 25 KPX rcommaaccent ntilde 25 KPX rcommaaccent p 30 KPX rcommaaccent period -50 KPX rcommaaccent semicolon 30 KPX rcommaaccent t 40 KPX rcommaaccent tcommaaccent 40 KPX rcommaaccent u 15 KPX rcommaaccent uacute 15 KPX rcommaaccent ucircumflex 15 KPX rcommaaccent udieresis 15 KPX rcommaaccent ugrave 15 KPX rcommaaccent uhungarumlaut 15 KPX rcommaaccent umacron 15 KPX rcommaaccent uogonek 15 KPX rcommaaccent uring 15 KPX rcommaaccent v 30 KPX rcommaaccent y 30 KPX rcommaaccent yacute 30 KPX rcommaaccent ydieresis 30 KPX s comma -15 KPX s period -15 KPX s w -30 KPX sacute comma -15 KPX sacute period -15 KPX sacute w -30 KPX scaron comma -15 KPX scaron period -15 KPX scaron w -30 KPX scedilla comma -15 KPX scedilla period -15 KPX scedilla w -30 KPX scommaaccent comma -15 KPX scommaaccent period -15 KPX scommaaccent w -30 KPX semicolon space -50 KPX space T -50 KPX space Tcaron -50 KPX space Tcommaaccent -50 KPX space V -50 KPX space W -40 KPX space Y -90 KPX space Yacute -90 KPX space Ydieresis -90 KPX space quotedblleft -30 KPX space quoteleft -60 KPX v a -25 KPX v aacute -25 KPX v abreve -25 KPX v acircumflex -25 KPX v adieresis -25 KPX v agrave -25 KPX v amacron -25 KPX v aogonek -25 KPX v aring -25 KPX v atilde -25 KPX v comma -80 KPX v e -25 KPX v eacute -25 KPX v ecaron -25 KPX v ecircumflex -25 KPX v edieresis -25 KPX v edotaccent -25 KPX v egrave -25 KPX v emacron -25 KPX v eogonek -25 KPX v o -25 KPX v oacute -25 KPX v ocircumflex -25 KPX v odieresis -25 KPX v ograve -25 KPX v ohungarumlaut -25 KPX v omacron -25 KPX v oslash -25 KPX v otilde -25 KPX v period -80 KPX w a -15 KPX w aacute -15 KPX w abreve -15 KPX w acircumflex -15 KPX w adieresis -15 KPX w agrave -15 KPX w amacron -15 KPX w aogonek -15 KPX w aring -15 KPX w atilde -15 KPX w comma -60 KPX w e -10 KPX w eacute -10 KPX w ecaron -10 KPX w ecircumflex -10 KPX w edieresis -10 KPX w edotaccent -10 KPX w egrave -10 KPX w emacron -10 KPX w eogonek -10 KPX w o -10 KPX w oacute -10 KPX w ocircumflex -10 KPX w odieresis -10 KPX w ograve -10 KPX w ohungarumlaut -10 KPX w omacron -10 KPX w oslash -10 KPX w otilde -10 KPX w period -60 KPX x e -30 KPX x eacute -30 KPX x ecaron -30 KPX x ecircumflex -30 KPX x edieresis -30 KPX x edotaccent -30 KPX x egrave -30 KPX x emacron -30 KPX x eogonek -30 KPX y a -20 KPX y aacute -20 KPX y abreve -20 KPX y acircumflex -20 KPX y adieresis -20 KPX y agrave -20 KPX y amacron -20 KPX y aogonek -20 KPX y aring -20 KPX y atilde -20 KPX y comma -100 KPX y e -20 KPX y eacute -20 KPX y ecaron -20 KPX y ecircumflex -20 KPX y edieresis -20 KPX y edotaccent -20 KPX y egrave -20 KPX y emacron -20 KPX y eogonek -20 KPX y o -20 KPX y oacute -20 KPX y ocircumflex -20 KPX y odieresis -20 KPX y ograve -20 KPX y ohungarumlaut -20 KPX y omacron -20 KPX y oslash -20 KPX y otilde -20 KPX y period -100 KPX yacute a -20 KPX yacute aacute -20 KPX yacute abreve -20 KPX yacute acircumflex -20 KPX yacute adieresis -20 KPX yacute agrave -20 KPX yacute amacron -20 KPX yacute aogonek -20 KPX yacute aring -20 KPX yacute atilde -20 KPX yacute comma -100 KPX yacute e -20 KPX yacute eacute -20 KPX yacute ecaron -20 KPX yacute ecircumflex -20 KPX yacute edieresis -20 KPX yacute edotaccent -20 KPX yacute egrave -20 KPX yacute emacron -20 KPX yacute eogonek -20 KPX yacute o -20 KPX yacute oacute -20 KPX yacute ocircumflex -20 KPX yacute odieresis -20 KPX yacute ograve -20 KPX yacute ohungarumlaut -20 KPX yacute omacron -20 KPX yacute oslash -20 KPX yacute otilde -20 KPX yacute period -100 KPX ydieresis a -20 KPX ydieresis aacute -20 KPX ydieresis abreve -20 KPX ydieresis acircumflex -20 KPX ydieresis adieresis -20 KPX ydieresis agrave -20 KPX ydieresis amacron -20 KPX ydieresis aogonek -20 KPX ydieresis aring -20 KPX ydieresis atilde -20 KPX ydieresis comma -100 KPX ydieresis e -20 KPX ydieresis eacute -20 KPX ydieresis ecaron -20 KPX ydieresis ecircumflex -20 KPX ydieresis edieresis -20 KPX ydieresis edotaccent -20 KPX ydieresis egrave -20 KPX ydieresis emacron -20 KPX ydieresis eogonek -20 KPX ydieresis o -20 KPX ydieresis oacute -20 KPX ydieresis ocircumflex -20 KPX ydieresis odieresis -20 KPX ydieresis ograve -20 KPX ydieresis ohungarumlaut -20 KPX ydieresis omacron -20 KPX ydieresis oslash -20 KPX ydieresis otilde -20 KPX ydieresis period -100 KPX z e -15 KPX z eacute -15 KPX z ecaron -15 KPX z ecircumflex -15 KPX z edieresis -15 KPX z edotaccent -15 KPX z egrave -15 KPX z emacron -15 KPX z eogonek -15 KPX z o -15 KPX z oacute -15 KPX z ocircumflex -15 KPX z odieresis -15 KPX z ograve -15 KPX z ohungarumlaut -15 KPX z omacron -15 KPX z oslash -15 KPX z otilde -15 KPX zacute e -15 KPX zacute eacute -15 KPX zacute ecaron -15 KPX zacute ecircumflex -15 KPX zacute edieresis -15 KPX zacute edotaccent -15 KPX zacute egrave -15 KPX zacute emacron -15 KPX zacute eogonek -15 KPX zacute o -15 KPX zacute oacute -15 KPX zacute ocircumflex -15 KPX zacute odieresis -15 KPX zacute ograve -15 KPX zacute ohungarumlaut -15 KPX zacute omacron -15 KPX zacute oslash -15 KPX zacute otilde -15 KPX zcaron e -15 KPX zcaron eacute -15 KPX zcaron ecaron -15 KPX zcaron ecircumflex -15 KPX zcaron edieresis -15 KPX zcaron edotaccent -15 KPX zcaron egrave -15 KPX zcaron emacron -15 KPX zcaron eogonek -15 KPX zcaron o -15 KPX zcaron oacute -15 KPX zcaron ocircumflex -15 KPX zcaron odieresis -15 KPX zcaron ograve -15 KPX zcaron ohungarumlaut -15 KPX zcaron omacron -15 KPX zcaron oslash -15 KPX zcaron otilde -15 KPX zdotaccent e -15 KPX zdotaccent eacute -15 KPX zdotaccent ecaron -15 KPX zdotaccent ecircumflex -15 KPX zdotaccent edieresis -15 KPX zdotaccent edotaccent -15 KPX zdotaccent egrave -15 KPX zdotaccent emacron -15 KPX zdotaccent eogonek -15 KPX zdotaccent o -15 KPX zdotaccent oacute -15 KPX zdotaccent ocircumflex -15 KPX zdotaccent odieresis -15 KPX zdotaccent ograve -15 KPX zdotaccent ohungarumlaut -15 KPX zdotaccent omacron -15 KPX zdotaccent oslash -15 KPX zdotaccent otilde -15 EndKernPairs EndKernData EndFontMetrics camlpdf-2.8.1/compressor/Helvetica.afm000066400000000000000000002210641477056064700177420ustar00rootroot00000000000000StartFontMetrics 4.1 Comment Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved. Comment Creation Date: Thu May 1 12:38:23 1997 Comment UniqueID 43054 Comment VMusage 37069 48094 FontName Helvetica FullName Helvetica FamilyName Helvetica Weight Medium ItalicAngle 0 IsFixedPitch false CharacterSet ExtendedRoman FontBBox -166 -225 1000 931 UnderlinePosition -100 UnderlineThickness 50 Version 002.000 Notice Copyright (c) 1985, 1987, 1989, 1990, 1997 Adobe Systems Incorporated. All Rights Reserved.Helvetica is a trademark of Linotype-Hell AG and/or its subsidiaries. EncodingScheme AdobeStandardEncoding CapHeight 718 XHeight 523 Ascender 718 Descender -207 StdHW 76 StdVW 88 StartCharMetrics 315 C 32 ; WX 278 ; N space ; B 0 0 0 0 ; C 33 ; WX 278 ; N exclam ; B 90 0 187 718 ; C 34 ; WX 355 ; N quotedbl ; B 70 463 285 718 ; C 35 ; WX 556 ; N numbersign ; B 28 0 529 688 ; C 36 ; WX 556 ; N dollar ; B 32 -115 520 775 ; C 37 ; WX 889 ; N percent ; B 39 -19 850 703 ; C 38 ; WX 667 ; N ampersand ; B 44 -15 645 718 ; C 39 ; WX 222 ; N quoteright ; B 53 463 157 718 ; C 40 ; WX 333 ; N parenleft ; B 68 -207 299 733 ; C 41 ; WX 333 ; N parenright ; B 34 -207 265 733 ; C 42 ; WX 389 ; N asterisk ; B 39 431 349 718 ; C 43 ; WX 584 ; N plus ; B 39 0 545 505 ; C 44 ; WX 278 ; N comma ; B 87 -147 191 106 ; C 45 ; WX 333 ; N hyphen ; B 44 232 289 322 ; C 46 ; WX 278 ; N period ; B 87 0 191 106 ; C 47 ; WX 278 ; N slash ; B -17 -19 295 737 ; C 48 ; WX 556 ; N zero ; B 37 -19 519 703 ; C 49 ; WX 556 ; N one ; B 101 0 359 703 ; C 50 ; WX 556 ; N two ; B 26 0 507 703 ; C 51 ; WX 556 ; N three ; B 34 -19 522 703 ; C 52 ; WX 556 ; N four ; B 25 0 523 703 ; C 53 ; WX 556 ; N five ; B 32 -19 514 688 ; C 54 ; WX 556 ; N six ; B 38 -19 518 703 ; C 55 ; WX 556 ; N seven ; B 37 0 523 688 ; C 56 ; WX 556 ; N eight ; B 38 -19 517 703 ; C 57 ; WX 556 ; N nine ; B 42 -19 514 703 ; C 58 ; WX 278 ; N colon ; B 87 0 191 516 ; C 59 ; WX 278 ; N semicolon ; B 87 -147 191 516 ; C 60 ; WX 584 ; N less ; B 48 11 536 495 ; C 61 ; WX 584 ; N equal ; B 39 115 545 390 ; C 62 ; WX 584 ; N greater ; B 48 11 536 495 ; C 63 ; WX 556 ; N question ; B 56 0 492 727 ; C 64 ; WX 1015 ; N at ; B 147 -19 868 737 ; C 65 ; WX 667 ; N A ; B 14 0 654 718 ; C 66 ; WX 667 ; N B ; B 74 0 627 718 ; C 67 ; WX 722 ; N C ; B 44 -19 681 737 ; C 68 ; WX 722 ; N D ; B 81 0 674 718 ; C 69 ; WX 667 ; N E ; B 86 0 616 718 ; C 70 ; WX 611 ; N F ; B 86 0 583 718 ; C 71 ; WX 778 ; N G ; B 48 -19 704 737 ; C 72 ; WX 722 ; N H ; B 77 0 646 718 ; C 73 ; WX 278 ; N I ; B 91 0 188 718 ; C 74 ; WX 500 ; N J ; B 17 -19 428 718 ; C 75 ; WX 667 ; N K ; B 76 0 663 718 ; C 76 ; WX 556 ; N L ; B 76 0 537 718 ; C 77 ; WX 833 ; N M ; B 73 0 761 718 ; C 78 ; WX 722 ; N N ; B 76 0 646 718 ; C 79 ; WX 778 ; N O ; B 39 -19 739 737 ; C 80 ; WX 667 ; N P ; B 86 0 622 718 ; C 81 ; WX 778 ; N Q ; B 39 -56 739 737 ; C 82 ; WX 722 ; N R ; B 88 0 684 718 ; C 83 ; WX 667 ; N S ; B 49 -19 620 737 ; C 84 ; WX 611 ; N T ; B 14 0 597 718 ; C 85 ; WX 722 ; N U ; B 79 -19 644 718 ; C 86 ; WX 667 ; N V ; B 20 0 647 718 ; C 87 ; WX 944 ; N W ; B 16 0 928 718 ; C 88 ; WX 667 ; N X ; B 19 0 648 718 ; C 89 ; WX 667 ; N Y ; B 14 0 653 718 ; C 90 ; WX 611 ; N Z ; B 23 0 588 718 ; C 91 ; WX 278 ; N bracketleft ; B 63 -196 250 722 ; C 92 ; WX 278 ; N backslash ; B -17 -19 295 737 ; C 93 ; WX 278 ; N bracketright ; B 28 -196 215 722 ; C 94 ; WX 469 ; N asciicircum ; B -14 264 483 688 ; C 95 ; WX 556 ; N underscore ; B 0 -125 556 -75 ; C 96 ; WX 222 ; N quoteleft ; B 65 470 169 725 ; C 97 ; WX 556 ; N a ; B 36 -15 530 538 ; C 98 ; WX 556 ; N b ; B 58 -15 517 718 ; C 99 ; WX 500 ; N c ; B 30 -15 477 538 ; C 100 ; WX 556 ; N d ; B 35 -15 499 718 ; C 101 ; WX 556 ; N e ; B 40 -15 516 538 ; C 102 ; WX 278 ; N f ; B 14 0 262 728 ; L i fi ; L l fl ; C 103 ; WX 556 ; N g ; B 40 -220 499 538 ; C 104 ; WX 556 ; N h ; B 65 0 491 718 ; C 105 ; WX 222 ; N i ; B 67 0 155 718 ; C 106 ; WX 222 ; N j ; B -16 -210 155 718 ; C 107 ; WX 500 ; N k ; B 67 0 501 718 ; C 108 ; WX 222 ; N l ; B 67 0 155 718 ; C 109 ; WX 833 ; N m ; B 65 0 769 538 ; C 110 ; WX 556 ; N n ; B 65 0 491 538 ; C 111 ; WX 556 ; N o ; B 35 -14 521 538 ; C 112 ; WX 556 ; N p ; B 58 -207 517 538 ; C 113 ; WX 556 ; N q ; B 35 -207 494 538 ; C 114 ; WX 333 ; N r ; B 77 0 332 538 ; C 115 ; WX 500 ; N s ; B 32 -15 464 538 ; C 116 ; WX 278 ; N t ; B 14 -7 257 669 ; C 117 ; WX 556 ; N u ; B 68 -15 489 523 ; C 118 ; WX 500 ; N v ; B 8 0 492 523 ; C 119 ; WX 722 ; N w ; B 14 0 709 523 ; C 120 ; WX 500 ; N x ; B 11 0 490 523 ; C 121 ; WX 500 ; N y ; B 11 -214 489 523 ; C 122 ; WX 500 ; N z ; B 31 0 469 523 ; C 123 ; WX 334 ; N braceleft ; B 42 -196 292 722 ; C 124 ; WX 260 ; N bar ; B 94 -225 167 775 ; C 125 ; WX 334 ; N braceright ; B 42 -196 292 722 ; C 126 ; WX 584 ; N asciitilde ; B 61 180 523 326 ; C 161 ; WX 333 ; N exclamdown ; B 118 -195 215 523 ; C 162 ; WX 556 ; N cent ; B 51 -115 513 623 ; C 163 ; WX 556 ; N sterling ; B 33 -16 539 718 ; C 164 ; WX 167 ; N fraction ; B -166 -19 333 703 ; C 165 ; WX 556 ; N yen ; B 3 0 553 688 ; C 166 ; WX 556 ; N florin ; B -11 -207 501 737 ; C 167 ; WX 556 ; N section ; B 43 -191 512 737 ; C 168 ; WX 556 ; N currency ; B 28 99 528 603 ; C 169 ; WX 191 ; N quotesingle ; B 59 463 132 718 ; C 170 ; WX 333 ; N quotedblleft ; B 38 470 307 725 ; C 171 ; WX 556 ; N guillemotleft ; B 97 108 459 446 ; C 172 ; WX 333 ; N guilsinglleft ; B 88 108 245 446 ; C 173 ; WX 333 ; N guilsinglright ; B 88 108 245 446 ; C 174 ; WX 500 ; N fi ; B 14 0 434 728 ; C 175 ; WX 500 ; N fl ; B 14 0 432 728 ; C 177 ; WX 556 ; N endash ; B 0 240 556 313 ; C 178 ; WX 556 ; N dagger ; B 43 -159 514 718 ; C 179 ; WX 556 ; N daggerdbl ; B 43 -159 514 718 ; C 180 ; WX 278 ; N periodcentered ; B 77 190 202 315 ; C 182 ; WX 537 ; N paragraph ; B 18 -173 497 718 ; C 183 ; WX 350 ; N bullet ; B 18 202 333 517 ; C 184 ; WX 222 ; N quotesinglbase ; B 53 -149 157 106 ; C 185 ; WX 333 ; N quotedblbase ; B 26 -149 295 106 ; C 186 ; WX 333 ; N quotedblright ; B 26 463 295 718 ; C 187 ; WX 556 ; N guillemotright ; B 97 108 459 446 ; C 188 ; WX 1000 ; N ellipsis ; B 115 0 885 106 ; C 189 ; WX 1000 ; N perthousand ; B 7 -19 994 703 ; C 191 ; WX 611 ; N questiondown ; B 91 -201 527 525 ; C 193 ; WX 333 ; N grave ; B 14 593 211 734 ; C 194 ; WX 333 ; N acute ; B 122 593 319 734 ; C 195 ; WX 333 ; N circumflex ; B 21 593 312 734 ; C 196 ; WX 333 ; N tilde ; B -4 606 337 722 ; C 197 ; WX 333 ; N macron ; B 10 627 323 684 ; C 198 ; WX 333 ; N breve ; B 13 595 321 731 ; C 199 ; WX 333 ; N dotaccent ; B 121 604 212 706 ; C 200 ; WX 333 ; N dieresis ; B 40 604 293 706 ; C 202 ; WX 333 ; N ring ; B 75 572 259 756 ; C 203 ; WX 333 ; N cedilla ; B 45 -225 259 0 ; C 205 ; WX 333 ; N hungarumlaut ; B 31 593 409 734 ; C 206 ; WX 333 ; N ogonek ; B 73 -225 287 0 ; C 207 ; WX 333 ; N caron ; B 21 593 312 734 ; C 208 ; WX 1000 ; N emdash ; B 0 240 1000 313 ; C 225 ; WX 1000 ; N AE ; B 8 0 951 718 ; C 227 ; WX 370 ; N ordfeminine ; B 24 405 346 737 ; C 232 ; WX 556 ; N Lslash ; B -20 0 537 718 ; C 233 ; WX 778 ; N Oslash ; B 39 -19 740 737 ; C 234 ; WX 1000 ; N OE ; B 36 -19 965 737 ; C 235 ; WX 365 ; N ordmasculine ; B 25 405 341 737 ; C 241 ; WX 889 ; N ae ; B 36 -15 847 538 ; C 245 ; WX 278 ; N dotlessi ; B 95 0 183 523 ; C 248 ; WX 222 ; N lslash ; B -20 0 242 718 ; C 249 ; WX 611 ; N oslash ; B 28 -22 537 545 ; C 250 ; WX 944 ; N oe ; B 35 -15 902 538 ; C 251 ; WX 611 ; N germandbls ; B 67 -15 571 728 ; C -1 ; WX 278 ; N Idieresis ; B 13 0 266 901 ; C -1 ; WX 556 ; N eacute ; B 40 -15 516 734 ; C -1 ; WX 556 ; N abreve ; B 36 -15 530 731 ; C -1 ; WX 556 ; N uhungarumlaut ; B 68 -15 521 734 ; C -1 ; WX 556 ; N ecaron ; B 40 -15 516 734 ; C -1 ; WX 667 ; N Ydieresis ; B 14 0 653 901 ; C -1 ; WX 584 ; N divide ; B 39 -19 545 524 ; C -1 ; WX 667 ; N Yacute ; B 14 0 653 929 ; C -1 ; WX 667 ; N Acircumflex ; B 14 0 654 929 ; C -1 ; WX 556 ; N aacute ; B 36 -15 530 734 ; C -1 ; WX 722 ; N Ucircumflex ; B 79 -19 644 929 ; C -1 ; WX 500 ; N yacute ; B 11 -214 489 734 ; C -1 ; WX 500 ; N scommaaccent ; B 32 -225 464 538 ; C -1 ; WX 556 ; N ecircumflex ; B 40 -15 516 734 ; C -1 ; WX 722 ; N Uring ; B 79 -19 644 931 ; C -1 ; WX 722 ; N Udieresis ; B 79 -19 644 901 ; C -1 ; WX 556 ; N aogonek ; B 36 -220 547 538 ; C -1 ; WX 722 ; N Uacute ; B 79 -19 644 929 ; C -1 ; WX 556 ; N uogonek ; B 68 -225 519 523 ; C -1 ; WX 667 ; N Edieresis ; B 86 0 616 901 ; C -1 ; WX 722 ; N Dcroat ; B 0 0 674 718 ; C -1 ; WX 250 ; N commaaccent ; B 87 -225 181 -40 ; C -1 ; WX 737 ; N copyright ; B -14 -19 752 737 ; C -1 ; WX 667 ; N Emacron ; B 86 0 616 879 ; C -1 ; WX 500 ; N ccaron ; B 30 -15 477 734 ; C -1 ; WX 556 ; N aring ; B 36 -15 530 756 ; C -1 ; WX 722 ; N Ncommaaccent ; B 76 -225 646 718 ; C -1 ; WX 222 ; N lacute ; B 67 0 264 929 ; C -1 ; WX 556 ; N agrave ; B 36 -15 530 734 ; C -1 ; WX 611 ; N Tcommaaccent ; B 14 -225 597 718 ; C -1 ; WX 722 ; N Cacute ; B 44 -19 681 929 ; C -1 ; WX 556 ; N atilde ; B 36 -15 530 722 ; C -1 ; WX 667 ; N Edotaccent ; B 86 0 616 901 ; C -1 ; WX 500 ; N scaron ; B 32 -15 464 734 ; C -1 ; WX 500 ; N scedilla ; B 32 -225 464 538 ; C -1 ; WX 278 ; N iacute ; B 95 0 292 734 ; C -1 ; WX 471 ; N lozenge ; B 10 0 462 728 ; C -1 ; WX 722 ; N Rcaron ; B 88 0 684 929 ; C -1 ; WX 778 ; N Gcommaaccent ; B 48 -225 704 737 ; C -1 ; WX 556 ; N ucircumflex ; B 68 -15 489 734 ; C -1 ; WX 556 ; N acircumflex ; B 36 -15 530 734 ; C -1 ; WX 667 ; N Amacron ; B 14 0 654 879 ; C -1 ; WX 333 ; N rcaron ; B 61 0 352 734 ; C -1 ; WX 500 ; N ccedilla ; B 30 -225 477 538 ; C -1 ; WX 611 ; N Zdotaccent ; B 23 0 588 901 ; C -1 ; WX 667 ; N Thorn ; B 86 0 622 718 ; C -1 ; WX 778 ; N Omacron ; B 39 -19 739 879 ; C -1 ; WX 722 ; N Racute ; B 88 0 684 929 ; C -1 ; WX 667 ; N Sacute ; B 49 -19 620 929 ; C -1 ; WX 643 ; N dcaron ; B 35 -15 655 718 ; C -1 ; WX 722 ; N Umacron ; B 79 -19 644 879 ; C -1 ; WX 556 ; N uring ; B 68 -15 489 756 ; C -1 ; WX 333 ; N threesuperior ; B 5 270 325 703 ; C -1 ; WX 778 ; N Ograve ; B 39 -19 739 929 ; C -1 ; WX 667 ; N Agrave ; B 14 0 654 929 ; C -1 ; WX 667 ; N Abreve ; B 14 0 654 926 ; C -1 ; WX 584 ; N multiply ; B 39 0 545 506 ; C -1 ; WX 556 ; N uacute ; B 68 -15 489 734 ; C -1 ; WX 611 ; N Tcaron ; B 14 0 597 929 ; C -1 ; WX 476 ; N partialdiff ; B 13 -38 463 714 ; C -1 ; WX 500 ; N ydieresis ; B 11 -214 489 706 ; C -1 ; WX 722 ; N Nacute ; B 76 0 646 929 ; C -1 ; WX 278 ; N icircumflex ; B -6 0 285 734 ; C -1 ; WX 667 ; N Ecircumflex ; B 86 0 616 929 ; C -1 ; WX 556 ; N adieresis ; B 36 -15 530 706 ; C -1 ; WX 556 ; N edieresis ; B 40 -15 516 706 ; C -1 ; WX 500 ; N cacute ; B 30 -15 477 734 ; C -1 ; WX 556 ; N nacute ; B 65 0 491 734 ; C -1 ; WX 556 ; N umacron ; B 68 -15 489 684 ; C -1 ; WX 722 ; N Ncaron ; B 76 0 646 929 ; C -1 ; WX 278 ; N Iacute ; B 91 0 292 929 ; C -1 ; WX 584 ; N plusminus ; B 39 0 545 506 ; C -1 ; WX 260 ; N brokenbar ; B 94 -150 167 700 ; C -1 ; WX 737 ; N registered ; B -14 -19 752 737 ; C -1 ; WX 778 ; N Gbreve ; B 48 -19 704 926 ; C -1 ; WX 278 ; N Idotaccent ; B 91 0 188 901 ; C -1 ; WX 600 ; N summation ; B 15 -10 586 706 ; C -1 ; WX 667 ; N Egrave ; B 86 0 616 929 ; C -1 ; WX 333 ; N racute ; B 77 0 332 734 ; C -1 ; WX 556 ; N omacron ; B 35 -14 521 684 ; C -1 ; WX 611 ; N Zacute ; B 23 0 588 929 ; C -1 ; WX 611 ; N Zcaron ; B 23 0 588 929 ; C -1 ; WX 549 ; N greaterequal ; B 26 0 523 674 ; C -1 ; WX 722 ; N Eth ; B 0 0 674 718 ; C -1 ; WX 722 ; N Ccedilla ; B 44 -225 681 737 ; C -1 ; WX 222 ; N lcommaaccent ; B 67 -225 167 718 ; C -1 ; WX 317 ; N tcaron ; B 14 -7 329 808 ; C -1 ; WX 556 ; N eogonek ; B 40 -225 516 538 ; C -1 ; WX 722 ; N Uogonek ; B 79 -225 644 718 ; C -1 ; WX 667 ; N Aacute ; B 14 0 654 929 ; C -1 ; WX 667 ; N Adieresis ; B 14 0 654 901 ; C -1 ; WX 556 ; N egrave ; B 40 -15 516 734 ; C -1 ; WX 500 ; N zacute ; B 31 0 469 734 ; C -1 ; WX 222 ; N iogonek ; B -31 -225 183 718 ; C -1 ; WX 778 ; N Oacute ; B 39 -19 739 929 ; C -1 ; WX 556 ; N oacute ; B 35 -14 521 734 ; C -1 ; WX 556 ; N amacron ; B 36 -15 530 684 ; C -1 ; WX 500 ; N sacute ; B 32 -15 464 734 ; C -1 ; WX 278 ; N idieresis ; B 13 0 266 706 ; C -1 ; WX 778 ; N Ocircumflex ; B 39 -19 739 929 ; C -1 ; WX 722 ; N Ugrave ; B 79 -19 644 929 ; C -1 ; WX 612 ; N Delta ; B 6 0 608 688 ; C -1 ; WX 556 ; N thorn ; B 58 -207 517 718 ; C -1 ; WX 333 ; N twosuperior ; B 4 281 323 703 ; C -1 ; WX 778 ; N Odieresis ; B 39 -19 739 901 ; C -1 ; WX 556 ; N mu ; B 68 -207 489 523 ; C -1 ; WX 278 ; N igrave ; B -13 0 184 734 ; C -1 ; WX 556 ; N ohungarumlaut ; B 35 -14 521 734 ; C -1 ; WX 667 ; N Eogonek ; B 86 -220 633 718 ; C -1 ; WX 556 ; N dcroat ; B 35 -15 550 718 ; C -1 ; WX 834 ; N threequarters ; B 45 -19 810 703 ; C -1 ; WX 667 ; N Scedilla ; B 49 -225 620 737 ; C -1 ; WX 299 ; N lcaron ; B 67 0 311 718 ; C -1 ; WX 667 ; N Kcommaaccent ; B 76 -225 663 718 ; C -1 ; WX 556 ; N Lacute ; B 76 0 537 929 ; C -1 ; WX 1000 ; N trademark ; B 46 306 903 718 ; C -1 ; WX 556 ; N edotaccent ; B 40 -15 516 706 ; C -1 ; WX 278 ; N Igrave ; B -13 0 188 929 ; C -1 ; WX 278 ; N Imacron ; B -17 0 296 879 ; C -1 ; WX 556 ; N Lcaron ; B 76 0 537 718 ; C -1 ; WX 834 ; N onehalf ; B 43 -19 773 703 ; C -1 ; WX 549 ; N lessequal ; B 26 0 523 674 ; C -1 ; WX 556 ; N ocircumflex ; B 35 -14 521 734 ; C -1 ; WX 556 ; N ntilde ; B 65 0 491 722 ; C -1 ; WX 722 ; N Uhungarumlaut ; B 79 -19 644 929 ; C -1 ; WX 667 ; N Eacute ; B 86 0 616 929 ; C -1 ; WX 556 ; N emacron ; B 40 -15 516 684 ; C -1 ; WX 556 ; N gbreve ; B 40 -220 499 731 ; C -1 ; WX 834 ; N onequarter ; B 73 -19 756 703 ; C -1 ; WX 667 ; N Scaron ; B 49 -19 620 929 ; C -1 ; WX 667 ; N Scommaaccent ; B 49 -225 620 737 ; C -1 ; WX 778 ; N Ohungarumlaut ; B 39 -19 739 929 ; C -1 ; WX 400 ; N degree ; B 54 411 346 703 ; C -1 ; WX 556 ; N ograve ; B 35 -14 521 734 ; C -1 ; WX 722 ; N Ccaron ; B 44 -19 681 929 ; C -1 ; WX 556 ; N ugrave ; B 68 -15 489 734 ; C -1 ; WX 453 ; N radical ; B -4 -80 458 762 ; C -1 ; WX 722 ; N Dcaron ; B 81 0 674 929 ; C -1 ; WX 333 ; N rcommaaccent ; B 77 -225 332 538 ; C -1 ; WX 722 ; N Ntilde ; B 76 0 646 917 ; C -1 ; WX 556 ; N otilde ; B 35 -14 521 722 ; C -1 ; WX 722 ; N Rcommaaccent ; B 88 -225 684 718 ; C -1 ; WX 556 ; N Lcommaaccent ; B 76 -225 537 718 ; C -1 ; WX 667 ; N Atilde ; B 14 0 654 917 ; C -1 ; WX 667 ; N Aogonek ; B 14 -225 654 718 ; C -1 ; WX 667 ; N Aring ; B 14 0 654 931 ; C -1 ; WX 778 ; N Otilde ; B 39 -19 739 917 ; C -1 ; WX 500 ; N zdotaccent ; B 31 0 469 706 ; C -1 ; WX 667 ; N Ecaron ; B 86 0 616 929 ; C -1 ; WX 278 ; N Iogonek ; B -3 -225 211 718 ; C -1 ; WX 500 ; N kcommaaccent ; B 67 -225 501 718 ; C -1 ; WX 584 ; N minus ; B 39 216 545 289 ; C -1 ; WX 278 ; N Icircumflex ; B -6 0 285 929 ; C -1 ; WX 556 ; N ncaron ; B 65 0 491 734 ; C -1 ; WX 278 ; N tcommaaccent ; B 14 -225 257 669 ; C -1 ; WX 584 ; N logicalnot ; B 39 108 545 390 ; C -1 ; WX 556 ; N odieresis ; B 35 -14 521 706 ; C -1 ; WX 556 ; N udieresis ; B 68 -15 489 706 ; C -1 ; WX 549 ; N notequal ; B 12 -35 537 551 ; C -1 ; WX 556 ; N gcommaaccent ; B 40 -220 499 822 ; C -1 ; WX 556 ; N eth ; B 35 -15 522 737 ; C -1 ; WX 500 ; N zcaron ; B 31 0 469 734 ; C -1 ; WX 556 ; N ncommaaccent ; B 65 -225 491 538 ; C -1 ; WX 333 ; N onesuperior ; B 43 281 222 703 ; C -1 ; WX 278 ; N imacron ; B 5 0 272 684 ; C -1 ; WX 556 ; N Euro ; B 0 0 0 0 ; EndCharMetrics StartKernData StartKernPairs 2705 KPX A C -30 KPX A Cacute -30 KPX A Ccaron -30 KPX A Ccedilla -30 KPX A G -30 KPX A Gbreve -30 KPX A Gcommaaccent -30 KPX A O -30 KPX A Oacute -30 KPX A Ocircumflex -30 KPX A Odieresis -30 KPX A Ograve -30 KPX A Ohungarumlaut -30 KPX A Omacron -30 KPX A Oslash -30 KPX A Otilde -30 KPX A Q -30 KPX A T -120 KPX A Tcaron -120 KPX A Tcommaaccent -120 KPX A U -50 KPX A Uacute -50 KPX A Ucircumflex -50 KPX A Udieresis -50 KPX A Ugrave -50 KPX A Uhungarumlaut -50 KPX A Umacron -50 KPX A Uogonek -50 KPX A Uring -50 KPX A V -70 KPX A W -50 KPX A Y -100 KPX A Yacute -100 KPX A Ydieresis -100 KPX A u -30 KPX A uacute -30 KPX A ucircumflex -30 KPX A udieresis -30 KPX A ugrave -30 KPX A uhungarumlaut -30 KPX A umacron -30 KPX A uogonek -30 KPX A uring -30 KPX A v -40 KPX A w -40 KPX A y -40 KPX A yacute -40 KPX A ydieresis -40 KPX Aacute C -30 KPX Aacute Cacute -30 KPX Aacute Ccaron -30 KPX Aacute Ccedilla -30 KPX Aacute G -30 KPX Aacute Gbreve -30 KPX Aacute Gcommaaccent -30 KPX Aacute O -30 KPX Aacute Oacute -30 KPX Aacute Ocircumflex -30 KPX Aacute Odieresis -30 KPX Aacute Ograve -30 KPX Aacute Ohungarumlaut -30 KPX Aacute Omacron -30 KPX Aacute Oslash -30 KPX Aacute Otilde -30 KPX Aacute Q -30 KPX Aacute T -120 KPX Aacute Tcaron -120 KPX Aacute Tcommaaccent -120 KPX Aacute U -50 KPX Aacute Uacute -50 KPX Aacute Ucircumflex -50 KPX Aacute Udieresis -50 KPX Aacute Ugrave -50 KPX Aacute Uhungarumlaut -50 KPX Aacute Umacron -50 KPX Aacute Uogonek -50 KPX Aacute Uring -50 KPX Aacute V -70 KPX Aacute W -50 KPX Aacute Y -100 KPX Aacute Yacute -100 KPX Aacute Ydieresis -100 KPX Aacute u -30 KPX Aacute uacute -30 KPX Aacute ucircumflex -30 KPX Aacute udieresis -30 KPX Aacute ugrave -30 KPX Aacute uhungarumlaut -30 KPX Aacute umacron -30 KPX Aacute uogonek -30 KPX Aacute uring -30 KPX Aacute v -40 KPX Aacute w -40 KPX Aacute y -40 KPX Aacute yacute -40 KPX Aacute ydieresis -40 KPX Abreve C -30 KPX Abreve Cacute -30 KPX Abreve Ccaron -30 KPX Abreve Ccedilla -30 KPX Abreve G -30 KPX Abreve Gbreve -30 KPX Abreve Gcommaaccent -30 KPX Abreve O -30 KPX Abreve Oacute -30 KPX Abreve Ocircumflex -30 KPX Abreve Odieresis -30 KPX Abreve Ograve -30 KPX Abreve Ohungarumlaut -30 KPX Abreve Omacron -30 KPX Abreve Oslash -30 KPX Abreve Otilde -30 KPX Abreve Q -30 KPX Abreve T -120 KPX Abreve Tcaron -120 KPX Abreve Tcommaaccent -120 KPX Abreve U -50 KPX Abreve Uacute -50 KPX Abreve Ucircumflex -50 KPX Abreve Udieresis -50 KPX Abreve Ugrave -50 KPX Abreve Uhungarumlaut -50 KPX Abreve Umacron -50 KPX Abreve Uogonek -50 KPX Abreve Uring -50 KPX Abreve V -70 KPX Abreve W -50 KPX Abreve Y -100 KPX Abreve Yacute -100 KPX Abreve Ydieresis -100 KPX Abreve u -30 KPX Abreve uacute -30 KPX Abreve ucircumflex -30 KPX Abreve udieresis -30 KPX Abreve ugrave -30 KPX Abreve uhungarumlaut -30 KPX Abreve umacron -30 KPX Abreve uogonek -30 KPX Abreve uring -30 KPX Abreve v -40 KPX Abreve w -40 KPX Abreve y -40 KPX Abreve yacute -40 KPX Abreve ydieresis -40 KPX Acircumflex C -30 KPX Acircumflex Cacute -30 KPX Acircumflex Ccaron -30 KPX Acircumflex Ccedilla -30 KPX Acircumflex G -30 KPX Acircumflex Gbreve -30 KPX Acircumflex Gcommaaccent -30 KPX Acircumflex O -30 KPX Acircumflex Oacute -30 KPX Acircumflex Ocircumflex -30 KPX Acircumflex Odieresis -30 KPX Acircumflex Ograve -30 KPX Acircumflex Ohungarumlaut -30 KPX Acircumflex Omacron -30 KPX Acircumflex Oslash -30 KPX Acircumflex Otilde -30 KPX Acircumflex Q -30 KPX Acircumflex T -120 KPX Acircumflex Tcaron -120 KPX Acircumflex Tcommaaccent -120 KPX Acircumflex U -50 KPX Acircumflex Uacute -50 KPX Acircumflex Ucircumflex -50 KPX Acircumflex Udieresis -50 KPX Acircumflex Ugrave -50 KPX Acircumflex Uhungarumlaut -50 KPX Acircumflex Umacron -50 KPX Acircumflex Uogonek -50 KPX Acircumflex Uring -50 KPX Acircumflex V -70 KPX Acircumflex W -50 KPX Acircumflex Y -100 KPX Acircumflex Yacute -100 KPX Acircumflex Ydieresis -100 KPX Acircumflex u -30 KPX Acircumflex uacute -30 KPX Acircumflex ucircumflex -30 KPX Acircumflex udieresis -30 KPX Acircumflex ugrave -30 KPX Acircumflex uhungarumlaut -30 KPX Acircumflex umacron -30 KPX Acircumflex uogonek -30 KPX Acircumflex uring -30 KPX Acircumflex v -40 KPX Acircumflex w -40 KPX Acircumflex y -40 KPX Acircumflex yacute -40 KPX Acircumflex ydieresis -40 KPX Adieresis C -30 KPX Adieresis Cacute -30 KPX Adieresis Ccaron -30 KPX Adieresis Ccedilla -30 KPX Adieresis G -30 KPX Adieresis Gbreve -30 KPX Adieresis Gcommaaccent -30 KPX Adieresis O -30 KPX Adieresis Oacute -30 KPX Adieresis Ocircumflex -30 KPX Adieresis Odieresis -30 KPX Adieresis Ograve -30 KPX Adieresis Ohungarumlaut -30 KPX Adieresis Omacron -30 KPX Adieresis Oslash -30 KPX Adieresis Otilde -30 KPX Adieresis Q -30 KPX Adieresis T -120 KPX Adieresis Tcaron -120 KPX Adieresis Tcommaaccent -120 KPX Adieresis U -50 KPX Adieresis Uacute -50 KPX Adieresis Ucircumflex -50 KPX Adieresis Udieresis -50 KPX Adieresis Ugrave -50 KPX Adieresis Uhungarumlaut -50 KPX Adieresis Umacron -50 KPX Adieresis Uogonek -50 KPX Adieresis Uring -50 KPX Adieresis V -70 KPX Adieresis W -50 KPX Adieresis Y -100 KPX Adieresis Yacute -100 KPX Adieresis Ydieresis -100 KPX Adieresis u -30 KPX Adieresis uacute -30 KPX Adieresis ucircumflex -30 KPX Adieresis udieresis -30 KPX Adieresis ugrave -30 KPX Adieresis uhungarumlaut -30 KPX Adieresis umacron -30 KPX Adieresis uogonek -30 KPX Adieresis uring -30 KPX Adieresis v -40 KPX Adieresis w -40 KPX Adieresis y -40 KPX Adieresis yacute -40 KPX Adieresis ydieresis -40 KPX Agrave C -30 KPX Agrave Cacute -30 KPX Agrave Ccaron -30 KPX Agrave Ccedilla -30 KPX Agrave G -30 KPX Agrave Gbreve -30 KPX Agrave Gcommaaccent -30 KPX Agrave O -30 KPX Agrave Oacute -30 KPX Agrave Ocircumflex -30 KPX Agrave Odieresis -30 KPX Agrave Ograve -30 KPX Agrave Ohungarumlaut -30 KPX Agrave Omacron -30 KPX Agrave Oslash -30 KPX Agrave Otilde -30 KPX Agrave Q -30 KPX Agrave T -120 KPX Agrave Tcaron -120 KPX Agrave Tcommaaccent -120 KPX Agrave U -50 KPX Agrave Uacute -50 KPX Agrave Ucircumflex -50 KPX Agrave Udieresis -50 KPX Agrave Ugrave -50 KPX Agrave Uhungarumlaut -50 KPX Agrave Umacron -50 KPX Agrave Uogonek -50 KPX Agrave Uring -50 KPX Agrave V -70 KPX Agrave W -50 KPX Agrave Y -100 KPX Agrave Yacute -100 KPX Agrave Ydieresis -100 KPX Agrave u -30 KPX Agrave uacute -30 KPX Agrave ucircumflex -30 KPX Agrave udieresis -30 KPX Agrave ugrave -30 KPX Agrave uhungarumlaut -30 KPX Agrave umacron -30 KPX Agrave uogonek -30 KPX Agrave uring -30 KPX Agrave v -40 KPX Agrave w -40 KPX Agrave y -40 KPX Agrave yacute -40 KPX Agrave ydieresis -40 KPX Amacron C -30 KPX Amacron Cacute -30 KPX Amacron Ccaron -30 KPX Amacron Ccedilla -30 KPX Amacron G -30 KPX Amacron Gbreve -30 KPX Amacron Gcommaaccent -30 KPX Amacron O -30 KPX Amacron Oacute -30 KPX Amacron Ocircumflex -30 KPX Amacron Odieresis -30 KPX Amacron Ograve -30 KPX Amacron Ohungarumlaut -30 KPX Amacron Omacron -30 KPX Amacron Oslash -30 KPX Amacron Otilde -30 KPX Amacron Q -30 KPX Amacron T -120 KPX Amacron Tcaron -120 KPX Amacron Tcommaaccent -120 KPX Amacron U -50 KPX Amacron Uacute -50 KPX Amacron Ucircumflex -50 KPX Amacron Udieresis -50 KPX Amacron Ugrave -50 KPX Amacron Uhungarumlaut -50 KPX Amacron Umacron -50 KPX Amacron Uogonek -50 KPX Amacron Uring -50 KPX Amacron V -70 KPX Amacron W -50 KPX Amacron Y -100 KPX Amacron Yacute -100 KPX Amacron Ydieresis -100 KPX Amacron u -30 KPX Amacron uacute -30 KPX Amacron ucircumflex -30 KPX Amacron udieresis -30 KPX Amacron ugrave -30 KPX Amacron uhungarumlaut -30 KPX Amacron umacron -30 KPX Amacron uogonek -30 KPX Amacron uring -30 KPX Amacron v -40 KPX Amacron w -40 KPX Amacron y -40 KPX Amacron yacute -40 KPX Amacron ydieresis -40 KPX Aogonek C -30 KPX Aogonek Cacute -30 KPX Aogonek Ccaron -30 KPX Aogonek Ccedilla -30 KPX Aogonek G -30 KPX Aogonek Gbreve -30 KPX Aogonek Gcommaaccent -30 KPX Aogonek O -30 KPX Aogonek Oacute -30 KPX Aogonek Ocircumflex -30 KPX Aogonek Odieresis -30 KPX Aogonek Ograve -30 KPX Aogonek Ohungarumlaut -30 KPX Aogonek Omacron -30 KPX Aogonek Oslash -30 KPX Aogonek Otilde -30 KPX Aogonek Q -30 KPX Aogonek T -120 KPX Aogonek Tcaron -120 KPX Aogonek Tcommaaccent -120 KPX Aogonek U -50 KPX Aogonek Uacute -50 KPX Aogonek Ucircumflex -50 KPX Aogonek Udieresis -50 KPX Aogonek Ugrave -50 KPX Aogonek Uhungarumlaut -50 KPX Aogonek Umacron -50 KPX Aogonek Uogonek -50 KPX Aogonek Uring -50 KPX Aogonek V -70 KPX Aogonek W -50 KPX Aogonek Y -100 KPX Aogonek Yacute -100 KPX Aogonek Ydieresis -100 KPX Aogonek u -30 KPX Aogonek uacute -30 KPX Aogonek ucircumflex -30 KPX Aogonek udieresis -30 KPX Aogonek ugrave -30 KPX Aogonek uhungarumlaut -30 KPX Aogonek umacron -30 KPX Aogonek uogonek -30 KPX Aogonek uring -30 KPX Aogonek v -40 KPX Aogonek w -40 KPX Aogonek y -40 KPX Aogonek yacute -40 KPX Aogonek ydieresis -40 KPX Aring C -30 KPX Aring Cacute -30 KPX Aring Ccaron -30 KPX Aring Ccedilla -30 KPX Aring G -30 KPX Aring Gbreve -30 KPX Aring Gcommaaccent -30 KPX Aring O -30 KPX Aring Oacute -30 KPX Aring Ocircumflex -30 KPX Aring Odieresis -30 KPX Aring Ograve -30 KPX Aring Ohungarumlaut -30 KPX Aring Omacron -30 KPX Aring Oslash -30 KPX Aring Otilde -30 KPX Aring Q -30 KPX Aring T -120 KPX Aring Tcaron -120 KPX Aring Tcommaaccent -120 KPX Aring U -50 KPX Aring Uacute -50 KPX Aring Ucircumflex -50 KPX Aring Udieresis -50 KPX Aring Ugrave -50 KPX Aring Uhungarumlaut -50 KPX Aring Umacron -50 KPX Aring Uogonek -50 KPX Aring Uring -50 KPX Aring V -70 KPX Aring W -50 KPX Aring Y -100 KPX Aring Yacute -100 KPX Aring Ydieresis -100 KPX Aring u -30 KPX Aring uacute -30 KPX Aring ucircumflex -30 KPX Aring udieresis -30 KPX Aring ugrave -30 KPX Aring uhungarumlaut -30 KPX Aring umacron -30 KPX Aring uogonek -30 KPX Aring uring -30 KPX Aring v -40 KPX Aring w -40 KPX Aring y -40 KPX Aring yacute -40 KPX Aring ydieresis -40 KPX Atilde C -30 KPX Atilde Cacute -30 KPX Atilde Ccaron -30 KPX Atilde Ccedilla -30 KPX Atilde G -30 KPX Atilde Gbreve -30 KPX Atilde Gcommaaccent -30 KPX Atilde O -30 KPX Atilde Oacute -30 KPX Atilde Ocircumflex -30 KPX Atilde Odieresis -30 KPX Atilde Ograve -30 KPX Atilde Ohungarumlaut -30 KPX Atilde Omacron -30 KPX Atilde Oslash -30 KPX Atilde Otilde -30 KPX Atilde Q -30 KPX Atilde T -120 KPX Atilde Tcaron -120 KPX Atilde Tcommaaccent -120 KPX Atilde U -50 KPX Atilde Uacute -50 KPX Atilde Ucircumflex -50 KPX Atilde Udieresis -50 KPX Atilde Ugrave -50 KPX Atilde Uhungarumlaut -50 KPX Atilde Umacron -50 KPX Atilde Uogonek -50 KPX Atilde Uring -50 KPX Atilde V -70 KPX Atilde W -50 KPX Atilde Y -100 KPX Atilde Yacute -100 KPX Atilde Ydieresis -100 KPX Atilde u -30 KPX Atilde uacute -30 KPX Atilde ucircumflex -30 KPX Atilde udieresis -30 KPX Atilde ugrave -30 KPX Atilde uhungarumlaut -30 KPX Atilde umacron -30 KPX Atilde uogonek -30 KPX Atilde uring -30 KPX Atilde v -40 KPX Atilde w -40 KPX Atilde y -40 KPX Atilde yacute -40 KPX Atilde ydieresis -40 KPX B U -10 KPX B Uacute -10 KPX B Ucircumflex -10 KPX B Udieresis -10 KPX B Ugrave -10 KPX B Uhungarumlaut -10 KPX B Umacron -10 KPX B Uogonek -10 KPX B Uring -10 KPX B comma -20 KPX B period -20 KPX C comma -30 KPX C period -30 KPX Cacute comma -30 KPX Cacute period -30 KPX Ccaron comma -30 KPX Ccaron period -30 KPX Ccedilla comma -30 KPX Ccedilla period -30 KPX D A -40 KPX D Aacute -40 KPX D Abreve -40 KPX D Acircumflex -40 KPX D Adieresis -40 KPX D Agrave -40 KPX D Amacron -40 KPX D Aogonek -40 KPX D Aring -40 KPX D Atilde -40 KPX D V -70 KPX D W -40 KPX D Y -90 KPX D Yacute -90 KPX D Ydieresis -90 KPX D comma -70 KPX D period -70 KPX Dcaron A -40 KPX Dcaron Aacute -40 KPX Dcaron Abreve -40 KPX Dcaron Acircumflex -40 KPX Dcaron Adieresis -40 KPX Dcaron Agrave -40 KPX Dcaron Amacron -40 KPX Dcaron Aogonek -40 KPX Dcaron Aring -40 KPX Dcaron Atilde -40 KPX Dcaron V -70 KPX Dcaron W -40 KPX Dcaron Y -90 KPX Dcaron Yacute -90 KPX Dcaron Ydieresis -90 KPX Dcaron comma -70 KPX Dcaron period -70 KPX Dcroat A -40 KPX Dcroat Aacute -40 KPX Dcroat Abreve -40 KPX Dcroat Acircumflex -40 KPX Dcroat Adieresis -40 KPX Dcroat Agrave -40 KPX Dcroat Amacron -40 KPX Dcroat Aogonek -40 KPX Dcroat Aring -40 KPX Dcroat Atilde -40 KPX Dcroat V -70 KPX Dcroat W -40 KPX Dcroat Y -90 KPX Dcroat Yacute -90 KPX Dcroat Ydieresis -90 KPX Dcroat comma -70 KPX Dcroat period -70 KPX F A -80 KPX F Aacute -80 KPX F Abreve -80 KPX F Acircumflex -80 KPX F Adieresis -80 KPX F Agrave -80 KPX F Amacron -80 KPX F Aogonek -80 KPX F Aring -80 KPX F Atilde -80 KPX F a -50 KPX F aacute -50 KPX F abreve -50 KPX F acircumflex -50 KPX F adieresis -50 KPX F agrave -50 KPX F amacron -50 KPX F aogonek -50 KPX F aring -50 KPX F atilde -50 KPX F comma -150 KPX F e -30 KPX F eacute -30 KPX F ecaron -30 KPX F ecircumflex -30 KPX F edieresis -30 KPX F edotaccent -30 KPX F egrave -30 KPX F emacron -30 KPX F eogonek -30 KPX F o -30 KPX F oacute -30 KPX F ocircumflex -30 KPX F odieresis -30 KPX F ograve -30 KPX F ohungarumlaut -30 KPX F omacron -30 KPX F oslash -30 KPX F otilde -30 KPX F period -150 KPX F r -45 KPX F racute -45 KPX F rcaron -45 KPX F rcommaaccent -45 KPX J A -20 KPX J Aacute -20 KPX J Abreve -20 KPX J Acircumflex -20 KPX J Adieresis -20 KPX J Agrave -20 KPX J Amacron -20 KPX J Aogonek -20 KPX J Aring -20 KPX J Atilde -20 KPX J a -20 KPX J aacute -20 KPX J abreve -20 KPX J acircumflex -20 KPX J adieresis -20 KPX J agrave -20 KPX J amacron -20 KPX J aogonek -20 KPX J aring -20 KPX J atilde -20 KPX J comma -30 KPX J period -30 KPX J u -20 KPX J uacute -20 KPX J ucircumflex -20 KPX J udieresis -20 KPX J ugrave -20 KPX J uhungarumlaut -20 KPX J umacron -20 KPX J uogonek -20 KPX J uring -20 KPX K O -50 KPX K Oacute -50 KPX K Ocircumflex -50 KPX K Odieresis -50 KPX K Ograve -50 KPX K Ohungarumlaut -50 KPX K Omacron -50 KPX K Oslash -50 KPX K Otilde -50 KPX K e -40 KPX K eacute -40 KPX K ecaron -40 KPX K ecircumflex -40 KPX K edieresis -40 KPX K edotaccent -40 KPX K egrave -40 KPX K emacron -40 KPX K eogonek -40 KPX K o -40 KPX K oacute -40 KPX K ocircumflex -40 KPX K odieresis -40 KPX K ograve -40 KPX K ohungarumlaut -40 KPX K omacron -40 KPX K oslash -40 KPX K otilde -40 KPX K u -30 KPX K uacute -30 KPX K ucircumflex -30 KPX K udieresis -30 KPX K ugrave -30 KPX K uhungarumlaut -30 KPX K umacron -30 KPX K uogonek -30 KPX K uring -30 KPX K y -50 KPX K yacute -50 KPX K ydieresis -50 KPX Kcommaaccent O -50 KPX Kcommaaccent Oacute -50 KPX Kcommaaccent Ocircumflex -50 KPX Kcommaaccent Odieresis -50 KPX Kcommaaccent Ograve -50 KPX Kcommaaccent Ohungarumlaut -50 KPX Kcommaaccent Omacron -50 KPX Kcommaaccent Oslash -50 KPX Kcommaaccent Otilde -50 KPX Kcommaaccent e -40 KPX Kcommaaccent eacute -40 KPX Kcommaaccent ecaron -40 KPX Kcommaaccent ecircumflex -40 KPX Kcommaaccent edieresis -40 KPX Kcommaaccent edotaccent -40 KPX Kcommaaccent egrave -40 KPX Kcommaaccent emacron -40 KPX Kcommaaccent eogonek -40 KPX Kcommaaccent o -40 KPX Kcommaaccent oacute -40 KPX Kcommaaccent ocircumflex -40 KPX Kcommaaccent odieresis -40 KPX Kcommaaccent ograve -40 KPX Kcommaaccent ohungarumlaut -40 KPX Kcommaaccent omacron -40 KPX Kcommaaccent oslash -40 KPX Kcommaaccent otilde -40 KPX Kcommaaccent u -30 KPX Kcommaaccent uacute -30 KPX Kcommaaccent ucircumflex -30 KPX Kcommaaccent udieresis -30 KPX Kcommaaccent ugrave -30 KPX Kcommaaccent uhungarumlaut -30 KPX Kcommaaccent umacron -30 KPX Kcommaaccent uogonek -30 KPX Kcommaaccent uring -30 KPX Kcommaaccent y -50 KPX Kcommaaccent yacute -50 KPX Kcommaaccent ydieresis -50 KPX L T -110 KPX L Tcaron -110 KPX L Tcommaaccent -110 KPX L V -110 KPX L W -70 KPX L Y -140 KPX L Yacute -140 KPX L Ydieresis -140 KPX L quotedblright -140 KPX L quoteright -160 KPX L y -30 KPX L yacute -30 KPX L ydieresis -30 KPX Lacute T -110 KPX Lacute Tcaron -110 KPX Lacute Tcommaaccent -110 KPX Lacute V -110 KPX Lacute W -70 KPX Lacute Y -140 KPX Lacute Yacute -140 KPX Lacute Ydieresis -140 KPX Lacute quotedblright -140 KPX Lacute quoteright -160 KPX Lacute y -30 KPX Lacute yacute -30 KPX Lacute ydieresis -30 KPX Lcaron T -110 KPX Lcaron Tcaron -110 KPX Lcaron Tcommaaccent -110 KPX Lcaron V -110 KPX Lcaron W -70 KPX Lcaron Y -140 KPX Lcaron Yacute -140 KPX Lcaron Ydieresis -140 KPX Lcaron quotedblright -140 KPX Lcaron quoteright -160 KPX Lcaron y -30 KPX Lcaron yacute -30 KPX Lcaron ydieresis -30 KPX Lcommaaccent T -110 KPX Lcommaaccent Tcaron -110 KPX Lcommaaccent Tcommaaccent -110 KPX Lcommaaccent V -110 KPX Lcommaaccent W -70 KPX Lcommaaccent Y -140 KPX Lcommaaccent Yacute -140 KPX Lcommaaccent Ydieresis -140 KPX Lcommaaccent quotedblright -140 KPX Lcommaaccent quoteright -160 KPX Lcommaaccent y -30 KPX Lcommaaccent yacute -30 KPX Lcommaaccent ydieresis -30 KPX Lslash T -110 KPX Lslash Tcaron -110 KPX Lslash Tcommaaccent -110 KPX Lslash V -110 KPX Lslash W -70 KPX Lslash Y -140 KPX Lslash Yacute -140 KPX Lslash Ydieresis -140 KPX Lslash quotedblright -140 KPX Lslash quoteright -160 KPX Lslash y -30 KPX Lslash yacute -30 KPX Lslash ydieresis -30 KPX O A -20 KPX O Aacute -20 KPX O Abreve -20 KPX O Acircumflex -20 KPX O Adieresis -20 KPX O Agrave -20 KPX O Amacron -20 KPX O Aogonek -20 KPX O Aring -20 KPX O Atilde -20 KPX O T -40 KPX O Tcaron -40 KPX O Tcommaaccent -40 KPX O V -50 KPX O W -30 KPX O X -60 KPX O Y -70 KPX O Yacute -70 KPX O Ydieresis -70 KPX O comma -40 KPX O period -40 KPX Oacute A -20 KPX Oacute Aacute -20 KPX Oacute Abreve -20 KPX Oacute Acircumflex -20 KPX Oacute Adieresis -20 KPX Oacute Agrave -20 KPX Oacute Amacron -20 KPX Oacute Aogonek -20 KPX Oacute Aring -20 KPX Oacute Atilde -20 KPX Oacute T -40 KPX Oacute Tcaron -40 KPX Oacute Tcommaaccent -40 KPX Oacute V -50 KPX Oacute W -30 KPX Oacute X -60 KPX Oacute Y -70 KPX Oacute Yacute -70 KPX Oacute Ydieresis -70 KPX Oacute comma -40 KPX Oacute period -40 KPX Ocircumflex A -20 KPX Ocircumflex Aacute -20 KPX Ocircumflex Abreve -20 KPX Ocircumflex Acircumflex -20 KPX Ocircumflex Adieresis -20 KPX Ocircumflex Agrave -20 KPX Ocircumflex Amacron -20 KPX Ocircumflex Aogonek -20 KPX Ocircumflex Aring -20 KPX Ocircumflex Atilde -20 KPX Ocircumflex T -40 KPX Ocircumflex Tcaron -40 KPX Ocircumflex Tcommaaccent -40 KPX Ocircumflex V -50 KPX Ocircumflex W -30 KPX Ocircumflex X -60 KPX Ocircumflex Y -70 KPX Ocircumflex Yacute -70 KPX Ocircumflex Ydieresis -70 KPX Ocircumflex comma -40 KPX Ocircumflex period -40 KPX Odieresis A -20 KPX Odieresis Aacute -20 KPX Odieresis Abreve -20 KPX Odieresis Acircumflex -20 KPX Odieresis Adieresis -20 KPX Odieresis Agrave -20 KPX Odieresis Amacron -20 KPX Odieresis Aogonek -20 KPX Odieresis Aring -20 KPX Odieresis Atilde -20 KPX Odieresis T -40 KPX Odieresis Tcaron -40 KPX Odieresis Tcommaaccent -40 KPX Odieresis V -50 KPX Odieresis W -30 KPX Odieresis X -60 KPX Odieresis Y -70 KPX Odieresis Yacute -70 KPX Odieresis Ydieresis -70 KPX Odieresis comma -40 KPX Odieresis period -40 KPX Ograve A -20 KPX Ograve Aacute -20 KPX Ograve Abreve -20 KPX Ograve Acircumflex -20 KPX Ograve Adieresis -20 KPX Ograve Agrave -20 KPX Ograve Amacron -20 KPX Ograve Aogonek -20 KPX Ograve Aring -20 KPX Ograve Atilde -20 KPX Ograve T -40 KPX Ograve Tcaron -40 KPX Ograve Tcommaaccent -40 KPX Ograve V -50 KPX Ograve W -30 KPX Ograve X -60 KPX Ograve Y -70 KPX Ograve Yacute -70 KPX Ograve Ydieresis -70 KPX Ograve comma -40 KPX Ograve period -40 KPX Ohungarumlaut A -20 KPX Ohungarumlaut Aacute -20 KPX Ohungarumlaut Abreve -20 KPX Ohungarumlaut Acircumflex -20 KPX Ohungarumlaut Adieresis -20 KPX Ohungarumlaut Agrave -20 KPX Ohungarumlaut Amacron -20 KPX Ohungarumlaut Aogonek -20 KPX Ohungarumlaut Aring -20 KPX Ohungarumlaut Atilde -20 KPX Ohungarumlaut T -40 KPX Ohungarumlaut Tcaron -40 KPX Ohungarumlaut Tcommaaccent -40 KPX Ohungarumlaut V -50 KPX Ohungarumlaut W -30 KPX Ohungarumlaut X -60 KPX Ohungarumlaut Y -70 KPX Ohungarumlaut Yacute -70 KPX Ohungarumlaut Ydieresis -70 KPX Ohungarumlaut comma -40 KPX Ohungarumlaut period -40 KPX Omacron A -20 KPX Omacron Aacute -20 KPX Omacron Abreve -20 KPX Omacron Acircumflex -20 KPX Omacron Adieresis -20 KPX Omacron Agrave -20 KPX Omacron Amacron -20 KPX Omacron Aogonek -20 KPX Omacron Aring -20 KPX Omacron Atilde -20 KPX Omacron T -40 KPX Omacron Tcaron -40 KPX Omacron Tcommaaccent -40 KPX Omacron V -50 KPX Omacron W -30 KPX Omacron X -60 KPX Omacron Y -70 KPX Omacron Yacute -70 KPX Omacron Ydieresis -70 KPX Omacron comma -40 KPX Omacron period -40 KPX Oslash A -20 KPX Oslash Aacute -20 KPX Oslash Abreve -20 KPX Oslash Acircumflex -20 KPX Oslash Adieresis -20 KPX Oslash Agrave -20 KPX Oslash Amacron -20 KPX Oslash Aogonek -20 KPX Oslash Aring -20 KPX Oslash Atilde -20 KPX Oslash T -40 KPX Oslash Tcaron -40 KPX Oslash Tcommaaccent -40 KPX Oslash V -50 KPX Oslash W -30 KPX Oslash X -60 KPX Oslash Y -70 KPX Oslash Yacute -70 KPX Oslash Ydieresis -70 KPX Oslash comma -40 KPX Oslash period -40 KPX Otilde A -20 KPX Otilde Aacute -20 KPX Otilde Abreve -20 KPX Otilde Acircumflex -20 KPX Otilde Adieresis -20 KPX Otilde Agrave -20 KPX Otilde Amacron -20 KPX Otilde Aogonek -20 KPX Otilde Aring -20 KPX Otilde Atilde -20 KPX Otilde T -40 KPX Otilde Tcaron -40 KPX Otilde Tcommaaccent -40 KPX Otilde V -50 KPX Otilde W -30 KPX Otilde X -60 KPX Otilde Y -70 KPX Otilde Yacute -70 KPX Otilde Ydieresis -70 KPX Otilde comma -40 KPX Otilde period -40 KPX P A -120 KPX P Aacute -120 KPX P Abreve -120 KPX P Acircumflex -120 KPX P Adieresis -120 KPX P Agrave -120 KPX P Amacron -120 KPX P Aogonek -120 KPX P Aring -120 KPX P Atilde -120 KPX P a -40 KPX P aacute -40 KPX P abreve -40 KPX P acircumflex -40 KPX P adieresis -40 KPX P agrave -40 KPX P amacron -40 KPX P aogonek -40 KPX P aring -40 KPX P atilde -40 KPX P comma -180 KPX P e -50 KPX P eacute -50 KPX P ecaron -50 KPX P ecircumflex -50 KPX P edieresis -50 KPX P edotaccent -50 KPX P egrave -50 KPX P emacron -50 KPX P eogonek -50 KPX P o -50 KPX P oacute -50 KPX P ocircumflex -50 KPX P odieresis -50 KPX P ograve -50 KPX P ohungarumlaut -50 KPX P omacron -50 KPX P oslash -50 KPX P otilde -50 KPX P period -180 KPX Q U -10 KPX Q Uacute -10 KPX Q Ucircumflex -10 KPX Q Udieresis -10 KPX Q Ugrave -10 KPX Q Uhungarumlaut -10 KPX Q Umacron -10 KPX Q Uogonek -10 KPX Q Uring -10 KPX R O -20 KPX R Oacute -20 KPX R Ocircumflex -20 KPX R Odieresis -20 KPX R Ograve -20 KPX R Ohungarumlaut -20 KPX R Omacron -20 KPX R Oslash -20 KPX R Otilde -20 KPX R T -30 KPX R Tcaron -30 KPX R Tcommaaccent -30 KPX R U -40 KPX R Uacute -40 KPX R Ucircumflex -40 KPX R Udieresis -40 KPX R Ugrave -40 KPX R Uhungarumlaut -40 KPX R Umacron -40 KPX R Uogonek -40 KPX R Uring -40 KPX R V -50 KPX R W -30 KPX R Y -50 KPX R Yacute -50 KPX R Ydieresis -50 KPX Racute O -20 KPX Racute Oacute -20 KPX Racute Ocircumflex -20 KPX Racute Odieresis -20 KPX Racute Ograve -20 KPX Racute Ohungarumlaut -20 KPX Racute Omacron -20 KPX Racute Oslash -20 KPX Racute Otilde -20 KPX Racute T -30 KPX Racute Tcaron -30 KPX Racute Tcommaaccent -30 KPX Racute U -40 KPX Racute Uacute -40 KPX Racute Ucircumflex -40 KPX Racute Udieresis -40 KPX Racute Ugrave -40 KPX Racute Uhungarumlaut -40 KPX Racute Umacron -40 KPX Racute Uogonek -40 KPX Racute Uring -40 KPX Racute V -50 KPX Racute W -30 KPX Racute Y -50 KPX Racute Yacute -50 KPX Racute Ydieresis -50 KPX Rcaron O -20 KPX Rcaron Oacute -20 KPX Rcaron Ocircumflex -20 KPX Rcaron Odieresis -20 KPX Rcaron Ograve -20 KPX Rcaron Ohungarumlaut -20 KPX Rcaron Omacron -20 KPX Rcaron Oslash -20 KPX Rcaron Otilde -20 KPX Rcaron T -30 KPX Rcaron Tcaron -30 KPX Rcaron Tcommaaccent -30 KPX Rcaron U -40 KPX Rcaron Uacute -40 KPX Rcaron Ucircumflex -40 KPX Rcaron Udieresis -40 KPX Rcaron Ugrave -40 KPX Rcaron Uhungarumlaut -40 KPX Rcaron Umacron -40 KPX Rcaron Uogonek -40 KPX Rcaron Uring -40 KPX Rcaron V -50 KPX Rcaron W -30 KPX Rcaron Y -50 KPX Rcaron Yacute -50 KPX Rcaron Ydieresis -50 KPX Rcommaaccent O -20 KPX Rcommaaccent Oacute -20 KPX Rcommaaccent Ocircumflex -20 KPX Rcommaaccent Odieresis -20 KPX Rcommaaccent Ograve -20 KPX Rcommaaccent Ohungarumlaut -20 KPX Rcommaaccent Omacron -20 KPX Rcommaaccent Oslash -20 KPX Rcommaaccent Otilde -20 KPX Rcommaaccent T -30 KPX Rcommaaccent Tcaron -30 KPX Rcommaaccent Tcommaaccent -30 KPX Rcommaaccent U -40 KPX Rcommaaccent Uacute -40 KPX Rcommaaccent Ucircumflex -40 KPX Rcommaaccent Udieresis -40 KPX Rcommaaccent Ugrave -40 KPX Rcommaaccent Uhungarumlaut -40 KPX Rcommaaccent Umacron -40 KPX Rcommaaccent Uogonek -40 KPX Rcommaaccent Uring -40 KPX Rcommaaccent V -50 KPX Rcommaaccent W -30 KPX Rcommaaccent Y -50 KPX Rcommaaccent Yacute -50 KPX Rcommaaccent Ydieresis -50 KPX S comma -20 KPX S period -20 KPX Sacute comma -20 KPX Sacute period -20 KPX Scaron comma -20 KPX Scaron period -20 KPX Scedilla comma -20 KPX Scedilla period -20 KPX Scommaaccent comma -20 KPX Scommaaccent period -20 KPX T A -120 KPX T Aacute -120 KPX T Abreve -120 KPX T Acircumflex -120 KPX T Adieresis -120 KPX T Agrave -120 KPX T Amacron -120 KPX T Aogonek -120 KPX T Aring -120 KPX T Atilde -120 KPX T O -40 KPX T Oacute -40 KPX T Ocircumflex -40 KPX T Odieresis -40 KPX T Ograve -40 KPX T Ohungarumlaut -40 KPX T Omacron -40 KPX T Oslash -40 KPX T Otilde -40 KPX T a -120 KPX T aacute -120 KPX T abreve -60 KPX T acircumflex -120 KPX T adieresis -120 KPX T agrave -120 KPX T amacron -60 KPX T aogonek -120 KPX T aring -120 KPX T atilde -60 KPX T colon -20 KPX T comma -120 KPX T e -120 KPX T eacute -120 KPX T ecaron -120 KPX T ecircumflex -120 KPX T edieresis -120 KPX T edotaccent -120 KPX T egrave -60 KPX T emacron -60 KPX T eogonek -120 KPX T hyphen -140 KPX T o -120 KPX T oacute -120 KPX T ocircumflex -120 KPX T odieresis -120 KPX T ograve -120 KPX T ohungarumlaut -120 KPX T omacron -60 KPX T oslash -120 KPX T otilde -60 KPX T period -120 KPX T r -120 KPX T racute -120 KPX T rcaron -120 KPX T rcommaaccent -120 KPX T semicolon -20 KPX T u -120 KPX T uacute -120 KPX T ucircumflex -120 KPX T udieresis -120 KPX T ugrave -120 KPX T uhungarumlaut -120 KPX T umacron -60 KPX T uogonek -120 KPX T uring -120 KPX T w -120 KPX T y -120 KPX T yacute -120 KPX T ydieresis -60 KPX Tcaron A -120 KPX Tcaron Aacute -120 KPX Tcaron Abreve -120 KPX Tcaron Acircumflex -120 KPX Tcaron Adieresis -120 KPX Tcaron Agrave -120 KPX Tcaron Amacron -120 KPX Tcaron Aogonek -120 KPX Tcaron Aring -120 KPX Tcaron Atilde -120 KPX Tcaron O -40 KPX Tcaron Oacute -40 KPX Tcaron Ocircumflex -40 KPX Tcaron Odieresis -40 KPX Tcaron Ograve -40 KPX Tcaron Ohungarumlaut -40 KPX Tcaron Omacron -40 KPX Tcaron Oslash -40 KPX Tcaron Otilde -40 KPX Tcaron a -120 KPX Tcaron aacute -120 KPX Tcaron abreve -60 KPX Tcaron acircumflex -120 KPX Tcaron adieresis -120 KPX Tcaron agrave -120 KPX Tcaron amacron -60 KPX Tcaron aogonek -120 KPX Tcaron aring -120 KPX Tcaron atilde -60 KPX Tcaron colon -20 KPX Tcaron comma -120 KPX Tcaron e -120 KPX Tcaron eacute -120 KPX Tcaron ecaron -120 KPX Tcaron ecircumflex -120 KPX Tcaron edieresis -120 KPX Tcaron edotaccent -120 KPX Tcaron egrave -60 KPX Tcaron emacron -60 KPX Tcaron eogonek -120 KPX Tcaron hyphen -140 KPX Tcaron o -120 KPX Tcaron oacute -120 KPX Tcaron ocircumflex -120 KPX Tcaron odieresis -120 KPX Tcaron ograve -120 KPX Tcaron ohungarumlaut -120 KPX Tcaron omacron -60 KPX Tcaron oslash -120 KPX Tcaron otilde -60 KPX Tcaron period -120 KPX Tcaron r -120 KPX Tcaron racute -120 KPX Tcaron rcaron -120 KPX Tcaron rcommaaccent -120 KPX Tcaron semicolon -20 KPX Tcaron u -120 KPX Tcaron uacute -120 KPX Tcaron ucircumflex -120 KPX Tcaron udieresis -120 KPX Tcaron ugrave -120 KPX Tcaron uhungarumlaut -120 KPX Tcaron umacron -60 KPX Tcaron uogonek -120 KPX Tcaron uring -120 KPX Tcaron w -120 KPX Tcaron y -120 KPX Tcaron yacute -120 KPX Tcaron ydieresis -60 KPX Tcommaaccent A -120 KPX Tcommaaccent Aacute -120 KPX Tcommaaccent Abreve -120 KPX Tcommaaccent Acircumflex -120 KPX Tcommaaccent Adieresis -120 KPX Tcommaaccent Agrave -120 KPX Tcommaaccent Amacron -120 KPX Tcommaaccent Aogonek -120 KPX Tcommaaccent Aring -120 KPX Tcommaaccent Atilde -120 KPX Tcommaaccent O -40 KPX Tcommaaccent Oacute -40 KPX Tcommaaccent Ocircumflex -40 KPX Tcommaaccent Odieresis -40 KPX Tcommaaccent Ograve -40 KPX Tcommaaccent Ohungarumlaut -40 KPX Tcommaaccent Omacron -40 KPX Tcommaaccent Oslash -40 KPX Tcommaaccent Otilde -40 KPX Tcommaaccent a -120 KPX Tcommaaccent aacute -120 KPX Tcommaaccent abreve -60 KPX Tcommaaccent acircumflex -120 KPX Tcommaaccent adieresis -120 KPX Tcommaaccent agrave -120 KPX Tcommaaccent amacron -60 KPX Tcommaaccent aogonek -120 KPX Tcommaaccent aring -120 KPX Tcommaaccent atilde -60 KPX Tcommaaccent colon -20 KPX Tcommaaccent comma -120 KPX Tcommaaccent e -120 KPX Tcommaaccent eacute -120 KPX Tcommaaccent ecaron -120 KPX Tcommaaccent ecircumflex -120 KPX Tcommaaccent edieresis -120 KPX Tcommaaccent edotaccent -120 KPX Tcommaaccent egrave -60 KPX Tcommaaccent emacron -60 KPX Tcommaaccent eogonek -120 KPX Tcommaaccent hyphen -140 KPX Tcommaaccent o -120 KPX Tcommaaccent oacute -120 KPX Tcommaaccent ocircumflex -120 KPX Tcommaaccent odieresis -120 KPX Tcommaaccent ograve -120 KPX Tcommaaccent ohungarumlaut -120 KPX Tcommaaccent omacron -60 KPX Tcommaaccent oslash -120 KPX Tcommaaccent otilde -60 KPX Tcommaaccent period -120 KPX Tcommaaccent r -120 KPX Tcommaaccent racute -120 KPX Tcommaaccent rcaron -120 KPX Tcommaaccent rcommaaccent -120 KPX Tcommaaccent semicolon -20 KPX Tcommaaccent u -120 KPX Tcommaaccent uacute -120 KPX Tcommaaccent ucircumflex -120 KPX Tcommaaccent udieresis -120 KPX Tcommaaccent ugrave -120 KPX Tcommaaccent uhungarumlaut -120 KPX Tcommaaccent umacron -60 KPX Tcommaaccent uogonek -120 KPX Tcommaaccent uring -120 KPX Tcommaaccent w -120 KPX Tcommaaccent y -120 KPX Tcommaaccent yacute -120 KPX Tcommaaccent ydieresis -60 KPX U A -40 KPX U Aacute -40 KPX U Abreve -40 KPX U Acircumflex -40 KPX U Adieresis -40 KPX U Agrave -40 KPX U Amacron -40 KPX U Aogonek -40 KPX U Aring -40 KPX U Atilde -40 KPX U comma -40 KPX U period -40 KPX Uacute A -40 KPX Uacute Aacute -40 KPX Uacute Abreve -40 KPX Uacute Acircumflex -40 KPX Uacute Adieresis -40 KPX Uacute Agrave -40 KPX Uacute Amacron -40 KPX Uacute Aogonek -40 KPX Uacute Aring -40 KPX Uacute Atilde -40 KPX Uacute comma -40 KPX Uacute period -40 KPX Ucircumflex A -40 KPX Ucircumflex Aacute -40 KPX Ucircumflex Abreve -40 KPX Ucircumflex Acircumflex -40 KPX Ucircumflex Adieresis -40 KPX Ucircumflex Agrave -40 KPX Ucircumflex Amacron -40 KPX Ucircumflex Aogonek -40 KPX Ucircumflex Aring -40 KPX Ucircumflex Atilde -40 KPX Ucircumflex comma -40 KPX Ucircumflex period -40 KPX Udieresis A -40 KPX Udieresis Aacute -40 KPX Udieresis Abreve -40 KPX Udieresis Acircumflex -40 KPX Udieresis Adieresis -40 KPX Udieresis Agrave -40 KPX Udieresis Amacron -40 KPX Udieresis Aogonek -40 KPX Udieresis Aring -40 KPX Udieresis Atilde -40 KPX Udieresis comma -40 KPX Udieresis period -40 KPX Ugrave A -40 KPX Ugrave Aacute -40 KPX Ugrave Abreve -40 KPX Ugrave Acircumflex -40 KPX Ugrave Adieresis -40 KPX Ugrave Agrave -40 KPX Ugrave Amacron -40 KPX Ugrave Aogonek -40 KPX Ugrave Aring -40 KPX Ugrave Atilde -40 KPX Ugrave comma -40 KPX Ugrave period -40 KPX Uhungarumlaut A -40 KPX Uhungarumlaut Aacute -40 KPX Uhungarumlaut Abreve -40 KPX Uhungarumlaut Acircumflex -40 KPX Uhungarumlaut Adieresis -40 KPX Uhungarumlaut Agrave -40 KPX Uhungarumlaut Amacron -40 KPX Uhungarumlaut Aogonek -40 KPX Uhungarumlaut Aring -40 KPX Uhungarumlaut Atilde -40 KPX Uhungarumlaut comma -40 KPX Uhungarumlaut period -40 KPX Umacron A -40 KPX Umacron Aacute -40 KPX Umacron Abreve -40 KPX Umacron Acircumflex -40 KPX Umacron Adieresis -40 KPX Umacron Agrave -40 KPX Umacron Amacron -40 KPX Umacron Aogonek -40 KPX Umacron Aring -40 KPX Umacron Atilde -40 KPX Umacron comma -40 KPX Umacron period -40 KPX Uogonek A -40 KPX Uogonek Aacute -40 KPX Uogonek Abreve -40 KPX Uogonek Acircumflex -40 KPX Uogonek Adieresis -40 KPX Uogonek Agrave -40 KPX Uogonek Amacron -40 KPX Uogonek Aogonek -40 KPX Uogonek Aring -40 KPX Uogonek Atilde -40 KPX Uogonek comma -40 KPX Uogonek period -40 KPX Uring A -40 KPX Uring Aacute -40 KPX Uring Abreve -40 KPX Uring Acircumflex -40 KPX Uring Adieresis -40 KPX Uring Agrave -40 KPX Uring Amacron -40 KPX Uring Aogonek -40 KPX Uring Aring -40 KPX Uring Atilde -40 KPX Uring comma -40 KPX Uring period -40 KPX V A -80 KPX V Aacute -80 KPX V Abreve -80 KPX V Acircumflex -80 KPX V Adieresis -80 KPX V Agrave -80 KPX V Amacron -80 KPX V Aogonek -80 KPX V Aring -80 KPX V Atilde -80 KPX V G -40 KPX V Gbreve -40 KPX V Gcommaaccent -40 KPX V O -40 KPX V Oacute -40 KPX V Ocircumflex -40 KPX V Odieresis -40 KPX V Ograve -40 KPX V Ohungarumlaut -40 KPX V Omacron -40 KPX V Oslash -40 KPX V Otilde -40 KPX V a -70 KPX V aacute -70 KPX V abreve -70 KPX V acircumflex -70 KPX V adieresis -70 KPX V agrave -70 KPX V amacron -70 KPX V aogonek -70 KPX V aring -70 KPX V atilde -70 KPX V colon -40 KPX V comma -125 KPX V e -80 KPX V eacute -80 KPX V ecaron -80 KPX V ecircumflex -80 KPX V edieresis -80 KPX V edotaccent -80 KPX V egrave -80 KPX V emacron -80 KPX V eogonek -80 KPX V hyphen -80 KPX V o -80 KPX V oacute -80 KPX V ocircumflex -80 KPX V odieresis -80 KPX V ograve -80 KPX V ohungarumlaut -80 KPX V omacron -80 KPX V oslash -80 KPX V otilde -80 KPX V period -125 KPX V semicolon -40 KPX V u -70 KPX V uacute -70 KPX V ucircumflex -70 KPX V udieresis -70 KPX V ugrave -70 KPX V uhungarumlaut -70 KPX V umacron -70 KPX V uogonek -70 KPX V uring -70 KPX W A -50 KPX W Aacute -50 KPX W Abreve -50 KPX W Acircumflex -50 KPX W Adieresis -50 KPX W Agrave -50 KPX W Amacron -50 KPX W Aogonek -50 KPX W Aring -50 KPX W Atilde -50 KPX W O -20 KPX W Oacute -20 KPX W Ocircumflex -20 KPX W Odieresis -20 KPX W Ograve -20 KPX W Ohungarumlaut -20 KPX W Omacron -20 KPX W Oslash -20 KPX W Otilde -20 KPX W a -40 KPX W aacute -40 KPX W abreve -40 KPX W acircumflex -40 KPX W adieresis -40 KPX W agrave -40 KPX W amacron -40 KPX W aogonek -40 KPX W aring -40 KPX W atilde -40 KPX W comma -80 KPX W e -30 KPX W eacute -30 KPX W ecaron -30 KPX W ecircumflex -30 KPX W edieresis -30 KPX W edotaccent -30 KPX W egrave -30 KPX W emacron -30 KPX W eogonek -30 KPX W hyphen -40 KPX W o -30 KPX W oacute -30 KPX W ocircumflex -30 KPX W odieresis -30 KPX W ograve -30 KPX W ohungarumlaut -30 KPX W omacron -30 KPX W oslash -30 KPX W otilde -30 KPX W period -80 KPX W u -30 KPX W uacute -30 KPX W ucircumflex -30 KPX W udieresis -30 KPX W ugrave -30 KPX W uhungarumlaut -30 KPX W umacron -30 KPX W uogonek -30 KPX W uring -30 KPX W y -20 KPX W yacute -20 KPX W ydieresis -20 KPX Y A -110 KPX Y Aacute -110 KPX Y Abreve -110 KPX Y Acircumflex -110 KPX Y Adieresis -110 KPX Y Agrave -110 KPX Y Amacron -110 KPX Y Aogonek -110 KPX Y Aring -110 KPX Y Atilde -110 KPX Y O -85 KPX Y Oacute -85 KPX Y Ocircumflex -85 KPX Y Odieresis -85 KPX Y Ograve -85 KPX Y Ohungarumlaut -85 KPX Y Omacron -85 KPX Y Oslash -85 KPX Y Otilde -85 KPX Y a -140 KPX Y aacute -140 KPX Y abreve -70 KPX Y acircumflex -140 KPX Y adieresis -140 KPX Y agrave -140 KPX Y amacron -70 KPX Y aogonek -140 KPX Y aring -140 KPX Y atilde -140 KPX Y colon -60 KPX Y comma -140 KPX Y e -140 KPX Y eacute -140 KPX Y ecaron -140 KPX Y ecircumflex -140 KPX Y edieresis -140 KPX Y edotaccent -140 KPX Y egrave -140 KPX Y emacron -70 KPX Y eogonek -140 KPX Y hyphen -140 KPX Y i -20 KPX Y iacute -20 KPX Y iogonek -20 KPX Y o -140 KPX Y oacute -140 KPX Y ocircumflex -140 KPX Y odieresis -140 KPX Y ograve -140 KPX Y ohungarumlaut -140 KPX Y omacron -140 KPX Y oslash -140 KPX Y otilde -140 KPX Y period -140 KPX Y semicolon -60 KPX Y u -110 KPX Y uacute -110 KPX Y ucircumflex -110 KPX Y udieresis -110 KPX Y ugrave -110 KPX Y uhungarumlaut -110 KPX Y umacron -110 KPX Y uogonek -110 KPX Y uring -110 KPX Yacute A -110 KPX Yacute Aacute -110 KPX Yacute Abreve -110 KPX Yacute Acircumflex -110 KPX Yacute Adieresis -110 KPX Yacute Agrave -110 KPX Yacute Amacron -110 KPX Yacute Aogonek -110 KPX Yacute Aring -110 KPX Yacute Atilde -110 KPX Yacute O -85 KPX Yacute Oacute -85 KPX Yacute Ocircumflex -85 KPX Yacute Odieresis -85 KPX Yacute Ograve -85 KPX Yacute Ohungarumlaut -85 KPX Yacute Omacron -85 KPX Yacute Oslash -85 KPX Yacute Otilde -85 KPX Yacute a -140 KPX Yacute aacute -140 KPX Yacute abreve -70 KPX Yacute acircumflex -140 KPX Yacute adieresis -140 KPX Yacute agrave -140 KPX Yacute amacron -70 KPX Yacute aogonek -140 KPX Yacute aring -140 KPX Yacute atilde -70 KPX Yacute colon -60 KPX Yacute comma -140 KPX Yacute e -140 KPX Yacute eacute -140 KPX Yacute ecaron -140 KPX Yacute ecircumflex -140 KPX Yacute edieresis -140 KPX Yacute edotaccent -140 KPX Yacute egrave -140 KPX Yacute emacron -70 KPX Yacute eogonek -140 KPX Yacute hyphen -140 KPX Yacute i -20 KPX Yacute iacute -20 KPX Yacute iogonek -20 KPX Yacute o -140 KPX Yacute oacute -140 KPX Yacute ocircumflex -140 KPX Yacute odieresis -140 KPX Yacute ograve -140 KPX Yacute ohungarumlaut -140 KPX Yacute omacron -70 KPX Yacute oslash -140 KPX Yacute otilde -140 KPX Yacute period -140 KPX Yacute semicolon -60 KPX Yacute u -110 KPX Yacute uacute -110 KPX Yacute ucircumflex -110 KPX Yacute udieresis -110 KPX Yacute ugrave -110 KPX Yacute uhungarumlaut -110 KPX Yacute umacron -110 KPX Yacute uogonek -110 KPX Yacute uring -110 KPX Ydieresis A -110 KPX Ydieresis Aacute -110 KPX Ydieresis Abreve -110 KPX Ydieresis Acircumflex -110 KPX Ydieresis Adieresis -110 KPX Ydieresis Agrave -110 KPX Ydieresis Amacron -110 KPX Ydieresis Aogonek -110 KPX Ydieresis Aring -110 KPX Ydieresis Atilde -110 KPX Ydieresis O -85 KPX Ydieresis Oacute -85 KPX Ydieresis Ocircumflex -85 KPX Ydieresis Odieresis -85 KPX Ydieresis Ograve -85 KPX Ydieresis Ohungarumlaut -85 KPX Ydieresis Omacron -85 KPX Ydieresis Oslash -85 KPX Ydieresis Otilde -85 KPX Ydieresis a -140 KPX Ydieresis aacute -140 KPX Ydieresis abreve -70 KPX Ydieresis acircumflex -140 KPX Ydieresis adieresis -140 KPX Ydieresis agrave -140 KPX Ydieresis amacron -70 KPX Ydieresis aogonek -140 KPX Ydieresis aring -140 KPX Ydieresis atilde -70 KPX Ydieresis colon -60 KPX Ydieresis comma -140 KPX Ydieresis e -140 KPX Ydieresis eacute -140 KPX Ydieresis ecaron -140 KPX Ydieresis ecircumflex -140 KPX Ydieresis edieresis -140 KPX Ydieresis edotaccent -140 KPX Ydieresis egrave -140 KPX Ydieresis emacron -70 KPX Ydieresis eogonek -140 KPX Ydieresis hyphen -140 KPX Ydieresis i -20 KPX Ydieresis iacute -20 KPX Ydieresis iogonek -20 KPX Ydieresis o -140 KPX Ydieresis oacute -140 KPX Ydieresis ocircumflex -140 KPX Ydieresis odieresis -140 KPX Ydieresis ograve -140 KPX Ydieresis ohungarumlaut -140 KPX Ydieresis omacron -140 KPX Ydieresis oslash -140 KPX Ydieresis otilde -140 KPX Ydieresis period -140 KPX Ydieresis semicolon -60 KPX Ydieresis u -110 KPX Ydieresis uacute -110 KPX Ydieresis ucircumflex -110 KPX Ydieresis udieresis -110 KPX Ydieresis ugrave -110 KPX Ydieresis uhungarumlaut -110 KPX Ydieresis umacron -110 KPX Ydieresis uogonek -110 KPX Ydieresis uring -110 KPX a v -20 KPX a w -20 KPX a y -30 KPX a yacute -30 KPX a ydieresis -30 KPX aacute v -20 KPX aacute w -20 KPX aacute y -30 KPX aacute yacute -30 KPX aacute ydieresis -30 KPX abreve v -20 KPX abreve w -20 KPX abreve y -30 KPX abreve yacute -30 KPX abreve ydieresis -30 KPX acircumflex v -20 KPX acircumflex w -20 KPX acircumflex y -30 KPX acircumflex yacute -30 KPX acircumflex ydieresis -30 KPX adieresis v -20 KPX adieresis w -20 KPX adieresis y -30 KPX adieresis yacute -30 KPX adieresis ydieresis -30 KPX agrave v -20 KPX agrave w -20 KPX agrave y -30 KPX agrave yacute -30 KPX agrave ydieresis -30 KPX amacron v -20 KPX amacron w -20 KPX amacron y -30 KPX amacron yacute -30 KPX amacron ydieresis -30 KPX aogonek v -20 KPX aogonek w -20 KPX aogonek y -30 KPX aogonek yacute -30 KPX aogonek ydieresis -30 KPX aring v -20 KPX aring w -20 KPX aring y -30 KPX aring yacute -30 KPX aring ydieresis -30 KPX atilde v -20 KPX atilde w -20 KPX atilde y -30 KPX atilde yacute -30 KPX atilde ydieresis -30 KPX b b -10 KPX b comma -40 KPX b l -20 KPX b lacute -20 KPX b lcommaaccent -20 KPX b lslash -20 KPX b period -40 KPX b u -20 KPX b uacute -20 KPX b ucircumflex -20 KPX b udieresis -20 KPX b ugrave -20 KPX b uhungarumlaut -20 KPX b umacron -20 KPX b uogonek -20 KPX b uring -20 KPX b v -20 KPX b y -20 KPX b yacute -20 KPX b ydieresis -20 KPX c comma -15 KPX c k -20 KPX c kcommaaccent -20 KPX cacute comma -15 KPX cacute k -20 KPX cacute kcommaaccent -20 KPX ccaron comma -15 KPX ccaron k -20 KPX ccaron kcommaaccent -20 KPX ccedilla comma -15 KPX ccedilla k -20 KPX ccedilla kcommaaccent -20 KPX colon space -50 KPX comma quotedblright -100 KPX comma quoteright -100 KPX e comma -15 KPX e period -15 KPX e v -30 KPX e w -20 KPX e x -30 KPX e y -20 KPX e yacute -20 KPX e ydieresis -20 KPX eacute comma -15 KPX eacute period -15 KPX eacute v -30 KPX eacute w -20 KPX eacute x -30 KPX eacute y -20 KPX eacute yacute -20 KPX eacute ydieresis -20 KPX ecaron comma -15 KPX ecaron period -15 KPX ecaron v -30 KPX ecaron w -20 KPX ecaron x -30 KPX ecaron y -20 KPX ecaron yacute -20 KPX ecaron ydieresis -20 KPX ecircumflex comma -15 KPX ecircumflex period -15 KPX ecircumflex v -30 KPX ecircumflex w -20 KPX ecircumflex x -30 KPX ecircumflex y -20 KPX ecircumflex yacute -20 KPX ecircumflex ydieresis -20 KPX edieresis comma -15 KPX edieresis period -15 KPX edieresis v -30 KPX edieresis w -20 KPX edieresis x -30 KPX edieresis y -20 KPX edieresis yacute -20 KPX edieresis ydieresis -20 KPX edotaccent comma -15 KPX edotaccent period -15 KPX edotaccent v -30 KPX edotaccent w -20 KPX edotaccent x -30 KPX edotaccent y -20 KPX edotaccent yacute -20 KPX edotaccent ydieresis -20 KPX egrave comma -15 KPX egrave period -15 KPX egrave v -30 KPX egrave w -20 KPX egrave x -30 KPX egrave y -20 KPX egrave yacute -20 KPX egrave ydieresis -20 KPX emacron comma -15 KPX emacron period -15 KPX emacron v -30 KPX emacron w -20 KPX emacron x -30 KPX emacron y -20 KPX emacron yacute -20 KPX emacron ydieresis -20 KPX eogonek comma -15 KPX eogonek period -15 KPX eogonek v -30 KPX eogonek w -20 KPX eogonek x -30 KPX eogonek y -20 KPX eogonek yacute -20 KPX eogonek ydieresis -20 KPX f a -30 KPX f aacute -30 KPX f abreve -30 KPX f acircumflex -30 KPX f adieresis -30 KPX f agrave -30 KPX f amacron -30 KPX f aogonek -30 KPX f aring -30 KPX f atilde -30 KPX f comma -30 KPX f dotlessi -28 KPX f e -30 KPX f eacute -30 KPX f ecaron -30 KPX f ecircumflex -30 KPX f edieresis -30 KPX f edotaccent -30 KPX f egrave -30 KPX f emacron -30 KPX f eogonek -30 KPX f o -30 KPX f oacute -30 KPX f ocircumflex -30 KPX f odieresis -30 KPX f ograve -30 KPX f ohungarumlaut -30 KPX f omacron -30 KPX f oslash -30 KPX f otilde -30 KPX f period -30 KPX f quotedblright 60 KPX f quoteright 50 KPX g r -10 KPX g racute -10 KPX g rcaron -10 KPX g rcommaaccent -10 KPX gbreve r -10 KPX gbreve racute -10 KPX gbreve rcaron -10 KPX gbreve rcommaaccent -10 KPX gcommaaccent r -10 KPX gcommaaccent racute -10 KPX gcommaaccent rcaron -10 KPX gcommaaccent rcommaaccent -10 KPX h y -30 KPX h yacute -30 KPX h ydieresis -30 KPX k e -20 KPX k eacute -20 KPX k ecaron -20 KPX k ecircumflex -20 KPX k edieresis -20 KPX k edotaccent -20 KPX k egrave -20 KPX k emacron -20 KPX k eogonek -20 KPX k o -20 KPX k oacute -20 KPX k ocircumflex -20 KPX k odieresis -20 KPX k ograve -20 KPX k ohungarumlaut -20 KPX k omacron -20 KPX k oslash -20 KPX k otilde -20 KPX kcommaaccent e -20 KPX kcommaaccent eacute -20 KPX kcommaaccent ecaron -20 KPX kcommaaccent ecircumflex -20 KPX kcommaaccent edieresis -20 KPX kcommaaccent edotaccent -20 KPX kcommaaccent egrave -20 KPX kcommaaccent emacron -20 KPX kcommaaccent eogonek -20 KPX kcommaaccent o -20 KPX kcommaaccent oacute -20 KPX kcommaaccent ocircumflex -20 KPX kcommaaccent odieresis -20 KPX kcommaaccent ograve -20 KPX kcommaaccent ohungarumlaut -20 KPX kcommaaccent omacron -20 KPX kcommaaccent oslash -20 KPX kcommaaccent otilde -20 KPX m u -10 KPX m uacute -10 KPX m ucircumflex -10 KPX m udieresis -10 KPX m ugrave -10 KPX m uhungarumlaut -10 KPX m umacron -10 KPX m uogonek -10 KPX m uring -10 KPX m y -15 KPX m yacute -15 KPX m ydieresis -15 KPX n u -10 KPX n uacute -10 KPX n ucircumflex -10 KPX n udieresis -10 KPX n ugrave -10 KPX n uhungarumlaut -10 KPX n umacron -10 KPX n uogonek -10 KPX n uring -10 KPX n v -20 KPX n y -15 KPX n yacute -15 KPX n ydieresis -15 KPX nacute u -10 KPX nacute uacute -10 KPX nacute ucircumflex -10 KPX nacute udieresis -10 KPX nacute ugrave -10 KPX nacute uhungarumlaut -10 KPX nacute umacron -10 KPX nacute uogonek -10 KPX nacute uring -10 KPX nacute v -20 KPX nacute y -15 KPX nacute yacute -15 KPX nacute ydieresis -15 KPX ncaron u -10 KPX ncaron uacute -10 KPX ncaron ucircumflex -10 KPX ncaron udieresis -10 KPX ncaron ugrave -10 KPX ncaron uhungarumlaut -10 KPX ncaron umacron -10 KPX ncaron uogonek -10 KPX ncaron uring -10 KPX ncaron v -20 KPX ncaron y -15 KPX ncaron yacute -15 KPX ncaron ydieresis -15 KPX ncommaaccent u -10 KPX ncommaaccent uacute -10 KPX ncommaaccent ucircumflex -10 KPX ncommaaccent udieresis -10 KPX ncommaaccent ugrave -10 KPX ncommaaccent uhungarumlaut -10 KPX ncommaaccent umacron -10 KPX ncommaaccent uogonek -10 KPX ncommaaccent uring -10 KPX ncommaaccent v -20 KPX ncommaaccent y -15 KPX ncommaaccent yacute -15 KPX ncommaaccent ydieresis -15 KPX ntilde u -10 KPX ntilde uacute -10 KPX ntilde ucircumflex -10 KPX ntilde udieresis -10 KPX ntilde ugrave -10 KPX ntilde uhungarumlaut -10 KPX ntilde umacron -10 KPX ntilde uogonek -10 KPX ntilde uring -10 KPX ntilde v -20 KPX ntilde y -15 KPX ntilde yacute -15 KPX ntilde ydieresis -15 KPX o comma -40 KPX o period -40 KPX o v -15 KPX o w -15 KPX o x -30 KPX o y -30 KPX o yacute -30 KPX o ydieresis -30 KPX oacute comma -40 KPX oacute period -40 KPX oacute v -15 KPX oacute w -15 KPX oacute x -30 KPX oacute y -30 KPX oacute yacute -30 KPX oacute ydieresis -30 KPX ocircumflex comma -40 KPX ocircumflex period -40 KPX ocircumflex v -15 KPX ocircumflex w -15 KPX ocircumflex x -30 KPX ocircumflex y -30 KPX ocircumflex yacute -30 KPX ocircumflex ydieresis -30 KPX odieresis comma -40 KPX odieresis period -40 KPX odieresis v -15 KPX odieresis w -15 KPX odieresis x -30 KPX odieresis y -30 KPX odieresis yacute -30 KPX odieresis ydieresis -30 KPX ograve comma -40 KPX ograve period -40 KPX ograve v -15 KPX ograve w -15 KPX ograve x -30 KPX ograve y -30 KPX ograve yacute -30 KPX ograve ydieresis -30 KPX ohungarumlaut comma -40 KPX ohungarumlaut period -40 KPX ohungarumlaut v -15 KPX ohungarumlaut w -15 KPX ohungarumlaut x -30 KPX ohungarumlaut y -30 KPX ohungarumlaut yacute -30 KPX ohungarumlaut ydieresis -30 KPX omacron comma -40 KPX omacron period -40 KPX omacron v -15 KPX omacron w -15 KPX omacron x -30 KPX omacron y -30 KPX omacron yacute -30 KPX omacron ydieresis -30 KPX oslash a -55 KPX oslash aacute -55 KPX oslash abreve -55 KPX oslash acircumflex -55 KPX oslash adieresis -55 KPX oslash agrave -55 KPX oslash amacron -55 KPX oslash aogonek -55 KPX oslash aring -55 KPX oslash atilde -55 KPX oslash b -55 KPX oslash c -55 KPX oslash cacute -55 KPX oslash ccaron -55 KPX oslash ccedilla -55 KPX oslash comma -95 KPX oslash d -55 KPX oslash dcroat -55 KPX oslash e -55 KPX oslash eacute -55 KPX oslash ecaron -55 KPX oslash ecircumflex -55 KPX oslash edieresis -55 KPX oslash edotaccent -55 KPX oslash egrave -55 KPX oslash emacron -55 KPX oslash eogonek -55 KPX oslash f -55 KPX oslash g -55 KPX oslash gbreve -55 KPX oslash gcommaaccent -55 KPX oslash h -55 KPX oslash i -55 KPX oslash iacute -55 KPX oslash icircumflex -55 KPX oslash idieresis -55 KPX oslash igrave -55 KPX oslash imacron -55 KPX oslash iogonek -55 KPX oslash j -55 KPX oslash k -55 KPX oslash kcommaaccent -55 KPX oslash l -55 KPX oslash lacute -55 KPX oslash lcommaaccent -55 KPX oslash lslash -55 KPX oslash m -55 KPX oslash n -55 KPX oslash nacute -55 KPX oslash ncaron -55 KPX oslash ncommaaccent -55 KPX oslash ntilde -55 KPX oslash o -55 KPX oslash oacute -55 KPX oslash ocircumflex -55 KPX oslash odieresis -55 KPX oslash ograve -55 KPX oslash ohungarumlaut -55 KPX oslash omacron -55 KPX oslash oslash -55 KPX oslash otilde -55 KPX oslash p -55 KPX oslash period -95 KPX oslash q -55 KPX oslash r -55 KPX oslash racute -55 KPX oslash rcaron -55 KPX oslash rcommaaccent -55 KPX oslash s -55 KPX oslash sacute -55 KPX oslash scaron -55 KPX oslash scedilla -55 KPX oslash scommaaccent -55 KPX oslash t -55 KPX oslash tcommaaccent -55 KPX oslash u -55 KPX oslash uacute -55 KPX oslash ucircumflex -55 KPX oslash udieresis -55 KPX oslash ugrave -55 KPX oslash uhungarumlaut -55 KPX oslash umacron -55 KPX oslash uogonek -55 KPX oslash uring -55 KPX oslash v -70 KPX oslash w -70 KPX oslash x -85 KPX oslash y -70 KPX oslash yacute -70 KPX oslash ydieresis -70 KPX oslash z -55 KPX oslash zacute -55 KPX oslash zcaron -55 KPX oslash zdotaccent -55 KPX otilde comma -40 KPX otilde period -40 KPX otilde v -15 KPX otilde w -15 KPX otilde x -30 KPX otilde y -30 KPX otilde yacute -30 KPX otilde ydieresis -30 KPX p comma -35 KPX p period -35 KPX p y -30 KPX p yacute -30 KPX p ydieresis -30 KPX period quotedblright -100 KPX period quoteright -100 KPX period space -60 KPX quotedblright space -40 KPX quoteleft quoteleft -57 KPX quoteright d -50 KPX quoteright dcroat -50 KPX quoteright quoteright -57 KPX quoteright r -50 KPX quoteright racute -50 KPX quoteright rcaron -50 KPX quoteright rcommaaccent -50 KPX quoteright s -50 KPX quoteright sacute -50 KPX quoteright scaron -50 KPX quoteright scedilla -50 KPX quoteright scommaaccent -50 KPX quoteright space -70 KPX r a -10 KPX r aacute -10 KPX r abreve -10 KPX r acircumflex -10 KPX r adieresis -10 KPX r agrave -10 KPX r amacron -10 KPX r aogonek -10 KPX r aring -10 KPX r atilde -10 KPX r colon 30 KPX r comma -50 KPX r i 15 KPX r iacute 15 KPX r icircumflex 15 KPX r idieresis 15 KPX r igrave 15 KPX r imacron 15 KPX r iogonek 15 KPX r k 15 KPX r kcommaaccent 15 KPX r l 15 KPX r lacute 15 KPX r lcommaaccent 15 KPX r lslash 15 KPX r m 25 KPX r n 25 KPX r nacute 25 KPX r ncaron 25 KPX r ncommaaccent 25 KPX r ntilde 25 KPX r p 30 KPX r period -50 KPX r semicolon 30 KPX r t 40 KPX r tcommaaccent 40 KPX r u 15 KPX r uacute 15 KPX r ucircumflex 15 KPX r udieresis 15 KPX r ugrave 15 KPX r uhungarumlaut 15 KPX r umacron 15 KPX r uogonek 15 KPX r uring 15 KPX r v 30 KPX r y 30 KPX r yacute 30 KPX r ydieresis 30 KPX racute a -10 KPX racute aacute -10 KPX racute abreve -10 KPX racute acircumflex -10 KPX racute adieresis -10 KPX racute agrave -10 KPX racute amacron -10 KPX racute aogonek -10 KPX racute aring -10 KPX racute atilde -10 KPX racute colon 30 KPX racute comma -50 KPX racute i 15 KPX racute iacute 15 KPX racute icircumflex 15 KPX racute idieresis 15 KPX racute igrave 15 KPX racute imacron 15 KPX racute iogonek 15 KPX racute k 15 KPX racute kcommaaccent 15 KPX racute l 15 KPX racute lacute 15 KPX racute lcommaaccent 15 KPX racute lslash 15 KPX racute m 25 KPX racute n 25 KPX racute nacute 25 KPX racute ncaron 25 KPX racute ncommaaccent 25 KPX racute ntilde 25 KPX racute p 30 KPX racute period -50 KPX racute semicolon 30 KPX racute t 40 KPX racute tcommaaccent 40 KPX racute u 15 KPX racute uacute 15 KPX racute ucircumflex 15 KPX racute udieresis 15 KPX racute ugrave 15 KPX racute uhungarumlaut 15 KPX racute umacron 15 KPX racute uogonek 15 KPX racute uring 15 KPX racute v 30 KPX racute y 30 KPX racute yacute 30 KPX racute ydieresis 30 KPX rcaron a -10 KPX rcaron aacute -10 KPX rcaron abreve -10 KPX rcaron acircumflex -10 KPX rcaron adieresis -10 KPX rcaron agrave -10 KPX rcaron amacron -10 KPX rcaron aogonek -10 KPX rcaron aring -10 KPX rcaron atilde -10 KPX rcaron colon 30 KPX rcaron comma -50 KPX rcaron i 15 KPX rcaron iacute 15 KPX rcaron icircumflex 15 KPX rcaron idieresis 15 KPX rcaron igrave 15 KPX rcaron imacron 15 KPX rcaron iogonek 15 KPX rcaron k 15 KPX rcaron kcommaaccent 15 KPX rcaron l 15 KPX rcaron lacute 15 KPX rcaron lcommaaccent 15 KPX rcaron lslash 15 KPX rcaron m 25 KPX rcaron n 25 KPX rcaron nacute 25 KPX rcaron ncaron 25 KPX rcaron ncommaaccent 25 KPX rcaron ntilde 25 KPX rcaron p 30 KPX rcaron period -50 KPX rcaron semicolon 30 KPX rcaron t 40 KPX rcaron tcommaaccent 40 KPX rcaron u 15 KPX rcaron uacute 15 KPX rcaron ucircumflex 15 KPX rcaron udieresis 15 KPX rcaron ugrave 15 KPX rcaron uhungarumlaut 15 KPX rcaron umacron 15 KPX rcaron uogonek 15 KPX rcaron uring 15 KPX rcaron v 30 KPX rcaron y 30 KPX rcaron yacute 30 KPX rcaron ydieresis 30 KPX rcommaaccent a -10 KPX rcommaaccent aacute -10 KPX rcommaaccent abreve -10 KPX rcommaaccent acircumflex -10 KPX rcommaaccent adieresis -10 KPX rcommaaccent agrave -10 KPX rcommaaccent amacron -10 KPX rcommaaccent aogonek -10 KPX rcommaaccent aring -10 KPX rcommaaccent atilde -10 KPX rcommaaccent colon 30 KPX rcommaaccent comma -50 KPX rcommaaccent i 15 KPX rcommaaccent iacute 15 KPX rcommaaccent icircumflex 15 KPX rcommaaccent idieresis 15 KPX rcommaaccent igrave 15 KPX rcommaaccent imacron 15 KPX rcommaaccent iogonek 15 KPX rcommaaccent k 15 KPX rcommaaccent kcommaaccent 15 KPX rcommaaccent l 15 KPX rcommaaccent lacute 15 KPX rcommaaccent lcommaaccent 15 KPX rcommaaccent lslash 15 KPX rcommaaccent m 25 KPX rcommaaccent n 25 KPX rcommaaccent nacute 25 KPX rcommaaccent ncaron 25 KPX rcommaaccent ncommaaccent 25 KPX rcommaaccent ntilde 25 KPX rcommaaccent p 30 KPX rcommaaccent period -50 KPX rcommaaccent semicolon 30 KPX rcommaaccent t 40 KPX rcommaaccent tcommaaccent 40 KPX rcommaaccent u 15 KPX rcommaaccent uacute 15 KPX rcommaaccent ucircumflex 15 KPX rcommaaccent udieresis 15 KPX rcommaaccent ugrave 15 KPX rcommaaccent uhungarumlaut 15 KPX rcommaaccent umacron 15 KPX rcommaaccent uogonek 15 KPX rcommaaccent uring 15 KPX rcommaaccent v 30 KPX rcommaaccent y 30 KPX rcommaaccent yacute 30 KPX rcommaaccent ydieresis 30 KPX s comma -15 KPX s period -15 KPX s w -30 KPX sacute comma -15 KPX sacute period -15 KPX sacute w -30 KPX scaron comma -15 KPX scaron period -15 KPX scaron w -30 KPX scedilla comma -15 KPX scedilla period -15 KPX scedilla w -30 KPX scommaaccent comma -15 KPX scommaaccent period -15 KPX scommaaccent w -30 KPX semicolon space -50 KPX space T -50 KPX space Tcaron -50 KPX space Tcommaaccent -50 KPX space V -50 KPX space W -40 KPX space Y -90 KPX space Yacute -90 KPX space Ydieresis -90 KPX space quotedblleft -30 KPX space quoteleft -60 KPX v a -25 KPX v aacute -25 KPX v abreve -25 KPX v acircumflex -25 KPX v adieresis -25 KPX v agrave -25 KPX v amacron -25 KPX v aogonek -25 KPX v aring -25 KPX v atilde -25 KPX v comma -80 KPX v e -25 KPX v eacute -25 KPX v ecaron -25 KPX v ecircumflex -25 KPX v edieresis -25 KPX v edotaccent -25 KPX v egrave -25 KPX v emacron -25 KPX v eogonek -25 KPX v o -25 KPX v oacute -25 KPX v ocircumflex -25 KPX v odieresis -25 KPX v ograve -25 KPX v ohungarumlaut -25 KPX v omacron -25 KPX v oslash -25 KPX v otilde -25 KPX v period -80 KPX w a -15 KPX w aacute -15 KPX w abreve -15 KPX w acircumflex -15 KPX w adieresis -15 KPX w agrave -15 KPX w amacron -15 KPX w aogonek -15 KPX w aring -15 KPX w atilde -15 KPX w comma -60 KPX w e -10 KPX w eacute -10 KPX w ecaron -10 KPX w ecircumflex -10 KPX w edieresis -10 KPX w edotaccent -10 KPX w egrave -10 KPX w emacron -10 KPX w eogonek -10 KPX w o -10 KPX w oacute -10 KPX w ocircumflex -10 KPX w odieresis -10 KPX w ograve -10 KPX w ohungarumlaut -10 KPX w omacron -10 KPX w oslash -10 KPX w otilde -10 KPX w period -60 KPX x e -30 KPX x eacute -30 KPX x ecaron -30 KPX x ecircumflex -30 KPX x edieresis -30 KPX x edotaccent -30 KPX x egrave -30 KPX x emacron -30 KPX x eogonek -30 KPX y a -20 KPX y aacute -20 KPX y abreve -20 KPX y acircumflex -20 KPX y adieresis -20 KPX y agrave -20 KPX y amacron -20 KPX y aogonek -20 KPX y aring -20 KPX y atilde -20 KPX y comma -100 KPX y e -20 KPX y eacute -20 KPX y ecaron -20 KPX y ecircumflex -20 KPX y edieresis -20 KPX y edotaccent -20 KPX y egrave -20 KPX y emacron -20 KPX y eogonek -20 KPX y o -20 KPX y oacute -20 KPX y ocircumflex -20 KPX y odieresis -20 KPX y ograve -20 KPX y ohungarumlaut -20 KPX y omacron -20 KPX y oslash -20 KPX y otilde -20 KPX y period -100 KPX yacute a -20 KPX yacute aacute -20 KPX yacute abreve -20 KPX yacute acircumflex -20 KPX yacute adieresis -20 KPX yacute agrave -20 KPX yacute amacron -20 KPX yacute aogonek -20 KPX yacute aring -20 KPX yacute atilde -20 KPX yacute comma -100 KPX yacute e -20 KPX yacute eacute -20 KPX yacute ecaron -20 KPX yacute ecircumflex -20 KPX yacute edieresis -20 KPX yacute edotaccent -20 KPX yacute egrave -20 KPX yacute emacron -20 KPX yacute eogonek -20 KPX yacute o -20 KPX yacute oacute -20 KPX yacute ocircumflex -20 KPX yacute odieresis -20 KPX yacute ograve -20 KPX yacute ohungarumlaut -20 KPX yacute omacron -20 KPX yacute oslash -20 KPX yacute otilde -20 KPX yacute period -100 KPX ydieresis a -20 KPX ydieresis aacute -20 KPX ydieresis abreve -20 KPX ydieresis acircumflex -20 KPX ydieresis adieresis -20 KPX ydieresis agrave -20 KPX ydieresis amacron -20 KPX ydieresis aogonek -20 KPX ydieresis aring -20 KPX ydieresis atilde -20 KPX ydieresis comma -100 KPX ydieresis e -20 KPX ydieresis eacute -20 KPX ydieresis ecaron -20 KPX ydieresis ecircumflex -20 KPX ydieresis edieresis -20 KPX ydieresis edotaccent -20 KPX ydieresis egrave -20 KPX ydieresis emacron -20 KPX ydieresis eogonek -20 KPX ydieresis o -20 KPX ydieresis oacute -20 KPX ydieresis ocircumflex -20 KPX ydieresis odieresis -20 KPX ydieresis ograve -20 KPX ydieresis ohungarumlaut -20 KPX ydieresis omacron -20 KPX ydieresis oslash -20 KPX ydieresis otilde -20 KPX ydieresis period -100 KPX z e -15 KPX z eacute -15 KPX z ecaron -15 KPX z ecircumflex -15 KPX z edieresis -15 KPX z edotaccent -15 KPX z egrave -15 KPX z emacron -15 KPX z eogonek -15 KPX z o -15 KPX z oacute -15 KPX z ocircumflex -15 KPX z odieresis -15 KPX z ograve -15 KPX z ohungarumlaut -15 KPX z omacron -15 KPX z oslash -15 KPX z otilde -15 KPX zacute e -15 KPX zacute eacute -15 KPX zacute ecaron -15 KPX zacute ecircumflex -15 KPX zacute edieresis -15 KPX zacute edotaccent -15 KPX zacute egrave -15 KPX zacute emacron -15 KPX zacute eogonek -15 KPX zacute o -15 KPX zacute oacute -15 KPX zacute ocircumflex -15 KPX zacute odieresis -15 KPX zacute ograve -15 KPX zacute ohungarumlaut -15 KPX zacute omacron -15 KPX zacute oslash -15 KPX zacute otilde -15 KPX zcaron e -15 KPX zcaron eacute -15 KPX zcaron ecaron -15 KPX zcaron ecircumflex -15 KPX zcaron edieresis -15 KPX zcaron edotaccent -15 KPX zcaron egrave -15 KPX zcaron emacron -15 KPX zcaron eogonek -15 KPX zcaron o -15 KPX zcaron oacute -15 KPX zcaron ocircumflex -15 KPX zcaron odieresis -15 KPX zcaron ograve -15 KPX zcaron ohungarumlaut -15 KPX zcaron omacron -15 KPX zcaron oslash -15 KPX zcaron otilde -15 KPX zdotaccent e -15 KPX zdotaccent eacute -15 KPX zdotaccent ecaron -15 KPX zdotaccent ecircumflex -15 KPX zdotaccent edieresis -15 KPX zdotaccent edotaccent -15 KPX zdotaccent egrave -15 KPX zdotaccent emacron -15 KPX zdotaccent eogonek -15 KPX zdotaccent o -15 KPX zdotaccent oacute -15 KPX zdotaccent ocircumflex -15 KPX zdotaccent odieresis -15 KPX zdotaccent ograve -15 KPX zdotaccent ohungarumlaut -15 KPX zdotaccent omacron -15 KPX zdotaccent oslash -15 KPX zdotaccent otilde -15 EndKernPairs EndKernData EndFontMetrics camlpdf-2.8.1/compressor/Makefile000066400000000000000000000004711477056064700170060ustar00rootroot00000000000000SOURCES = compressor.ml RESULT = compressor PACKS = camlpdf TARGETS := native-code OCAMLFLAGS = -bin-annot OCAMLNCFLAGS = -g -safe-string -w -3 OCAMLBCFLAGS = -g -safe-string -w -3 OCAMLLDFLAGS = -g all : $(TARGETS) clean :: rm -rf doc foo foo2 out.pdf out2.pdf *.cmt *.cmti *.zlib -include OCamlMakefile camlpdf-2.8.1/compressor/OCamlMakefile000077500000000000000000001050311477056064700177230ustar00rootroot00000000000000########################################################################### # OCamlMakefile # Copyright (C) 1999- Markus Mottl # # For updates see: # http://www.ocaml.info/home/ocaml_sources.html # ########################################################################### # Modified by damien for .glade.ml compilation # Set these variables to the names of the sources to be processed and # the result variable. Order matters during linkage! ifndef SOURCES SOURCES := foo.ml endif export SOURCES ifndef RES_CLIB_SUF RES_CLIB_SUF := _stubs endif export RES_CLIB_SUF ifndef RESULT RESULT := foo endif export RESULT := $(strip $(RESULT)) export LIB_PACK_NAME ifndef DOC_FILES DOC_FILES := $(filter %.mli, $(SOURCES)) endif export DOC_FILES FIRST_DOC_FILE := $(firstword $(DOC_FILES)) export BCSUFFIX export NCSUFFIX ifndef TOPSUFFIX TOPSUFFIX := .top endif export TOPSUFFIX # Eventually set include- and library-paths, libraries to link, # additional compilation-, link- and ocamlyacc-flags # Path- and library information needs not be written with "-I" and such... # Define THREADS if you need it, otherwise leave it unset (same for # USE_CAMLP4)! export THREADS export VMTHREADS export ANNOTATE export USE_CAMLP4 export INCDIRS export LIBDIRS export EXTLIBDIRS export RESULTDEPS export OCAML_DEFAULT_DIRS export LIBS export CLIBS export CFRAMEWORKS export OCAMLFLAGS export OCAMLNCFLAGS export OCAMLBCFLAGS export OCAMLLDFLAGS export OCAMLNLDFLAGS export OCAMLBLDFLAGS export OCAMLMKLIB_FLAGS ifndef OCAMLCPFLAGS OCAMLCPFLAGS := a endif export OCAMLCPFLAGS ifndef DOC_DIR DOC_DIR := doc endif export DOC_DIR export PPFLAGS export LFLAGS export YFLAGS export IDLFLAGS export OCAMLDOCFLAGS export OCAMLFIND_INSTFLAGS export DVIPSFLAGS export STATIC # Add a list of optional trash files that should be deleted by "make clean" export TRASH ECHO := echo ifdef REALLY_QUIET export REALLY_QUIET ECHO := true LFLAGS := $(LFLAGS) -q YFLAGS := $(YFLAGS) -q endif #################### variables depending on your OCaml-installation SYSTEM := $(shell ocamlc -config 2>/dev/null | grep system | sed 's/system: //') # This may be # - mingw # - mingw64 # - win32 # - cygwin # - some other string means Unix # - empty means ocamlc does not support -config ifeq ($(SYSTEM),$(filter $(SYSTEM),mingw mingw64)) MINGW=1 endif ifeq ($(SYSTEM),win32) MSVC=1 endif ifdef MINGW export MINGW WIN32 := 1 # The default value 'cc' makes 'ocamlc -cc "cc"' raises the error 'The # NTVDM CPU has encountered an illegal instruction'. ifndef CC MNO_CYGWIN := $(shell gcc -Wextra -v --help 2>/dev/null | grep -q '\-mno-cygwin'; echo $$?) CC := gcc else MNO_CYGWIN := $(shell $$CC -Wextra -v --help 2>/dev/null | grep -q '\-mno-cygwin'; echo $$?) endif # We are compiling with cygwin tools: ifeq ($(MNO_CYGWIN),0) CFLAGS_WIN32 := -mno-cygwin endif # The OCaml C header files use this flag: CFLAGS += -D__MINGW32__ endif ifdef MSVC export MSVC WIN32 := 1 ifndef STATIC CPPFLAGS_WIN32 := -DCAML_DLL endif CFLAGS_WIN32 += -nologo EXT_OBJ := obj EXT_LIB := lib ifeq ($(CC),gcc) # work around GNU Make default value ifdef THREADS CC := cl -MT else CC := cl endif endif ifeq ($(CXX),g++) # work around GNU Make default value CXX := $(CC) endif CFLAG_O := -Fo endif ifdef WIN32 EXT_CXX := cpp EXE := .exe endif ifndef EXT_OBJ EXT_OBJ := o endif ifndef EXT_LIB EXT_LIB := a endif ifndef EXT_CXX EXT_CXX := cc endif ifndef EXE EXE := # empty endif ifndef CFLAG_O CFLAG_O := -o # do not delete this comment (preserves trailing whitespace)! endif export CC export CXX export CFLAGS export CXXFLAGS export LDFLAGS export CPPFLAGS ifndef RPATH_FLAG ifdef ELF_RPATH_FLAG RPATH_FLAG := $(ELF_RPATH_FLAG) else RPATH_FLAG := -R endif endif export RPATH_FLAG ifndef MSVC ifndef PIC_CFLAGS PIC_CFLAGS := -fPIC endif ifndef PIC_CPPFLAGS PIC_CPPFLAGS := -DPIC endif endif export PIC_CFLAGS export PIC_CPPFLAGS BCRESULT := $(addsuffix $(BCSUFFIX), $(RESULT)) NCRESULT := $(addsuffix $(NCSUFFIX), $(RESULT)) TOPRESULT := $(addsuffix $(TOPSUFFIX), $(RESULT)) ifndef OCAMLFIND OCAMLFIND := ocamlfind endif export OCAMLFIND ifndef OCAML OCAML := ocaml endif export OCAML ifndef OCAMLC OCAMLC := ocamlc endif export OCAMLC ifndef OCAMLOPT OCAMLOPT := ocamlopt endif export OCAMLOPT ifndef OCAMLMKTOP OCAMLMKTOP := ocamlmktop endif export OCAMLMKTOP ifndef OCAMLCP OCAMLCP := ocamlcp endif export OCAMLCP ifndef OCAMLDEP OCAMLDEP := ocamldep endif export OCAMLDEP ifndef OCAMLLEX OCAMLLEX := ocamllex endif export OCAMLLEX ifndef OCAMLYACC OCAMLYACC := ocamlyacc endif export OCAMLYACC ifndef OCAMLMKLIB OCAMLMKLIB := ocamlmklib endif export OCAMLMKLIB ifndef OCAML_GLADECC OCAML_GLADECC := lablgladecc2 endif export OCAML_GLADECC ifndef OCAML_GLADECC_FLAGS OCAML_GLADECC_FLAGS := endif export OCAML_GLADECC_FLAGS ifndef CAMELEON_REPORT CAMELEON_REPORT := report endif export CAMELEON_REPORT ifndef CAMELEON_REPORT_FLAGS CAMELEON_REPORT_FLAGS := endif export CAMELEON_REPORT_FLAGS ifndef CAMELEON_ZOGGY CAMELEON_ZOGGY := camlp4o pa_zog.cma pr_o.cmo endif export CAMELEON_ZOGGY ifndef CAMELEON_ZOGGY_FLAGS CAMELEON_ZOGGY_FLAGS := endif export CAMELEON_ZOGGY_FLAGS ifndef OXRIDL OXRIDL := oxridl endif export OXRIDL ifndef CAMLIDL CAMLIDL := camlidl endif export CAMLIDL ifndef CAMLIDLDLL CAMLIDLDLL := camlidldll endif export CAMLIDLDLL ifndef NOIDLHEADER MAYBE_IDL_HEADER := -header endif export NOIDLHEADER export NO_CUSTOM ifndef CAMLP4 CAMLP4 := camlp4 endif export CAMLP4 ifndef REAL_OCAMLFIND ifdef PACKS ifndef CREATE_LIB ifdef THREADS PACKS += threads endif endif empty := space := $(empty) $(empty) comma := , ifdef PREDS PRE_OCAML_FIND_PREDICATES := $(subst $(space),$(comma),$(PREDS)) PRE_OCAML_FIND_PACKAGES := $(subst $(space),$(comma),$(PACKS)) OCAML_FIND_PREDICATES := -predicates $(PRE_OCAML_FIND_PREDICATES) # OCAML_DEP_PREDICATES := -syntax $(PRE_OCAML_FIND_PREDICATES) OCAML_FIND_PACKAGES := $(OCAML_FIND_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES) OCAML_DEP_PACKAGES := $(OCAML_DEP_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES) else OCAML_FIND_PACKAGES := -package $(subst $(space),$(comma),$(PACKS)) OCAML_DEP_PACKAGES := endif OCAML_FIND_LINKPKG := -linkpkg REAL_OCAMLFIND := $(OCAMLFIND) endif endif export OCAML_FIND_PACKAGES export OCAML_DEP_PACKAGES export OCAML_FIND_LINKPKG export REAL_OCAMLFIND ifndef OCAMLDOC OCAMLDOC := ocamldoc endif export OCAMLDOC ifndef LATEX LATEX := latex endif export LATEX ifndef DVIPS DVIPS := dvips endif export DVIPS ifndef PS2PDF PS2PDF := ps2pdf endif export PS2PDF ifndef OCAMLMAKEFILE OCAMLMAKEFILE := OCamlMakefile endif export OCAMLMAKEFILE ifndef OCAMLLIBPATH OCAMLLIBPATH := \ $(shell $(OCAMLC) 2>/dev/null -where || echo /usr/local/lib/ocaml) endif export OCAMLLIBPATH ifndef OCAML_LIB_INSTALL OCAML_LIB_INSTALL := $(OCAMLLIBPATH)/contrib endif export OCAML_LIB_INSTALL ########################################################################### #################### change following sections only if #################### you know what you are doing! # delete target files when a build command fails .PHONY: .DELETE_ON_ERROR .DELETE_ON_ERROR: # for pedants using "--warn-undefined-variables" export MAYBE_IDL export REAL_RESULT export CAMLIDLFLAGS export THREAD_FLAG export RES_CLIB export MAKEDLL export ANNOT_FLAG export C_OXRIDL export SUBPROJS export CFLAGS_WIN32 export CPPFLAGS_WIN32 INCFLAGS := SHELL := /bin/sh MLDEPDIR := ._d BCDIDIR := ._bcdi NCDIDIR := ._ncdi FILTER_EXTNS := %.mli %.ml %.mll %.mly %.idl %.oxridl %.c %.m %.$(EXT_CXX) %.rep %.zog %.glade FILTERED := $(filter $(FILTER_EXTNS), $(SOURCES)) SOURCE_DIRS := $(filter-out ./, $(sort $(dir $(FILTERED)))) FILTERED_REP := $(filter %.rep, $(FILTERED)) DEP_REP := $(FILTERED_REP:%.rep=$(MLDEPDIR)/%.d) AUTO_REP := $(FILTERED_REP:.rep=.ml) FILTERED_ZOG := $(filter %.zog, $(FILTERED)) DEP_ZOG := $(FILTERED_ZOG:%.zog=$(MLDEPDIR)/%.d) AUTO_ZOG := $(FILTERED_ZOG:.zog=.ml) FILTERED_GLADE := $(filter %.glade, $(FILTERED)) DEP_GLADE := $(FILTERED_GLADE:%.glade=$(MLDEPDIR)/%.d) AUTO_GLADE := $(FILTERED_GLADE:.glade=.ml) FILTERED_ML := $(filter %.ml, $(FILTERED)) DEP_ML := $(FILTERED_ML:%.ml=$(MLDEPDIR)/%.d) FILTERED_MLI := $(filter %.mli, $(FILTERED)) DEP_MLI := $(FILTERED_MLI:.mli=.di) FILTERED_MLL := $(filter %.mll, $(FILTERED)) DEP_MLL := $(FILTERED_MLL:%.mll=$(MLDEPDIR)/%.d) AUTO_MLL := $(FILTERED_MLL:.mll=.ml) FILTERED_MLY := $(filter %.mly, $(FILTERED)) DEP_MLY := $(FILTERED_MLY:%.mly=$(MLDEPDIR)/%.d) $(FILTERED_MLY:.mly=.di) AUTO_MLY := $(FILTERED_MLY:.mly=.mli) $(FILTERED_MLY:.mly=.ml) FILTERED_IDL := $(filter %.idl, $(FILTERED)) DEP_IDL := $(FILTERED_IDL:%.idl=$(MLDEPDIR)/%.d) $(FILTERED_IDL:.idl=.di) C_IDL := $(FILTERED_IDL:%.idl=%_stubs.c) ifndef NOIDLHEADER C_IDL += $(FILTERED_IDL:.idl=.h) endif OBJ_C_IDL := $(FILTERED_IDL:%.idl=%_stubs.$(EXT_OBJ)) AUTO_IDL := $(FILTERED_IDL:.idl=.mli) $(FILTERED_IDL:.idl=.ml) $(C_IDL) FILTERED_OXRIDL := $(filter %.oxridl, $(FILTERED)) DEP_OXRIDL := $(FILTERED_OXRIDL:%.oxridl=$(MLDEPDIR)/%.d) $(FILTERED_OXRIDL:.oxridl=.di) AUTO_OXRIDL := $(FILTERED_OXRIDL:.oxridl=.mli) $(FILTERED_OXRIDL:.oxridl=.ml) $(C_OXRIDL) FILTERED_C_CXX := $(filter %.c %.m %.$(EXT_CXX), $(FILTERED)) OBJ_C_CXX := $(FILTERED_C_CXX:.c=.$(EXT_OBJ)) OBJ_C_CXX := $(OBJ_C_CXX:.m=.$(EXT_OBJ)) OBJ_C_CXX := $(OBJ_C_CXX:.$(EXT_CXX)=.$(EXT_OBJ)) PRE_TARGETS += $(AUTO_MLL) $(AUTO_MLY) $(AUTO_IDL) $(AUTO_OXRIDL) $(AUTO_ZOG) $(AUTO_REP) $(AUTO_GLADE) ALL_DEPS := $(DEP_ML) $(DEP_MLI) $(DEP_MLL) $(DEP_MLY) $(DEP_IDL) $(DEP_OXRIDL) $(DEP_ZOG) $(DEP_REP) $(DEP_GLADE) MLDEPS := $(filter %.d, $(ALL_DEPS)) MLIDEPS := $(filter %.di, $(ALL_DEPS)) BCDEPIS := $(MLIDEPS:%.di=$(BCDIDIR)/%.di) NCDEPIS := $(MLIDEPS:%.di=$(NCDIDIR)/%.di) ALLML := $(filter %.mli %.ml %.mll %.mly %.idl %.oxridl %.rep %.zog %.glade, $(FILTERED)) IMPLO_INTF := $(ALLML:%.mli=%.mli.__) IMPLO_INTF := $(foreach file, $(IMPLO_INTF), \ $(basename $(file)).cmi $(basename $(file)).cmo) IMPLO_INTF := $(filter-out %.mli.cmo, $(IMPLO_INTF)) IMPLO_INTF := $(IMPLO_INTF:%.mli.cmi=%.cmi) IMPLX_INTF := $(IMPLO_INTF:.cmo=.cmx) INTF := $(filter %.cmi, $(IMPLO_INTF)) IMPL_CMO := $(filter %.cmo, $(IMPLO_INTF)) IMPL_CMX := $(IMPL_CMO:.cmo=.cmx) IMPL_ASM := $(IMPL_CMO:.cmo=.asm) IMPL_S := $(IMPL_CMO:.cmo=.s) OBJ_LINK := $(OBJ_C_IDL) $(OBJ_C_CXX) OBJ_FILES := $(IMPL_CMO:.cmo=.$(EXT_OBJ)) $(OBJ_LINK) EXECS := $(addsuffix $(EXE), \ $(sort $(TOPRESULT) $(BCRESULT) $(NCRESULT))) ifdef WIN32 EXECS += $(BCRESULT).dll $(NCRESULT).dll endif CLIB_BASE := $(RESULT)$(RES_CLIB_SUF) ifneq ($(strip $(OBJ_LINK)),) RES_CLIB := lib$(CLIB_BASE).$(EXT_LIB) endif ifdef WIN32 DLLSONAME := dll$(CLIB_BASE).dll else DLLSONAME := dll$(CLIB_BASE).so endif NONEXECS := $(INTF) $(IMPL_CMO) $(IMPL_CMX) $(IMPL_ASM) $(IMPL_S) \ $(OBJ_FILES) $(PRE_TARGETS) $(BCRESULT).cma $(NCRESULT).cmxa \ $(NCRESULT).$(EXT_LIB) $(BCRESULT).cmi $(BCRESULT).cmo \ $(NCRESULT).cmi $(NCRESULT).cmx $(NCRESULT).$(EXT_OBJ) \ $(RES_CLIB) $(IMPL_CMO:.cmo=.annot) \ $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(LIB_PACK_NAME).cmx \ $(LIB_PACK_NAME).$(EXT_OBJ) ifndef STATIC NONEXECS += $(DLLSONAME) endif ifndef LIBINSTALL_FILES LIBINSTALL_FILES := $(RESULT).mli $(RESULT).cmi $(RESULT).cma \ $(RESULT).cmxa $(RESULT).$(EXT_LIB) $(RES_CLIB) ifndef STATIC ifneq ($(strip $(OBJ_LINK)),) LIBINSTALL_FILES += $(DLLSONAME) endif endif endif export LIBINSTALL_FILES ifdef WIN32 # some extra stuff is created while linking DLLs NONEXECS += $(BCRESULT).$(EXT_LIB) $(BCRESULT).exp $(NCRESULT).exp $(CLIB_BASE).exp $(CLIB_BASE).lib endif TARGETS := $(EXECS) $(NONEXECS) # If there are IDL-files ifneq ($(strip $(FILTERED_IDL)),) MAYBE_IDL := -cclib -lcamlidl endif ifdef USE_CAMLP4 CAMLP4PATH := \ $(shell $(CAMLP4) -where 2>/dev/null || echo /usr/local/lib/camlp4) INCFLAGS := -I $(CAMLP4PATH) CINCFLAGS := -I$(CAMLP4PATH) endif INCFLAGS := $(INCFLAGS) $(INCDIRS:%=-I %) $(SOURCE_DIRS:%=-I %) $(OCAML_DEFAULT_DIRS:%=-I %) CINCFLAGS += $(SOURCE_DIRS:%=-I%) $(INCDIRS:%=-I%) $(OCAML_DEFAULT_DIRS:%=-I%) ifndef MSVC CLIBFLAGS += $(SOURCE_DIRS:%=-L%) $(LIBDIRS:%=-L%) \ $(EXTLIBDIRS:%=-L%) $(OCAML_DEFAULT_DIRS:%=-L%) ifeq ($(ELF_RPATH), yes) CLIBFLAGS += $(EXTLIBDIRS:%=-Wl,$(RPATH_FLAG)%) endif endif ifndef PROFILING INTF_OCAMLC := $(OCAMLC) else ifndef THREADS INTF_OCAMLC := $(OCAMLCP) -p $(OCAMLCPFLAGS) else # OCaml does not support profiling byte code # with threads (yet), therefore we force an error. ifndef REAL_OCAMLC $(error Profiling of multithreaded byte code not yet supported by OCaml) endif INTF_OCAMLC := $(OCAMLC) endif endif ifndef MSVC COMMON_LDFLAGS := $(LDFLAGS:%=-ccopt %) $(SOURCE_DIRS:%=-ccopt -L%) \ $(LIBDIRS:%=-ccopt -L%) $(EXTLIBDIRS:%=-ccopt -L%) \ $(EXTLIBDIRS:%=-ccopt -Wl $(OCAML_DEFAULT_DIRS:%=-ccopt -L%)) ifeq ($(ELF_RPATH),yes) COMMON_LDFLAGS += $(EXTLIBDIRS:%=-ccopt -Wl,$(RPATH_FLAG)%) endif else COMMON_LDFLAGS := -ccopt "/link -NODEFAULTLIB:LIBC $(LDFLAGS:%=%) $(SOURCE_DIRS:%=-LIBPATH:%) \ $(LIBDIRS:%=-LIBPATH:%) $(EXTLIBDIRS:%=-LIBPATH:%) \ $(OCAML_DEFAULT_DIRS:%=-LIBPATH:%) " endif CLIBS_OPTS := $(CLIBS:%=-cclib -l%) $(CFRAMEWORKS:%=-cclib '-framework %') ifdef MSVC ifndef STATIC # MSVC libraries do not have 'lib' prefix CLIBS_OPTS := $(CLIBS:%=-cclib %.lib) endif endif ifneq ($(strip $(OBJ_LINK)),) ifdef CREATE_LIB OBJS_LIBS := -cclib -l$(CLIB_BASE) $(CLIBS_OPTS) $(MAYBE_IDL) else OBJS_LIBS := $(OBJ_LINK) $(CLIBS_OPTS) $(MAYBE_IDL) endif else OBJS_LIBS := $(CLIBS_OPTS) $(MAYBE_IDL) endif ifdef LIB_PACK_NAME FOR_PACK_NAME := $(shell echo $(LIB_PACK_NAME) | awk '{print toupper(substr($$0,1,1))substr($$0,2)}') endif # If we have to make byte-code ifndef REAL_OCAMLC BYTE_OCAML := y # EXTRADEPS is added dependencies we have to insert for all # executable files we generate. Ideally it should be all of the # libraries we use, but it's hard to find the ones that get searched on # the path since I don't know the paths built into the compiler, so # just include the ones with slashes in their names. EXTRADEPS := $(addsuffix .cma,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i)))) ifndef LIB_PACK_NAME SPECIAL_OCAMLFLAGS := $(OCAMLBCFLAGS) else SPECIAL_OCAMLFLAGS := -for-pack $(FOR_PACK_NAME) $(OCAMLBCFLAGS) endif REAL_OCAMLC := $(INTF_OCAMLC) REAL_IMPL := $(IMPL_CMO) REAL_IMPL_INTF := $(IMPLO_INTF) IMPL_SUF := .cmo DEPFLAGS := MAKE_DEPS := $(MLDEPS) $(BCDEPIS) ifdef CREATE_LIB override CFLAGS := $(PIC_CFLAGS) $(CFLAGS) override CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS) ifndef STATIC ifneq ($(strip $(OBJ_LINK)),) MAKEDLL := $(DLLSONAME) ALL_LDFLAGS := -dllib $(DLLSONAME) endif endif endif ifndef NO_CUSTOM ifneq "$(strip $(OBJ_LINK) $(THREADS) $(MAYBE_IDL) $(CLIBS) $(CFRAMEWORKS))" "" ALL_LDFLAGS += -custom endif endif ALL_LDFLAGS += $(INCFLAGS) $(OCAMLLDFLAGS) $(OCAMLBLDFLAGS) \ $(COMMON_LDFLAGS) $(LIBS:%=%.cma) CAMLIDLDLLFLAGS := ifdef THREADS ifdef VMTHREADS THREAD_FLAG := -vmthread else THREAD_FLAG := -thread endif ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS) ifndef CREATE_LIB ifndef REAL_OCAMLFIND ALL_LDFLAGS := $(ALL_LDFLAGS) endif endif endif # we have to make native-code else EXTRADEPS := $(addsuffix .cmxa,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i)))) ifndef PROFILING SPECIAL_OCAMLFLAGS := $(OCAMLNCFLAGS) PLDFLAGS := else SPECIAL_OCAMLFLAGS := -p $(OCAMLNCFLAGS) PLDFLAGS := -p endif ifndef LIB_PACK_NAME SPECIAL_OCAMLFLAGS := $(OCAMLNCFLAGS) else SPECIAL_OCAMLFLAGS := -for-pack $(FOR_PACK_NAME) $(OCAMLNCFLAGS) endif REAL_IMPL := $(IMPL_CMX) REAL_IMPL_INTF := $(IMPLX_INTF) IMPL_SUF := .cmx override CPPFLAGS := -DNATIVE_CODE $(CPPFLAGS) DEPFLAGS := -native MAKE_DEPS := $(MLDEPS) $(NCDEPIS) ALL_LDFLAGS := $(PLDFLAGS) $(INCFLAGS) $(OCAMLLDFLAGS) \ $(OCAMLNLDFLAGS) $(COMMON_LDFLAGS) CAMLIDLDLLFLAGS := -opt ifndef CREATE_LIB ALL_LDFLAGS += $(LIBS:%=%.cmxa) else override CFLAGS := $(PIC_CFLAGS) $(CFLAGS) override CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS) endif ifdef THREADS THREAD_FLAG := -thread ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS) ifndef CREATE_LIB ifndef REAL_OCAMLFIND ALL_LDFLAGS := $(ALL_LDFLAGS) endif endif endif endif export MAKE_DEPS ifdef ANNOTATE ANNOT_FLAG := -annot else endif ALL_OCAMLCFLAGS := $(THREAD_FLAG) $(ANNOT_FLAG) $(OCAMLFLAGS) \ $(INCFLAGS) $(SPECIAL_OCAMLFLAGS) ifdef make_deps -include $(MAKE_DEPS) PRE_TARGETS := endif ########################################################################### # USER RULES # Call "OCamlMakefile QUIET=" to get rid of all of the @'s. QUIET=@ # generates byte-code (default) byte-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ REAL_RESULT="$(BCRESULT)" make_deps=yes bc: byte-code byte-code-nolink: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ REAL_RESULT="$(BCRESULT)" make_deps=yes bcnl: byte-code-nolink top: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(TOPRESULT) \ REAL_RESULT="$(BCRESULT)" make_deps=yes # generates native-code native-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ make_deps=yes nc: native-code native-code-nolink: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ make_deps=yes ncnl: native-code-nolink # generates byte-code libraries byte-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).cma \ REAL_RESULT="$(BCRESULT)" \ CREATE_LIB=yes \ make_deps=yes bcl: byte-code-library # generates native-code libraries native-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(NCRESULT).cmxa \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ CREATE_LIB=yes \ make_deps=yes ncl: native-code-library ifdef WIN32 # generates byte-code dll byte-code-dll: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).dll \ REAL_RESULT="$(BCRESULT)" \ make_deps=yes bcd: byte-code-dll # generates native-code dll native-code-dll: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(NCRESULT).dll \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ make_deps=yes ncd: native-code-dll endif # generates byte-code with debugging information debug-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ REAL_RESULT="$(BCRESULT)" make_deps=yes \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dc: debug-code debug-code-nolink: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ REAL_RESULT="$(BCRESULT)" make_deps=yes \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dcnl: debug-code-nolink # generates byte-code with debugging information (native code) debug-native-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \ REAL_RESULT="$(NCRESULT)" make_deps=yes \ REAL_OCAMLC="$(OCAMLOPT)" \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dnc: debug-native-code debug-native-code-nolink: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ REAL_RESULT="$(NCRESULT)" make_deps=yes \ REAL_OCAMLC="$(OCAMLOPT)" \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dncnl: debug-native-code-nolink # generates byte-code libraries with debugging information debug-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).cma \ REAL_RESULT="$(BCRESULT)" make_deps=yes \ CREATE_LIB=yes \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dcl: debug-code-library # generates byte-code libraries with debugging information (native code) debug-native-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(NCRESULT).cmxa \ REAL_RESULT="$(NCRESULT)" make_deps=yes \ REAL_OCAMLC="$(OCAMLOPT)" \ CREATE_LIB=yes \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dncl: debug-native-code-library # generates byte-code for profiling profiling-byte-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ REAL_RESULT="$(BCRESULT)" PROFILING="y" \ make_deps=yes pbc: profiling-byte-code # generates native-code profiling-native-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ PROFILING="y" \ make_deps=yes pnc: profiling-native-code # generates byte-code libraries profiling-byte-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).cma \ REAL_RESULT="$(BCRESULT)" PROFILING="y" \ CREATE_LIB=yes \ make_deps=yes pbcl: profiling-byte-code-library # generates native-code libraries profiling-native-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(NCRESULT).cmxa \ REAL_RESULT="$(NCRESULT)" PROFILING="y" \ REAL_OCAMLC="$(OCAMLOPT)" \ CREATE_LIB=yes \ make_deps=yes pncl: profiling-native-code-library # packs byte-code objects pack-byte-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT).cmo \ REAL_RESULT="$(BCRESULT)" \ PACK_LIB=yes make_deps=yes pabc: pack-byte-code # packs native-code objects pack-native-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(NCRESULT).cmx $(NCRESULT).$(EXT_OBJ) \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ PACK_LIB=yes make_deps=yes panc: pack-native-code # generates HTML-documentation htdoc: $(DOC_DIR)/$(RESULT)/html/index.html # generates Latex-documentation ladoc: $(DOC_DIR)/$(RESULT)/latex/doc.tex # generates PostScript-documentation psdoc: $(DOC_DIR)/$(RESULT)/latex/doc.ps # generates PDF-documentation pdfdoc: $(DOC_DIR)/$(RESULT)/latex/doc.pdf # generates all supported forms of documentation doc: htdoc ladoc psdoc pdfdoc ########################################################################### # LOW LEVEL RULES $(REAL_RESULT): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(REAL_OCAMLC) \ $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \ $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@$(EXE) \ $(REAL_IMPL) nolink: $(REAL_IMPL_INTF) $(OBJ_LINK) ifdef WIN32 $(REAL_RESULT).dll: $(REAL_IMPL_INTF) $(OBJ_LINK) $(CAMLIDLDLL) $(CAMLIDLDLLFLAGS) $(OBJ_LINK) $(CLIBS) \ -o $@ $(REAL_IMPL) endif %$(TOPSUFFIX): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) $(REAL_OCAMLFIND) $(OCAMLMKTOP) \ $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \ $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@$(EXE) \ $(REAL_IMPL) .SUFFIXES: .mli .ml .cmi .cmo .cmx .cma .cmxa .$(EXT_OBJ) \ .mly .di .d .$(EXT_LIB) .idl %.oxridl .c .m .$(EXT_CXX) .h .so \ .rep .zog .glade ifndef STATIC ifdef MINGW # From OCaml 3.11.0, ocamlmklib is available on windows OCAMLMLIB_EXISTS = $(shell which $(OCAMLMKLIB)) ifeq ($(strip $(OCAMLMLIB_EXISTS)),) $(DLLSONAME): $(OBJ_LINK) $(CC) $(CFLAGS) $(CFLAGS_WIN32) $(OBJ_LINK) -shared -o $@ \ $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/lib%.a))) \ '$(OCAMLLIBPATH)/ocamlrun.a' \ -Wl,--whole-archive \ -Wl,--export-all-symbols \ -Wl,--allow-multiple-definition \ -Wl,--enable-auto-import else $(DLLSONAME): $(OBJ_LINK) $(OCAMLMKLIB) $(INCFLAGS) $(CLIBFLAGS) \ -o $(CLIB_BASE) $(OBJ_LINK) $(CLIBS:%=-l%) \ $(CFRAMEWORKS:%=-framework %) \ $(OCAMLMKLIB_FLAGS) endif else ifdef MSVC $(DLLSONAME): $(OBJ_LINK) link /NOLOGO /DLL /OUT:$@ $(OBJ_LINK) \ $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/%.lib))) \ '$(OCAMLLIBPATH)/ocamlrun.lib' else $(DLLSONAME): $(OBJ_LINK) $(OCAMLMKLIB) $(INCFLAGS) $(CLIBFLAGS) \ -o $(CLIB_BASE) $(OBJ_LINK) $(CLIBS:%=-l%) $(CFRAMEWORKS:%=-framework %) \ $(OCAMLMKLIB_FLAGS) endif endif endif ifndef LIB_PACK_NAME $(RESULT).cma: $(REAL_IMPL_INTF) $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@ $(REAL_IMPL) $(RESULT).cmxa $(RESULT).$(EXT_LIB): $(REAL_IMPL_INTF) $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(OCAMLOPT) -a $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@ $(REAL_IMPL) else # Packing a bytecode library LIB_PACK_NAME_MLI = $(wildcard $(LIB_PACK_NAME).mli) ifeq ($(LIB_PACK_NAME_MLI),) LIB_PACK_NAME_CMI = $(LIB_PACK_NAME).cmi else # $(LIB_PACK_NAME).mli exists, it likely depends on other compiled interfaces LIB_PACK_NAME_CMI = $(LIB_PACK_NAME).cmi: $(REAL_IMPL_INTF) endif ifdef BYTE_OCAML $(LIB_PACK_NAME_CMI) $(LIB_PACK_NAME).cmo: $(REAL_IMPL_INTF) $(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack -o $(LIB_PACK_NAME).cmo $(OCAMLLDFLAGS) $(REAL_IMPL) # Packing into a unit which can be transformed into a library # Remember the .ml's must have been compiled with -for-pack $(LIB_PACK_NAME) else $(LIB_PACK_NAME_CMI) $(LIB_PACK_NAME).cmx: $(REAL_IMPL_INTF) $(REAL_OCAMLFIND) $(OCAMLOPT) -pack -o $(LIB_PACK_NAME).cmx $(OCAMLLDFLAGS) $(REAL_IMPL) endif $(RESULT).cma: $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@ $(LIB_PACK_NAME).cmo $(RESULT).cmxa $(RESULT).$(EXT_LIB): $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmx $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(OCAMLOPT) -a $(OBJS_LIBS) $(filter-out -custom, $(ALL_LDFLAGS)) -o $@ $(LIB_PACK_NAME).cmx endif $(RES_CLIB): $(OBJ_LINK) ifndef MSVC ifneq ($(strip $(OBJ_LINK)),) $(AR) rcs $@ $(OBJ_LINK) endif else ifneq ($(strip $(OBJ_LINK)),) lib -nologo -debugtype:cv -out:$(RES_CLIB) $(OBJ_LINK) endif endif %.cmi: %.mli $(EXTRADEPS) $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ $(ECHO) $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ else \ $(ECHO) $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp \"$$pp $(PPFLAGS)\" $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp "$$pp $(PPFLAGS)" $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ fi %.cmi: %$(IMPL_SUF); %$(IMPL_SUF) %.$(EXT_OBJ): %.ml $(EXTRADEPS) $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ $(ECHO) $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(ALL_OCAMLCFLAGS) $<; \ $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(ALL_OCAMLCFLAGS) $<; \ else \ $(ECHO) $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp \"$$pp $(PPFLAGS)\" $(ALL_OCAMLCFLAGS) $<; \ $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp "$$pp $(PPFLAGS)" $(ALL_OCAMLCFLAGS) $<; \ fi .PRECIOUS: %.ml %.ml: %.mll $(OCAMLLEX) $(LFLAGS) $< .PRECIOUS: %.ml %.mli %.ml %.mli: %.mly $(OCAMLYACC) $(YFLAGS) $< $(QUIET)pp=`sed -n -e 's/.*(\*pp \([^*]*\) \*).*/\1/p;q' $<`; \ if [ ! -z "$$pp" ]; then \ mv $*.ml $*.ml.temporary; \ echo "(*pp $$pp $(PPFLAGS)*)" > $*.ml; \ cat $*.ml.temporary >> $*.ml; \ rm $*.ml.temporary; \ mv $*.mli $*.mli.temporary; \ echo "(*pp $$pp $(PPFLAGS)*)" > $*.mli; \ cat $*.mli.temporary >> $*.mli; \ rm $*.mli.temporary; \ fi .PRECIOUS: %.ml %.ml: %.rep $(CAMELEON_REPORT) $(CAMELEON_REPORT_FLAGS) -gen $< .PRECIOUS: %.ml %.ml: %.zog $(CAMELEON_ZOGGY) $(CAMELEON_ZOGGY_FLAGS) -impl $< > $@ .PRECIOUS: %.ml %.ml: %.glade $(OCAML_GLADECC) $(OCAML_GLADECC_FLAGS) $< > $@ .PRECIOUS: %.ml %.mli %.ml %.mli: %.oxridl $(OXRIDL) $< .PRECIOUS: %.ml %.mli %_stubs.c %.h %.ml %.mli %_stubs.c %.h: %.idl $(CAMLIDL) $(MAYBE_IDL_HEADER) $(IDLFLAGS) \ $(CAMLIDLFLAGS) $< $(QUIET)if [ $(NOIDLHEADER) ]; then touch $*.h; fi %.$(EXT_OBJ): %.c $(OCAMLC) -c -cc "$(CC)" -ccopt "$(CFLAGS) \ $(CPPFLAGS) $(CPPFLAGS_WIN32) \ $(CFLAGS_WIN32) $(CINCFLAGS) $(CFLAG_O)$@ " $< %.$(EXT_OBJ): %.m $(CC) -c $(CFLAGS) $(CINCFLAGS) $(CPPFLAGS) \ -I'$(OCAMLLIBPATH)' \ $< $(CFLAG_O)$@ %.$(EXT_OBJ): %.$(EXT_CXX) $(CXX) -c $(CXXFLAGS) $(CINCFLAGS) $(CPPFLAGS) \ -I'$(OCAMLLIBPATH)' \ $< $(CFLAG_O)$@ $(MLDEPDIR)/%.d: %.ml $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ $(INCFLAGS) $< \> $@; \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ $(INCFLAGS) $< > $@; \ else \ $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ -pp \"$$pp $(PPFLAGS)\" $(INCFLAGS) $< \> $@; \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ -pp "$$pp $(PPFLAGS)" $(INCFLAGS) $< > $@; \ fi $(BCDIDIR)/%.di $(NCDIDIR)/%.di: %.mli $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(INCFLAGS) $< \> $@; \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(INCFLAGS) $< > $@; \ else \ $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \ -pp \"$$pp $(PPFLAGS)\" $(INCFLAGS) $< \> $@; \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \ -pp "$$pp $(PPFLAGS)" $(INCFLAGS) $< > $@; \ fi $(DOC_DIR)/$(RESULT)/html: mkdir -p $@ $(DOC_DIR)/$(RESULT)/html/index.html: $(DOC_DIR)/$(RESULT)/html $(DOC_FILES) rm -rf $ [] substitutes data files specified by __DATA:\n into the template, writing to . The data is printed in way which meets OCaml's syntax. It is optionally compressed by zlib. *) open Pdfutil let contents_of_file filename = let ch = open_in_bin filename in let s = really_input_string ch (in_channel_length ch) in close_in ch; s let contents_to_file filename contents = let ch = open_out_bin filename in output_string ch contents; close_out ch let rec process a = function | '_'::'_'::'D'::'A'::'T'::'A'::':'::more -> let filename, rest = cleavewhile (neq '\n') more in let data = all_but_last (explode (contents_of_file (implode filename))) in let compressed = Pdfio.string_of_bytes (Pdfcodec.encode_flate (Pdfio.bytes_of_string (implode data))) in let ocaml = explode (Printf.sprintf "%S" compressed) in process (rev ocaml @ a) rest | h::t -> process (h::a) t | [] -> rev a let go infile outfile compress = let indata = explode (contents_of_file infile) in let processed = process [] indata in contents_to_file outfile (implode processed) let () = match Sys.argv with | [|_; infile; outfile|] -> go infile outfile false | [|_; infile; outfile; "compress"|] -> go infile outfile true | _ -> Printf.eprintf "compressor: unknown command line\n" camlpdf-2.8.1/compressor/glyphlist.txt000066400000000000000000002251251477056064700201330ustar00rootroot00000000000000# Name: Adobe Glyph List # Table version: 2.0 # Date: September 20, 2002 # # See http://partners.adobe.com/asn/developer/typeforum/unicodegn.html # # Format: Semicolon-delimited fields: # (1) glyph name # (2) Unicode scalar value A;0041 AE;00C6 AEacute;01FC AEmacron;01E2 AEsmall;F7E6 Aacute;00C1 Aacutesmall;F7E1 Abreve;0102 Abreveacute;1EAE Abrevecyrillic;04D0 Abrevedotbelow;1EB6 Abrevegrave;1EB0 Abrevehookabove;1EB2 Abrevetilde;1EB4 Acaron;01CD Acircle;24B6 Acircumflex;00C2 Acircumflexacute;1EA4 Acircumflexdotbelow;1EAC Acircumflexgrave;1EA6 Acircumflexhookabove;1EA8 Acircumflexsmall;F7E2 Acircumflextilde;1EAA Acute;F6C9 Acutesmall;F7B4 Acyrillic;0410 Adblgrave;0200 Adieresis;00C4 Adieresiscyrillic;04D2 Adieresismacron;01DE Adieresissmall;F7E4 Adotbelow;1EA0 Adotmacron;01E0 Agrave;00C0 Agravesmall;F7E0 Ahookabove;1EA2 Aiecyrillic;04D4 Ainvertedbreve;0202 Alpha;0391 Alphatonos;0386 Amacron;0100 Amonospace;FF21 Aogonek;0104 Aring;00C5 Aringacute;01FA Aringbelow;1E00 Aringsmall;F7E5 Asmall;F761 Atilde;00C3 Atildesmall;F7E3 Aybarmenian;0531 B;0042 Bcircle;24B7 Bdotaccent;1E02 Bdotbelow;1E04 Becyrillic;0411 Benarmenian;0532 Beta;0392 Bhook;0181 Blinebelow;1E06 Bmonospace;FF22 Brevesmall;F6F4 Bsmall;F762 Btopbar;0182 C;0043 Caarmenian;053E Cacute;0106 Caron;F6CA Caronsmall;F6F5 Ccaron;010C Ccedilla;00C7 Ccedillaacute;1E08 Ccedillasmall;F7E7 Ccircle;24B8 Ccircumflex;0108 Cdot;010A Cdotaccent;010A Cedillasmall;F7B8 Chaarmenian;0549 Cheabkhasiancyrillic;04BC Checyrillic;0427 Chedescenderabkhasiancyrillic;04BE Chedescendercyrillic;04B6 Chedieresiscyrillic;04F4 Cheharmenian;0543 Chekhakassiancyrillic;04CB Cheverticalstrokecyrillic;04B8 Chi;03A7 Chook;0187 Circumflexsmall;F6F6 Cmonospace;FF23 Coarmenian;0551 Csmall;F763 D;0044 DZ;01F1 DZcaron;01C4 Daarmenian;0534 Dafrican;0189 Dcaron;010E Dcedilla;1E10 Dcircle;24B9 Dcircumflexbelow;1E12 Dcroat;0110 Ddotaccent;1E0A Ddotbelow;1E0C Decyrillic;0414 Deicoptic;03EE Delta;2206 Deltagreek;0394 Dhook;018A Dieresis;F6CB DieresisAcute;F6CC DieresisGrave;F6CD Dieresissmall;F7A8 Digammagreek;03DC Djecyrillic;0402 Dlinebelow;1E0E Dmonospace;FF24 Dotaccentsmall;F6F7 Dslash;0110 Dsmall;F764 Dtopbar;018B Dz;01F2 Dzcaron;01C5 Dzeabkhasiancyrillic;04E0 Dzecyrillic;0405 Dzhecyrillic;040F E;0045 Eacute;00C9 Eacutesmall;F7E9 Ebreve;0114 Ecaron;011A Ecedillabreve;1E1C Echarmenian;0535 Ecircle;24BA Ecircumflex;00CA Ecircumflexacute;1EBE Ecircumflexbelow;1E18 Ecircumflexdotbelow;1EC6 Ecircumflexgrave;1EC0 Ecircumflexhookabove;1EC2 Ecircumflexsmall;F7EA Ecircumflextilde;1EC4 Ecyrillic;0404 Edblgrave;0204 Edieresis;00CB Edieresissmall;F7EB Edot;0116 Edotaccent;0116 Edotbelow;1EB8 Efcyrillic;0424 Egrave;00C8 Egravesmall;F7E8 Eharmenian;0537 Ehookabove;1EBA Eightroman;2167 Einvertedbreve;0206 Eiotifiedcyrillic;0464 Elcyrillic;041B Elevenroman;216A Emacron;0112 Emacronacute;1E16 Emacrongrave;1E14 Emcyrillic;041C Emonospace;FF25 Encyrillic;041D Endescendercyrillic;04A2 Eng;014A Enghecyrillic;04A4 Enhookcyrillic;04C7 Eogonek;0118 Eopen;0190 Epsilon;0395 Epsilontonos;0388 Ercyrillic;0420 Ereversed;018E Ereversedcyrillic;042D Escyrillic;0421 Esdescendercyrillic;04AA Esh;01A9 Esmall;F765 Eta;0397 Etarmenian;0538 Etatonos;0389 Eth;00D0 Ethsmall;F7F0 Etilde;1EBC Etildebelow;1E1A Euro;20AC Ezh;01B7 Ezhcaron;01EE Ezhreversed;01B8 F;0046 Fcircle;24BB Fdotaccent;1E1E Feharmenian;0556 Feicoptic;03E4 Fhook;0191 Fitacyrillic;0472 Fiveroman;2164 Fmonospace;FF26 Fourroman;2163 Fsmall;F766 G;0047 GBsquare;3387 Gacute;01F4 Gamma;0393 Gammaafrican;0194 Gangiacoptic;03EA Gbreve;011E Gcaron;01E6 Gcedilla;0122 Gcircle;24BC Gcircumflex;011C Gcommaaccent;0122 Gdot;0120 Gdotaccent;0120 Gecyrillic;0413 Ghadarmenian;0542 Ghemiddlehookcyrillic;0494 Ghestrokecyrillic;0492 Gheupturncyrillic;0490 Ghook;0193 Gimarmenian;0533 Gjecyrillic;0403 Gmacron;1E20 Gmonospace;FF27 Grave;F6CE Gravesmall;F760 Gsmall;F767 Gsmallhook;029B Gstroke;01E4 H;0048 H18533;25CF H18543;25AA H18551;25AB H22073;25A1 HPsquare;33CB Haabkhasiancyrillic;04A8 Hadescendercyrillic;04B2 Hardsigncyrillic;042A Hbar;0126 Hbrevebelow;1E2A Hcedilla;1E28 Hcircle;24BD Hcircumflex;0124 Hdieresis;1E26 Hdotaccent;1E22 Hdotbelow;1E24 Hmonospace;FF28 Hoarmenian;0540 Horicoptic;03E8 Hsmall;F768 Hungarumlaut;F6CF Hungarumlautsmall;F6F8 Hzsquare;3390 I;0049 IAcyrillic;042F IJ;0132 IUcyrillic;042E Iacute;00CD Iacutesmall;F7ED Ibreve;012C Icaron;01CF Icircle;24BE Icircumflex;00CE Icircumflexsmall;F7EE Icyrillic;0406 Idblgrave;0208 Idieresis;00CF Idieresisacute;1E2E Idieresiscyrillic;04E4 Idieresissmall;F7EF Idot;0130 Idotaccent;0130 Idotbelow;1ECA Iebrevecyrillic;04D6 Iecyrillic;0415 Ifraktur;2111 Igrave;00CC Igravesmall;F7EC Ihookabove;1EC8 Iicyrillic;0418 Iinvertedbreve;020A Iishortcyrillic;0419 Imacron;012A Imacroncyrillic;04E2 Imonospace;FF29 Iniarmenian;053B Iocyrillic;0401 Iogonek;012E Iota;0399 Iotaafrican;0196 Iotadieresis;03AA Iotatonos;038A Ismall;F769 Istroke;0197 Itilde;0128 Itildebelow;1E2C Izhitsacyrillic;0474 Izhitsadblgravecyrillic;0476 J;004A Jaarmenian;0541 Jcircle;24BF Jcircumflex;0134 Jecyrillic;0408 Jheharmenian;054B Jmonospace;FF2A Jsmall;F76A K;004B KBsquare;3385 KKsquare;33CD Kabashkircyrillic;04A0 Kacute;1E30 Kacyrillic;041A Kadescendercyrillic;049A Kahookcyrillic;04C3 Kappa;039A Kastrokecyrillic;049E Kaverticalstrokecyrillic;049C Kcaron;01E8 Kcedilla;0136 Kcircle;24C0 Kcommaaccent;0136 Kdotbelow;1E32 Keharmenian;0554 Kenarmenian;053F Khacyrillic;0425 Kheicoptic;03E6 Khook;0198 Kjecyrillic;040C Klinebelow;1E34 Kmonospace;FF2B Koppacyrillic;0480 Koppagreek;03DE Ksicyrillic;046E Ksmall;F76B L;004C LJ;01C7 LL;F6BF Lacute;0139 Lambda;039B Lcaron;013D Lcedilla;013B Lcircle;24C1 Lcircumflexbelow;1E3C Lcommaaccent;013B Ldot;013F Ldotaccent;013F Ldotbelow;1E36 Ldotbelowmacron;1E38 Liwnarmenian;053C Lj;01C8 Ljecyrillic;0409 Llinebelow;1E3A Lmonospace;FF2C Lslash;0141 Lslashsmall;F6F9 Lsmall;F76C M;004D MBsquare;3386 Macron;F6D0 Macronsmall;F7AF Macute;1E3E Mcircle;24C2 Mdotaccent;1E40 Mdotbelow;1E42 Menarmenian;0544 Mmonospace;FF2D Msmall;F76D Mturned;019C Mu;039C N;004E NJ;01CA Nacute;0143 Ncaron;0147 Ncedilla;0145 Ncircle;24C3 Ncircumflexbelow;1E4A Ncommaaccent;0145 Ndotaccent;1E44 Ndotbelow;1E46 Nhookleft;019D Nineroman;2168 Nj;01CB Njecyrillic;040A Nlinebelow;1E48 Nmonospace;FF2E Nowarmenian;0546 Nsmall;F76E Ntilde;00D1 Ntildesmall;F7F1 Nu;039D O;004F OE;0152 OEsmall;F6FA Oacute;00D3 Oacutesmall;F7F3 Obarredcyrillic;04E8 Obarreddieresiscyrillic;04EA Obreve;014E Ocaron;01D1 Ocenteredtilde;019F Ocircle;24C4 Ocircumflex;00D4 Ocircumflexacute;1ED0 Ocircumflexdotbelow;1ED8 Ocircumflexgrave;1ED2 Ocircumflexhookabove;1ED4 Ocircumflexsmall;F7F4 Ocircumflextilde;1ED6 Ocyrillic;041E Odblacute;0150 Odblgrave;020C Odieresis;00D6 Odieresiscyrillic;04E6 Odieresissmall;F7F6 Odotbelow;1ECC Ogoneksmall;F6FB Ograve;00D2 Ogravesmall;F7F2 Oharmenian;0555 Ohm;2126 Ohookabove;1ECE Ohorn;01A0 Ohornacute;1EDA Ohorndotbelow;1EE2 Ohorngrave;1EDC Ohornhookabove;1EDE Ohorntilde;1EE0 Ohungarumlaut;0150 Oi;01A2 Oinvertedbreve;020E Omacron;014C Omacronacute;1E52 Omacrongrave;1E50 Omega;2126 Omegacyrillic;0460 Omegagreek;03A9 Omegaroundcyrillic;047A Omegatitlocyrillic;047C Omegatonos;038F Omicron;039F Omicrontonos;038C Omonospace;FF2F Oneroman;2160 Oogonek;01EA Oogonekmacron;01EC Oopen;0186 Oslash;00D8 Oslashacute;01FE Oslashsmall;F7F8 Osmall;F76F Ostrokeacute;01FE Otcyrillic;047E Otilde;00D5 Otildeacute;1E4C Otildedieresis;1E4E Otildesmall;F7F5 P;0050 Pacute;1E54 Pcircle;24C5 Pdotaccent;1E56 Pecyrillic;041F Peharmenian;054A Pemiddlehookcyrillic;04A6 Phi;03A6 Phook;01A4 Pi;03A0 Piwrarmenian;0553 Pmonospace;FF30 Psi;03A8 Psicyrillic;0470 Psmall;F770 Q;0051 Qcircle;24C6 Qmonospace;FF31 Qsmall;F771 R;0052 Raarmenian;054C Racute;0154 Rcaron;0158 Rcedilla;0156 Rcircle;24C7 Rcommaaccent;0156 Rdblgrave;0210 Rdotaccent;1E58 Rdotbelow;1E5A Rdotbelowmacron;1E5C Reharmenian;0550 Rfraktur;211C Rho;03A1 Ringsmall;F6FC Rinvertedbreve;0212 Rlinebelow;1E5E Rmonospace;FF32 Rsmall;F772 Rsmallinverted;0281 Rsmallinvertedsuperior;02B6 S;0053 SF010000;250C SF020000;2514 SF030000;2510 SF040000;2518 SF050000;253C SF060000;252C SF070000;2534 SF080000;251C SF090000;2524 SF100000;2500 SF110000;2502 SF190000;2561 SF200000;2562 SF210000;2556 SF220000;2555 SF230000;2563 SF240000;2551 SF250000;2557 SF260000;255D SF270000;255C SF280000;255B SF360000;255E SF370000;255F SF380000;255A SF390000;2554 SF400000;2569 SF410000;2566 SF420000;2560 SF430000;2550 SF440000;256C SF450000;2567 SF460000;2568 SF470000;2564 SF480000;2565 SF490000;2559 SF500000;2558 SF510000;2552 SF520000;2553 SF530000;256B SF540000;256A Sacute;015A Sacutedotaccent;1E64 Sampigreek;03E0 Scaron;0160 Scarondotaccent;1E66 Scaronsmall;F6FD Scedilla;015E Schwa;018F Schwacyrillic;04D8 Schwadieresiscyrillic;04DA Scircle;24C8 Scircumflex;015C Scommaaccent;0218 Sdotaccent;1E60 Sdotbelow;1E62 Sdotbelowdotaccent;1E68 Seharmenian;054D Sevenroman;2166 Shaarmenian;0547 Shacyrillic;0428 Shchacyrillic;0429 Sheicoptic;03E2 Shhacyrillic;04BA Shimacoptic;03EC Sigma;03A3 Sixroman;2165 Smonospace;FF33 Softsigncyrillic;042C Ssmall;F773 Stigmagreek;03DA T;0054 Tau;03A4 Tbar;0166 Tcaron;0164 Tcedilla;0162 Tcircle;24C9 Tcircumflexbelow;1E70 Tcommaaccent;0162 Tdotaccent;1E6A Tdotbelow;1E6C Tecyrillic;0422 Tedescendercyrillic;04AC Tenroman;2169 Tetsecyrillic;04B4 Theta;0398 Thook;01AC Thorn;00DE Thornsmall;F7FE Threeroman;2162 Tildesmall;F6FE Tiwnarmenian;054F Tlinebelow;1E6E Tmonospace;FF34 Toarmenian;0539 Tonefive;01BC Tonesix;0184 Tonetwo;01A7 Tretroflexhook;01AE Tsecyrillic;0426 Tshecyrillic;040B Tsmall;F774 Twelveroman;216B Tworoman;2161 U;0055 Uacute;00DA Uacutesmall;F7FA Ubreve;016C Ucaron;01D3 Ucircle;24CA Ucircumflex;00DB Ucircumflexbelow;1E76 Ucircumflexsmall;F7FB Ucyrillic;0423 Udblacute;0170 Udblgrave;0214 Udieresis;00DC Udieresisacute;01D7 Udieresisbelow;1E72 Udieresiscaron;01D9 Udieresiscyrillic;04F0 Udieresisgrave;01DB Udieresismacron;01D5 Udieresissmall;F7FC Udotbelow;1EE4 Ugrave;00D9 Ugravesmall;F7F9 Uhookabove;1EE6 Uhorn;01AF Uhornacute;1EE8 Uhorndotbelow;1EF0 Uhorngrave;1EEA Uhornhookabove;1EEC Uhorntilde;1EEE Uhungarumlaut;0170 Uhungarumlautcyrillic;04F2 Uinvertedbreve;0216 Ukcyrillic;0478 Umacron;016A Umacroncyrillic;04EE Umacrondieresis;1E7A Umonospace;FF35 Uogonek;0172 Upsilon;03A5 Upsilon1;03D2 Upsilonacutehooksymbolgreek;03D3 Upsilonafrican;01B1 Upsilondieresis;03AB Upsilondieresishooksymbolgreek;03D4 Upsilonhooksymbol;03D2 Upsilontonos;038E Uring;016E Ushortcyrillic;040E Usmall;F775 Ustraightcyrillic;04AE Ustraightstrokecyrillic;04B0 Utilde;0168 Utildeacute;1E78 Utildebelow;1E74 V;0056 Vcircle;24CB Vdotbelow;1E7E Vecyrillic;0412 Vewarmenian;054E Vhook;01B2 Vmonospace;FF36 Voarmenian;0548 Vsmall;F776 Vtilde;1E7C W;0057 Wacute;1E82 Wcircle;24CC Wcircumflex;0174 Wdieresis;1E84 Wdotaccent;1E86 Wdotbelow;1E88 Wgrave;1E80 Wmonospace;FF37 Wsmall;F777 X;0058 Xcircle;24CD Xdieresis;1E8C Xdotaccent;1E8A Xeharmenian;053D Xi;039E Xmonospace;FF38 Xsmall;F778 Y;0059 Yacute;00DD Yacutesmall;F7FD Yatcyrillic;0462 Ycircle;24CE Ycircumflex;0176 Ydieresis;0178 Ydieresissmall;F7FF Ydotaccent;1E8E Ydotbelow;1EF4 Yericyrillic;042B Yerudieresiscyrillic;04F8 Ygrave;1EF2 Yhook;01B3 Yhookabove;1EF6 Yiarmenian;0545 Yicyrillic;0407 Yiwnarmenian;0552 Ymonospace;FF39 Ysmall;F779 Ytilde;1EF8 Yusbigcyrillic;046A Yusbigiotifiedcyrillic;046C Yuslittlecyrillic;0466 Yuslittleiotifiedcyrillic;0468 Z;005A Zaarmenian;0536 Zacute;0179 Zcaron;017D Zcaronsmall;F6FF Zcircle;24CF Zcircumflex;1E90 Zdot;017B Zdotaccent;017B Zdotbelow;1E92 Zecyrillic;0417 Zedescendercyrillic;0498 Zedieresiscyrillic;04DE Zeta;0396 Zhearmenian;053A Zhebrevecyrillic;04C1 Zhecyrillic;0416 Zhedescendercyrillic;0496 Zhedieresiscyrillic;04DC Zlinebelow;1E94 Zmonospace;FF3A Zsmall;F77A Zstroke;01B5 a;0061 aabengali;0986 aacute;00E1 aadeva;0906 aagujarati;0A86 aagurmukhi;0A06 aamatragurmukhi;0A3E aarusquare;3303 aavowelsignbengali;09BE aavowelsigndeva;093E aavowelsigngujarati;0ABE abbreviationmarkarmenian;055F abbreviationsigndeva;0970 abengali;0985 abopomofo;311A abreve;0103 abreveacute;1EAF abrevecyrillic;04D1 abrevedotbelow;1EB7 abrevegrave;1EB1 abrevehookabove;1EB3 abrevetilde;1EB5 acaron;01CE acircle;24D0 acircumflex;00E2 acircumflexacute;1EA5 acircumflexdotbelow;1EAD acircumflexgrave;1EA7 acircumflexhookabove;1EA9 acircumflextilde;1EAB acute;00B4 acutebelowcmb;0317 acutecmb;0301 acutecomb;0301 acutedeva;0954 acutelowmod;02CF acutetonecmb;0341 acyrillic;0430 adblgrave;0201 addakgurmukhi;0A71 adeva;0905 adieresis;00E4 adieresiscyrillic;04D3 adieresismacron;01DF adotbelow;1EA1 adotmacron;01E1 ae;00E6 aeacute;01FD aekorean;3150 aemacron;01E3 afii00208;2015 afii08941;20A4 afii10017;0410 afii10018;0411 afii10019;0412 afii10020;0413 afii10021;0414 afii10022;0415 afii10023;0401 afii10024;0416 afii10025;0417 afii10026;0418 afii10027;0419 afii10028;041A afii10029;041B afii10030;041C afii10031;041D afii10032;041E afii10033;041F afii10034;0420 afii10035;0421 afii10036;0422 afii10037;0423 afii10038;0424 afii10039;0425 afii10040;0426 afii10041;0427 afii10042;0428 afii10043;0429 afii10044;042A afii10045;042B afii10046;042C afii10047;042D afii10048;042E afii10049;042F afii10050;0490 afii10051;0402 afii10052;0403 afii10053;0404 afii10054;0405 afii10055;0406 afii10056;0407 afii10057;0408 afii10058;0409 afii10059;040A afii10060;040B afii10061;040C afii10062;040E afii10063;F6C4 afii10064;F6C5 afii10065;0430 afii10066;0431 afii10067;0432 afii10068;0433 afii10069;0434 afii10070;0435 afii10071;0451 afii10072;0436 afii10073;0437 afii10074;0438 afii10075;0439 afii10076;043A afii10077;043B afii10078;043C afii10079;043D afii10080;043E afii10081;043F afii10082;0440 afii10083;0441 afii10084;0442 afii10085;0443 afii10086;0444 afii10087;0445 afii10088;0446 afii10089;0447 afii10090;0448 afii10091;0449 afii10092;044A afii10093;044B afii10094;044C afii10095;044D afii10096;044E afii10097;044F afii10098;0491 afii10099;0452 afii10100;0453 afii10101;0454 afii10102;0455 afii10103;0456 afii10104;0457 afii10105;0458 afii10106;0459 afii10107;045A afii10108;045B afii10109;045C afii10110;045E afii10145;040F afii10146;0462 afii10147;0472 afii10148;0474 afii10192;F6C6 afii10193;045F afii10194;0463 afii10195;0473 afii10196;0475 afii10831;F6C7 afii10832;F6C8 afii10846;04D9 afii299;200E afii300;200F afii301;200D afii57381;066A afii57388;060C afii57392;0660 afii57393;0661 afii57394;0662 afii57395;0663 afii57396;0664 afii57397;0665 afii57398;0666 afii57399;0667 afii57400;0668 afii57401;0669 afii57403;061B afii57407;061F afii57409;0621 afii57410;0622 afii57411;0623 afii57412;0624 afii57413;0625 afii57414;0626 afii57415;0627 afii57416;0628 afii57417;0629 afii57418;062A afii57419;062B afii57420;062C afii57421;062D afii57422;062E afii57423;062F afii57424;0630 afii57425;0631 afii57426;0632 afii57427;0633 afii57428;0634 afii57429;0635 afii57430;0636 afii57431;0637 afii57432;0638 afii57433;0639 afii57434;063A afii57440;0640 afii57441;0641 afii57442;0642 afii57443;0643 afii57444;0644 afii57445;0645 afii57446;0646 afii57448;0648 afii57449;0649 afii57450;064A afii57451;064B afii57452;064C afii57453;064D afii57454;064E afii57455;064F afii57456;0650 afii57457;0651 afii57458;0652 afii57470;0647 afii57505;06A4 afii57506;067E afii57507;0686 afii57508;0698 afii57509;06AF afii57511;0679 afii57512;0688 afii57513;0691 afii57514;06BA afii57519;06D2 afii57534;06D5 afii57636;20AA afii57645;05BE afii57658;05C3 afii57664;05D0 afii57665;05D1 afii57666;05D2 afii57667;05D3 afii57668;05D4 afii57669;05D5 afii57670;05D6 afii57671;05D7 afii57672;05D8 afii57673;05D9 afii57674;05DA afii57675;05DB afii57676;05DC afii57677;05DD afii57678;05DE afii57679;05DF afii57680;05E0 afii57681;05E1 afii57682;05E2 afii57683;05E3 afii57684;05E4 afii57685;05E5 afii57686;05E6 afii57687;05E7 afii57688;05E8 afii57689;05E9 afii57690;05EA afii57694;FB2A afii57695;FB2B afii57700;FB4B afii57705;FB1F afii57716;05F0 afii57717;05F1 afii57718;05F2 afii57723;FB35 afii57793;05B4 afii57794;05B5 afii57795;05B6 afii57796;05BB afii57797;05B8 afii57798;05B7 afii57799;05B0 afii57800;05B2 afii57801;05B1 afii57802;05B3 afii57803;05C2 afii57804;05C1 afii57806;05B9 afii57807;05BC afii57839;05BD afii57841;05BF afii57842;05C0 afii57929;02BC afii61248;2105 afii61289;2113 afii61352;2116 afii61573;202C afii61574;202D afii61575;202E afii61664;200C afii63167;066D afii64937;02BD agrave;00E0 agujarati;0A85 agurmukhi;0A05 ahiragana;3042 ahookabove;1EA3 aibengali;0990 aibopomofo;311E aideva;0910 aiecyrillic;04D5 aigujarati;0A90 aigurmukhi;0A10 aimatragurmukhi;0A48 ainarabic;0639 ainfinalarabic;FECA aininitialarabic;FECB ainmedialarabic;FECC ainvertedbreve;0203 aivowelsignbengali;09C8 aivowelsigndeva;0948 aivowelsigngujarati;0AC8 akatakana;30A2 akatakanahalfwidth;FF71 akorean;314F alef;05D0 alefarabic;0627 alefdageshhebrew;FB30 aleffinalarabic;FE8E alefhamzaabovearabic;0623 alefhamzaabovefinalarabic;FE84 alefhamzabelowarabic;0625 alefhamzabelowfinalarabic;FE88 alefhebrew;05D0 aleflamedhebrew;FB4F alefmaddaabovearabic;0622 alefmaddaabovefinalarabic;FE82 alefmaksuraarabic;0649 alefmaksurafinalarabic;FEF0 alefmaksurainitialarabic;FEF3 alefmaksuramedialarabic;FEF4 alefpatahhebrew;FB2E alefqamatshebrew;FB2F aleph;2135 allequal;224C alpha;03B1 alphatonos;03AC amacron;0101 amonospace;FF41 ampersand;0026 ampersandmonospace;FF06 ampersandsmall;F726 amsquare;33C2 anbopomofo;3122 angbopomofo;3124 angkhankhuthai;0E5A angle;2220 anglebracketleft;3008 anglebracketleftvertical;FE3F anglebracketright;3009 anglebracketrightvertical;FE40 angleleft;2329 angleright;232A angstrom;212B anoteleia;0387 anudattadeva;0952 anusvarabengali;0982 anusvaradeva;0902 anusvaragujarati;0A82 aogonek;0105 apaatosquare;3300 aparen;249C apostrophearmenian;055A apostrophemod;02BC apple;F8FF approaches;2250 approxequal;2248 approxequalorimage;2252 approximatelyequal;2245 araeaekorean;318E araeakorean;318D arc;2312 arighthalfring;1E9A aring;00E5 aringacute;01FB aringbelow;1E01 arrowboth;2194 arrowdashdown;21E3 arrowdashleft;21E0 arrowdashright;21E2 arrowdashup;21E1 arrowdblboth;21D4 arrowdbldown;21D3 arrowdblleft;21D0 arrowdblright;21D2 arrowdblup;21D1 arrowdown;2193 arrowdownleft;2199 arrowdownright;2198 arrowdownwhite;21E9 arrowheaddownmod;02C5 arrowheadleftmod;02C2 arrowheadrightmod;02C3 arrowheadupmod;02C4 arrowhorizex;F8E7 arrowleft;2190 arrowleftdbl;21D0 arrowleftdblstroke;21CD arrowleftoverright;21C6 arrowleftwhite;21E6 arrowright;2192 arrowrightdblstroke;21CF arrowrightheavy;279E arrowrightoverleft;21C4 arrowrightwhite;21E8 arrowtableft;21E4 arrowtabright;21E5 arrowup;2191 arrowupdn;2195 arrowupdnbse;21A8 arrowupdownbase;21A8 arrowupleft;2196 arrowupleftofdown;21C5 arrowupright;2197 arrowupwhite;21E7 arrowvertex;F8E6 asciicircum;005E asciicircummonospace;FF3E asciitilde;007E asciitildemonospace;FF5E ascript;0251 ascriptturned;0252 asmallhiragana;3041 asmallkatakana;30A1 asmallkatakanahalfwidth;FF67 asterisk;002A asteriskaltonearabic;066D asteriskarabic;066D asteriskmath;2217 asteriskmonospace;FF0A asterisksmall;FE61 asterism;2042 asuperior;F6E9 asymptoticallyequal;2243 at;0040 atilde;00E3 atmonospace;FF20 atsmall;FE6B aturned;0250 aubengali;0994 aubopomofo;3120 audeva;0914 augujarati;0A94 augurmukhi;0A14 aulengthmarkbengali;09D7 aumatragurmukhi;0A4C auvowelsignbengali;09CC auvowelsigndeva;094C auvowelsigngujarati;0ACC avagrahadeva;093D aybarmenian;0561 ayin;05E2 ayinaltonehebrew;FB20 ayinhebrew;05E2 b;0062 babengali;09AC backslash;005C backslashmonospace;FF3C badeva;092C bagujarati;0AAC bagurmukhi;0A2C bahiragana;3070 bahtthai;0E3F bakatakana;30D0 bar;007C barmonospace;FF5C bbopomofo;3105 bcircle;24D1 bdotaccent;1E03 bdotbelow;1E05 beamedsixteenthnotes;266C because;2235 becyrillic;0431 beharabic;0628 behfinalarabic;FE90 behinitialarabic;FE91 behiragana;3079 behmedialarabic;FE92 behmeeminitialarabic;FC9F behmeemisolatedarabic;FC08 behnoonfinalarabic;FC6D bekatakana;30D9 benarmenian;0562 bet;05D1 beta;03B2 betasymbolgreek;03D0 betdagesh;FB31 betdageshhebrew;FB31 bethebrew;05D1 betrafehebrew;FB4C bhabengali;09AD bhadeva;092D bhagujarati;0AAD bhagurmukhi;0A2D bhook;0253 bihiragana;3073 bikatakana;30D3 bilabialclick;0298 bindigurmukhi;0A02 birusquare;3331 blackcircle;25CF blackdiamond;25C6 blackdownpointingtriangle;25BC blackleftpointingpointer;25C4 blackleftpointingtriangle;25C0 blacklenticularbracketleft;3010 blacklenticularbracketleftvertical;FE3B blacklenticularbracketright;3011 blacklenticularbracketrightvertical;FE3C blacklowerlefttriangle;25E3 blacklowerrighttriangle;25E2 blackrectangle;25AC blackrightpointingpointer;25BA blackrightpointingtriangle;25B6 blacksmallsquare;25AA blacksmilingface;263B blacksquare;25A0 blackstar;2605 blackupperlefttriangle;25E4 blackupperrighttriangle;25E5 blackuppointingsmalltriangle;25B4 blackuppointingtriangle;25B2 blank;2423 blinebelow;1E07 block;2588 bmonospace;FF42 bobaimaithai;0E1A bohiragana;307C bokatakana;30DC bparen;249D bqsquare;33C3 braceex;F8F4 braceleft;007B braceleftbt;F8F3 braceleftmid;F8F2 braceleftmonospace;FF5B braceleftsmall;FE5B bracelefttp;F8F1 braceleftvertical;FE37 braceright;007D bracerightbt;F8FE bracerightmid;F8FD bracerightmonospace;FF5D bracerightsmall;FE5C bracerighttp;F8FC bracerightvertical;FE38 bracketleft;005B bracketleftbt;F8F0 bracketleftex;F8EF bracketleftmonospace;FF3B bracketlefttp;F8EE bracketright;005D bracketrightbt;F8FB bracketrightex;F8FA bracketrightmonospace;FF3D bracketrighttp;F8F9 breve;02D8 brevebelowcmb;032E brevecmb;0306 breveinvertedbelowcmb;032F breveinvertedcmb;0311 breveinverteddoublecmb;0361 bridgebelowcmb;032A bridgeinvertedbelowcmb;033A brokenbar;00A6 bstroke;0180 bsuperior;F6EA btopbar;0183 buhiragana;3076 bukatakana;30D6 bullet;2022 bulletinverse;25D8 bulletoperator;2219 bullseye;25CE c;0063 caarmenian;056E cabengali;099A cacute;0107 cadeva;091A cagujarati;0A9A cagurmukhi;0A1A calsquare;3388 candrabindubengali;0981 candrabinducmb;0310 candrabindudeva;0901 candrabindugujarati;0A81 capslock;21EA careof;2105 caron;02C7 caronbelowcmb;032C caroncmb;030C carriagereturn;21B5 cbopomofo;3118 ccaron;010D ccedilla;00E7 ccedillaacute;1E09 ccircle;24D2 ccircumflex;0109 ccurl;0255 cdot;010B cdotaccent;010B cdsquare;33C5 cedilla;00B8 cedillacmb;0327 cent;00A2 centigrade;2103 centinferior;F6DF centmonospace;FFE0 centoldstyle;F7A2 centsuperior;F6E0 chaarmenian;0579 chabengali;099B chadeva;091B chagujarati;0A9B chagurmukhi;0A1B chbopomofo;3114 cheabkhasiancyrillic;04BD checkmark;2713 checyrillic;0447 chedescenderabkhasiancyrillic;04BF chedescendercyrillic;04B7 chedieresiscyrillic;04F5 cheharmenian;0573 chekhakassiancyrillic;04CC cheverticalstrokecyrillic;04B9 chi;03C7 chieuchacirclekorean;3277 chieuchaparenkorean;3217 chieuchcirclekorean;3269 chieuchkorean;314A chieuchparenkorean;3209 chochangthai;0E0A chochanthai;0E08 chochingthai;0E09 chochoethai;0E0C chook;0188 cieucacirclekorean;3276 cieucaparenkorean;3216 cieuccirclekorean;3268 cieuckorean;3148 cieucparenkorean;3208 cieucuparenkorean;321C circle;25CB circlemultiply;2297 circleot;2299 circleplus;2295 circlepostalmark;3036 circlewithlefthalfblack;25D0 circlewithrighthalfblack;25D1 circumflex;02C6 circumflexbelowcmb;032D circumflexcmb;0302 clear;2327 clickalveolar;01C2 clickdental;01C0 clicklateral;01C1 clickretroflex;01C3 club;2663 clubsuitblack;2663 clubsuitwhite;2667 cmcubedsquare;33A4 cmonospace;FF43 cmsquaredsquare;33A0 coarmenian;0581 colon;003A colonmonetary;20A1 colonmonospace;FF1A colonsign;20A1 colonsmall;FE55 colontriangularhalfmod;02D1 colontriangularmod;02D0 comma;002C commaabovecmb;0313 commaaboverightcmb;0315 commaaccent;F6C3 commaarabic;060C commaarmenian;055D commainferior;F6E1 commamonospace;FF0C commareversedabovecmb;0314 commareversedmod;02BD commasmall;FE50 commasuperior;F6E2 commaturnedabovecmb;0312 commaturnedmod;02BB compass;263C congruent;2245 contourintegral;222E control;2303 controlACK;0006 controlBEL;0007 controlBS;0008 controlCAN;0018 controlCR;000D controlDC1;0011 controlDC2;0012 controlDC3;0013 controlDC4;0014 controlDEL;007F controlDLE;0010 controlEM;0019 controlENQ;0005 controlEOT;0004 controlESC;001B controlETB;0017 controlETX;0003 controlFF;000C controlFS;001C controlGS;001D controlHT;0009 controlLF;000A controlNAK;0015 controlRS;001E controlSI;000F controlSO;000E controlSOT;0002 controlSTX;0001 controlSUB;001A controlSYN;0016 controlUS;001F controlVT;000B copyright;00A9 copyrightsans;F8E9 copyrightserif;F6D9 cornerbracketleft;300C cornerbracketlefthalfwidth;FF62 cornerbracketleftvertical;FE41 cornerbracketright;300D cornerbracketrighthalfwidth;FF63 cornerbracketrightvertical;FE42 corporationsquare;337F cosquare;33C7 coverkgsquare;33C6 cparen;249E cruzeiro;20A2 cstretched;0297 curlyand;22CF curlyor;22CE currency;00A4 cyrBreve;F6D1 cyrFlex;F6D2 cyrbreve;F6D4 cyrflex;F6D5 d;0064 daarmenian;0564 dabengali;09A6 dadarabic;0636 dadeva;0926 dadfinalarabic;FEBE dadinitialarabic;FEBF dadmedialarabic;FEC0 dagesh;05BC dageshhebrew;05BC dagger;2020 daggerdbl;2021 dagujarati;0AA6 dagurmukhi;0A26 dahiragana;3060 dakatakana;30C0 dalarabic;062F dalet;05D3 daletdagesh;FB33 daletdageshhebrew;FB33 dalethatafpatah;05D3 05B2 dalethatafpatahhebrew;05D3 05B2 dalethatafsegol;05D3 05B1 dalethatafsegolhebrew;05D3 05B1 dalethebrew;05D3 dalethiriq;05D3 05B4 dalethiriqhebrew;05D3 05B4 daletholam;05D3 05B9 daletholamhebrew;05D3 05B9 daletpatah;05D3 05B7 daletpatahhebrew;05D3 05B7 daletqamats;05D3 05B8 daletqamatshebrew;05D3 05B8 daletqubuts;05D3 05BB daletqubutshebrew;05D3 05BB daletsegol;05D3 05B6 daletsegolhebrew;05D3 05B6 daletsheva;05D3 05B0 daletshevahebrew;05D3 05B0 dalettsere;05D3 05B5 dalettserehebrew;05D3 05B5 dalfinalarabic;FEAA dammaarabic;064F dammalowarabic;064F dammatanaltonearabic;064C dammatanarabic;064C danda;0964 dargahebrew;05A7 dargalefthebrew;05A7 dasiapneumatacyrilliccmb;0485 dblGrave;F6D3 dblanglebracketleft;300A dblanglebracketleftvertical;FE3D dblanglebracketright;300B dblanglebracketrightvertical;FE3E dblarchinvertedbelowcmb;032B dblarrowleft;21D4 dblarrowright;21D2 dbldanda;0965 dblgrave;F6D6 dblgravecmb;030F dblintegral;222C dbllowline;2017 dbllowlinecmb;0333 dbloverlinecmb;033F dblprimemod;02BA dblverticalbar;2016 dblverticallineabovecmb;030E dbopomofo;3109 dbsquare;33C8 dcaron;010F dcedilla;1E11 dcircle;24D3 dcircumflexbelow;1E13 dcroat;0111 ddabengali;09A1 ddadeva;0921 ddagujarati;0AA1 ddagurmukhi;0A21 ddalarabic;0688 ddalfinalarabic;FB89 dddhadeva;095C ddhabengali;09A2 ddhadeva;0922 ddhagujarati;0AA2 ddhagurmukhi;0A22 ddotaccent;1E0B ddotbelow;1E0D decimalseparatorarabic;066B decimalseparatorpersian;066B decyrillic;0434 degree;00B0 dehihebrew;05AD dehiragana;3067 deicoptic;03EF dekatakana;30C7 deleteleft;232B deleteright;2326 delta;03B4 deltaturned;018D denominatorminusonenumeratorbengali;09F8 dezh;02A4 dhabengali;09A7 dhadeva;0927 dhagujarati;0AA7 dhagurmukhi;0A27 dhook;0257 dialytikatonos;0385 dialytikatonoscmb;0344 diamond;2666 diamondsuitwhite;2662 dieresis;00A8 dieresisacute;F6D7 dieresisbelowcmb;0324 dieresiscmb;0308 dieresisgrave;F6D8 dieresistonos;0385 dihiragana;3062 dikatakana;30C2 dittomark;3003 divide;00F7 divides;2223 divisionslash;2215 djecyrillic;0452 dkshade;2593 dlinebelow;1E0F dlsquare;3397 dmacron;0111 dmonospace;FF44 dnblock;2584 dochadathai;0E0E dodekthai;0E14 dohiragana;3069 dokatakana;30C9 dollar;0024 dollarinferior;F6E3 dollarmonospace;FF04 dollaroldstyle;F724 dollarsmall;FE69 dollarsuperior;F6E4 dong;20AB dorusquare;3326 dotaccent;02D9 dotaccentcmb;0307 dotbelowcmb;0323 dotbelowcomb;0323 dotkatakana;30FB dotlessi;0131 dotlessj;F6BE dotlessjstrokehook;0284 dotmath;22C5 dottedcircle;25CC doubleyodpatah;FB1F doubleyodpatahhebrew;FB1F downtackbelowcmb;031E downtackmod;02D5 dparen;249F dsuperior;F6EB dtail;0256 dtopbar;018C duhiragana;3065 dukatakana;30C5 dz;01F3 dzaltone;02A3 dzcaron;01C6 dzcurl;02A5 dzeabkhasiancyrillic;04E1 dzecyrillic;0455 dzhecyrillic;045F e;0065 eacute;00E9 earth;2641 ebengali;098F ebopomofo;311C ebreve;0115 ecandradeva;090D ecandragujarati;0A8D ecandravowelsigndeva;0945 ecandravowelsigngujarati;0AC5 ecaron;011B ecedillabreve;1E1D echarmenian;0565 echyiwnarmenian;0587 ecircle;24D4 ecircumflex;00EA ecircumflexacute;1EBF ecircumflexbelow;1E19 ecircumflexdotbelow;1EC7 ecircumflexgrave;1EC1 ecircumflexhookabove;1EC3 ecircumflextilde;1EC5 ecyrillic;0454 edblgrave;0205 edeva;090F edieresis;00EB edot;0117 edotaccent;0117 edotbelow;1EB9 eegurmukhi;0A0F eematragurmukhi;0A47 efcyrillic;0444 egrave;00E8 egujarati;0A8F eharmenian;0567 ehbopomofo;311D ehiragana;3048 ehookabove;1EBB eibopomofo;311F eight;0038 eightarabic;0668 eightbengali;09EE eightcircle;2467 eightcircleinversesansserif;2791 eightdeva;096E eighteencircle;2471 eighteenparen;2485 eighteenperiod;2499 eightgujarati;0AEE eightgurmukhi;0A6E eighthackarabic;0668 eighthangzhou;3028 eighthnotebeamed;266B eightideographicparen;3227 eightinferior;2088 eightmonospace;FF18 eightoldstyle;F738 eightparen;247B eightperiod;248F eightpersian;06F8 eightroman;2177 eightsuperior;2078 eightthai;0E58 einvertedbreve;0207 eiotifiedcyrillic;0465 ekatakana;30A8 ekatakanahalfwidth;FF74 ekonkargurmukhi;0A74 ekorean;3154 elcyrillic;043B element;2208 elevencircle;246A elevenparen;247E elevenperiod;2492 elevenroman;217A ellipsis;2026 ellipsisvertical;22EE emacron;0113 emacronacute;1E17 emacrongrave;1E15 emcyrillic;043C emdash;2014 emdashvertical;FE31 emonospace;FF45 emphasismarkarmenian;055B emptyset;2205 enbopomofo;3123 encyrillic;043D endash;2013 endashvertical;FE32 endescendercyrillic;04A3 eng;014B engbopomofo;3125 enghecyrillic;04A5 enhookcyrillic;04C8 enspace;2002 eogonek;0119 eokorean;3153 eopen;025B eopenclosed;029A eopenreversed;025C eopenreversedclosed;025E eopenreversedhook;025D eparen;24A0 epsilon;03B5 epsilontonos;03AD equal;003D equalmonospace;FF1D equalsmall;FE66 equalsuperior;207C equivalence;2261 erbopomofo;3126 ercyrillic;0440 ereversed;0258 ereversedcyrillic;044D escyrillic;0441 esdescendercyrillic;04AB esh;0283 eshcurl;0286 eshortdeva;090E eshortvowelsigndeva;0946 eshreversedloop;01AA eshsquatreversed;0285 esmallhiragana;3047 esmallkatakana;30A7 esmallkatakanahalfwidth;FF6A estimated;212E esuperior;F6EC eta;03B7 etarmenian;0568 etatonos;03AE eth;00F0 etilde;1EBD etildebelow;1E1B etnahtafoukhhebrew;0591 etnahtafoukhlefthebrew;0591 etnahtahebrew;0591 etnahtalefthebrew;0591 eturned;01DD eukorean;3161 euro;20AC evowelsignbengali;09C7 evowelsigndeva;0947 evowelsigngujarati;0AC7 exclam;0021 exclamarmenian;055C exclamdbl;203C exclamdown;00A1 exclamdownsmall;F7A1 exclammonospace;FF01 exclamsmall;F721 existential;2203 ezh;0292 ezhcaron;01EF ezhcurl;0293 ezhreversed;01B9 ezhtail;01BA f;0066 fadeva;095E fagurmukhi;0A5E fahrenheit;2109 fathaarabic;064E fathalowarabic;064E fathatanarabic;064B fbopomofo;3108 fcircle;24D5 fdotaccent;1E1F feharabic;0641 feharmenian;0586 fehfinalarabic;FED2 fehinitialarabic;FED3 fehmedialarabic;FED4 feicoptic;03E5 female;2640 ff;FB00 ffi;FB03 ffl;FB04 fi;FB01 fifteencircle;246E fifteenparen;2482 fifteenperiod;2496 figuredash;2012 filledbox;25A0 filledrect;25AC finalkaf;05DA finalkafdagesh;FB3A finalkafdageshhebrew;FB3A finalkafhebrew;05DA finalkafqamats;05DA 05B8 finalkafqamatshebrew;05DA 05B8 finalkafsheva;05DA 05B0 finalkafshevahebrew;05DA 05B0 finalmem;05DD finalmemhebrew;05DD finalnun;05DF finalnunhebrew;05DF finalpe;05E3 finalpehebrew;05E3 finaltsadi;05E5 finaltsadihebrew;05E5 firsttonechinese;02C9 fisheye;25C9 fitacyrillic;0473 five;0035 fivearabic;0665 fivebengali;09EB fivecircle;2464 fivecircleinversesansserif;278E fivedeva;096B fiveeighths;215D fivegujarati;0AEB fivegurmukhi;0A6B fivehackarabic;0665 fivehangzhou;3025 fiveideographicparen;3224 fiveinferior;2085 fivemonospace;FF15 fiveoldstyle;F735 fiveparen;2478 fiveperiod;248C fivepersian;06F5 fiveroman;2174 fivesuperior;2075 fivethai;0E55 fl;FB02 florin;0192 fmonospace;FF46 fmsquare;3399 fofanthai;0E1F fofathai;0E1D fongmanthai;0E4F forall;2200 four;0034 fourarabic;0664 fourbengali;09EA fourcircle;2463 fourcircleinversesansserif;278D fourdeva;096A fourgujarati;0AEA fourgurmukhi;0A6A fourhackarabic;0664 fourhangzhou;3024 fourideographicparen;3223 fourinferior;2084 fourmonospace;FF14 fournumeratorbengali;09F7 fouroldstyle;F734 fourparen;2477 fourperiod;248B fourpersian;06F4 fourroman;2173 foursuperior;2074 fourteencircle;246D fourteenparen;2481 fourteenperiod;2495 fourthai;0E54 fourthtonechinese;02CB fparen;24A1 fraction;2044 franc;20A3 g;0067 gabengali;0997 gacute;01F5 gadeva;0917 gafarabic;06AF gaffinalarabic;FB93 gafinitialarabic;FB94 gafmedialarabic;FB95 gagujarati;0A97 gagurmukhi;0A17 gahiragana;304C gakatakana;30AC gamma;03B3 gammalatinsmall;0263 gammasuperior;02E0 gangiacoptic;03EB gbopomofo;310D gbreve;011F gcaron;01E7 gcedilla;0123 gcircle;24D6 gcircumflex;011D gcommaaccent;0123 gdot;0121 gdotaccent;0121 gecyrillic;0433 gehiragana;3052 gekatakana;30B2 geometricallyequal;2251 gereshaccenthebrew;059C gereshhebrew;05F3 gereshmuqdamhebrew;059D germandbls;00DF gershayimaccenthebrew;059E gershayimhebrew;05F4 getamark;3013 ghabengali;0998 ghadarmenian;0572 ghadeva;0918 ghagujarati;0A98 ghagurmukhi;0A18 ghainarabic;063A ghainfinalarabic;FECE ghaininitialarabic;FECF ghainmedialarabic;FED0 ghemiddlehookcyrillic;0495 ghestrokecyrillic;0493 gheupturncyrillic;0491 ghhadeva;095A ghhagurmukhi;0A5A ghook;0260 ghzsquare;3393 gihiragana;304E gikatakana;30AE gimarmenian;0563 gimel;05D2 gimeldagesh;FB32 gimeldageshhebrew;FB32 gimelhebrew;05D2 gjecyrillic;0453 glottalinvertedstroke;01BE glottalstop;0294 glottalstopinverted;0296 glottalstopmod;02C0 glottalstopreversed;0295 glottalstopreversedmod;02C1 glottalstopreversedsuperior;02E4 glottalstopstroke;02A1 glottalstopstrokereversed;02A2 gmacron;1E21 gmonospace;FF47 gohiragana;3054 gokatakana;30B4 gparen;24A2 gpasquare;33AC gradient;2207 grave;0060 gravebelowcmb;0316 gravecmb;0300 gravecomb;0300 gravedeva;0953 gravelowmod;02CE gravemonospace;FF40 gravetonecmb;0340 greater;003E greaterequal;2265 greaterequalorless;22DB greatermonospace;FF1E greaterorequivalent;2273 greaterorless;2277 greateroverequal;2267 greatersmall;FE65 gscript;0261 gstroke;01E5 guhiragana;3050 guillemotleft;00AB guillemotright;00BB guilsinglleft;2039 guilsinglright;203A gukatakana;30B0 guramusquare;3318 gysquare;33C9 h;0068 haabkhasiancyrillic;04A9 haaltonearabic;06C1 habengali;09B9 hadescendercyrillic;04B3 hadeva;0939 hagujarati;0AB9 hagurmukhi;0A39 haharabic;062D hahfinalarabic;FEA2 hahinitialarabic;FEA3 hahiragana;306F hahmedialarabic;FEA4 haitusquare;332A hakatakana;30CF hakatakanahalfwidth;FF8A halantgurmukhi;0A4D hamzaarabic;0621 hamzadammaarabic;0621 064F hamzadammatanarabic;0621 064C hamzafathaarabic;0621 064E hamzafathatanarabic;0621 064B hamzalowarabic;0621 hamzalowkasraarabic;0621 0650 hamzalowkasratanarabic;0621 064D hamzasukunarabic;0621 0652 hangulfiller;3164 hardsigncyrillic;044A harpoonleftbarbup;21BC harpoonrightbarbup;21C0 hasquare;33CA hatafpatah;05B2 hatafpatah16;05B2 hatafpatah23;05B2 hatafpatah2f;05B2 hatafpatahhebrew;05B2 hatafpatahnarrowhebrew;05B2 hatafpatahquarterhebrew;05B2 hatafpatahwidehebrew;05B2 hatafqamats;05B3 hatafqamats1b;05B3 hatafqamats28;05B3 hatafqamats34;05B3 hatafqamatshebrew;05B3 hatafqamatsnarrowhebrew;05B3 hatafqamatsquarterhebrew;05B3 hatafqamatswidehebrew;05B3 hatafsegol;05B1 hatafsegol17;05B1 hatafsegol24;05B1 hatafsegol30;05B1 hatafsegolhebrew;05B1 hatafsegolnarrowhebrew;05B1 hatafsegolquarterhebrew;05B1 hatafsegolwidehebrew;05B1 hbar;0127 hbopomofo;310F hbrevebelow;1E2B hcedilla;1E29 hcircle;24D7 hcircumflex;0125 hdieresis;1E27 hdotaccent;1E23 hdotbelow;1E25 he;05D4 heart;2665 heartsuitblack;2665 heartsuitwhite;2661 hedagesh;FB34 hedageshhebrew;FB34 hehaltonearabic;06C1 heharabic;0647 hehebrew;05D4 hehfinalaltonearabic;FBA7 hehfinalalttwoarabic;FEEA hehfinalarabic;FEEA hehhamzaabovefinalarabic;FBA5 hehhamzaaboveisolatedarabic;FBA4 hehinitialaltonearabic;FBA8 hehinitialarabic;FEEB hehiragana;3078 hehmedialaltonearabic;FBA9 hehmedialarabic;FEEC heiseierasquare;337B hekatakana;30D8 hekatakanahalfwidth;FF8D hekutaarusquare;3336 henghook;0267 herutusquare;3339 het;05D7 hethebrew;05D7 hhook;0266 hhooksuperior;02B1 hieuhacirclekorean;327B hieuhaparenkorean;321B hieuhcirclekorean;326D hieuhkorean;314E hieuhparenkorean;320D hihiragana;3072 hikatakana;30D2 hikatakanahalfwidth;FF8B hiriq;05B4 hiriq14;05B4 hiriq21;05B4 hiriq2d;05B4 hiriqhebrew;05B4 hiriqnarrowhebrew;05B4 hiriqquarterhebrew;05B4 hiriqwidehebrew;05B4 hlinebelow;1E96 hmonospace;FF48 hoarmenian;0570 hohipthai;0E2B hohiragana;307B hokatakana;30DB hokatakanahalfwidth;FF8E holam;05B9 holam19;05B9 holam26;05B9 holam32;05B9 holamhebrew;05B9 holamnarrowhebrew;05B9 holamquarterhebrew;05B9 holamwidehebrew;05B9 honokhukthai;0E2E hookabovecomb;0309 hookcmb;0309 hookpalatalizedbelowcmb;0321 hookretroflexbelowcmb;0322 hoonsquare;3342 horicoptic;03E9 horizontalbar;2015 horncmb;031B hotsprings;2668 house;2302 hparen;24A3 hsuperior;02B0 hturned;0265 huhiragana;3075 huiitosquare;3333 hukatakana;30D5 hukatakanahalfwidth;FF8C hungarumlaut;02DD hungarumlautcmb;030B hv;0195 hyphen;002D hypheninferior;F6E5 hyphenmonospace;FF0D hyphensmall;FE63 hyphensuperior;F6E6 hyphentwo;2010 i;0069 iacute;00ED iacyrillic;044F ibengali;0987 ibopomofo;3127 ibreve;012D icaron;01D0 icircle;24D8 icircumflex;00EE icyrillic;0456 idblgrave;0209 ideographearthcircle;328F ideographfirecircle;328B ideographicallianceparen;323F ideographiccallparen;323A ideographiccentrecircle;32A5 ideographicclose;3006 ideographiccomma;3001 ideographiccommaleft;FF64 ideographiccongratulationparen;3237 ideographiccorrectcircle;32A3 ideographicearthparen;322F ideographicenterpriseparen;323D ideographicexcellentcircle;329D ideographicfestivalparen;3240 ideographicfinancialcircle;3296 ideographicfinancialparen;3236 ideographicfireparen;322B ideographichaveparen;3232 ideographichighcircle;32A4 ideographiciterationmark;3005 ideographiclaborcircle;3298 ideographiclaborparen;3238 ideographicleftcircle;32A7 ideographiclowcircle;32A6 ideographicmedicinecircle;32A9 ideographicmetalparen;322E ideographicmoonparen;322A ideographicnameparen;3234 ideographicperiod;3002 ideographicprintcircle;329E ideographicreachparen;3243 ideographicrepresentparen;3239 ideographicresourceparen;323E ideographicrightcircle;32A8 ideographicsecretcircle;3299 ideographicselfparen;3242 ideographicsocietyparen;3233 ideographicspace;3000 ideographicspecialparen;3235 ideographicstockparen;3231 ideographicstudyparen;323B ideographicsunparen;3230 ideographicsuperviseparen;323C ideographicwaterparen;322C ideographicwoodparen;322D ideographiczero;3007 ideographmetalcircle;328E ideographmooncircle;328A ideographnamecircle;3294 ideographsuncircle;3290 ideographwatercircle;328C ideographwoodcircle;328D ideva;0907 idieresis;00EF idieresisacute;1E2F idieresiscyrillic;04E5 idotbelow;1ECB iebrevecyrillic;04D7 iecyrillic;0435 ieungacirclekorean;3275 ieungaparenkorean;3215 ieungcirclekorean;3267 ieungkorean;3147 ieungparenkorean;3207 igrave;00EC igujarati;0A87 igurmukhi;0A07 ihiragana;3044 ihookabove;1EC9 iibengali;0988 iicyrillic;0438 iideva;0908 iigujarati;0A88 iigurmukhi;0A08 iimatragurmukhi;0A40 iinvertedbreve;020B iishortcyrillic;0439 iivowelsignbengali;09C0 iivowelsigndeva;0940 iivowelsigngujarati;0AC0 ij;0133 ikatakana;30A4 ikatakanahalfwidth;FF72 ikorean;3163 ilde;02DC iluyhebrew;05AC imacron;012B imacroncyrillic;04E3 imageorapproximatelyequal;2253 imatragurmukhi;0A3F imonospace;FF49 increment;2206 infinity;221E iniarmenian;056B integral;222B integralbottom;2321 integralbt;2321 integralex;F8F5 integraltop;2320 integraltp;2320 intersection;2229 intisquare;3305 invbullet;25D8 invcircle;25D9 invsmileface;263B iocyrillic;0451 iogonek;012F iota;03B9 iotadieresis;03CA iotadieresistonos;0390 iotalatin;0269 iotatonos;03AF iparen;24A4 irigurmukhi;0A72 ismallhiragana;3043 ismallkatakana;30A3 ismallkatakanahalfwidth;FF68 issharbengali;09FA istroke;0268 isuperior;F6ED iterationhiragana;309D iterationkatakana;30FD itilde;0129 itildebelow;1E2D iubopomofo;3129 iucyrillic;044E ivowelsignbengali;09BF ivowelsigndeva;093F ivowelsigngujarati;0ABF izhitsacyrillic;0475 izhitsadblgravecyrillic;0477 j;006A jaarmenian;0571 jabengali;099C jadeva;091C jagujarati;0A9C jagurmukhi;0A1C jbopomofo;3110 jcaron;01F0 jcircle;24D9 jcircumflex;0135 jcrossedtail;029D jdotlessstroke;025F jecyrillic;0458 jeemarabic;062C jeemfinalarabic;FE9E jeeminitialarabic;FE9F jeemmedialarabic;FEA0 jeharabic;0698 jehfinalarabic;FB8B jhabengali;099D jhadeva;091D jhagujarati;0A9D jhagurmukhi;0A1D jheharmenian;057B jis;3004 jmonospace;FF4A jparen;24A5 jsuperior;02B2 k;006B kabashkircyrillic;04A1 kabengali;0995 kacute;1E31 kacyrillic;043A kadescendercyrillic;049B kadeva;0915 kaf;05DB kafarabic;0643 kafdagesh;FB3B kafdageshhebrew;FB3B kaffinalarabic;FEDA kafhebrew;05DB kafinitialarabic;FEDB kafmedialarabic;FEDC kafrafehebrew;FB4D kagujarati;0A95 kagurmukhi;0A15 kahiragana;304B kahookcyrillic;04C4 kakatakana;30AB kakatakanahalfwidth;FF76 kappa;03BA kappasymbolgreek;03F0 kapyeounmieumkorean;3171 kapyeounphieuphkorean;3184 kapyeounpieupkorean;3178 kapyeounssangpieupkorean;3179 karoriisquare;330D kashidaautoarabic;0640 kashidaautonosidebearingarabic;0640 kasmallkatakana;30F5 kasquare;3384 kasraarabic;0650 kasratanarabic;064D kastrokecyrillic;049F katahiraprolongmarkhalfwidth;FF70 kaverticalstrokecyrillic;049D kbopomofo;310E kcalsquare;3389 kcaron;01E9 kcedilla;0137 kcircle;24DA kcommaaccent;0137 kdotbelow;1E33 keharmenian;0584 kehiragana;3051 kekatakana;30B1 kekatakanahalfwidth;FF79 kenarmenian;056F kesmallkatakana;30F6 kgreenlandic;0138 khabengali;0996 khacyrillic;0445 khadeva;0916 khagujarati;0A96 khagurmukhi;0A16 khaharabic;062E khahfinalarabic;FEA6 khahinitialarabic;FEA7 khahmedialarabic;FEA8 kheicoptic;03E7 khhadeva;0959 khhagurmukhi;0A59 khieukhacirclekorean;3278 khieukhaparenkorean;3218 khieukhcirclekorean;326A khieukhkorean;314B khieukhparenkorean;320A khokhaithai;0E02 khokhonthai;0E05 khokhuatthai;0E03 khokhwaithai;0E04 khomutthai;0E5B khook;0199 khorakhangthai;0E06 khzsquare;3391 kihiragana;304D kikatakana;30AD kikatakanahalfwidth;FF77 kiroguramusquare;3315 kiromeetorusquare;3316 kirosquare;3314 kiyeokacirclekorean;326E kiyeokaparenkorean;320E kiyeokcirclekorean;3260 kiyeokkorean;3131 kiyeokparenkorean;3200 kiyeoksioskorean;3133 kjecyrillic;045C klinebelow;1E35 klsquare;3398 kmcubedsquare;33A6 kmonospace;FF4B kmsquaredsquare;33A2 kohiragana;3053 kohmsquare;33C0 kokaithai;0E01 kokatakana;30B3 kokatakanahalfwidth;FF7A kooposquare;331E koppacyrillic;0481 koreanstandardsymbol;327F koroniscmb;0343 kparen;24A6 kpasquare;33AA ksicyrillic;046F ktsquare;33CF kturned;029E kuhiragana;304F kukatakana;30AF kukatakanahalfwidth;FF78 kvsquare;33B8 kwsquare;33BE l;006C labengali;09B2 lacute;013A ladeva;0932 lagujarati;0AB2 lagurmukhi;0A32 lakkhangyaothai;0E45 lamaleffinalarabic;FEFC lamalefhamzaabovefinalarabic;FEF8 lamalefhamzaaboveisolatedarabic;FEF7 lamalefhamzabelowfinalarabic;FEFA lamalefhamzabelowisolatedarabic;FEF9 lamalefisolatedarabic;FEFB lamalefmaddaabovefinalarabic;FEF6 lamalefmaddaaboveisolatedarabic;FEF5 lamarabic;0644 lambda;03BB lambdastroke;019B lamed;05DC lameddagesh;FB3C lameddageshhebrew;FB3C lamedhebrew;05DC lamedholam;05DC 05B9 lamedholamdagesh;05DC 05B9 05BC lamedholamdageshhebrew;05DC 05B9 05BC lamedholamhebrew;05DC 05B9 lamfinalarabic;FEDE lamhahinitialarabic;FCCA laminitialarabic;FEDF lamjeeminitialarabic;FCC9 lamkhahinitialarabic;FCCB lamlamhehisolatedarabic;FDF2 lammedialarabic;FEE0 lammeemhahinitialarabic;FD88 lammeeminitialarabic;FCCC lammeemjeeminitialarabic;FEDF FEE4 FEA0 lammeemkhahinitialarabic;FEDF FEE4 FEA8 largecircle;25EF lbar;019A lbelt;026C lbopomofo;310C lcaron;013E lcedilla;013C lcircle;24DB lcircumflexbelow;1E3D lcommaaccent;013C ldot;0140 ldotaccent;0140 ldotbelow;1E37 ldotbelowmacron;1E39 leftangleabovecmb;031A lefttackbelowcmb;0318 less;003C lessequal;2264 lessequalorgreater;22DA lessmonospace;FF1C lessorequivalent;2272 lessorgreater;2276 lessoverequal;2266 lesssmall;FE64 lezh;026E lfblock;258C lhookretroflex;026D lira;20A4 liwnarmenian;056C lj;01C9 ljecyrillic;0459 ll;F6C0 lladeva;0933 llagujarati;0AB3 llinebelow;1E3B llladeva;0934 llvocalicbengali;09E1 llvocalicdeva;0961 llvocalicvowelsignbengali;09E3 llvocalicvowelsigndeva;0963 lmiddletilde;026B lmonospace;FF4C lmsquare;33D0 lochulathai;0E2C logicaland;2227 logicalnot;00AC logicalnotreversed;2310 logicalor;2228 lolingthai;0E25 longs;017F lowlinecenterline;FE4E lowlinecmb;0332 lowlinedashed;FE4D lozenge;25CA lparen;24A7 lslash;0142 lsquare;2113 lsuperior;F6EE ltshade;2591 luthai;0E26 lvocalicbengali;098C lvocalicdeva;090C lvocalicvowelsignbengali;09E2 lvocalicvowelsigndeva;0962 lxsquare;33D3 m;006D mabengali;09AE macron;00AF macronbelowcmb;0331 macroncmb;0304 macronlowmod;02CD macronmonospace;FFE3 macute;1E3F madeva;092E magujarati;0AAE magurmukhi;0A2E mahapakhhebrew;05A4 mahapakhlefthebrew;05A4 mahiragana;307E maichattawalowleftthai;F895 maichattawalowrightthai;F894 maichattawathai;0E4B maichattawaupperleftthai;F893 maieklowleftthai;F88C maieklowrightthai;F88B maiekthai;0E48 maiekupperleftthai;F88A maihanakatleftthai;F884 maihanakatthai;0E31 maitaikhuleftthai;F889 maitaikhuthai;0E47 maitholowleftthai;F88F maitholowrightthai;F88E maithothai;0E49 maithoupperleftthai;F88D maitrilowleftthai;F892 maitrilowrightthai;F891 maitrithai;0E4A maitriupperleftthai;F890 maiyamokthai;0E46 makatakana;30DE makatakanahalfwidth;FF8F male;2642 mansyonsquare;3347 maqafhebrew;05BE mars;2642 masoracirclehebrew;05AF masquare;3383 mbopomofo;3107 mbsquare;33D4 mcircle;24DC mcubedsquare;33A5 mdotaccent;1E41 mdotbelow;1E43 meemarabic;0645 meemfinalarabic;FEE2 meeminitialarabic;FEE3 meemmedialarabic;FEE4 meemmeeminitialarabic;FCD1 meemmeemisolatedarabic;FC48 meetorusquare;334D mehiragana;3081 meizierasquare;337E mekatakana;30E1 mekatakanahalfwidth;FF92 mem;05DE memdagesh;FB3E memdageshhebrew;FB3E memhebrew;05DE menarmenian;0574 merkhahebrew;05A5 merkhakefulahebrew;05A6 merkhakefulalefthebrew;05A6 merkhalefthebrew;05A5 mhook;0271 mhzsquare;3392 middledotkatakanahalfwidth;FF65 middot;00B7 mieumacirclekorean;3272 mieumaparenkorean;3212 mieumcirclekorean;3264 mieumkorean;3141 mieumpansioskorean;3170 mieumparenkorean;3204 mieumpieupkorean;316E mieumsioskorean;316F mihiragana;307F mikatakana;30DF mikatakanahalfwidth;FF90 minus;2212 minusbelowcmb;0320 minuscircle;2296 minusmod;02D7 minusplus;2213 minute;2032 miribaarusquare;334A mirisquare;3349 mlonglegturned;0270 mlsquare;3396 mmcubedsquare;33A3 mmonospace;FF4D mmsquaredsquare;339F mohiragana;3082 mohmsquare;33C1 mokatakana;30E2 mokatakanahalfwidth;FF93 molsquare;33D6 momathai;0E21 moverssquare;33A7 moverssquaredsquare;33A8 mparen;24A8 mpasquare;33AB mssquare;33B3 msuperior;F6EF mturned;026F mu;00B5 mu1;00B5 muasquare;3382 muchgreater;226B muchless;226A mufsquare;338C mugreek;03BC mugsquare;338D muhiragana;3080 mukatakana;30E0 mukatakanahalfwidth;FF91 mulsquare;3395 multiply;00D7 mumsquare;339B munahhebrew;05A3 munahlefthebrew;05A3 musicalnote;266A musicalnotedbl;266B musicflatsign;266D musicsharpsign;266F mussquare;33B2 muvsquare;33B6 muwsquare;33BC mvmegasquare;33B9 mvsquare;33B7 mwmegasquare;33BF mwsquare;33BD n;006E nabengali;09A8 nabla;2207 nacute;0144 nadeva;0928 nagujarati;0AA8 nagurmukhi;0A28 nahiragana;306A nakatakana;30CA nakatakanahalfwidth;FF85 napostrophe;0149 nasquare;3381 nbopomofo;310B nbspace;00A0 ncaron;0148 ncedilla;0146 ncircle;24DD ncircumflexbelow;1E4B ncommaaccent;0146 ndotaccent;1E45 ndotbelow;1E47 nehiragana;306D nekatakana;30CD nekatakanahalfwidth;FF88 newsheqelsign;20AA nfsquare;338B ngabengali;0999 ngadeva;0919 ngagujarati;0A99 ngagurmukhi;0A19 ngonguthai;0E07 nhiragana;3093 nhookleft;0272 nhookretroflex;0273 nieunacirclekorean;326F nieunaparenkorean;320F nieuncieuckorean;3135 nieuncirclekorean;3261 nieunhieuhkorean;3136 nieunkorean;3134 nieunpansioskorean;3168 nieunparenkorean;3201 nieunsioskorean;3167 nieuntikeutkorean;3166 nihiragana;306B nikatakana;30CB nikatakanahalfwidth;FF86 nikhahitleftthai;F899 nikhahitthai;0E4D nine;0039 ninearabic;0669 ninebengali;09EF ninecircle;2468 ninecircleinversesansserif;2792 ninedeva;096F ninegujarati;0AEF ninegurmukhi;0A6F ninehackarabic;0669 ninehangzhou;3029 nineideographicparen;3228 nineinferior;2089 ninemonospace;FF19 nineoldstyle;F739 nineparen;247C nineperiod;2490 ninepersian;06F9 nineroman;2178 ninesuperior;2079 nineteencircle;2472 nineteenparen;2486 nineteenperiod;249A ninethai;0E59 nj;01CC njecyrillic;045A nkatakana;30F3 nkatakanahalfwidth;FF9D nlegrightlong;019E nlinebelow;1E49 nmonospace;FF4E nmsquare;339A nnabengali;09A3 nnadeva;0923 nnagujarati;0AA3 nnagurmukhi;0A23 nnnadeva;0929 nohiragana;306E nokatakana;30CE nokatakanahalfwidth;FF89 nonbreakingspace;00A0 nonenthai;0E13 nonuthai;0E19 noonarabic;0646 noonfinalarabic;FEE6 noonghunnaarabic;06BA noonghunnafinalarabic;FB9F noonhehinitialarabic;FEE7 FEEC nooninitialarabic;FEE7 noonjeeminitialarabic;FCD2 noonjeemisolatedarabic;FC4B noonmedialarabic;FEE8 noonmeeminitialarabic;FCD5 noonmeemisolatedarabic;FC4E noonnoonfinalarabic;FC8D notcontains;220C notelement;2209 notelementof;2209 notequal;2260 notgreater;226F notgreaternorequal;2271 notgreaternorless;2279 notidentical;2262 notless;226E notlessnorequal;2270 notparallel;2226 notprecedes;2280 notsubset;2284 notsucceeds;2281 notsuperset;2285 nowarmenian;0576 nparen;24A9 nssquare;33B1 nsuperior;207F ntilde;00F1 nu;03BD nuhiragana;306C nukatakana;30CC nukatakanahalfwidth;FF87 nuktabengali;09BC nuktadeva;093C nuktagujarati;0ABC nuktagurmukhi;0A3C numbersign;0023 numbersignmonospace;FF03 numbersignsmall;FE5F numeralsigngreek;0374 numeralsignlowergreek;0375 numero;2116 nun;05E0 nundagesh;FB40 nundageshhebrew;FB40 nunhebrew;05E0 nvsquare;33B5 nwsquare;33BB nyabengali;099E nyadeva;091E nyagujarati;0A9E nyagurmukhi;0A1E o;006F oacute;00F3 oangthai;0E2D obarred;0275 obarredcyrillic;04E9 obarreddieresiscyrillic;04EB obengali;0993 obopomofo;311B obreve;014F ocandradeva;0911 ocandragujarati;0A91 ocandravowelsigndeva;0949 ocandravowelsigngujarati;0AC9 ocaron;01D2 ocircle;24DE ocircumflex;00F4 ocircumflexacute;1ED1 ocircumflexdotbelow;1ED9 ocircumflexgrave;1ED3 ocircumflexhookabove;1ED5 ocircumflextilde;1ED7 ocyrillic;043E odblacute;0151 odblgrave;020D odeva;0913 odieresis;00F6 odieresiscyrillic;04E7 odotbelow;1ECD oe;0153 oekorean;315A ogonek;02DB ogonekcmb;0328 ograve;00F2 ogujarati;0A93 oharmenian;0585 ohiragana;304A ohookabove;1ECF ohorn;01A1 ohornacute;1EDB ohorndotbelow;1EE3 ohorngrave;1EDD ohornhookabove;1EDF ohorntilde;1EE1 ohungarumlaut;0151 oi;01A3 oinvertedbreve;020F okatakana;30AA okatakanahalfwidth;FF75 okorean;3157 olehebrew;05AB omacron;014D omacronacute;1E53 omacrongrave;1E51 omdeva;0950 omega;03C9 omega1;03D6 omegacyrillic;0461 omegalatinclosed;0277 omegaroundcyrillic;047B omegatitlocyrillic;047D omegatonos;03CE omgujarati;0AD0 omicron;03BF omicrontonos;03CC omonospace;FF4F one;0031 onearabic;0661 onebengali;09E7 onecircle;2460 onecircleinversesansserif;278A onedeva;0967 onedotenleader;2024 oneeighth;215B onefitted;F6DC onegujarati;0AE7 onegurmukhi;0A67 onehackarabic;0661 onehalf;00BD onehangzhou;3021 oneideographicparen;3220 oneinferior;2081 onemonospace;FF11 onenumeratorbengali;09F4 oneoldstyle;F731 oneparen;2474 oneperiod;2488 onepersian;06F1 onequarter;00BC oneroman;2170 onesuperior;00B9 onethai;0E51 onethird;2153 oogonek;01EB oogonekmacron;01ED oogurmukhi;0A13 oomatragurmukhi;0A4B oopen;0254 oparen;24AA openbullet;25E6 option;2325 ordfeminine;00AA ordmasculine;00BA orthogonal;221F oshortdeva;0912 oshortvowelsigndeva;094A oslash;00F8 oslashacute;01FF osmallhiragana;3049 osmallkatakana;30A9 osmallkatakanahalfwidth;FF6B ostrokeacute;01FF osuperior;F6F0 otcyrillic;047F otilde;00F5 otildeacute;1E4D otildedieresis;1E4F oubopomofo;3121 overline;203E overlinecenterline;FE4A overlinecmb;0305 overlinedashed;FE49 overlinedblwavy;FE4C overlinewavy;FE4B overscore;00AF ovowelsignbengali;09CB ovowelsigndeva;094B ovowelsigngujarati;0ACB p;0070 paampssquare;3380 paasentosquare;332B pabengali;09AA pacute;1E55 padeva;092A pagedown;21DF pageup;21DE pagujarati;0AAA pagurmukhi;0A2A pahiragana;3071 paiyannoithai;0E2F pakatakana;30D1 palatalizationcyrilliccmb;0484 palochkacyrillic;04C0 pansioskorean;317F paragraph;00B6 parallel;2225 parenleft;0028 parenleftaltonearabic;FD3E parenleftbt;F8ED parenleftex;F8EC parenleftinferior;208D parenleftmonospace;FF08 parenleftsmall;FE59 parenleftsuperior;207D parenlefttp;F8EB parenleftvertical;FE35 parenright;0029 parenrightaltonearabic;FD3F parenrightbt;F8F8 parenrightex;F8F7 parenrightinferior;208E parenrightmonospace;FF09 parenrightsmall;FE5A parenrightsuperior;207E parenrighttp;F8F6 parenrightvertical;FE36 partialdiff;2202 paseqhebrew;05C0 pashtahebrew;0599 pasquare;33A9 patah;05B7 patah11;05B7 patah1d;05B7 patah2a;05B7 patahhebrew;05B7 patahnarrowhebrew;05B7 patahquarterhebrew;05B7 patahwidehebrew;05B7 pazerhebrew;05A1 pbopomofo;3106 pcircle;24DF pdotaccent;1E57 pe;05E4 pecyrillic;043F pedagesh;FB44 pedageshhebrew;FB44 peezisquare;333B pefinaldageshhebrew;FB43 peharabic;067E peharmenian;057A pehebrew;05E4 pehfinalarabic;FB57 pehinitialarabic;FB58 pehiragana;307A pehmedialarabic;FB59 pekatakana;30DA pemiddlehookcyrillic;04A7 perafehebrew;FB4E percent;0025 percentarabic;066A percentmonospace;FF05 percentsmall;FE6A period;002E periodarmenian;0589 periodcentered;00B7 periodhalfwidth;FF61 periodinferior;F6E7 periodmonospace;FF0E periodsmall;FE52 periodsuperior;F6E8 perispomenigreekcmb;0342 perpendicular;22A5 perthousand;2030 peseta;20A7 pfsquare;338A phabengali;09AB phadeva;092B phagujarati;0AAB phagurmukhi;0A2B phi;03C6 phi1;03D5 phieuphacirclekorean;327A phieuphaparenkorean;321A phieuphcirclekorean;326C phieuphkorean;314D phieuphparenkorean;320C philatin;0278 phinthuthai;0E3A phisymbolgreek;03D5 phook;01A5 phophanthai;0E1E phophungthai;0E1C phosamphaothai;0E20 pi;03C0 pieupacirclekorean;3273 pieupaparenkorean;3213 pieupcieuckorean;3176 pieupcirclekorean;3265 pieupkiyeokkorean;3172 pieupkorean;3142 pieupparenkorean;3205 pieupsioskiyeokkorean;3174 pieupsioskorean;3144 pieupsiostikeutkorean;3175 pieupthieuthkorean;3177 pieuptikeutkorean;3173 pihiragana;3074 pikatakana;30D4 pisymbolgreek;03D6 piwrarmenian;0583 plus;002B plusbelowcmb;031F pluscircle;2295 plusminus;00B1 plusmod;02D6 plusmonospace;FF0B plussmall;FE62 plussuperior;207A pmonospace;FF50 pmsquare;33D8 pohiragana;307D pointingindexdownwhite;261F pointingindexleftwhite;261C pointingindexrightwhite;261E pointingindexupwhite;261D pokatakana;30DD poplathai;0E1B postalmark;3012 postalmarkface;3020 pparen;24AB precedes;227A prescription;211E primemod;02B9 primereversed;2035 product;220F projective;2305 prolongedkana;30FC propellor;2318 propersubset;2282 propersuperset;2283 proportion;2237 proportional;221D psi;03C8 psicyrillic;0471 psilipneumatacyrilliccmb;0486 pssquare;33B0 puhiragana;3077 pukatakana;30D7 pvsquare;33B4 pwsquare;33BA q;0071 qadeva;0958 qadmahebrew;05A8 qafarabic;0642 qaffinalarabic;FED6 qafinitialarabic;FED7 qafmedialarabic;FED8 qamats;05B8 qamats10;05B8 qamats1a;05B8 qamats1c;05B8 qamats27;05B8 qamats29;05B8 qamats33;05B8 qamatsde;05B8 qamatshebrew;05B8 qamatsnarrowhebrew;05B8 qamatsqatanhebrew;05B8 qamatsqatannarrowhebrew;05B8 qamatsqatanquarterhebrew;05B8 qamatsqatanwidehebrew;05B8 qamatsquarterhebrew;05B8 qamatswidehebrew;05B8 qarneyparahebrew;059F qbopomofo;3111 qcircle;24E0 qhook;02A0 qmonospace;FF51 qof;05E7 qofdagesh;FB47 qofdageshhebrew;FB47 qofhatafpatah;05E7 05B2 qofhatafpatahhebrew;05E7 05B2 qofhatafsegol;05E7 05B1 qofhatafsegolhebrew;05E7 05B1 qofhebrew;05E7 qofhiriq;05E7 05B4 qofhiriqhebrew;05E7 05B4 qofholam;05E7 05B9 qofholamhebrew;05E7 05B9 qofpatah;05E7 05B7 qofpatahhebrew;05E7 05B7 qofqamats;05E7 05B8 qofqamatshebrew;05E7 05B8 qofqubuts;05E7 05BB qofqubutshebrew;05E7 05BB qofsegol;05E7 05B6 qofsegolhebrew;05E7 05B6 qofsheva;05E7 05B0 qofshevahebrew;05E7 05B0 qoftsere;05E7 05B5 qoftserehebrew;05E7 05B5 qparen;24AC quarternote;2669 qubuts;05BB qubuts18;05BB qubuts25;05BB qubuts31;05BB qubutshebrew;05BB qubutsnarrowhebrew;05BB qubutsquarterhebrew;05BB qubutswidehebrew;05BB question;003F questionarabic;061F questionarmenian;055E questiondown;00BF questiondownsmall;F7BF questiongreek;037E questionmonospace;FF1F questionsmall;F73F quotedbl;0022 quotedblbase;201E quotedblleft;201C quotedblmonospace;FF02 quotedblprime;301E quotedblprimereversed;301D quotedblright;201D quoteleft;2018 quoteleftreversed;201B quotereversed;201B quoteright;2019 quoterightn;0149 quotesinglbase;201A quotesingle;0027 quotesinglemonospace;FF07 r;0072 raarmenian;057C rabengali;09B0 racute;0155 radeva;0930 radical;221A radicalex;F8E5 radoverssquare;33AE radoverssquaredsquare;33AF radsquare;33AD rafe;05BF rafehebrew;05BF ragujarati;0AB0 ragurmukhi;0A30 rahiragana;3089 rakatakana;30E9 rakatakanahalfwidth;FF97 ralowerdiagonalbengali;09F1 ramiddlediagonalbengali;09F0 ramshorn;0264 ratio;2236 rbopomofo;3116 rcaron;0159 rcedilla;0157 rcircle;24E1 rcommaaccent;0157 rdblgrave;0211 rdotaccent;1E59 rdotbelow;1E5B rdotbelowmacron;1E5D referencemark;203B reflexsubset;2286 reflexsuperset;2287 registered;00AE registersans;F8E8 registerserif;F6DA reharabic;0631 reharmenian;0580 rehfinalarabic;FEAE rehiragana;308C rehyehaleflamarabic;0631 FEF3 FE8E 0644 rekatakana;30EC rekatakanahalfwidth;FF9A resh;05E8 reshdageshhebrew;FB48 reshhatafpatah;05E8 05B2 reshhatafpatahhebrew;05E8 05B2 reshhatafsegol;05E8 05B1 reshhatafsegolhebrew;05E8 05B1 reshhebrew;05E8 reshhiriq;05E8 05B4 reshhiriqhebrew;05E8 05B4 reshholam;05E8 05B9 reshholamhebrew;05E8 05B9 reshpatah;05E8 05B7 reshpatahhebrew;05E8 05B7 reshqamats;05E8 05B8 reshqamatshebrew;05E8 05B8 reshqubuts;05E8 05BB reshqubutshebrew;05E8 05BB reshsegol;05E8 05B6 reshsegolhebrew;05E8 05B6 reshsheva;05E8 05B0 reshshevahebrew;05E8 05B0 reshtsere;05E8 05B5 reshtserehebrew;05E8 05B5 reversedtilde;223D reviahebrew;0597 reviamugrashhebrew;0597 revlogicalnot;2310 rfishhook;027E rfishhookreversed;027F rhabengali;09DD rhadeva;095D rho;03C1 rhook;027D rhookturned;027B rhookturnedsuperior;02B5 rhosymbolgreek;03F1 rhotichookmod;02DE rieulacirclekorean;3271 rieulaparenkorean;3211 rieulcirclekorean;3263 rieulhieuhkorean;3140 rieulkiyeokkorean;313A rieulkiyeoksioskorean;3169 rieulkorean;3139 rieulmieumkorean;313B rieulpansioskorean;316C rieulparenkorean;3203 rieulphieuphkorean;313F rieulpieupkorean;313C rieulpieupsioskorean;316B rieulsioskorean;313D rieulthieuthkorean;313E rieultikeutkorean;316A rieulyeorinhieuhkorean;316D rightangle;221F righttackbelowcmb;0319 righttriangle;22BF rihiragana;308A rikatakana;30EA rikatakanahalfwidth;FF98 ring;02DA ringbelowcmb;0325 ringcmb;030A ringhalfleft;02BF ringhalfleftarmenian;0559 ringhalfleftbelowcmb;031C ringhalfleftcentered;02D3 ringhalfright;02BE ringhalfrightbelowcmb;0339 ringhalfrightcentered;02D2 rinvertedbreve;0213 rittorusquare;3351 rlinebelow;1E5F rlongleg;027C rlonglegturned;027A rmonospace;FF52 rohiragana;308D rokatakana;30ED rokatakanahalfwidth;FF9B roruathai;0E23 rparen;24AD rrabengali;09DC rradeva;0931 rragurmukhi;0A5C rreharabic;0691 rrehfinalarabic;FB8D rrvocalicbengali;09E0 rrvocalicdeva;0960 rrvocalicgujarati;0AE0 rrvocalicvowelsignbengali;09C4 rrvocalicvowelsigndeva;0944 rrvocalicvowelsigngujarati;0AC4 rsuperior;F6F1 rtblock;2590 rturned;0279 rturnedsuperior;02B4 ruhiragana;308B rukatakana;30EB rukatakanahalfwidth;FF99 rupeemarkbengali;09F2 rupeesignbengali;09F3 rupiah;F6DD ruthai;0E24 rvocalicbengali;098B rvocalicdeva;090B rvocalicgujarati;0A8B rvocalicvowelsignbengali;09C3 rvocalicvowelsigndeva;0943 rvocalicvowelsigngujarati;0AC3 s;0073 sabengali;09B8 sacute;015B sacutedotaccent;1E65 sadarabic;0635 sadeva;0938 sadfinalarabic;FEBA sadinitialarabic;FEBB sadmedialarabic;FEBC sagujarati;0AB8 sagurmukhi;0A38 sahiragana;3055 sakatakana;30B5 sakatakanahalfwidth;FF7B sallallahoualayhewasallamarabic;FDFA samekh;05E1 samekhdagesh;FB41 samekhdageshhebrew;FB41 samekhhebrew;05E1 saraaathai;0E32 saraaethai;0E41 saraaimaimalaithai;0E44 saraaimaimuanthai;0E43 saraamthai;0E33 saraathai;0E30 saraethai;0E40 saraiileftthai;F886 saraiithai;0E35 saraileftthai;F885 saraithai;0E34 saraothai;0E42 saraueeleftthai;F888 saraueethai;0E37 saraueleftthai;F887 sarauethai;0E36 sarauthai;0E38 sarauuthai;0E39 sbopomofo;3119 scaron;0161 scarondotaccent;1E67 scedilla;015F schwa;0259 schwacyrillic;04D9 schwadieresiscyrillic;04DB schwahook;025A scircle;24E2 scircumflex;015D scommaaccent;0219 sdotaccent;1E61 sdotbelow;1E63 sdotbelowdotaccent;1E69 seagullbelowcmb;033C second;2033 secondtonechinese;02CA section;00A7 seenarabic;0633 seenfinalarabic;FEB2 seeninitialarabic;FEB3 seenmedialarabic;FEB4 segol;05B6 segol13;05B6 segol1f;05B6 segol2c;05B6 segolhebrew;05B6 segolnarrowhebrew;05B6 segolquarterhebrew;05B6 segoltahebrew;0592 segolwidehebrew;05B6 seharmenian;057D sehiragana;305B sekatakana;30BB sekatakanahalfwidth;FF7E semicolon;003B semicolonarabic;061B semicolonmonospace;FF1B semicolonsmall;FE54 semivoicedmarkkana;309C semivoicedmarkkanahalfwidth;FF9F sentisquare;3322 sentosquare;3323 seven;0037 sevenarabic;0667 sevenbengali;09ED sevencircle;2466 sevencircleinversesansserif;2790 sevendeva;096D seveneighths;215E sevengujarati;0AED sevengurmukhi;0A6D sevenhackarabic;0667 sevenhangzhou;3027 sevenideographicparen;3226 seveninferior;2087 sevenmonospace;FF17 sevenoldstyle;F737 sevenparen;247A sevenperiod;248E sevenpersian;06F7 sevenroman;2176 sevensuperior;2077 seventeencircle;2470 seventeenparen;2484 seventeenperiod;2498 seventhai;0E57 sfthyphen;00AD shaarmenian;0577 shabengali;09B6 shacyrillic;0448 shaddaarabic;0651 shaddadammaarabic;FC61 shaddadammatanarabic;FC5E shaddafathaarabic;FC60 shaddafathatanarabic;0651 064B shaddakasraarabic;FC62 shaddakasratanarabic;FC5F shade;2592 shadedark;2593 shadelight;2591 shademedium;2592 shadeva;0936 shagujarati;0AB6 shagurmukhi;0A36 shalshelethebrew;0593 shbopomofo;3115 shchacyrillic;0449 sheenarabic;0634 sheenfinalarabic;FEB6 sheeninitialarabic;FEB7 sheenmedialarabic;FEB8 sheicoptic;03E3 sheqel;20AA sheqelhebrew;20AA sheva;05B0 sheva115;05B0 sheva15;05B0 sheva22;05B0 sheva2e;05B0 shevahebrew;05B0 shevanarrowhebrew;05B0 shevaquarterhebrew;05B0 shevawidehebrew;05B0 shhacyrillic;04BB shimacoptic;03ED shin;05E9 shindagesh;FB49 shindageshhebrew;FB49 shindageshshindot;FB2C shindageshshindothebrew;FB2C shindageshsindot;FB2D shindageshsindothebrew;FB2D shindothebrew;05C1 shinhebrew;05E9 shinshindot;FB2A shinshindothebrew;FB2A shinsindot;FB2B shinsindothebrew;FB2B shook;0282 sigma;03C3 sigma1;03C2 sigmafinal;03C2 sigmalunatesymbolgreek;03F2 sihiragana;3057 sikatakana;30B7 sikatakanahalfwidth;FF7C siluqhebrew;05BD siluqlefthebrew;05BD similar;223C sindothebrew;05C2 siosacirclekorean;3274 siosaparenkorean;3214 sioscieuckorean;317E sioscirclekorean;3266 sioskiyeokkorean;317A sioskorean;3145 siosnieunkorean;317B siosparenkorean;3206 siospieupkorean;317D siostikeutkorean;317C six;0036 sixarabic;0666 sixbengali;09EC sixcircle;2465 sixcircleinversesansserif;278F sixdeva;096C sixgujarati;0AEC sixgurmukhi;0A6C sixhackarabic;0666 sixhangzhou;3026 sixideographicparen;3225 sixinferior;2086 sixmonospace;FF16 sixoldstyle;F736 sixparen;2479 sixperiod;248D sixpersian;06F6 sixroman;2175 sixsuperior;2076 sixteencircle;246F sixteencurrencydenominatorbengali;09F9 sixteenparen;2483 sixteenperiod;2497 sixthai;0E56 slash;002F slashmonospace;FF0F slong;017F slongdotaccent;1E9B smileface;263A smonospace;FF53 sofpasuqhebrew;05C3 softhyphen;00AD softsigncyrillic;044C sohiragana;305D sokatakana;30BD sokatakanahalfwidth;FF7F soliduslongoverlaycmb;0338 solidusshortoverlaycmb;0337 sorusithai;0E29 sosalathai;0E28 sosothai;0E0B sosuathai;0E2A space;0020 spacehackarabic;0020 spade;2660 spadesuitblack;2660 spadesuitwhite;2664 sparen;24AE squarebelowcmb;033B squarecc;33C4 squarecm;339D squarediagonalcrosshatchfill;25A9 squarehorizontalfill;25A4 squarekg;338F squarekm;339E squarekmcapital;33CE squareln;33D1 squarelog;33D2 squaremg;338E squaremil;33D5 squaremm;339C squaremsquared;33A1 squareorthogonalcrosshatchfill;25A6 squareupperlefttolowerrightfill;25A7 squareupperrighttolowerleftfill;25A8 squareverticalfill;25A5 squarewhitewithsmallblack;25A3 srsquare;33DB ssabengali;09B7 ssadeva;0937 ssagujarati;0AB7 ssangcieuckorean;3149 ssanghieuhkorean;3185 ssangieungkorean;3180 ssangkiyeokkorean;3132 ssangnieunkorean;3165 ssangpieupkorean;3143 ssangsioskorean;3146 ssangtikeutkorean;3138 ssuperior;F6F2 sterling;00A3 sterlingmonospace;FFE1 strokelongoverlaycmb;0336 strokeshortoverlaycmb;0335 subset;2282 subsetnotequal;228A subsetorequal;2286 succeeds;227B suchthat;220B suhiragana;3059 sukatakana;30B9 sukatakanahalfwidth;FF7D sukunarabic;0652 summation;2211 sun;263C superset;2283 supersetnotequal;228B supersetorequal;2287 svsquare;33DC syouwaerasquare;337C t;0074 tabengali;09A4 tackdown;22A4 tackleft;22A3 tadeva;0924 tagujarati;0AA4 tagurmukhi;0A24 taharabic;0637 tahfinalarabic;FEC2 tahinitialarabic;FEC3 tahiragana;305F tahmedialarabic;FEC4 taisyouerasquare;337D takatakana;30BF takatakanahalfwidth;FF80 tatweelarabic;0640 tau;03C4 tav;05EA tavdages;FB4A tavdagesh;FB4A tavdageshhebrew;FB4A tavhebrew;05EA tbar;0167 tbopomofo;310A tcaron;0165 tccurl;02A8 tcedilla;0163 tcheharabic;0686 tchehfinalarabic;FB7B tchehinitialarabic;FB7C tchehmedialarabic;FB7D tchehmeeminitialarabic;FB7C FEE4 tcircle;24E3 tcircumflexbelow;1E71 tcommaaccent;0163 tdieresis;1E97 tdotaccent;1E6B tdotbelow;1E6D tecyrillic;0442 tedescendercyrillic;04AD teharabic;062A tehfinalarabic;FE96 tehhahinitialarabic;FCA2 tehhahisolatedarabic;FC0C tehinitialarabic;FE97 tehiragana;3066 tehjeeminitialarabic;FCA1 tehjeemisolatedarabic;FC0B tehmarbutaarabic;0629 tehmarbutafinalarabic;FE94 tehmedialarabic;FE98 tehmeeminitialarabic;FCA4 tehmeemisolatedarabic;FC0E tehnoonfinalarabic;FC73 tekatakana;30C6 tekatakanahalfwidth;FF83 telephone;2121 telephoneblack;260E telishagedolahebrew;05A0 telishaqetanahebrew;05A9 tencircle;2469 tenideographicparen;3229 tenparen;247D tenperiod;2491 tenroman;2179 tesh;02A7 tet;05D8 tetdagesh;FB38 tetdageshhebrew;FB38 tethebrew;05D8 tetsecyrillic;04B5 tevirhebrew;059B tevirlefthebrew;059B thabengali;09A5 thadeva;0925 thagujarati;0AA5 thagurmukhi;0A25 thalarabic;0630 thalfinalarabic;FEAC thanthakhatlowleftthai;F898 thanthakhatlowrightthai;F897 thanthakhatthai;0E4C thanthakhatupperleftthai;F896 theharabic;062B thehfinalarabic;FE9A thehinitialarabic;FE9B thehmedialarabic;FE9C thereexists;2203 therefore;2234 theta;03B8 theta1;03D1 thetasymbolgreek;03D1 thieuthacirclekorean;3279 thieuthaparenkorean;3219 thieuthcirclekorean;326B thieuthkorean;314C thieuthparenkorean;320B thirteencircle;246C thirteenparen;2480 thirteenperiod;2494 thonangmonthothai;0E11 thook;01AD thophuthaothai;0E12 thorn;00FE thothahanthai;0E17 thothanthai;0E10 thothongthai;0E18 thothungthai;0E16 thousandcyrillic;0482 thousandsseparatorarabic;066C thousandsseparatorpersian;066C three;0033 threearabic;0663 threebengali;09E9 threecircle;2462 threecircleinversesansserif;278C threedeva;0969 threeeighths;215C threegujarati;0AE9 threegurmukhi;0A69 threehackarabic;0663 threehangzhou;3023 threeideographicparen;3222 threeinferior;2083 threemonospace;FF13 threenumeratorbengali;09F6 threeoldstyle;F733 threeparen;2476 threeperiod;248A threepersian;06F3 threequarters;00BE threequartersemdash;F6DE threeroman;2172 threesuperior;00B3 threethai;0E53 thzsquare;3394 tihiragana;3061 tikatakana;30C1 tikatakanahalfwidth;FF81 tikeutacirclekorean;3270 tikeutaparenkorean;3210 tikeutcirclekorean;3262 tikeutkorean;3137 tikeutparenkorean;3202 tilde;02DC tildebelowcmb;0330 tildecmb;0303 tildecomb;0303 tildedoublecmb;0360 tildeoperator;223C tildeoverlaycmb;0334 tildeverticalcmb;033E timescircle;2297 tipehahebrew;0596 tipehalefthebrew;0596 tippigurmukhi;0A70 titlocyrilliccmb;0483 tiwnarmenian;057F tlinebelow;1E6F tmonospace;FF54 toarmenian;0569 tohiragana;3068 tokatakana;30C8 tokatakanahalfwidth;FF84 tonebarextrahighmod;02E5 tonebarextralowmod;02E9 tonebarhighmod;02E6 tonebarlowmod;02E8 tonebarmidmod;02E7 tonefive;01BD tonesix;0185 tonetwo;01A8 tonos;0384 tonsquare;3327 topatakthai;0E0F tortoiseshellbracketleft;3014 tortoiseshellbracketleftsmall;FE5D tortoiseshellbracketleftvertical;FE39 tortoiseshellbracketright;3015 tortoiseshellbracketrightsmall;FE5E tortoiseshellbracketrightvertical;FE3A totaothai;0E15 tpalatalhook;01AB tparen;24AF trademark;2122 trademarksans;F8EA trademarkserif;F6DB tretroflexhook;0288 triagdn;25BC triaglf;25C4 triagrt;25BA triagup;25B2 ts;02A6 tsadi;05E6 tsadidagesh;FB46 tsadidageshhebrew;FB46 tsadihebrew;05E6 tsecyrillic;0446 tsere;05B5 tsere12;05B5 tsere1e;05B5 tsere2b;05B5 tserehebrew;05B5 tserenarrowhebrew;05B5 tserequarterhebrew;05B5 tserewidehebrew;05B5 tshecyrillic;045B tsuperior;F6F3 ttabengali;099F ttadeva;091F ttagujarati;0A9F ttagurmukhi;0A1F tteharabic;0679 ttehfinalarabic;FB67 ttehinitialarabic;FB68 ttehmedialarabic;FB69 tthabengali;09A0 tthadeva;0920 tthagujarati;0AA0 tthagurmukhi;0A20 tturned;0287 tuhiragana;3064 tukatakana;30C4 tukatakanahalfwidth;FF82 tusmallhiragana;3063 tusmallkatakana;30C3 tusmallkatakanahalfwidth;FF6F twelvecircle;246B twelveparen;247F twelveperiod;2493 twelveroman;217B twentycircle;2473 twentyhangzhou;5344 twentyparen;2487 twentyperiod;249B two;0032 twoarabic;0662 twobengali;09E8 twocircle;2461 twocircleinversesansserif;278B twodeva;0968 twodotenleader;2025 twodotleader;2025 twodotleadervertical;FE30 twogujarati;0AE8 twogurmukhi;0A68 twohackarabic;0662 twohangzhou;3022 twoideographicparen;3221 twoinferior;2082 twomonospace;FF12 twonumeratorbengali;09F5 twooldstyle;F732 twoparen;2475 twoperiod;2489 twopersian;06F2 tworoman;2171 twostroke;01BB twosuperior;00B2 twothai;0E52 twothirds;2154 u;0075 uacute;00FA ubar;0289 ubengali;0989 ubopomofo;3128 ubreve;016D ucaron;01D4 ucircle;24E4 ucircumflex;00FB ucircumflexbelow;1E77 ucyrillic;0443 udattadeva;0951 udblacute;0171 udblgrave;0215 udeva;0909 udieresis;00FC udieresisacute;01D8 udieresisbelow;1E73 udieresiscaron;01DA udieresiscyrillic;04F1 udieresisgrave;01DC udieresismacron;01D6 udotbelow;1EE5 ugrave;00F9 ugujarati;0A89 ugurmukhi;0A09 uhiragana;3046 uhookabove;1EE7 uhorn;01B0 uhornacute;1EE9 uhorndotbelow;1EF1 uhorngrave;1EEB uhornhookabove;1EED uhorntilde;1EEF uhungarumlaut;0171 uhungarumlautcyrillic;04F3 uinvertedbreve;0217 ukatakana;30A6 ukatakanahalfwidth;FF73 ukcyrillic;0479 ukorean;315C umacron;016B umacroncyrillic;04EF umacrondieresis;1E7B umatragurmukhi;0A41 umonospace;FF55 underscore;005F underscoredbl;2017 underscoremonospace;FF3F underscorevertical;FE33 underscorewavy;FE4F union;222A universal;2200 uogonek;0173 uparen;24B0 upblock;2580 upperdothebrew;05C4 upsilon;03C5 upsilondieresis;03CB upsilondieresistonos;03B0 upsilonlatin;028A upsilontonos;03CD uptackbelowcmb;031D uptackmod;02D4 uragurmukhi;0A73 uring;016F ushortcyrillic;045E usmallhiragana;3045 usmallkatakana;30A5 usmallkatakanahalfwidth;FF69 ustraightcyrillic;04AF ustraightstrokecyrillic;04B1 utilde;0169 utildeacute;1E79 utildebelow;1E75 uubengali;098A uudeva;090A uugujarati;0A8A uugurmukhi;0A0A uumatragurmukhi;0A42 uuvowelsignbengali;09C2 uuvowelsigndeva;0942 uuvowelsigngujarati;0AC2 uvowelsignbengali;09C1 uvowelsigndeva;0941 uvowelsigngujarati;0AC1 v;0076 vadeva;0935 vagujarati;0AB5 vagurmukhi;0A35 vakatakana;30F7 vav;05D5 vavdagesh;FB35 vavdagesh65;FB35 vavdageshhebrew;FB35 vavhebrew;05D5 vavholam;FB4B vavholamhebrew;FB4B vavvavhebrew;05F0 vavyodhebrew;05F1 vcircle;24E5 vdotbelow;1E7F vecyrillic;0432 veharabic;06A4 vehfinalarabic;FB6B vehinitialarabic;FB6C vehmedialarabic;FB6D vekatakana;30F9 venus;2640 verticalbar;007C verticallineabovecmb;030D verticallinebelowcmb;0329 verticallinelowmod;02CC verticallinemod;02C8 vewarmenian;057E vhook;028B vikatakana;30F8 viramabengali;09CD viramadeva;094D viramagujarati;0ACD visargabengali;0983 visargadeva;0903 visargagujarati;0A83 vmonospace;FF56 voarmenian;0578 voicediterationhiragana;309E voicediterationkatakana;30FE voicedmarkkana;309B voicedmarkkanahalfwidth;FF9E vokatakana;30FA vparen;24B1 vtilde;1E7D vturned;028C vuhiragana;3094 vukatakana;30F4 w;0077 wacute;1E83 waekorean;3159 wahiragana;308F wakatakana;30EF wakatakanahalfwidth;FF9C wakorean;3158 wasmallhiragana;308E wasmallkatakana;30EE wattosquare;3357 wavedash;301C wavyunderscorevertical;FE34 wawarabic;0648 wawfinalarabic;FEEE wawhamzaabovearabic;0624 wawhamzaabovefinalarabic;FE86 wbsquare;33DD wcircle;24E6 wcircumflex;0175 wdieresis;1E85 wdotaccent;1E87 wdotbelow;1E89 wehiragana;3091 weierstrass;2118 wekatakana;30F1 wekorean;315E weokorean;315D wgrave;1E81 whitebullet;25E6 whitecircle;25CB whitecircleinverse;25D9 whitecornerbracketleft;300E whitecornerbracketleftvertical;FE43 whitecornerbracketright;300F whitecornerbracketrightvertical;FE44 whitediamond;25C7 whitediamondcontainingblacksmalldiamond;25C8 whitedownpointingsmalltriangle;25BF whitedownpointingtriangle;25BD whiteleftpointingsmalltriangle;25C3 whiteleftpointingtriangle;25C1 whitelenticularbracketleft;3016 whitelenticularbracketright;3017 whiterightpointingsmalltriangle;25B9 whiterightpointingtriangle;25B7 whitesmallsquare;25AB whitesmilingface;263A whitesquare;25A1 whitestar;2606 whitetelephone;260F whitetortoiseshellbracketleft;3018 whitetortoiseshellbracketright;3019 whiteuppointingsmalltriangle;25B5 whiteuppointingtriangle;25B3 wihiragana;3090 wikatakana;30F0 wikorean;315F wmonospace;FF57 wohiragana;3092 wokatakana;30F2 wokatakanahalfwidth;FF66 won;20A9 wonmonospace;FFE6 wowaenthai;0E27 wparen;24B2 wring;1E98 wsuperior;02B7 wturned;028D wynn;01BF x;0078 xabovecmb;033D xbopomofo;3112 xcircle;24E7 xdieresis;1E8D xdotaccent;1E8B xeharmenian;056D xi;03BE xmonospace;FF58 xparen;24B3 xsuperior;02E3 y;0079 yaadosquare;334E yabengali;09AF yacute;00FD yadeva;092F yaekorean;3152 yagujarati;0AAF yagurmukhi;0A2F yahiragana;3084 yakatakana;30E4 yakatakanahalfwidth;FF94 yakorean;3151 yamakkanthai;0E4E yasmallhiragana;3083 yasmallkatakana;30E3 yasmallkatakanahalfwidth;FF6C yatcyrillic;0463 ycircle;24E8 ycircumflex;0177 ydieresis;00FF ydotaccent;1E8F ydotbelow;1EF5 yeharabic;064A yehbarreearabic;06D2 yehbarreefinalarabic;FBAF yehfinalarabic;FEF2 yehhamzaabovearabic;0626 yehhamzaabovefinalarabic;FE8A yehhamzaaboveinitialarabic;FE8B yehhamzaabovemedialarabic;FE8C yehinitialarabic;FEF3 yehmedialarabic;FEF4 yehmeeminitialarabic;FCDD yehmeemisolatedarabic;FC58 yehnoonfinalarabic;FC94 yehthreedotsbelowarabic;06D1 yekorean;3156 yen;00A5 yenmonospace;FFE5 yeokorean;3155 yeorinhieuhkorean;3186 yerahbenyomohebrew;05AA yerahbenyomolefthebrew;05AA yericyrillic;044B yerudieresiscyrillic;04F9 yesieungkorean;3181 yesieungpansioskorean;3183 yesieungsioskorean;3182 yetivhebrew;059A ygrave;1EF3 yhook;01B4 yhookabove;1EF7 yiarmenian;0575 yicyrillic;0457 yikorean;3162 yinyang;262F yiwnarmenian;0582 ymonospace;FF59 yod;05D9 yoddagesh;FB39 yoddageshhebrew;FB39 yodhebrew;05D9 yodyodhebrew;05F2 yodyodpatahhebrew;FB1F yohiragana;3088 yoikorean;3189 yokatakana;30E8 yokatakanahalfwidth;FF96 yokorean;315B yosmallhiragana;3087 yosmallkatakana;30E7 yosmallkatakanahalfwidth;FF6E yotgreek;03F3 yoyaekorean;3188 yoyakorean;3187 yoyakthai;0E22 yoyingthai;0E0D yparen;24B4 ypogegrammeni;037A ypogegrammenigreekcmb;0345 yr;01A6 yring;1E99 ysuperior;02B8 ytilde;1EF9 yturned;028E yuhiragana;3086 yuikorean;318C yukatakana;30E6 yukatakanahalfwidth;FF95 yukorean;3160 yusbigcyrillic;046B yusbigiotifiedcyrillic;046D yuslittlecyrillic;0467 yuslittleiotifiedcyrillic;0469 yusmallhiragana;3085 yusmallkatakana;30E5 yusmallkatakanahalfwidth;FF6D yuyekorean;318B yuyeokorean;318A yyabengali;09DF yyadeva;095F z;007A zaarmenian;0566 zacute;017A zadeva;095B zagurmukhi;0A5B zaharabic;0638 zahfinalarabic;FEC6 zahinitialarabic;FEC7 zahiragana;3056 zahmedialarabic;FEC8 zainarabic;0632 zainfinalarabic;FEB0 zakatakana;30B6 zaqefgadolhebrew;0595 zaqefqatanhebrew;0594 zarqahebrew;0598 zayin;05D6 zayindagesh;FB36 zayindageshhebrew;FB36 zayinhebrew;05D6 zbopomofo;3117 zcaron;017E zcircle;24E9 zcircumflex;1E91 zcurl;0291 zdot;017C zdotaccent;017C zdotbelow;1E93 zecyrillic;0437 zedescendercyrillic;0499 zedieresiscyrillic;04DF zehiragana;305C zekatakana;30BC zero;0030 zeroarabic;0660 zerobengali;09E6 zerodeva;0966 zerogujarati;0AE6 zerogurmukhi;0A66 zerohackarabic;0660 zeroinferior;2080 zeromonospace;FF10 zerooldstyle;F730 zeropersian;06F0 zerosuperior;2070 zerothai;0E50 zerowidthjoiner;FEFF zerowidthnonjoiner;200C zerowidthspace;200B zeta;03B6 zhbopomofo;3113 zhearmenian;056A zhebrevecyrillic;04C2 zhecyrillic;0436 zhedescendercyrillic;0497 zhedieresiscyrillic;04DD zihiragana;3058 zikatakana;30B8 zinorhebrew;05AE zlinebelow;1E95 zmonospace;FF5A zohiragana;305E zokatakana;30BE zparen;24B5 zretroflexhook;0290 zstroke;01B6 zuhiragana;305A zukatakana;30BA #--end camlpdf-2.8.1/compressor/run000077500000000000000000000001601477056064700160730ustar00rootroot00000000000000./compressor ../pdfglyphlist.source.ml ../pdfglyphlist.ml ./compressor ../pdfafmdata.source.ml ../pdfafmdata.ml camlpdf-2.8.1/examples/000077500000000000000000000000001477056064700147665ustar00rootroot00000000000000camlpdf-2.8.1/examples/Makefile000066400000000000000000000015011477056064700164230ustar00rootroot00000000000000export PACKS = camlpdf export OCAMLBCFLAGS = -g -w -3 export OCAMLNCFLAGS = -g -w -3 export OCAMLLDFLAGS = -g define PROJ_pdfhello SOURCES=pdfhello.ml RESULT=pdfhello endef export PROJ_pdfhello define PROJ_pdfdecomp SOURCES=pdfdecomp.ml RESULT=pdfdecomp endef export PROJ_pdfdecomp define PROJ_pdfmerge SOURCES=pdfmergeexample.ml RESULT=pdfmergeexample endef export PROJ_pdfmerge define PROJ_pdfdraft SOURCES=pdfdraft.ml RESULT=pdfdraft endef export PROJ_pdfdraft define PROJ_pdftest SOURCES=pdftest.ml RESULT=pdftest endef export PROJ_pdftest define PROJ_pdfencrypt SOURCES=pdfencrypt.ml RESULT=pdfencrypt endef export PROJ_pdfencrypt ifndef SUBPROJS export SUBPROJS = pdfhello pdfdecomp pdfmerge pdfdraft pdftest pdfencrypt endif all: native-code %: @make -f OCamlMakefile subprojs SUBTARGET=$@ camlpdf-2.8.1/examples/OCamlMakefile000077500000000000000000001050311477056064700173450ustar00rootroot00000000000000########################################################################### # OCamlMakefile # Copyright (C) 1999- Markus Mottl # # For updates see: # http://www.ocaml.info/home/ocaml_sources.html # ########################################################################### # Modified by damien for .glade.ml compilation # Set these variables to the names of the sources to be processed and # the result variable. Order matters during linkage! ifndef SOURCES SOURCES := foo.ml endif export SOURCES ifndef RES_CLIB_SUF RES_CLIB_SUF := _stubs endif export RES_CLIB_SUF ifndef RESULT RESULT := foo endif export RESULT := $(strip $(RESULT)) export LIB_PACK_NAME ifndef DOC_FILES DOC_FILES := $(filter %.mli, $(SOURCES)) endif export DOC_FILES FIRST_DOC_FILE := $(firstword $(DOC_FILES)) export BCSUFFIX export NCSUFFIX ifndef TOPSUFFIX TOPSUFFIX := .top endif export TOPSUFFIX # Eventually set include- and library-paths, libraries to link, # additional compilation-, link- and ocamlyacc-flags # Path- and library information needs not be written with "-I" and such... # Define THREADS if you need it, otherwise leave it unset (same for # USE_CAMLP4)! export THREADS export VMTHREADS export ANNOTATE export USE_CAMLP4 export INCDIRS export LIBDIRS export EXTLIBDIRS export RESULTDEPS export OCAML_DEFAULT_DIRS export LIBS export CLIBS export CFRAMEWORKS export OCAMLFLAGS export OCAMLNCFLAGS export OCAMLBCFLAGS export OCAMLLDFLAGS export OCAMLNLDFLAGS export OCAMLBLDFLAGS export OCAMLMKLIB_FLAGS ifndef OCAMLCPFLAGS OCAMLCPFLAGS := a endif export OCAMLCPFLAGS ifndef DOC_DIR DOC_DIR := doc endif export DOC_DIR export PPFLAGS export LFLAGS export YFLAGS export IDLFLAGS export OCAMLDOCFLAGS export OCAMLFIND_INSTFLAGS export DVIPSFLAGS export STATIC # Add a list of optional trash files that should be deleted by "make clean" export TRASH ECHO := echo ifdef REALLY_QUIET export REALLY_QUIET ECHO := true LFLAGS := $(LFLAGS) -q YFLAGS := $(YFLAGS) -q endif #################### variables depending on your OCaml-installation SYSTEM := $(shell ocamlc -config 2>/dev/null | grep system | sed 's/system: //') # This may be # - mingw # - mingw64 # - win32 # - cygwin # - some other string means Unix # - empty means ocamlc does not support -config ifeq ($(SYSTEM),$(filter $(SYSTEM),mingw mingw64)) MINGW=1 endif ifeq ($(SYSTEM),win32) MSVC=1 endif ifdef MINGW export MINGW WIN32 := 1 # The default value 'cc' makes 'ocamlc -cc "cc"' raises the error 'The # NTVDM CPU has encountered an illegal instruction'. ifndef CC MNO_CYGWIN := $(shell gcc -Wextra -v --help 2>/dev/null | grep -q '\-mno-cygwin'; echo $$?) CC := gcc else MNO_CYGWIN := $(shell $$CC -Wextra -v --help 2>/dev/null | grep -q '\-mno-cygwin'; echo $$?) endif # We are compiling with cygwin tools: ifeq ($(MNO_CYGWIN),0) CFLAGS_WIN32 := -mno-cygwin endif # The OCaml C header files use this flag: CFLAGS += -D__MINGW32__ endif ifdef MSVC export MSVC WIN32 := 1 ifndef STATIC CPPFLAGS_WIN32 := -DCAML_DLL endif CFLAGS_WIN32 += -nologo EXT_OBJ := obj EXT_LIB := lib ifeq ($(CC),gcc) # work around GNU Make default value ifdef THREADS CC := cl -MT else CC := cl endif endif ifeq ($(CXX),g++) # work around GNU Make default value CXX := $(CC) endif CFLAG_O := -Fo endif ifdef WIN32 EXT_CXX := cpp EXE := .exe endif ifndef EXT_OBJ EXT_OBJ := o endif ifndef EXT_LIB EXT_LIB := a endif ifndef EXT_CXX EXT_CXX := cc endif ifndef EXE EXE := # empty endif ifndef CFLAG_O CFLAG_O := -o # do not delete this comment (preserves trailing whitespace)! endif export CC export CXX export CFLAGS export CXXFLAGS export LDFLAGS export CPPFLAGS ifndef RPATH_FLAG ifdef ELF_RPATH_FLAG RPATH_FLAG := $(ELF_RPATH_FLAG) else RPATH_FLAG := -R endif endif export RPATH_FLAG ifndef MSVC ifndef PIC_CFLAGS PIC_CFLAGS := -fPIC endif ifndef PIC_CPPFLAGS PIC_CPPFLAGS := -DPIC endif endif export PIC_CFLAGS export PIC_CPPFLAGS BCRESULT := $(addsuffix $(BCSUFFIX), $(RESULT)) NCRESULT := $(addsuffix $(NCSUFFIX), $(RESULT)) TOPRESULT := $(addsuffix $(TOPSUFFIX), $(RESULT)) ifndef OCAMLFIND OCAMLFIND := ocamlfind endif export OCAMLFIND ifndef OCAML OCAML := ocaml endif export OCAML ifndef OCAMLC OCAMLC := ocamlc endif export OCAMLC ifndef OCAMLOPT OCAMLOPT := ocamlopt endif export OCAMLOPT ifndef OCAMLMKTOP OCAMLMKTOP := ocamlmktop endif export OCAMLMKTOP ifndef OCAMLCP OCAMLCP := ocamlcp endif export OCAMLCP ifndef OCAMLDEP OCAMLDEP := ocamldep endif export OCAMLDEP ifndef OCAMLLEX OCAMLLEX := ocamllex endif export OCAMLLEX ifndef OCAMLYACC OCAMLYACC := ocamlyacc endif export OCAMLYACC ifndef OCAMLMKLIB OCAMLMKLIB := ocamlmklib endif export OCAMLMKLIB ifndef OCAML_GLADECC OCAML_GLADECC := lablgladecc2 endif export OCAML_GLADECC ifndef OCAML_GLADECC_FLAGS OCAML_GLADECC_FLAGS := endif export OCAML_GLADECC_FLAGS ifndef CAMELEON_REPORT CAMELEON_REPORT := report endif export CAMELEON_REPORT ifndef CAMELEON_REPORT_FLAGS CAMELEON_REPORT_FLAGS := endif export CAMELEON_REPORT_FLAGS ifndef CAMELEON_ZOGGY CAMELEON_ZOGGY := camlp4o pa_zog.cma pr_o.cmo endif export CAMELEON_ZOGGY ifndef CAMELEON_ZOGGY_FLAGS CAMELEON_ZOGGY_FLAGS := endif export CAMELEON_ZOGGY_FLAGS ifndef OXRIDL OXRIDL := oxridl endif export OXRIDL ifndef CAMLIDL CAMLIDL := camlidl endif export CAMLIDL ifndef CAMLIDLDLL CAMLIDLDLL := camlidldll endif export CAMLIDLDLL ifndef NOIDLHEADER MAYBE_IDL_HEADER := -header endif export NOIDLHEADER export NO_CUSTOM ifndef CAMLP4 CAMLP4 := camlp4 endif export CAMLP4 ifndef REAL_OCAMLFIND ifdef PACKS ifndef CREATE_LIB ifdef THREADS PACKS += threads endif endif empty := space := $(empty) $(empty) comma := , ifdef PREDS PRE_OCAML_FIND_PREDICATES := $(subst $(space),$(comma),$(PREDS)) PRE_OCAML_FIND_PACKAGES := $(subst $(space),$(comma),$(PACKS)) OCAML_FIND_PREDICATES := -predicates $(PRE_OCAML_FIND_PREDICATES) # OCAML_DEP_PREDICATES := -syntax $(PRE_OCAML_FIND_PREDICATES) OCAML_FIND_PACKAGES := $(OCAML_FIND_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES) OCAML_DEP_PACKAGES := $(OCAML_DEP_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES) else OCAML_FIND_PACKAGES := -package $(subst $(space),$(comma),$(PACKS)) OCAML_DEP_PACKAGES := endif OCAML_FIND_LINKPKG := -linkpkg REAL_OCAMLFIND := $(OCAMLFIND) endif endif export OCAML_FIND_PACKAGES export OCAML_DEP_PACKAGES export OCAML_FIND_LINKPKG export REAL_OCAMLFIND ifndef OCAMLDOC OCAMLDOC := ocamldoc endif export OCAMLDOC ifndef LATEX LATEX := latex endif export LATEX ifndef DVIPS DVIPS := dvips endif export DVIPS ifndef PS2PDF PS2PDF := ps2pdf endif export PS2PDF ifndef OCAMLMAKEFILE OCAMLMAKEFILE := OCamlMakefile endif export OCAMLMAKEFILE ifndef OCAMLLIBPATH OCAMLLIBPATH := \ $(shell $(OCAMLC) 2>/dev/null -where || echo /usr/local/lib/ocaml) endif export OCAMLLIBPATH ifndef OCAML_LIB_INSTALL OCAML_LIB_INSTALL := $(OCAMLLIBPATH)/contrib endif export OCAML_LIB_INSTALL ########################################################################### #################### change following sections only if #################### you know what you are doing! # delete target files when a build command fails .PHONY: .DELETE_ON_ERROR .DELETE_ON_ERROR: # for pedants using "--warn-undefined-variables" export MAYBE_IDL export REAL_RESULT export CAMLIDLFLAGS export THREAD_FLAG export RES_CLIB export MAKEDLL export ANNOT_FLAG export C_OXRIDL export SUBPROJS export CFLAGS_WIN32 export CPPFLAGS_WIN32 INCFLAGS := SHELL := /bin/sh MLDEPDIR := ._d BCDIDIR := ._bcdi NCDIDIR := ._ncdi FILTER_EXTNS := %.mli %.ml %.mll %.mly %.idl %.oxridl %.c %.m %.$(EXT_CXX) %.rep %.zog %.glade FILTERED := $(filter $(FILTER_EXTNS), $(SOURCES)) SOURCE_DIRS := $(filter-out ./, $(sort $(dir $(FILTERED)))) FILTERED_REP := $(filter %.rep, $(FILTERED)) DEP_REP := $(FILTERED_REP:%.rep=$(MLDEPDIR)/%.d) AUTO_REP := $(FILTERED_REP:.rep=.ml) FILTERED_ZOG := $(filter %.zog, $(FILTERED)) DEP_ZOG := $(FILTERED_ZOG:%.zog=$(MLDEPDIR)/%.d) AUTO_ZOG := $(FILTERED_ZOG:.zog=.ml) FILTERED_GLADE := $(filter %.glade, $(FILTERED)) DEP_GLADE := $(FILTERED_GLADE:%.glade=$(MLDEPDIR)/%.d) AUTO_GLADE := $(FILTERED_GLADE:.glade=.ml) FILTERED_ML := $(filter %.ml, $(FILTERED)) DEP_ML := $(FILTERED_ML:%.ml=$(MLDEPDIR)/%.d) FILTERED_MLI := $(filter %.mli, $(FILTERED)) DEP_MLI := $(FILTERED_MLI:.mli=.di) FILTERED_MLL := $(filter %.mll, $(FILTERED)) DEP_MLL := $(FILTERED_MLL:%.mll=$(MLDEPDIR)/%.d) AUTO_MLL := $(FILTERED_MLL:.mll=.ml) FILTERED_MLY := $(filter %.mly, $(FILTERED)) DEP_MLY := $(FILTERED_MLY:%.mly=$(MLDEPDIR)/%.d) $(FILTERED_MLY:.mly=.di) AUTO_MLY := $(FILTERED_MLY:.mly=.mli) $(FILTERED_MLY:.mly=.ml) FILTERED_IDL := $(filter %.idl, $(FILTERED)) DEP_IDL := $(FILTERED_IDL:%.idl=$(MLDEPDIR)/%.d) $(FILTERED_IDL:.idl=.di) C_IDL := $(FILTERED_IDL:%.idl=%_stubs.c) ifndef NOIDLHEADER C_IDL += $(FILTERED_IDL:.idl=.h) endif OBJ_C_IDL := $(FILTERED_IDL:%.idl=%_stubs.$(EXT_OBJ)) AUTO_IDL := $(FILTERED_IDL:.idl=.mli) $(FILTERED_IDL:.idl=.ml) $(C_IDL) FILTERED_OXRIDL := $(filter %.oxridl, $(FILTERED)) DEP_OXRIDL := $(FILTERED_OXRIDL:%.oxridl=$(MLDEPDIR)/%.d) $(FILTERED_OXRIDL:.oxridl=.di) AUTO_OXRIDL := $(FILTERED_OXRIDL:.oxridl=.mli) $(FILTERED_OXRIDL:.oxridl=.ml) $(C_OXRIDL) FILTERED_C_CXX := $(filter %.c %.m %.$(EXT_CXX), $(FILTERED)) OBJ_C_CXX := $(FILTERED_C_CXX:.c=.$(EXT_OBJ)) OBJ_C_CXX := $(OBJ_C_CXX:.m=.$(EXT_OBJ)) OBJ_C_CXX := $(OBJ_C_CXX:.$(EXT_CXX)=.$(EXT_OBJ)) PRE_TARGETS += $(AUTO_MLL) $(AUTO_MLY) $(AUTO_IDL) $(AUTO_OXRIDL) $(AUTO_ZOG) $(AUTO_REP) $(AUTO_GLADE) ALL_DEPS := $(DEP_ML) $(DEP_MLI) $(DEP_MLL) $(DEP_MLY) $(DEP_IDL) $(DEP_OXRIDL) $(DEP_ZOG) $(DEP_REP) $(DEP_GLADE) MLDEPS := $(filter %.d, $(ALL_DEPS)) MLIDEPS := $(filter %.di, $(ALL_DEPS)) BCDEPIS := $(MLIDEPS:%.di=$(BCDIDIR)/%.di) NCDEPIS := $(MLIDEPS:%.di=$(NCDIDIR)/%.di) ALLML := $(filter %.mli %.ml %.mll %.mly %.idl %.oxridl %.rep %.zog %.glade, $(FILTERED)) IMPLO_INTF := $(ALLML:%.mli=%.mli.__) IMPLO_INTF := $(foreach file, $(IMPLO_INTF), \ $(basename $(file)).cmi $(basename $(file)).cmo) IMPLO_INTF := $(filter-out %.mli.cmo, $(IMPLO_INTF)) IMPLO_INTF := $(IMPLO_INTF:%.mli.cmi=%.cmi) IMPLX_INTF := $(IMPLO_INTF:.cmo=.cmx) INTF := $(filter %.cmi, $(IMPLO_INTF)) IMPL_CMO := $(filter %.cmo, $(IMPLO_INTF)) IMPL_CMX := $(IMPL_CMO:.cmo=.cmx) IMPL_ASM := $(IMPL_CMO:.cmo=.asm) IMPL_S := $(IMPL_CMO:.cmo=.s) OBJ_LINK := $(OBJ_C_IDL) $(OBJ_C_CXX) OBJ_FILES := $(IMPL_CMO:.cmo=.$(EXT_OBJ)) $(OBJ_LINK) EXECS := $(addsuffix $(EXE), \ $(sort $(TOPRESULT) $(BCRESULT) $(NCRESULT))) ifdef WIN32 EXECS += $(BCRESULT).dll $(NCRESULT).dll endif CLIB_BASE := $(RESULT)$(RES_CLIB_SUF) ifneq ($(strip $(OBJ_LINK)),) RES_CLIB := lib$(CLIB_BASE).$(EXT_LIB) endif ifdef WIN32 DLLSONAME := dll$(CLIB_BASE).dll else DLLSONAME := dll$(CLIB_BASE).so endif NONEXECS := $(INTF) $(IMPL_CMO) $(IMPL_CMX) $(IMPL_ASM) $(IMPL_S) \ $(OBJ_FILES) $(PRE_TARGETS) $(BCRESULT).cma $(NCRESULT).cmxa \ $(NCRESULT).$(EXT_LIB) $(BCRESULT).cmi $(BCRESULT).cmo \ $(NCRESULT).cmi $(NCRESULT).cmx $(NCRESULT).$(EXT_OBJ) \ $(RES_CLIB) $(IMPL_CMO:.cmo=.annot) \ $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(LIB_PACK_NAME).cmx \ $(LIB_PACK_NAME).$(EXT_OBJ) ifndef STATIC NONEXECS += $(DLLSONAME) endif ifndef LIBINSTALL_FILES LIBINSTALL_FILES := $(RESULT).mli $(RESULT).cmi $(RESULT).cma \ $(RESULT).cmxa $(RESULT).$(EXT_LIB) $(RES_CLIB) ifndef STATIC ifneq ($(strip $(OBJ_LINK)),) LIBINSTALL_FILES += $(DLLSONAME) endif endif endif export LIBINSTALL_FILES ifdef WIN32 # some extra stuff is created while linking DLLs NONEXECS += $(BCRESULT).$(EXT_LIB) $(BCRESULT).exp $(NCRESULT).exp $(CLIB_BASE).exp $(CLIB_BASE).lib endif TARGETS := $(EXECS) $(NONEXECS) # If there are IDL-files ifneq ($(strip $(FILTERED_IDL)),) MAYBE_IDL := -cclib -lcamlidl endif ifdef USE_CAMLP4 CAMLP4PATH := \ $(shell $(CAMLP4) -where 2>/dev/null || echo /usr/local/lib/camlp4) INCFLAGS := -I $(CAMLP4PATH) CINCFLAGS := -I$(CAMLP4PATH) endif INCFLAGS := $(INCFLAGS) $(INCDIRS:%=-I %) $(SOURCE_DIRS:%=-I %) $(OCAML_DEFAULT_DIRS:%=-I %) CINCFLAGS += $(SOURCE_DIRS:%=-I%) $(INCDIRS:%=-I%) $(OCAML_DEFAULT_DIRS:%=-I%) ifndef MSVC CLIBFLAGS += $(SOURCE_DIRS:%=-L%) $(LIBDIRS:%=-L%) \ $(EXTLIBDIRS:%=-L%) $(OCAML_DEFAULT_DIRS:%=-L%) ifeq ($(ELF_RPATH), yes) CLIBFLAGS += $(EXTLIBDIRS:%=-Wl,$(RPATH_FLAG)%) endif endif ifndef PROFILING INTF_OCAMLC := $(OCAMLC) else ifndef THREADS INTF_OCAMLC := $(OCAMLCP) -p $(OCAMLCPFLAGS) else # OCaml does not support profiling byte code # with threads (yet), therefore we force an error. ifndef REAL_OCAMLC $(error Profiling of multithreaded byte code not yet supported by OCaml) endif INTF_OCAMLC := $(OCAMLC) endif endif ifndef MSVC COMMON_LDFLAGS := $(LDFLAGS:%=-ccopt %) $(SOURCE_DIRS:%=-ccopt -L%) \ $(LIBDIRS:%=-ccopt -L%) $(EXTLIBDIRS:%=-ccopt -L%) \ $(EXTLIBDIRS:%=-ccopt -Wl $(OCAML_DEFAULT_DIRS:%=-ccopt -L%)) ifeq ($(ELF_RPATH),yes) COMMON_LDFLAGS += $(EXTLIBDIRS:%=-ccopt -Wl,$(RPATH_FLAG)%) endif else COMMON_LDFLAGS := -ccopt "/link -NODEFAULTLIB:LIBC $(LDFLAGS:%=%) $(SOURCE_DIRS:%=-LIBPATH:%) \ $(LIBDIRS:%=-LIBPATH:%) $(EXTLIBDIRS:%=-LIBPATH:%) \ $(OCAML_DEFAULT_DIRS:%=-LIBPATH:%) " endif CLIBS_OPTS := $(CLIBS:%=-cclib -l%) $(CFRAMEWORKS:%=-cclib '-framework %') ifdef MSVC ifndef STATIC # MSVC libraries do not have 'lib' prefix CLIBS_OPTS := $(CLIBS:%=-cclib %.lib) endif endif ifneq ($(strip $(OBJ_LINK)),) ifdef CREATE_LIB OBJS_LIBS := -cclib -l$(CLIB_BASE) $(CLIBS_OPTS) $(MAYBE_IDL) else OBJS_LIBS := $(OBJ_LINK) $(CLIBS_OPTS) $(MAYBE_IDL) endif else OBJS_LIBS := $(CLIBS_OPTS) $(MAYBE_IDL) endif ifdef LIB_PACK_NAME FOR_PACK_NAME := $(shell echo $(LIB_PACK_NAME) | awk '{print toupper(substr($$0,1,1))substr($$0,2)}') endif # If we have to make byte-code ifndef REAL_OCAMLC BYTE_OCAML := y # EXTRADEPS is added dependencies we have to insert for all # executable files we generate. Ideally it should be all of the # libraries we use, but it's hard to find the ones that get searched on # the path since I don't know the paths built into the compiler, so # just include the ones with slashes in their names. EXTRADEPS := $(addsuffix .cma,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i)))) ifndef LIB_PACK_NAME SPECIAL_OCAMLFLAGS := $(OCAMLBCFLAGS) else SPECIAL_OCAMLFLAGS := -for-pack $(FOR_PACK_NAME) $(OCAMLBCFLAGS) endif REAL_OCAMLC := $(INTF_OCAMLC) REAL_IMPL := $(IMPL_CMO) REAL_IMPL_INTF := $(IMPLO_INTF) IMPL_SUF := .cmo DEPFLAGS := MAKE_DEPS := $(MLDEPS) $(BCDEPIS) ifdef CREATE_LIB override CFLAGS := $(PIC_CFLAGS) $(CFLAGS) override CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS) ifndef STATIC ifneq ($(strip $(OBJ_LINK)),) MAKEDLL := $(DLLSONAME) ALL_LDFLAGS := -dllib $(DLLSONAME) endif endif endif ifndef NO_CUSTOM ifneq "$(strip $(OBJ_LINK) $(THREADS) $(MAYBE_IDL) $(CLIBS) $(CFRAMEWORKS))" "" ALL_LDFLAGS += -custom endif endif ALL_LDFLAGS += $(INCFLAGS) $(OCAMLLDFLAGS) $(OCAMLBLDFLAGS) \ $(COMMON_LDFLAGS) $(LIBS:%=%.cma) CAMLIDLDLLFLAGS := ifdef THREADS ifdef VMTHREADS THREAD_FLAG := -vmthread else THREAD_FLAG := -thread endif ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS) ifndef CREATE_LIB ifndef REAL_OCAMLFIND ALL_LDFLAGS := $(ALL_LDFLAGS) endif endif endif # we have to make native-code else EXTRADEPS := $(addsuffix .cmxa,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i)))) ifndef PROFILING SPECIAL_OCAMLFLAGS := $(OCAMLNCFLAGS) PLDFLAGS := else SPECIAL_OCAMLFLAGS := -p $(OCAMLNCFLAGS) PLDFLAGS := -p endif ifndef LIB_PACK_NAME SPECIAL_OCAMLFLAGS := $(OCAMLNCFLAGS) else SPECIAL_OCAMLFLAGS := -for-pack $(FOR_PACK_NAME) $(OCAMLNCFLAGS) endif REAL_IMPL := $(IMPL_CMX) REAL_IMPL_INTF := $(IMPLX_INTF) IMPL_SUF := .cmx override CPPFLAGS := -DNATIVE_CODE $(CPPFLAGS) DEPFLAGS := -native MAKE_DEPS := $(MLDEPS) $(NCDEPIS) ALL_LDFLAGS := $(PLDFLAGS) $(INCFLAGS) $(OCAMLLDFLAGS) \ $(OCAMLNLDFLAGS) $(COMMON_LDFLAGS) CAMLIDLDLLFLAGS := -opt ifndef CREATE_LIB ALL_LDFLAGS += $(LIBS:%=%.cmxa) else override CFLAGS := $(PIC_CFLAGS) $(CFLAGS) override CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS) endif ifdef THREADS THREAD_FLAG := -thread ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS) ifndef CREATE_LIB ifndef REAL_OCAMLFIND ALL_LDFLAGS := $(ALL_LDFLAGS) endif endif endif endif export MAKE_DEPS ifdef ANNOTATE ANNOT_FLAG := -annot else endif ALL_OCAMLCFLAGS := $(THREAD_FLAG) $(ANNOT_FLAG) $(OCAMLFLAGS) \ $(INCFLAGS) $(SPECIAL_OCAMLFLAGS) ifdef make_deps -include $(MAKE_DEPS) PRE_TARGETS := endif ########################################################################### # USER RULES # Call "OCamlMakefile QUIET=" to get rid of all of the @'s. QUIET=@ # generates byte-code (default) byte-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ REAL_RESULT="$(BCRESULT)" make_deps=yes bc: byte-code byte-code-nolink: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ REAL_RESULT="$(BCRESULT)" make_deps=yes bcnl: byte-code-nolink top: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(TOPRESULT) \ REAL_RESULT="$(BCRESULT)" make_deps=yes # generates native-code native-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ make_deps=yes nc: native-code native-code-nolink: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ make_deps=yes ncnl: native-code-nolink # generates byte-code libraries byte-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).cma \ REAL_RESULT="$(BCRESULT)" \ CREATE_LIB=yes \ make_deps=yes bcl: byte-code-library # generates native-code libraries native-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(NCRESULT).cmxa \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ CREATE_LIB=yes \ make_deps=yes ncl: native-code-library ifdef WIN32 # generates byte-code dll byte-code-dll: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).dll \ REAL_RESULT="$(BCRESULT)" \ make_deps=yes bcd: byte-code-dll # generates native-code dll native-code-dll: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(NCRESULT).dll \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ make_deps=yes ncd: native-code-dll endif # generates byte-code with debugging information debug-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ REAL_RESULT="$(BCRESULT)" make_deps=yes \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dc: debug-code debug-code-nolink: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ REAL_RESULT="$(BCRESULT)" make_deps=yes \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dcnl: debug-code-nolink # generates byte-code with debugging information (native code) debug-native-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \ REAL_RESULT="$(NCRESULT)" make_deps=yes \ REAL_OCAMLC="$(OCAMLOPT)" \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dnc: debug-native-code debug-native-code-nolink: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \ REAL_RESULT="$(NCRESULT)" make_deps=yes \ REAL_OCAMLC="$(OCAMLOPT)" \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dncnl: debug-native-code-nolink # generates byte-code libraries with debugging information debug-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).cma \ REAL_RESULT="$(BCRESULT)" make_deps=yes \ CREATE_LIB=yes \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dcl: debug-code-library # generates byte-code libraries with debugging information (native code) debug-native-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(NCRESULT).cmxa \ REAL_RESULT="$(NCRESULT)" make_deps=yes \ REAL_OCAMLC="$(OCAMLOPT)" \ CREATE_LIB=yes \ OCAMLFLAGS="-g $(OCAMLFLAGS)" \ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)" dncl: debug-native-code-library # generates byte-code for profiling profiling-byte-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \ REAL_RESULT="$(BCRESULT)" PROFILING="y" \ make_deps=yes pbc: profiling-byte-code # generates native-code profiling-native-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ PROFILING="y" \ make_deps=yes pnc: profiling-native-code # generates byte-code libraries profiling-byte-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(BCRESULT).cma \ REAL_RESULT="$(BCRESULT)" PROFILING="y" \ CREATE_LIB=yes \ make_deps=yes pbcl: profiling-byte-code-library # generates native-code libraries profiling-native-code-library: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(RES_CLIB) $(NCRESULT).cmxa \ REAL_RESULT="$(NCRESULT)" PROFILING="y" \ REAL_OCAMLC="$(OCAMLOPT)" \ CREATE_LIB=yes \ make_deps=yes pncl: profiling-native-code-library # packs byte-code objects pack-byte-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT).cmo \ REAL_RESULT="$(BCRESULT)" \ PACK_LIB=yes make_deps=yes pabc: pack-byte-code # packs native-code objects pack-native-code: $(PRE_TARGETS) $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \ $(NCRESULT).cmx $(NCRESULT).$(EXT_OBJ) \ REAL_RESULT="$(NCRESULT)" \ REAL_OCAMLC="$(OCAMLOPT)" \ PACK_LIB=yes make_deps=yes panc: pack-native-code # generates HTML-documentation htdoc: $(DOC_DIR)/$(RESULT)/html/index.html # generates Latex-documentation ladoc: $(DOC_DIR)/$(RESULT)/latex/doc.tex # generates PostScript-documentation psdoc: $(DOC_DIR)/$(RESULT)/latex/doc.ps # generates PDF-documentation pdfdoc: $(DOC_DIR)/$(RESULT)/latex/doc.pdf # generates all supported forms of documentation doc: htdoc ladoc psdoc pdfdoc ########################################################################### # LOW LEVEL RULES $(REAL_RESULT): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(REAL_OCAMLC) \ $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \ $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@$(EXE) \ $(REAL_IMPL) nolink: $(REAL_IMPL_INTF) $(OBJ_LINK) ifdef WIN32 $(REAL_RESULT).dll: $(REAL_IMPL_INTF) $(OBJ_LINK) $(CAMLIDLDLL) $(CAMLIDLDLLFLAGS) $(OBJ_LINK) $(CLIBS) \ -o $@ $(REAL_IMPL) endif %$(TOPSUFFIX): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) $(REAL_OCAMLFIND) $(OCAMLMKTOP) \ $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \ $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@$(EXE) \ $(REAL_IMPL) .SUFFIXES: .mli .ml .cmi .cmo .cmx .cma .cmxa .$(EXT_OBJ) \ .mly .di .d .$(EXT_LIB) .idl %.oxridl .c .m .$(EXT_CXX) .h .so \ .rep .zog .glade ifndef STATIC ifdef MINGW # From OCaml 3.11.0, ocamlmklib is available on windows OCAMLMLIB_EXISTS = $(shell which $(OCAMLMKLIB)) ifeq ($(strip $(OCAMLMLIB_EXISTS)),) $(DLLSONAME): $(OBJ_LINK) $(CC) $(CFLAGS) $(CFLAGS_WIN32) $(OBJ_LINK) -shared -o $@ \ $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/lib%.a))) \ '$(OCAMLLIBPATH)/ocamlrun.a' \ -Wl,--whole-archive \ -Wl,--export-all-symbols \ -Wl,--allow-multiple-definition \ -Wl,--enable-auto-import else $(DLLSONAME): $(OBJ_LINK) $(OCAMLMKLIB) $(INCFLAGS) $(CLIBFLAGS) \ -o $(CLIB_BASE) $(OBJ_LINK) $(CLIBS:%=-l%) \ $(CFRAMEWORKS:%=-framework %) \ $(OCAMLMKLIB_FLAGS) endif else ifdef MSVC $(DLLSONAME): $(OBJ_LINK) link /NOLOGO /DLL /OUT:$@ $(OBJ_LINK) \ $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/%.lib))) \ '$(OCAMLLIBPATH)/ocamlrun.lib' else $(DLLSONAME): $(OBJ_LINK) $(OCAMLMKLIB) $(INCFLAGS) $(CLIBFLAGS) \ -o $(CLIB_BASE) $(OBJ_LINK) $(CLIBS:%=-l%) $(CFRAMEWORKS:%=-framework %) \ $(OCAMLMKLIB_FLAGS) endif endif endif ifndef LIB_PACK_NAME $(RESULT).cma: $(REAL_IMPL_INTF) $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@ $(REAL_IMPL) $(RESULT).cmxa $(RESULT).$(EXT_LIB): $(REAL_IMPL_INTF) $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(OCAMLOPT) -a $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@ $(REAL_IMPL) else # Packing a bytecode library LIB_PACK_NAME_MLI = $(wildcard $(LIB_PACK_NAME).mli) ifeq ($(LIB_PACK_NAME_MLI),) LIB_PACK_NAME_CMI = $(LIB_PACK_NAME).cmi else # $(LIB_PACK_NAME).mli exists, it likely depends on other compiled interfaces LIB_PACK_NAME_CMI = $(LIB_PACK_NAME).cmi: $(REAL_IMPL_INTF) endif ifdef BYTE_OCAML $(LIB_PACK_NAME_CMI) $(LIB_PACK_NAME).cmo: $(REAL_IMPL_INTF) $(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack -o $(LIB_PACK_NAME).cmo $(OCAMLLDFLAGS) $(REAL_IMPL) # Packing into a unit which can be transformed into a library # Remember the .ml's must have been compiled with -for-pack $(LIB_PACK_NAME) else $(LIB_PACK_NAME_CMI) $(LIB_PACK_NAME).cmx: $(REAL_IMPL_INTF) $(REAL_OCAMLFIND) $(OCAMLOPT) -pack -o $(LIB_PACK_NAME).cmx $(OCAMLLDFLAGS) $(REAL_IMPL) endif $(RESULT).cma: $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(OBJS_LIBS) $(ALL_LDFLAGS) -o $@ $(LIB_PACK_NAME).cmo $(RESULT).cmxa $(RESULT).$(EXT_LIB): $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmx $(EXTRADEPS) $(RESULTDEPS) $(REAL_OCAMLFIND) $(OCAMLOPT) -a $(OBJS_LIBS) $(filter-out -custom, $(ALL_LDFLAGS)) -o $@ $(LIB_PACK_NAME).cmx endif $(RES_CLIB): $(OBJ_LINK) ifndef MSVC ifneq ($(strip $(OBJ_LINK)),) $(AR) rcs $@ $(OBJ_LINK) endif else ifneq ($(strip $(OBJ_LINK)),) lib -nologo -debugtype:cv -out:$(RES_CLIB) $(OBJ_LINK) endif endif %.cmi: %.mli $(EXTRADEPS) $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ $(ECHO) $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ else \ $(ECHO) $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp \"$$pp $(PPFLAGS)\" $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp "$$pp $(PPFLAGS)" $(THREAD_FLAG) $(ANNOT_FLAG) \ $(OCAMLFLAGS) $(INCFLAGS) $<; \ fi %.cmi: %$(IMPL_SUF); %$(IMPL_SUF) %.$(EXT_OBJ): %.ml $(EXTRADEPS) $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ $(ECHO) $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(ALL_OCAMLCFLAGS) $<; \ $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c $(ALL_OCAMLCFLAGS) $<; \ else \ $(ECHO) $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp \"$$pp $(PPFLAGS)\" $(ALL_OCAMLCFLAGS) $<; \ $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \ -c -pp "$$pp $(PPFLAGS)" $(ALL_OCAMLCFLAGS) $<; \ fi .PRECIOUS: %.ml %.ml: %.mll $(OCAMLLEX) $(LFLAGS) $< .PRECIOUS: %.ml %.mli %.ml %.mli: %.mly $(OCAMLYACC) $(YFLAGS) $< $(QUIET)pp=`sed -n -e 's/.*(\*pp \([^*]*\) \*).*/\1/p;q' $<`; \ if [ ! -z "$$pp" ]; then \ mv $*.ml $*.ml.temporary; \ echo "(*pp $$pp $(PPFLAGS)*)" > $*.ml; \ cat $*.ml.temporary >> $*.ml; \ rm $*.ml.temporary; \ mv $*.mli $*.mli.temporary; \ echo "(*pp $$pp $(PPFLAGS)*)" > $*.mli; \ cat $*.mli.temporary >> $*.mli; \ rm $*.mli.temporary; \ fi .PRECIOUS: %.ml %.ml: %.rep $(CAMELEON_REPORT) $(CAMELEON_REPORT_FLAGS) -gen $< .PRECIOUS: %.ml %.ml: %.zog $(CAMELEON_ZOGGY) $(CAMELEON_ZOGGY_FLAGS) -impl $< > $@ .PRECIOUS: %.ml %.ml: %.glade $(OCAML_GLADECC) $(OCAML_GLADECC_FLAGS) $< > $@ .PRECIOUS: %.ml %.mli %.ml %.mli: %.oxridl $(OXRIDL) $< .PRECIOUS: %.ml %.mli %_stubs.c %.h %.ml %.mli %_stubs.c %.h: %.idl $(CAMLIDL) $(MAYBE_IDL_HEADER) $(IDLFLAGS) \ $(CAMLIDLFLAGS) $< $(QUIET)if [ $(NOIDLHEADER) ]; then touch $*.h; fi %.$(EXT_OBJ): %.c $(OCAMLC) -c -cc "$(CC)" -ccopt "$(CFLAGS) \ $(CPPFLAGS) $(CPPFLAGS_WIN32) \ $(CFLAGS_WIN32) $(CINCFLAGS) $(CFLAG_O)$@ " $< %.$(EXT_OBJ): %.m $(CC) -c $(CFLAGS) $(CINCFLAGS) $(CPPFLAGS) \ -I'$(OCAMLLIBPATH)' \ $< $(CFLAG_O)$@ %.$(EXT_OBJ): %.$(EXT_CXX) $(CXX) -c $(CXXFLAGS) $(CINCFLAGS) $(CPPFLAGS) \ -I'$(OCAMLLIBPATH)' \ $< $(CFLAG_O)$@ $(MLDEPDIR)/%.d: %.ml $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ $(INCFLAGS) $< \> $@; \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ $(INCFLAGS) $< > $@; \ else \ $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ -pp \"$$pp $(PPFLAGS)\" $(INCFLAGS) $< \> $@; \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \ -pp "$$pp $(PPFLAGS)" $(INCFLAGS) $< > $@; \ fi $(BCDIDIR)/%.di $(NCDIDIR)/%.di: %.mli $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \ if [ -z "$$pp" ]; then \ $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(INCFLAGS) $< \> $@; \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(INCFLAGS) $< > $@; \ else \ $(ECHO) $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \ -pp \"$$pp $(PPFLAGS)\" $(INCFLAGS) $< \> $@; \ $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \ -pp "$$pp $(PPFLAGS)" $(INCFLAGS) $< > $@; \ fi $(DOC_DIR)/$(RESULT)/html: mkdir -p $@ $(DOC_DIR)/$(RESULT)/html/index.html: $(DOC_DIR)/$(RESULT)/html $(DOC_FILES) rm -rf $ begin try let pdf = Pdfread.pdf_of_file None None in_file in Pdf.iter_stream (Pdfcodec.decode_pdfstream_until_unknown pdf) pdf; Pdfwrite.pdf_to_file pdf out_file with err -> Printf.printf "Failed to decompress file.\n%s\n\n" (Printexc.to_string err); exit 1 end | _ -> print_string "Syntax: pdfdecomp \n\n"; exit 1 camlpdf-2.8.1/examples/pdfdraft.ml000066400000000000000000000064441477056064700171220ustar00rootroot00000000000000(* Make a PDF suitable for draft printing by replacing its images by crossed boxes. Usage: pdfdraft input.pdf output.pdf *) open Pdfutil (* Predicate on an xobject: true if an image xobject. *) let isimage pdf (_, xobj) = Pdf.lookup_direct pdf "/Subtype" xobj = Some (Pdf.Name "/Image") (* Given a set of resources for a page, and the name of a resource, determine if that name refers to an image xobject. *) let xobject_isimage pdf resources name = match resources with | Pdf.Dictionary _ -> begin match Pdf.lookup_direct pdf "/XObject" resources with | Some xobjects -> isimage pdf ("", Pdf.lookup_fail "xobject not there" pdf name xobjects) | _ -> false end | _ -> failwith "bad resources" (* Remove any image xobjects from a set of resources. *) let remove_image_xobjects pdf resources = match resources with | Pdf.Dictionary res -> begin match Pdf.lookup_direct pdf "/XObject" resources with | Some (Pdf.Dictionary xobjects) -> Pdf.Dictionary (replace "/XObject" (Pdf.Dictionary (lose (isimage pdf) xobjects)) res) | _ -> resources end | _ -> failwith "bad resources" (* The subsitute for an image. *) let substitute = rev [Pdfops.Op_q; Pdfops.Op_w 0.; Pdfops.Op_G 0.; Pdfops.Op_re (0., 0., 1., 1.); Pdfops.Op_m (0., 0.); Pdfops.Op_l (1., 1.); Pdfops.Op_m (0., 1.); Pdfops.Op_l (1., 0.); Pdfops.Op_S; Pdfops.Op_Q] (* Remove references to images from a graphics stream. *) let rec remove_images_stream pdf resources prev = function | [] -> rev prev | (Pdfops.Op_Do name) as h::t -> if xobject_isimage pdf resources name then remove_images_stream pdf resources (substitute @ prev) t else remove_images_stream pdf resources (h::prev) t | Pdfops.InlineImage _::t -> remove_images_stream pdf resources (substitute @ prev) t | h::t -> remove_images_stream pdf resources (h::prev) t (* Remove images from a page. *) let remove_images_page pdf page = let content' = remove_images_stream pdf page.Pdfpage.resources [] (Pdfops.parse_operators pdf page.Pdfpage.resources page.Pdfpage.content) in {page with Pdfpage.content = (let stream = Pdfops.stream_of_ops content' in Pdfcodec.encode_pdfstream pdf Pdfcodec.Flate stream; [stream]); Pdfpage.resources = remove_image_xobjects pdf page.Pdfpage.resources} (* Remove images from all pages in a document. *) let remove_images pdf = let pages = Pdfpage.pages_of_pagetree pdf in let pages' = map (remove_images_page pdf) pages in let pdf, pagetree_num = Pdfpage.add_pagetree pages' pdf in let pdf = Pdfpage.add_root pagetree_num [] pdf in Pdf.remove_unreferenced pdf; pdf (* Read command line arguments and call [remove_images] *) let _ = match Array.to_list Sys.argv with | [_; in_file; out_file] -> begin try let ch = open_in_bin in_file in let pdf = Pdfread.pdf_of_channel None None ch in Pdfwrite.pdf_to_file (remove_images pdf) out_file; close_in ch with err -> Printf.printf "Failed to produce output.\n%s\n\n" (Printexc.to_string err); exit 1 end | _ -> print_string "Syntax: pdfdraft \n\n"; exit 1 camlpdf-2.8.1/examples/pdfencrypt.ml000066400000000000000000000017141477056064700175010ustar00rootroot00000000000000(* Encrypt a PDF file. Syntax is pdfencrypt in.pdf out.pdf ownerpassword. The user password is blank. The permissions applied are NoEdit and NoPrint *) open Pdfutil (* Read command line arguments and call [decrypt_pdf] *) let _ = let pw, in_file, out_file = match Array.to_list Sys.argv with | [_; in_file; out_file; pw] -> pw, in_file, out_file | _ -> print_string "Syntax: pdfencrypt \n\n"; exit 1 in begin try let pdf = Pdfread.pdf_of_file None None in_file and encryption = {Pdfwrite.encryption_method = Pdfwrite.AES128bit false; Pdfwrite.owner_password = pw; Pdfwrite.user_password = ""; Pdfwrite.permissions = [Pdfcrypt.NoEdit; Pdfcrypt.NoPrint]} in Pdfwrite.pdf_to_file_options (Some encryption) false pdf out_file with err -> Printf.printf "Failed to produce output.\n%s\n\n" (Printexc.to_string err); exit 1 end camlpdf-2.8.1/examples/pdfhello.ml000066400000000000000000000016611477056064700171210ustar00rootroot00000000000000(* We build a font dictionary for one of the 14 standard PostScript fonts, (which are supported by all PDF readers), make a graphics stream using the Pdfops module, build a PDF document in memory and then write it to hello.pdf *) let font = Pdf.Dictionary [("/Type", Pdf.Name "/Font"); ("/Subtype", Pdf.Name "/Type1"); ("/BaseFont", Pdf.Name "/Times-Italic")] and ops = [Pdfops.Op_cm (Pdftransform.matrix_of_transform [Pdftransform.Translate (50., 770.)]); Pdfops.Op_BT; Pdfops.Op_Tf ("/F0", 36.); Pdfops.Op_Tj "Hello, World!"; Pdfops.Op_ET] in let page = {(Pdfpage.blankpage Pdfpaper.a4) with Pdfpage.content = [Pdfops.stream_of_ops ops]; Pdfpage.resources = Pdf.Dictionary [("/Font", Pdf.Dictionary [("/F0", font)])]} in let pdf, pageroot = Pdfpage.add_pagetree [page] (Pdf.empty ()) in let pdf = Pdfpage.add_root pageroot [] pdf in Pdfwrite.pdf_to_file pdf "hello.pdf" camlpdf-2.8.1/examples/pdfmergeexample.ml000066400000000000000000000030271477056064700204670ustar00rootroot00000000000000(* pdfmergeexample a.pdf b.pdf c.pdf appends b.pdf to a.pdf and writes to c.pdf. This is written from scratch, rather than relying on Pdfmerge *) open Pdfutil (* We read all the files, read their pages and concatenate them, dealing with clashing object numbers. We then build a new page tree, and build the output PDF document, with a new root and trailer dictionary. We then remove any unreferenced objects, and write to file. *) let merge_pdfs pdfs out_name = let pdfs = Pdf.renumber_pdfs pdfs and minor' = fold_left max 0 (map (fun p -> p.Pdf.minor) pdfs) in let pages = flatten (map Pdfpage.pages_of_pagetree pdfs) and pdf = ref (Pdf.empty ()) in iter (Pdf.objiter (fun k v -> ignore (Pdf.addobj_given_num !pdf (k, v)))) pdfs; let pdf, pagetree_num = Pdfpage.add_pagetree pages !pdf in let pdf = Pdfpage.add_root pagetree_num [] pdf in let pdf = {pdf with Pdf.major = 1; Pdf.minor = minor'} in Pdf.remove_unreferenced pdf; pdf (* Read command line arguments, read files, call merge_pdfs, write result. *) let _ = let in_names, out_name = match rev (tl (Array.to_list Sys.argv)) with | h::t::t' -> rev (t::t'), h | _ -> print_string "Syntax: pdfmerge \n\n"; exit 1 in try let pdfs = map (Pdfread.pdf_of_file None None) in_names in let result = merge_pdfs pdfs out_name in Pdfwrite.pdf_to_file result out_name with err -> Printf.printf "Failed to merge files.\n%s\n\n" (Printexc.to_string err); exit 1 camlpdf-2.8.1/examples/pdftest.ml000066400000000000000000000020211477056064700167640ustar00rootroot00000000000000(* pdftest in.pdf out.pdf reads, lexes, parses a document in.pdf and its graphics streams, then writes it to out.pdf. *) open Pdfutil let _ = let in_name, out_name = match tl (Array.to_list Sys.argv) with | [i; o] -> (i, o) | _ -> print_string "Syntax: pdftest \n\n"; exit 1 in try let pdf = Pdfread.pdf_of_file None None in_name in if Pdfcrypt.is_encrypted pdf then failwith "File is encrypted."; let pages = Pdfpage.pages_of_pagetree pdf in let pages' = map (fun page -> let ops = Pdfops.parse_operators pdf page.Pdfpage.resources page.Pdfpage.content in {page with Pdfpage.content = [Pdfops.stream_of_ops ops]}) pages in let pdf = Pdfpage.change_pages true pdf pages' in Pdf.remove_unreferenced pdf; Pdfwrite.pdf_to_file pdf out_name with err -> Printf.printf "Test failed:\n%s\n\n" (Printexc.to_string err); exit 1 camlpdf-2.8.1/flatestubs.c000066400000000000000000000156701477056064700155010ustar00rootroot00000000000000/* Modifed for CamlPDF: * * - to prefix names with 'camlpdf' to avoid clashing symbols when zlib * also linked * - to harden against such malformed flate streams as may commonly * appear in PDF files */ /***********************************************************************/ /* */ /* The CamlZip library */ /* */ /* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ /* */ /* Copyright 2001 Institut National de Recherche en Informatique et */ /* en Automatique. All rights reserved. This file is distributed */ /* under the terms of the GNU Library General Public License, with */ /* the special exception on linking described in file LICENSE. */ /* */ /***********************************************************************/ /* $Id: zlibstubs.c,v 1.3 2006/04/04 08:29:07 xleroy Exp $ */ /* Stub code to interface with Zlib */ #include "miniz.c" //Modified to use miniz.c rather than zlib #include #include #include #include #include #include #define ZStream_val(v) ((mz_stream *) (v)) // So that the code links ok when using js_of_ocaml char* camlpdf_caml_zlib_decompress(char *s) { return s; } char* camlpdf_caml_zlib_compress(char *s) { return s; } static const value * camlpdf_camlzip_error_exn = NULL; static void camlpdf_camlzip_error(char * fn, value vzs) { char * msg; value s1 = Val_unit, s2 = Val_unit, bucket = Val_unit; msg = ZStream_val(vzs)->msg; if (msg == NULL) msg = ""; if (camlpdf_camlzip_error_exn == NULL) { camlpdf_camlzip_error_exn = caml_named_value("Pdfflate.Error"); if (camlpdf_camlzip_error_exn == NULL) caml_invalid_argument("Exception Pdfflate.Error not initialized"); } Begin_roots3(s1, s2, bucket); s1 = caml_copy_string(fn); s2 = caml_copy_string(msg); bucket = caml_alloc_small(3, 0); Field(bucket, 0) = *camlpdf_camlzip_error_exn; Field(bucket, 1) = s1; Field(bucket, 2) = s2; End_roots(); caml_raise(bucket); } static value camlpdf_camlzip_new_stream(void) { value res = caml_alloc((sizeof(mz_stream) + sizeof(value) - 1) / sizeof(value), Abstract_tag); ZStream_val(res)->zalloc = NULL; ZStream_val(res)->zfree = NULL; ZStream_val(res)->opaque = NULL; ZStream_val(res)->next_in = NULL; ZStream_val(res)->next_out = NULL; return res; } value camlpdf_camlzip_deflateInit(value vlevel, value expect_header) { value vzs = camlpdf_camlzip_new_stream(); if (mz_deflateInit2(ZStream_val(vzs), Int_val(vlevel), MZ_DEFLATED, Bool_val(expect_header) ? 15 : -15, 8, MZ_DEFAULT_STRATEGY) != MZ_OK) camlpdf_camlzip_error("Zlib.deflateInit", vzs); return vzs; } static int camlpdf_camlzip_flush_table[] = { MZ_NO_FLUSH, MZ_SYNC_FLUSH, MZ_FULL_FLUSH, MZ_FINISH }; value camlpdf_camlzip_deflate(value vzs, value srcbuf, value srcpos, value srclen, value dstbuf, value dstpos, value dstlen, value vflush) { mz_stream * zs = ZStream_val(vzs); int retcode; long used_in, used_out; value res; zs->next_in = &Byte_u(srcbuf, Long_val(srcpos)); zs->avail_in = Long_val(srclen); zs->next_out = &Byte_u(dstbuf, Long_val(dstpos)); zs->avail_out = Long_val(dstlen); retcode = mz_deflate(zs, camlpdf_camlzip_flush_table[Int_val(vflush)]); if (retcode < 0) camlpdf_camlzip_error("Zlib.deflate", vzs); used_in = Long_val(srclen) - zs->avail_in; used_out = Long_val(dstlen) - zs->avail_out; zs->next_in = NULL; /* not required, but cleaner */ zs->next_out = NULL; /* (avoid dangling pointers into Caml heap) */ res = caml_alloc_small(3, 0); Field(res, 0) = Val_bool(retcode == MZ_STREAM_END); Field(res, 1) = Val_int(used_in); Field(res, 2) = Val_int(used_out); return res; } value camlpdf_camlzip_deflate_bytecode(value * arg, int nargs) { return camlpdf_camlzip_deflate(arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7]); } value camlpdf_camlzip_deflateEnd(value vzs) { if (mz_deflateEnd(ZStream_val(vzs)) != MZ_OK) camlpdf_camlzip_error("Zlib.deflateEnd", vzs); return Val_unit; } /* CamlZIP now treats Z_BUF_ERROR and Z_DATA_ERROR as non-fatal. However, this * can lead to lack of progress on some malformed streams (at least with * miniz.c -- maybe not zlib. So we have this hack. */ int camlpdf_buf_error_count; value camlpdf_camlzip_inflateInit(value expect_header) { camlpdf_buf_error_count = 0; value vzs = camlpdf_camlzip_new_stream(); if (mz_inflateInit2(ZStream_val(vzs), Bool_val(expect_header) ? 15 : -15) != MZ_OK) camlpdf_camlzip_error("Zlib.inflateInit", vzs); return vzs; } value camlpdf_camlzip_inflate(value vzs, value srcbuf, value srcpos, value srclen, value dstbuf, value dstpos, value dstlen, value vflush) { mz_stream * zs = ZStream_val(vzs); int retcode; long used_in, used_out; value res; /*printf("srclen = %li\n", Long_val(srclen));*/ zs->next_in = &Byte_u(srcbuf, Long_val(srcpos)); zs->avail_in = Long_val(srclen); zs->next_out = &Byte_u(dstbuf, Long_val(dstpos)); zs->avail_out = Long_val(dstlen); retcode = mz_inflate(zs, camlpdf_camlzip_flush_table[Int_val(vflush)]); /*printf("retcode = %i\n", retcode);*/ if (retcode == MZ_BUF_ERROR || retcode == MZ_DATA_ERROR) camlpdf_buf_error_count += 1; else camlpdf_buf_error_count = 0; if (retcode < 0 && retcode != MZ_BUF_ERROR && retcode != MZ_DATA_ERROR || retcode == MZ_NEED_DICT) camlpdf_camlzip_error("Zlib.inflate", vzs); used_in = Long_val(srclen) - zs->avail_in; used_out = Long_val(dstlen) - zs->avail_out; zs->next_in = NULL; /* not required, but cleaner */ zs->next_out = NULL; /* (avoid dangling pointers into Caml heap) */ res = caml_alloc_small(3, 0); Field(res, 0) = Val_bool(retcode == MZ_STREAM_END || camlpdf_buf_error_count > 1); Field(res, 1) = Val_int(used_in); Field(res, 2) = Val_int(used_out); return res; } value camlpdf_camlzip_inflate_bytecode(value * arg, int nargs) { return camlpdf_camlzip_inflate(arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7]); } value camlpdf_camlzip_inflateEnd(value vzs) { if (mz_inflateEnd(ZStream_val(vzs)) != MZ_OK) camlpdf_camlzip_error("Zlib.inflateEnd", vzs); return Val_unit; } value camlpdf_camlzip_update_crc32(value crc, value buf, value pos, value len) { return caml_copy_int32(mz_crc32((uint32_t) Int32_val(crc), &Byte_u(buf, Long_val(pos)), Long_val(len))); } camlpdf-2.8.1/introduction_to_camlpdf.pdf000066400000000000000000003226371477056064700205710ustar00rootroot00000000000000%PDF-1.5 %ÐÔÅØ 6 0 obj << /Length 240 /Filter /FlateDecode >> stream xÚMMkÃ0 †ïþ:¦Ð¸–ì(ñ±Ÿ£e‡ =ŒJÒ-†&î2ýýÅ8…áƒ^ ?²6µX ¤$3PR%‹’¡T(K„º…·l=,r*«ì8„qA*óíOœŸ»Á§ú²;¤ðëB—ÒöÒßbû½>M4R¦è!ÖÒ’…œ´$k’è仸h¡²sç‚>Ã$yÀVZ&ެ!i*ȱ”L3¹¾î–P¤e ¤HGZìkñ%ÔtŒAÉh¦Y¬$ƒÐôbuìv^¼ŠÍ¼ƒêÉVq¨#ÇI·õÝu¼!}ói¼Ü;×|§ÛshÖ?Î)U: endstream endobj 4 0 obj << /Type /XObject /Subtype /Form /FormType 1 /PTEX.FileName (./logo.pdf) /PTEX.PageNumber 1 /PTEX.InfoDict 13 0 R /BBox [0 0 56.693 56.693] /Group 11 0 R /Resources << /ExtGState << /G0 14 0 R /G1 15 0 R >>/ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] >> /Length 584 /Filter /FlateDecode >> stream xœT»nAÌ-í?LhôN?æ%Y0–@ˆÜ>s’ø|ü=Õ½»$´ÒÞÕÌtuuwÍÎïï~î——óçÃéqŸÎ&¾˜¿^÷X9ìÓ|óõpºÛàÕUzûîúìyzžròçÓíúçø0Í·9=¼LÖh´šµÜÓÓd…zæ„wíéq²LUGbI qÓ”I:'é¤ÝV°›Xp^VˆwµäK­­Àƒ 4¥Á#ŽTäªT¸,”º¡ÝùdÃÆd®Ëˆ3*xZ*™òœEUk²NÝdk¥*’´¢8—rÒ’ØW’¬IªFe™z—„Z W+ÚMÂÔ¸o˜+)Â\uAíwy뮇¨¦5ÒŶ–R¯Ï³ò†Cvå^Òª——×#LôÕõ£0s8ŠxU\#©aH,rwtò•ÆÍC!£ªmX¦„¡šË+R*ØCì‚¡-"WdT´§à‰FÈ@È’eE» sÒuˆÛ¨à—Ç1ÄBÃĉ\ œa1$i­{hI+Ç2bòE†Ú‹Rfvë˜ìOóî¦ï“ùà±ÍTáÇ'7s˜QØÇôSl˜?TfŸ“×+A­-Üàž.BŽQÂ3Lª Æ5xÅRH!(®ŠË|…Ðkeðº¦ÜÝÌC£Ï,a_PùY†]‡;­ÇtÝœ#®¬à^‚àYÜ+àR|*`V 'fECÐw?­¨AÓßÝðþ|{ƒ€üþ³ßÿxn>\ŸÍÿþ¾¤s¹øŸoŒSüôkóš endstream endobj 18 0 obj << /Length 345 /Filter /FlateDecode >> stream xÚ]RMSà ¼÷Wp$3 BR’p³~ÄÑñàØÜÔ%4Í´ ˆ3þ{I^ìTo}o—Ý7ÕâªäDdI†ªb> stream xÚ­XMoÛ8½ûWÍÅb–Ÿ’˜bÙÝØ»íb})Ú‹N„Ê’#ÉNýïwÈ¡©Uœ¸.@C†|3œy3ænÂ" ?,b”‘4M£DH’r-דO_h”ÁßE”F÷~é::&’i‹è¿É¿“ß“×Wi1F´RÎ4V[€ÑrzŸJõŒ¥S{·ÍAH¦cÝîP“„(°p€Z-ͺXåevØ">‰îm+4áÚâ7/›Ö…ÍpX•øÝWÛ¥fß´vMfs©Øô/ç­¦ËjmglÚàè>ooq±)÷(¬«ÌÖ¥³/ú>tq"O9šÔ›6÷šÁÙÕ ¿ïÿ€CDDKÍ1r¥ÅLói…K¯·y|¡iÏBÊ(÷;Þ‡?¯F|&aqÚ­;GÐÒìòÓZµAU{&ç ˆâ2Œ³ƒºl«zS¦Ì¦ýÆÇxòv1¹ûʱL <ò*÷A8¡@ê˜s'óFø‹~: 9ÇcÂ4` F’˜£7ÖæëˆíR§„Ñô'ÔŽœ0dÂNå!í»ìHÊÐöž#[ ÂÒ”! R ßsÒ”h¿9I·îâé CAõiAV± R&Ïz;†à=d•p¢DÚ ò<¦—ŒGüxFœ\¦¿ ≎”‹A’êRA>¦!EÈk0ÞŸâ騝|Ä —Z˜ä”èTõ€¥Ö‘ä„væÒ'§šbq‡oÑBßíÄÎâÆÜw,›¼ÈËv%Ý\³ÓØbuþ0Damö(l›íöP³&´‚†ã; ߸ü{äæèŸLr8™`Ã}³üjnlgI r=K´'cM•t½‘蚪ÐBí»»ïÖìÍóvpõÙìÀ%tBRq"EÂü=s˜JÀSúü%RÀŒÃUm #ÜY~àZãÑìì¸}¼A#ž qœgž¾À„b„w§Z<4'Ÿ©¢U¸n*à]}Ÿ7&N݇€ŽÒiQ™PÓzÜvÎéªöæZW7a·ÝÙâD·¬: x+ñŒë™‚;ã@Q¦sð¥R Ûüc °³uãne ~}ÆÐáûámÙ:'¸EgP 7oÞà`U…Y7Iº˜š…®ò,ìòEÁI¯À‹î5ö 0F4ÍqÕ~¶¥KA'ý†gÖ‘­W€Zä×Á Ó pmm8^³].mÓ¬¶E±ÇÇ›\fYîV&¸Þ(ð>ÒØ\`AU•gµ—vG UÈm.ÜŒcS§%ƒŸ®^ã¬È›Ö!0&ûy\áoaµ3ya® ;ÀlFA}¦ËÊáêqËpÅ£›¡L”™©Ã_›}Ùšo?¸>À×GÀ×v)z½3~SÛ,_BëÙtŽ>¿;'„xG³´§¯±Nê×Û=¾@:’Ö·½®ê{ˆ¾´²i¿s¸á?,r^Ñ|Œ1µEÒ=M©ö¶¶&ó'£¼g‚-Ckš¡š~Ú‘Fã…ÿ'ªÏuÐ@;uZå—Z€˜‰ ,¼Ãÿ&Qv endstream endobj 30 0 obj << /Length 1807 /Filter /FlateDecode >> stream xÚ­X[sÛ6~÷¯à8ÍTž‰ ÜIÚYÏf›Í4ÛÎ6mܾ8,RS^’Šãvúß÷€(‚¢ì4Ù‰'€„sùpîЇ#`øG"(’q„Œ£ˆ’`Y]^á Ãÿ±8 î:Ò"`±DœÄ°Ïƒ·G?}ØB(Š˜ür!‘°RÉ‚ _„ÜÊø×ÅÑ╌ƒÅ’ÊàbI–4P°Šà" .gONæãÙ“:ý°ÍêÔ|:^ª"ß$«ã³³“« PÌ A±°<‹_›´nï«u¹@ÕF Žü-òìfaYO$•$ib¶meÖ&UõrmöÕ®¿Tƒ[ѲPV[^)­ýûb`EÁ#“/±â¾;µ ,ùßqgç !‡®@Ó`Ådf½(ÀëT_cñ*ƇØB‚D,}¶7ɪNUbXj¤8FXøœE•lsp?à´<¯î³ßÚU{O¯ÚÄf÷æå+³y’óÔÒe¥¡$³"=ÿªúþ„eÚ¶VàÙ:É–í#W×7 dYU*Húñ¬/ßa¿€áŸí\üºL û8 ˆÈÙ!EFÂë—ÀÀPZ⋺V÷‡D\jŠ·m•·ÖižAë8?ÛAš:¾Ú›´–ö6û#õ/צ·©@®E\9!ŠóeÜ©æ:ÏJè’ &ñüµRy“Zˆú˜&×i¹¬ï7Úæ¡Î¼¿÷Á/¨ûõK !œ|e#tÂBЏ ~¬ªß;Ów%½µ5½K¯`»^Õ6ûgµ\$ÁΣZÞN”q ¸"î(MYVÝšìúÅ©u£äˆ ›ñÐÅ¥bFq$úBÁå+ÄÐc\ïP™z¶l(€R‚ÂHúT™<¢—r Ýã€Ú®X>¢6‡Ô0×fáÎ+|çf½28³MŸÏ>˜×¯þóÒ$”fZ³ïScøg›ý# Y¡ùs‚”H^Æâœ„‡=sÔÈ#C>gš®[LZ¦ç×I# )<þ¹ˆúx5EÙ|iïÜíGMfßv×ïzÔŽïÛ!ñ@ªµéŠÐ ³í‡+3R7 A±5ÝšÙˆÌnkµYû&t¦€ãQh®â Ú>ôÌ }IúÉMY7÷f57ÓÕ®¯—jÎÁãsÄ’ŽÒÔõ¾}@JG?•‡ÞÁf‹ÏƒhØÈ*4òÇnSHÀªP±ú†99†÷¢(‹ F¥/Jƒç¡¯7¦ÿšÉ®½wY‚C˜©;ï¹[•#oZ¨£Û¬YwίŒ-`ÓÇ fË &õ²UYiª.|¥Ì0‘=&ï©è]VEQ•ù½ùvÛ¸¸Ø˜dž›ç‚9ÍÚ´hМtš™$ˆF‘¯ùóM>ÅáهĵV69¼<ð:$â=»2âLû0­ŸŒ/õÌà¸[gËé\¤"‚H·¡bRxc–&-]„盵xÕ4ÙMžN<´¬Í!­ÍèA5>ð<Š1ÌR4F4¶Íøefkô©®ÉxöÂÑ=ÚoÐýˆ?öt4>P %IÌU\¡×’¨-VÔe0…‚ ÊÞÏÚàØFT§ÖØôý*‚nN|Ÿ‰—qÚ™Üãµ ÉÎ}µ5HŠìvÝšm“ºÛØJŸ•æ³²èÓO–2M²ZnÈz±eYµªxúRBb8–È]Ö®ÇóQúi“«RµúéÝgä.ÀÈùù.c$X??±t‹)^Þï8}'^BåÉ«Ûñ// êðkåï{" õ#øÿ籄du6 ÷ÿ¿Q^ø endstream endobj 36 0 obj << /Length 1351 /Filter /FlateDecode >> stream xÚ¥WÝsÛ6 Ï_¡u×›}Óü%qÍò&¹v×]3ÇÛ’\O–¨X>R‰n’ýõ£ʶlÚ[û ‚ü |9"ÖâLPŽÏ\PâDùÑÍvb½ù»ƒ󨲿r‰Ðtæ\ýyôe[¡(`Þ÷ ¡¾Ã0GDŸØ#;.ö‘Ë„r6=_z ð<×™&!QÎOøÈ§ž3›,âröyx7ÕòœÁHp;t8ò0` Óø’P¶&“ ÔèݘÎÓz8¢¼e–‘º[ a¨U5$Á@†ù1,<ÎÓhneÓH¥eVÏ0Ȇ¡.s Ô,]íÇ¡ AÇžÙ£VÇži''`Ôøƒ,îÕ&Ú×@œžÚÜ¡×J[}à"N;'üU/Â,3EeþæÖµŒÁ³…êì Óȹ6˜%e„ k³T&0çÅiqo5ÕE~°a,A¸ý™çÜ3ësòþ¦ï÷çQ^BÔÛ¸ðlj¼{iX™×;9M`¼Å¿“YVÃüŸ²ÊâŸô*1|Ÿa¼˜Ú¼N)×WÒUðO=„÷²ó~¡d¡Ž{A5K÷³ô_ÃwUÖê:ªÒesiw˜,³f›‘²;¥Øá)µeäÖñ>}~ã«FH£ña¬z·ÒÞ2‘ÐStbSÓ§ˆøÛŠÖÏ… Ÿ€¾¥Ô%@b&͹ ‹~¾Cl'&ŠÈHT%Œ×@…ØÌ7õ­šÈº\T‘¬—†»›._ê@yñK$ ó&>Ù´Až.[WaÐ#Ÿo½¼R£Íøz1SͤY!ã3íò4Íe=z¯Â, Ll²ôÞ:”Ü -0}×ü!ã4<+Ÿ€õf2pÁõ9&0·)nÂ÷Ü;knúòÛű6¤¨µ÷jkΙó½œOJ*ÙE¦%½Æo!ãkcQ¿‚MîÖ}²©2ÁB—é Sy²;£å%mÍ*¶KµÙDñýP1² ©kà äšØ1ÉþV¬¼7³&ëkkZïð„'&ÞÖãµî(KÕ³×f¨9ˆ¡O•L¬Äï‘-U"Ð¥®G»0#œeò¸úZ5å6:³gµ,­I-»çìê¬ »’õ‡]æ*Ôöä½¢!h€©‘5”rí[Û%•-†ñòL猙ìã'†iíhÑãúü¾û þ¾|Jýƒø]W¼Œ_Uašéç{)üvü/@`[9_§ÿ™4áPJSïú‰6¿?7Ò|£œÈ,e|ºú2Ù\½ÛõÉVª m{‚‹Àš‚bÙi»-éàDOøë×/棋éZO¡ïDßÓSlw7 »HqHwÓ6&º§Ñ݈àúê_F=†H§þuøu;mÏËh‘Ë®\sÏÑoì5½L¢o[Sëoªc€i™æÆí1w£¹ÞƱ«822@ß¼ÓÕ!ýÃmO¢5çÕâsCA›ÃfCC—Ȩl!,†5€!>È-’Áäk˜-¤F™#þàƒT¿9Ñ<,î ÒX47ôÕù% aY5õVŠE>ƒ$Òj1|“¬ù®uÕO9ØñX¥^.ßâVÃB&Ñv„-ŸSöùµ¾„äé®uo˜QJ7:ßÕ3u/ñ}$\ ñõ3äòCœ ýÄ(O‹Ý›¥“ŒôÍ›eZ·Á Íî¯0,ŠÔ€Èo+ph¡ÂrÔÜ©ïkŠôåŸTù)I3¹ÔˆWó¦3¢ Ç«VÇ{vû‰.wÎÿ^¹‚!¦I͈µ,Ó*½ÿ[ž,ê endstream endobj 41 0 obj << /Length 1089 /Filter /FlateDecode >> stream xÚ­WKoÛ8¾ûW>Ù‹šæ[ä¦[ Ù6E 4È&¾¹>È6¨°%×b¶ °?¾#Q’EYÖnÒM”D~Ãy}3ão`ø'I!ãHQ¬vƒùkØü`Ä´ ¾GwÓq¢áyÜ þ\ÎÓ+„ - f›£4",T0[óѵùaÇ*ðèΚ}6^Ì>M¯„ 4Ò’Ê6‹° &”!:¨Ùƒq tùÕ¬læ^âÄ­‘[nÞ]¹‡uºzÜ™¤¼':Œ‰Uø[íÓÞ¸»5nÜM”B,ÌÝQ\{³ÞŒ¡½[Ýå*‹ Á*Ôïù‰ÁûÙàÛ‰c¥d(ü9Žõ…(Â…BZÓ>!8 ˜#!Y3:R7-•aIÉCD•tš^™HŒG™=˜hçžÿpÊx…Ѻ2ùÎ:'ç"‘Ðx½íƒ9øÛ™]zx*#Rîe6Þnýc¶ŠúŒé¶Œ—gÅD*D9&EÚ•VüãÔþZ÷Ç<_—OÖ Z;€ð³ôƒiA âÅÉþ±{@Xˆ¸G!gý›ÛqòßãÄa 59‡ˆ¶«)FœÖÙU(óªÊæMfª—­IîíC—“( ‘T¼ ”&íPCr—‰}ŒveN—›®!Nç½x™¦[%-×ÃGã‡êcbÍ}ž$MLå¿îknM´õÏo¶iÔ‡€“{“¹oçA×ÑÎ<òöpˆž|LËÅÛ8³=Þx¯lœ&Ñ¡%å ¸q;á q`ðɬZAZJLˆPqÔ9§Õu ©ÇÑ¢çÒÂU–£³éJú’Ø=õ¥* àSÖ‰h™þm Ñ},è0óc²Žu|ZØV@i%uxë®vúmŒ[“U©‘MKÍ’ôXžó»„àPØÉ‹ üi«É…„ýB:{¸×ØjaŒ@3¦Îâ«´.癎¦VÕºîÃUÎ÷Ôôž^É Fš©_ë•T$eØïJB5Â!ý×^ÉŒE¸$+s9‚Ë”Y~í* ¯_»íé Êíô&º7Ž!XÆü£°{(f–ü<ñ„ßv‹ég³Ž£Ëô‡;3Ç%Ò{Z  ¡K¹Š¤À=’/º´žÞ¦6²¦Ò¡ëÄŸ)”ì$ÄŠË©¯ï¢,,f¾yÓ%Ï$ëótxA O³)Â¥úè@Œqºœhã¬YönÉÀ9f]r?;¥Cò¸[V倹å; Jm&­7Èú\ë! e Iò‹Ã%ŒÜHÂ,Ûïlˆ](Û„hIÉ›„¡X!Â˲Ñhk0ˆ€,’ íṄO†¯Ú½wXPgxQbÊÇ KîT@¿š“‹:ã> stream xÚµW[oÛ6~÷¯²‡9@Ãò"Jbƒ=´k´†®5°‡$‰¶µY’+ÑI³aÿ}‡<”-Évº¤ X¼~<ç|çB~™°€ÂŒ2’$I‹$œY9¹¼¦A“J„J‚{·´ „ŠHÈ´WÁçÉo“7³ÉË‹$#JJÌæ;4*“`–—ÓßOãpZ7ÕâôŒK:½/Ì[Ó…nO¯g^^È(PDE<²848ãœ0"ÂûÊ4§,™Öù&Óv'›¦øÉê²L«;¦Æo»¬ïß,ýòlÓ8]ÈëlSBïv7­—ŽMï—©Ñwº9p@½ÖU‹Í+*iÝXÑ­°hv³Î … …H½®o/°qWh/^]á÷¡Þ4ØjZ£ËWwòn6ù²ÇS$Á²æóû¦0šÀÚSßÌ‹•m>«¬íüÉù!›‹ªnüËÌ燖l™sû-uØÜ"Y†ÎÏÑû=Ý8W$Ö‚ýçMkê²øK#GK®´OR¨°Yò ûîm1$—OÈAY0«@Æ!áB :³¥F¥í/U„EI§2P²†Ø<šLCY·®„\y»ä:]µ{Þy½…kÉé™`2‚âS¿+K},´-®ŠÖÕó6ç˜ÊAŒuQýHI™Ùê»Hðˆ0Æ'˜ XŽ(CFa?€¤„… íùúè6޼Â?îã™!næ¦žßØ†iô.bÎw!B!D<ò]ºÚƒ|5„ôg¢Ù{!KI (´Ë¿»MY]—U{2^Â$y_åE£3?^ŸoÁ¢!V‡Tê¼Hoë¯ý³%‰_lW“×M“>Œç;Éðl£6…[$z¾UóøÄ'ÝÙG*Ix,¥¢òÑS†[’Ðú–Š#'^Ï3V´Ñ-$ülGìñ3Þ™)ê*mŽªkÓÝÉË `áäÅQºžE{@Ñóqfk H[ ÿš–ÞG½¸.ÿa!>onÍ#(öÖƒy^pžžö£à’(&¾¿à80*H×I§þ»4[îò7¶Šv¸±¢fµûæ¾2kiQm¯W”ò;ÝÕn_¡Á…;ÒÞ©ò5îŠsy¨ÈJãNo°Y¬dÀ¨‘p£š•½ºÇät›Ùök`†S{Q‡0¯mM ¡<¡>þÂã /kvzŽ_wÍq·@Æl±ƒ›ÖøiA´Ì`…´ë+׈íAn ´'ÆS?Úì¥e‹–«)¸”ylîm^4ézYd6Ù¹›OÚ¼nFK?ûüF²AɶQ}„\:ºzX |I8túõ‰¯ïöÍúBxQ!¶«ÂÕ?÷e¼“I}ËSøØZðåö¦;v”]>?è*g’„â8©p…LY Ë·+v8ïåÛw6ÀtŠ}+d6 x¸6Îì¨çÒc<#Í•i_v÷:ï «Ý‹dfÝË?„`°>`þOðyvßÀQL"ìö‘µue¼*@ñŸŽÛÚý<7a1dþ$<è&æqaID”âCT)R>¸Ü=—;¢.À€w{êûŒ±…° ~™ç-.óþb—i‹cUíáoµ}/ÙV«×i¶Ïú “ äW(jQ™zdVxÖ•÷ÜÖwÚÖUofit·ÑæG¿<[¦ÕBà¾Akw¼¢Ý“dVÓ¾VÅHh/!…¢ÁñPÙÖýÊG endstream endobj 52 0 obj << /Length 1742 /Filter /FlateDecode >> stream xÚíXÝÛ6 ¿¿Â»=ÔôT}Ûj±—í>0¬Û ×¢pcçâÖ‰3ÛwéVôeÊv”8ñ®wC"K$ERä”þ:c… ˜âD›(ˆ„$1gÁ|uvõŽ),þP"Ll[ÒU Œ&’Áë³?Îþ:Â8‰…þv!1ÑL&NÉ 1DÑȉx>;{òR› &FkÌÓœPÍGDØ©4¸ ¿¿¸Ô”†EÖà`“\g8úÿ¾¼¥Šþš× Y¦I ³ ?·y³ÄÑï鮑ªl’Æ—Ò-ýÙ.úõÙ³‹w30!¸d”£6·I±¯ÆS_@ã‰%„xbÌ£ÒŨ6óe²¾ÎÞ·áÊ")êléÊ®¿ÛSØì+ÜQúÞI×zYn{Iã{]zܬóÆR½˜í„‹’pÞìÂå0l5„­wŠý6æ” Ä×mÌÊ÷ä*6 ¿Øô›µš+âQر ›e†“Õ‹C1y¹Æ¥Éü8@pn³G°…ŽéºÌ××ÈÖ”8µ-«O8ƒ1Ú’UÉf™Ïkœ_gŸ›Çv…É:ÝÛý6϶V¦=Š}ç¨ü4Õ쵄”(oЇór½¸©³§‡GÕ‹Ò‚¡î„h?>(‘X‹ÿˆ‡Ð0•)ÿ§ö½RûîG}sV†äæÎ¹Gc ¶âmÀtÒ#Q¬Ð”wŒvYEÃÙc,„t³† ›@RC´ä˜_3ÈÈ–ËÐ#\‘ ”îqÁ1]p–›úô–œF`‘ô™WezS@´D!@™M›åY­›ç[ °‡)6^„Ò6å ÂµrÿY2_âȆ`Žˆ€ËÍæ52/Êj•¥=ïökgeY7¯çU¾i.‹üS†Î.7Y•4eåÁmc‡i•lqä`ó‘À† r9k9žk›`]'¿ H{-þV#bO žˆlÀÛ÷B=ÎQJŸN¦5áñ4ì÷¡M;36Š\ÆÛ#áŒ@ x) áDd“Tuö~8€ö)‰€Ì#ïA¥uß9euySÍ;ÈòÖ\X9HxdŽ@V¯îYV9g žÝ`ÕOûØ•ãxµy?_¹í¾Ìªd]Ûˆ%‰‡‡Œ<ÃÁ@ðÁ# ­PDìÛ0°ÌXöd¦›Ž@ë@î×-5"Ð/%QDÉWçí±#\ô|6ºõ@0s’m/}þä%=ŒßBÛHOqDê󟲢(뛲*ÒïÎ'X_ÌÞ¯$ß>‡‰l…¥ï×&‚îq¼W˜¾HŸªWĈ±Çõj3‚?±"ÙÒ)u²Bûï)}|û8QÞö˜8',å*¹öuÞEY&E“!ŠóY¹×Šp•4UþÙ‘”ø¿)ë¼ëFw(¿dÂR ±i?J)ÜRS"…ïÇç³ ?ÊHi´Çd K„z/&-U4”bm©‚FJø:¿˜2TqH$Î=¦U—œ€Pï%'‹‘T!¥‹¸De×ùzí®Kb¸ùd8mÓb'w#²m[»PgsWÇ‚¨Û^€žm ïn?æ[!)¡H§©¼¯kûí!†i´·ýlqĹ=—’DPásÍ—eYg5úAèóÃìZµ|Õ-üÜ$E>DZ…ø¾ám_g§P½'¼fOWÁ—§ÀK:¡¶*É|®|=Ú92mˆô£›Œ®ëkµÄF1oO:©þÆïÜ]móÆ‘ºvÚ;˜w/B]Óh*§ªU‚b ‡šš˜µzjy¯T€ |°¸í>Ž] °›N§M’¯;ûzÿô¨iÝnTçR M¸u;à s—†¾}fa’¦#­8sm¯xiVù:sÓ»›áÔ[ÎõxÀô:X Û®£n]™`÷°awhtÒ»»©x©ð†ap㺅kÑiƒ%ô݆©Iƒ¡‚È‚ëÃZ,EL"îo_LXlë©·x¸‹%8ÑÅ=^½z¹ŠÛl’“®PÂÅÜJr¢¨ïŠ×ÓWû„¤"L«_hÖ Þ"Û,|cBèR²YÚÛi¤Â7††n.Ûó›¢}e¶TŽÜ„ÛgX ’ú\ÆîŠo'ZÁ $Ìtn„¹ÖQd ‹mU€¹U^ù¦´èùW’ôãMÝ8ÂÈ>k༫0VNþO6^¥ ˹ÚñR÷z›UN¢EJ‡¤¸kÿþiÁ)C8×]:ü A  endstream endobj 57 0 obj << /Length 1107 /Filter /FlateDecode >> stream xÚ­W[oÛ6~÷¯Ð²gˆÞE9Û°n½¬Å°uˆ>¸F Z´­U–܈™[ýï;)G;ž›&:?ŸË÷Ò$ÀðO‚ RJ!ãHQÌ׃é  ,¾ 0b‘ ¶•ë:`‘DœD`gÁõàïÁ‡>¡H1ùµ a‚rD${Ü•B<ää×Éàò¹Œ…")y0Y„D ¤ ³¯’`:üþ|$1fÚ8c›&fåÌŸÎg“W%H@l#‚Q$”Ûô:Y”&Γø6!ýÑ4¶-â¬ÔÎ?»ˆÞ¤ù“¼LŸåó"Ióe…‹=d´ƒ¬\'éZ—/Mœ¥s‡qö»Î²âÂ}xSÜfÉwgWWĨ›ú7Îz™ŒÝ#ÍMYõðWÇPQûkÏÍ]œÝ´JãRÍŠ¸U7 F Æ!*$¤ê‡jE ¦‚Æ[ä¶2éKÿ$cTçH…Èø$û¡{¡ù`I¡HýŸ|‹Mù³ð |àæ\~qycʶǺ ^è¯ÍÍÚ¹¾ÅróÝÄ>’«ûÚtá÷f÷{›ùîAÁ=žzˆëY]O")q¦•ùxGb âk“¥e»¬! > stream xÚ­VKÛ6¾ûW¨§ÊÀŠzK¤oMÚE4H“(Š$Y¢-e)Q•¨uÝ__Ž8ÒúU¬X †ÎÌ7Oúï…oyúç[~„¥VF„¾•׋¯ß=«ÐÌ÷–GBF­ýxµ¶B–Ègš֗ŧśõ½O˜E K’ÈZoµ2J’4¶R‘0bÖº°¾Úm±-¹’Ôbù}ýÞ½“#êÊB­s¼ûf¨D±t‚س3óùÑ;¿3û?—,°e'ŠŸ€cÎþøõÞÛnéS[Öf×ç]¦òÒ=Áé UÇ÷‹Ÿp<—u{ з²®³¡Šªá†T%*u0%Í×h¡ñ¾?ñ?ÎðjÞíøk£ÓJÙŽŸÅò›ç‚÷/‰^—mÕ«ÃË=ªGRæCÍõtŠ÷7û̳bJÒ„±jï0ƒê4ƒ&L§˜Á”¡ÞfµÐý¹Ÿœù!;,Õ¡ÉU%›ltùv7x“w‡öÕÃŒj/ŠóØÇÉÓö‚dìwâùǃ$¤ÌJBŸÞZ#X—`3¢ö»õÒ·?ün6Sö2ðßmǰDé0sZõæp£§‚£fŽÕ „R^|AsKU 7ךuüžñ"J©ž\'ö%G£Ìû©Ø‹IJƒ±É“ç£ã7ñIÂØˆ¿©ñ›,Ðcö_KæÛr0Œ±fû–ó‹®ì¹Ø:¹Ô…¤kÏø?<T¶Ñ“‹˜ÐÓÔò}ÝBq±÷,'òHªŽ-r?tÚlIè|pò2cŽ~=j9?¾‘£¨©mÀ3¨Ê7ì©Ï7R>àä8ýPàæ±bâ\ 9öÂñ)¯dœ²«3µºÒ ˆÕ8m°–Jµ+×íKÙÙñJˆÑùvÛn4ízI˜°@k÷#’B^ \’€E¸iŽeÍaÊFWÉÝÝËîìÃX´p¦Íbfù”®K?ó­yôDBÞ‡¬2qÍÓ3/—Nb+\R»ª‡e‹‹KjïzZ,-0  ¶°d°8K'Nì 8 ìóù¶„RnïfÕ-ž\Ô5Ìbj¶^Ͱ䓑8ì½ÓØÈ17G3ÐøGR›B3 âæj?Öx)µÇõ<°ºd ÑÙÎsýÆ}Q}ÜRëa”ÜÕÄmõ˜UZjuC˜6ð@tµ)PûtzLgðü¥Îþ•Í$«íàu'Œ#ýàƒM¹øm½ø(ñçù endstream endobj 76 0 obj << /Length1 1612 /Length2 17750 /Length3 0 /Length 18593 /Filter /FlateDecode >> stream xÚ¬µeTÝÒ%Šw÷»»»;ÁÝ6°qwwwwww Ü] î7ï9Ýýõ8·ïŸ¾ß=ƳªjÍšU³VmJR•¯Œ¢æ¦@){WFV&>€ÈÎÔÍEÑÁ^Q héøkä„§¤wš¸‚ì%L\|- 9@h`c°òòòÂSÄ=A–V® 5-Zzz†ÿ²ü0õüŸž¿7]@–öª¿î@[G; ½ë_ˆÿë‹_@€«`²Ä•Utd•¤4ÒJi =ÐÙÄ âfj 2(€Ì€ö.@Z€…ƒ3Àö߀™ƒ½9èŸÒ\˜þb‰ºL.Ž@3Ðßk@3 ã?.€#ÐÙäâò÷rX:›Ø»þí«dofëfþ¿v ‡rtvøa÷×÷LÅÁÅÕÅÌäè ø›UEBêß<]­L\ÿÉíúë8Xü4w0sû§¤ùþÂüõºš€ì]®@×r™æ G[Ï¿¹ÿ‚9:ƒþEÃÍdoù_ Î@Kgs[ ‹Ë_˜¿Øÿtç¿êüoÕ›8:Úzþë¶Ã¿¢þ« ÐÖ‚ ž•íoN3׿¹-AöðÌÿ Ь½…€•åßvs7Çÿés:ÿ«A4ÿÌ í_&æö¶žs <³’ƒëß”šÿ;•™þûDþoø¿Eàÿyÿÿ‰ûŸýoøÿï{þOh)7[[%»¿ðïø»a €vŒ­‰óÿ+ÜÄdëù¸ðŸZÀ“üÿÀ‘u5ùÛ Q{Ë¿‚°0±üÛr‘yÍU@®fV Û¿ú—]ÃÞèl ²þUô_Í0²²°ü‡OÝ dfcÿOë9ÿíÚ›ÿ'ù¿"ý‹:³¬¶”‚¢ýîÔE©üÕÞUÝÓñ/±ÿQŠ¢ƒùÿ:üƒ!&æàðbüûÙØ¹\ò°²úü²ý †õ¿ÎŠ&®Î €Þß’YXÿUøÿøý×Éà?`$íÍÌÿ™•¯®&öæÇëþq›¹9;ÿUõ_/þoÁÿóü¯A=€fðkËfüÁÖéY®õ8y£Szƒý¬£!ŽeMêÅ…þµ}~éỼUÆou!LÍ3|žKgŽï‡rtGãýضÔ}©ÀËBrÚB´-ª.nú£@fÃ2¤Œs­h¯«E…(].Í£½)U5ÃÒ·/D3]ìΰW´þäî…þ˜ŽÈ¾fiqXݨÍ`èõEgçTI¿¨‡ŒŽôÝ@ÐçÆÁQò›àø¦œ‘&»z;ß5™}@¿¸sÛãW B­†d:Onöw%¹Òmñ‚ ä.lµÆ¥Ì˜SõËv­øš‡Íö£¤ÀŸdYª…vf°™åf`tu× GÉI»ÛÖäŒi°c Í Ûf)ȵy+äQ~èÅq`ß"Þ¿ɵDL>,2ttÓI&cÆ÷Û­3Æ6ׯ¼ö›©T¦?\ñm›èŸ[ç v“ð~ O)ëCù”tCËŽw_n<í"s|üá&½Â=\¨2ÐÛ›ÓÉŸ[ÁÄ:t]Ág0€Áä›ÝÏHO±IOýìîjóhµ4" ŠÇ”§åò§8Ë5Râșã_²ÞÙÇÉ'ô:§ /¿3$FÑjPúÚ*¸ï(_5úu$ªX¦@õ¿Õ!š $ëRš]HO‡ð\,Šö]&mŠ‹®]O²­âÇí K–ŽkJ¤±^ w ¼¿ö?ÆýŠ:³ßÀ,®jq>;K°"ðͳ¦ƒS5ç@Hvk¯:1ê§–~cFÔcÝ}.O…B]š²ô-óA  ±Âo9nªFãŠ"–ÖQÊôS.öÝ5S”Æ¿Hµ®R5p<ò­_UDm ­”—¶Pµ!´ŠÞ%ƒvÖ1H:„…£7ȇ|3OªÃ}óýtì±ùõÁ€ ¬ú™m™¥gQvRwøøNÓNWBo ‡¤à)ÈV#`YF!ûÈPÛ¾¬B«9Uó0EßÏ Èž|³ÅH±ârëö…Zo©_k9å¬ Xÿ a&îù‡Ñ‹óm@éωm6ž4PrVPÛZx=m'àÀWH]!S¶ Bk»+™ƒ¾§2GFmgTÚ-﬿oÕ©À¥ù…sË/ž&Æ©ãûW šEöñü^‡ÔOú"©»Þ:Gu‡D'ámcÅÌ`ŸüŽ‘ü0W x¨VÐÚ½‘—„ ûjÕ’Fªp¥>xiPˆ¬^lò¡ 43`䧴yÚCfÒª u$7TÎ5ì{ mEÇm€äÍúDãœ@଒Yv$Gpòà3 ¾Ñ E°¶ð%Ä!u¼à×±zæêJï>“F!U'_(xŒ6n¹}¾t¦*«(ÇéNUu A­öÅp-4ªâR¼;{ &¿~h7¯µlììÆy8òMQ?d-^6¿ јc¯·C¥yN8óv½…¬pr![!7™ Ý”ŸQc$¿C¤ÛLvKÛ$sÆ>hfý  û“HL„¥ÈE˜ýéSšVc‚_ÙuâØEe™åõ©‡5jxã§NdÅe?UŠ2-¹ŽÓ½ÖO ôlõÁz«ò£#â¼|H•Òn)Ýs_£é\€JÒNg-ØEL´Ìà™¸<œŒFÎ.kÔÚþb²åÛkŠ]¶Ï†c«úrläTLQsm ÿ{PêýÌ6^ËV(¹ÍëÖUŠÑäÁŠýúCÁUiÆw¹`$¹„w5ƒ?Î&Ýv!IUAJy€óóܱÂ8唿_Däé§Oâœåóä…Š.t@"ŒÕĉÎÓÅ¥ŸÐ³`ËcÍš?¤Ên"ð—«¶¤Œ”IYþð{¸äy"˜>‚m“zxW#â$!9j¢Ç“%ýA’jjp$l•LM+ ’Û8e›;G‰b9/Ìôf c7$—¹“g©&@q¦s[ù-˜Ò²ýCÅÃ7!èïjl7¼’õÐOØêPõȸååp‹|®gðbó-ÿç;”cÎ{+üÌÈ’ÆSëpWê(`ØÈ×A•ˆ\›¾Åc8ƒ©Ø{84¿û7á4Ùf³Kû¡.ÒöNÞ`¶È ó¯võz¥#ôÂl!t°­Óõƒ•9:(::;Åø+ï?QG×ä—˜ú鋬KÐv¼ÙzeHõÌM Wˆ”ä¼\q|}:äñFÀäýø¥Å!©1’I}t®¹¢Ñ»Ã*¨ù/Y¤gúæõ†Îóo ¥ÐÊ¿ÇÂöêóqÅ,)ÍaÀkð‘fË4DâÍ'bŽË¨ŸTØþ_éMfçu|`§¬‡ÒÈ_`Ö};ú6?½à/+6óM×Mš”n!Jj–B•3%æNÁІ±Û Öiþkä–dýe™å‘ÚÚæÓ¼½ÜC#¨swrÇ¿« e‚&ß;:ù@û]Æm-Ǿ#¹T3}Y¼Ñ û8ì"·Íº¯Å¸<)D¨ˆè[¿KÈAOo¶À×óã`“¥PA= [(ó!cøóä)á…ϧáaÌ)jg~Þ¯—êyTÖD8S9ª€\)Ú…Ä@$4X¶©ñ ;øp¾ýŽåŸOé3^3Þ7Ïa[5 \“ÇPº5DKÁ°Ü¿J2®æ´mÝ×£K(ÿ H$¨ÊˆÚïï\Éþ‰ê6MgÕ–Pt'(ñh*s.Ý´û…7ý‡û Q"f/,ô£˜xfP:ZõI·tvKôÊý›·^jU|Ý”DÉ€ûÖý•󥈙_Þ‘cÑÊ#9á#,5P‘ÆÜ…ÆEÒVLÍ5ç!Û!«ù¾ØÎJy<=w…àœ×c²ÓãŠ$ ï£&ìß9¡/¿hãó„'- ¯‰5±z¹† úgD«™Bë…'Jv¥ð‹×ào¸]$¾j/ª°r+†àÃ÷¯Üø¤RÄ×¼„²±ZÅZmÓÆk ÓådiØ6 š\¶4«auVpŸRν\P¦jX¾Iýú¹:÷zÌŽÕKmR/ÓõÝž(3ôæY†ƒwŽg¨&ç®Ðª±¨®®I›í#›}âæ¬mf:«:U̺}ŠÖÃô†² 9Á¼àYÍFõTV9?dù”Ûë CмüõQyÍŽÎ\ŒKïͤ27¥–Áêžæ‹†ÃÚ¡¦‚üêþÉ{vžJ¾®!"Óå|5—y­;¾ƒøïTÕ9èe¯}sÜZP[=Ô¦YóøOÖmË¡? »Æ3‰üÎjÕº‰.ôñ æ?V‡(jɈð…IM®Né{—SËü eßÜu•H†4ldú¾^Ì$ÛÀa;ªêÒó3É->iýd:\1Yž9þm•s¥ƒµÞ¾‹Ö$A±,ã'1Ò„£Â¶œq’¦Ïô?²nÉó~ áÀ+$"­Ãu&UCê óÌ šûä³—çÑü¼ÖƵO0ˆ“o·_ùNœcÂñzųgï ×~~3?$¨« ´†[{m¸€ÊUÿÔèܰðiÆ>yüñò†â$Î/ÝrOÙê¸æÇNÖ^“2Ýs×'6@¤ï/nsfp¥¯È°H¾ñ$ûU(ïë °X•ó©rjÎ~Õ)JjMÌ*ÞS×( uûeüöô“MËF ¡B)@}·B"ñ7Míz‹f–;†"'2™s¶Ê— ÙoÆã®ŒcÊê mІ}=%q«Ñ´èåßÙfE×Ò·§HQÙú3ù´ËBâd^Ý––)ûÈݨ£ð“a˜Ë YÛ¼•1aä×9lÀð<=)qÞ 1ªRÜF?Þ{-œ¿=ŒmÕµ—¬•ØGÔ¬þW³ïúͧ{ü7·%uýî ú‹*:ƒ•Q”®Ÿ¦=ûýž$IÁ|Y=ë)¾­¸ 5ÔlgúßȆ2âc¢ãåæ…_oê„}áÎTPPÑpÉ„~Œ¸JnÁÐf‡åWþ!5¢ÀËAø®!üž4³û™ªÂø0/9!P\’4é¨q‘(øœ1 "Ç,DªÝÊ’ŸŒ*ÕøŸ`Pã"·h€Ò¤·‚˜ÔzÃ(ñVs'Ý6JñÝBÛTEt¬­†Ø!ÍãOú|ÍÄi>7)°Õ~A‘Ý·´8Øýd™QÛ·üÑfÿçôè6@¥Kðâ×'uñõ*ÓÄOêXt‰;°obœŸc’4ÁÖ§ÍGœSTáîmGËž¨¹û™ïT$Xº¤Þ"¼HBb‘šo8¼aí¬ÖJƒG¯|KoE”sßì°o©­¹]^o%¬Žãq¸×å‰ñ~çGÙžnbÏÝ̹P2<¹×80T>Ò{mxÅSw5XRÀ¨€E/VŠk ˆK×.ZÍlGHÊQËÈÉ`87…AÅý¢ýÓûS¢Èt#ÝÌ! ùb$óÎÿdq¾t®ÜКªŽTJ{Uëòœ2¸íDxù.gã™7øg†ùÈói³¯j2a·GNm³Zü YsígÊ"‚WväÅÔ¢}v¨§}œžÈ6¦ß³ÉéŽäÁÛÃ+Gè—²ºôº70Î, ‘Œš:ú¡‡±?ø? •¬ð³ê¬9cðyA¢ÔÎŒ;ôÊšËúü‰BR‡„-î½Aד]Y ºËkð^WžVξvŒ£y{ĹÞ?“"~vëƒ_Ÿ’ öÿ *8f•›„SÜaúaLni=Yä¶ ™çË>Ä/dÓ5‚ÊËN4|PáMeµgÁŽÕÌ27ŽÄÈû¶¨!’œd%] ¡é1j°}Í´#>ržO—ô'í(•‹¯ýšªÄt߀–AÏÕ/K=È„‹ï’<Æ¢B¾ÆÄˆdÙt}©·*ªçuÒ¡d,é+äVþxçÉAn#i ‚©¹»¦á,S“Í\t2áÁQ¾f ᢫¸â‡øx|Ebº»LäKÚ)2¯ßÏzÈ¥;Ôš fÊÝø®¨ÏÇ„,—´&º>RŽ`g’1|X³>”5öMä””©¬¢ÍÆ †éÀJèKp4É«Ö'Øát¼¡9IÄ%—Þãâ¶á~d¼3Æ`‹•ro`åŒQâLì*ßFoùû%1tv4~Ü‚»Á™ 6>v! й-Ž=¢ ò`q‚˜œ®Ý\~‡qÔ³lS!þ ¤²xSvÚÝÇöþÐä~‘ øàÝ~V¼òæX6jeÕ£;…×P™çj‘‹ÀB>¸ .—ÓeDÍ)“8’`}ˬHÄ¿ô‹urÞ9ý‰d8ø ÜSjÓWöÔsÃ\BâÅL ”Ø¼Ž°´}¨‹°v³Œl&mâSgík4µ§žÉýVóûã;gµtgŸ ÌÒ‹àqƒQ©#Aö“ž:›iföÛŒº„7aº“Ò°j•Aa††|œìLǸ6ÑÉ$(*¼.HKŠÓ³Sh)r¥{}QÜ6ÒÌç±"ÅɆ6\RìeåÍÐ9²-©"£D¿¡oa·šÇX«)°êú£FÌ#‹§ûø¸ìèw挋+Ô^¹!á–õÅ,‚7pð“ol\Ðp¶8Ô\B^{uifBEÌ’¬ÀS•—+N_öNløUÊ—î \Ù(á{s:&,âzNp=5Ú%ªQ×ñûä`%™©™¼fªtQo^R°ç§¡j¢+ï.B]è'Ÿ,oLïdð t)iä¬o3è´I=µ=ï7òî7ñ€f_ÒW,šé¯•nà!¼„?Ç—qC~ÍsÙðûr¿x›5…M-œ2;ë`]n~¼! G™téh48&£õvíĸæq§Â …—á»äm–ÝÉ`­„"%¢uÀ «d˦äP®^÷·~GEÿO6ZVY­WHG-çJãÎúÜ}ŠþŸ¾±±~m,Ì×Gÿó²Âkâˆ%ÓW-HŒ–ÕAt¡( qTµÌ Èå'ÁÄæÆÙåæ—ab¼WÕÎØÓ…oˆÉzYÀ x˜SÔ'vê± ²«¯#ìuüä'³Y5Š"¿( £6Ja½+³X+ÃWŠ«¶ƒ¼4°U~EШ‹Uvæ`uY|•gŽ,ÕÁíR®˜.BjuZ^æÏT1ÜcÕ•tÑþ–¡&t»$±d‹xýéÙ%ĨC-+zjÌîª*‰ÌaNº7òët´D[ŸFÈjU9„þ5}ï…K9˜ôŒ%¬hàŠéÁ v_´!Ì^én”ù”6 ÃÖ/ í‘æSȇ{C”ùÁûuºR$yÚ²©êÌ)êñ‹6³=ê<<Åà7îBÔÔ®(¸ªÖ‰GU%§cãGĻԗu},ØkŸNЬ$£Çú/–q\·º‘ëûˆÇ\¤. ¾òkA²…±àYN´A3;îmtrHÇB£™:¢ÛY‰^½•hï·§Â V _T–ãnpvߊ¥‘üË‹3u»e×|›…½K!E’¼D:ì>T×%phøìŒÓ™?éÈŽ­”ö–kwÂJ¥gœŒÎêåÏIÔ AVd›»kõ3ÑDz°¦>Ÿ+Ñ þ‘ &¯œÐoÕ µ˜fÈ(‡ÓQÞÒMqî‰ÆlóU–²Vx¨,K œŒ*ã%¯Ã¡U¾õÊgëbÒ*u&ÛÂHØ ÏÙõV¿3êïi™ÔU¾ í¹§ðX eB¢‘Æ Sy|ü¸æ( øÚà'QŽ_¹öW¦)Ù’"à騽g‰hÊìç{4´£]¼ó:’<áv¢Ûô¡å©_%®¼pÀÒ©þ– iZ²†-"]{·“ÚâwÇÖWñeñÜue zaížžŽ D„Ó,͇$™öhI/eðvÕŒÀôHvß?,67IͨvBƒã ìÀÉjÝSwiUˆùÇFÙr!Aì9ŠÞË £V¾)“Š»Æ¹Â$IJ1RcöD­˜Õ"¬;4Ž—~õUpûôÖ¼»n"¾ý™Â¬¶þTÈG䬡ÛC¿£“žaR ø½ û£÷—Ú¡NsY›F霘ÁqÏôÔ$Ñ/’FU+(3)‘™÷rë’Y¹ÑÏw[ÃŽy7†S)”bit¯Á|ûå Œ pmIÀÛC“´Züþò™4¹sKxß{p\{Aqp¯2c3ªpB]ÂI8;Œµ;'ÞŽ_oÏÝÎ!*0Ô(aF‡Oi;S­µ^{íFg×ùØŸÛÚ'¦ªÏÑ8@v“ñPV<ÍX×…Y­¨«ùŸ]ÜB܃zz®hÌ,½aw½çâß+£!#äDqâN©«#­ß幦3êmW,Òä³—5üe”6z6Ø$ $cAmô¹TQ¶EêžÇ7h,Ûý½%6˜Ï²¬Ò©ðöækÚ—˜-ZfúgìëÑxÓó ¯72aÔ*™jvŠ™Âåg}±½ËaŽäûù‡±.[1Ú©Pˆ¹ñ!E "°îåØu¿²d¦úÄ ×k1 ÷ÖI ‰¸.¬Ôƒw“m1‰ñä,¼~šCn˜ ¤ß•vbÎm¨òÌQýìº6Â7ãåy!qÃ}…úå¾™?"“.3òv‰… 35K~Õ?)Ò¹Æk ´”+ÛýB~&`³–tl¾ž¢¡ÎUãÌ(õ`¶¢2òÝó£]ë9xPÏ«?‹â¢W^SZø,6òa'%Ü_0Y‹ñÐÁ-à;‡©|‰‡o¨Uç?á(&͸`%W­w(ÙN%ã%Ëg ˆè>¨±a/}RíŸvPñå0\Ò(r«5Mæ°Ì@yG4§Tm{ÍÔG\Z“ò½PÈ“q€Ò°ß.~ä°ÑÀÂ̾©’h@5q"œ@¦7×h Wy˜þ°'¹#³Ž¯†¯0ÍöwÃ~kófíýc‚NÄ4’¿C㛲¹Ô[àÇítóœP%ˆBù¤®‰²Í/‡½yK(žçÖ¹G/ÛrKš\±wËö©í@ìu¦…j·eÐ.o!Izý˜3±j¾#¡ÞÈdRTJÚ¶Uú±€OhÁ“ØW‚·½‚¢®‚üéÒ#ϰöU”?î]Ä~Q ‘¸6¾ŸVoųA{f0SMgOÏYÞ´ ÷ºOšãSK<ææA¹'*ÅËó53"K¦HVŒYˆO²$ÙµòpÅÖhXý ÊÙ Jˆå'LÚz¸Ì›­¬| ŒNβs½ZwE"Ä~rš8q¦ c¿Y¦+ñ¨`¸´Õ^¬§žŸx4”©œå}¾%. IòSŒ¸gŠÞo½oÏþýX¿ï<¤2¶[¢]»‚Ê"§Î UFÀY1>}@ÂØÕ£=Ò>önG1,SPÃỌ†ë@N+\âЙ})ËÖIku¿®l]æì—hõ뇹ǯ¶+Tã }mFÄWc ¤¥¡ÈR)þ)0Â&­± ìÝùŸ5ƒ-jÝÓÌ go[GÀ¨™áGQ"D#ï·kªÎð˜\AŠ±Í£Øßé¬`£ý›t[7Ü—^×O<¥¿åÔÚeĪ~JÄ}›3y(Ô÷JÐ$=î,êuUYá6²®z#r å«2»DAÒb %üÎheC©”ÇìJŠÍn;ÓÿÁ½ ¢ƒE® âN¥PÿíÓŧ8΢“¬'­ª"Ô¤q28(©w|%MоÿN¥›¶sðŒ[¸SÔg#ûd9/ŒHÕAºÚ‘‹ Æõ&°¶ÿ)‘2Á O˜5>.ºË(f­ ŽùÒrrYübâ¹ô¼ ø© +†Š9ËÑ×Á‚9’ŽãB4Òô–£Îù¥:cåöðó5|ó£5zøò&$RSd¼+œ§”Êê©/;/#í¢×Ë 2Q^ûpúÌŽ’`úÂ&-¬ÄÊ€M Ÿžo]3àkærѺ>58ýÁ(ˆ'žÏЙ>˜¸•‰Štæ6Á‡’”75Ô‘=éÙºA%öÛTò2é-Ѥ^zÉòeò„ü>æ¬#^êöœš— äzp4fù G‚yYªu.Ó–M|1Zó‘g2 Ç5wÉ Ã,a8è-ŸCˆñ’K›‡ÀƒŸ¼%®”\â©·N,ý‡á3ÃìÙIp]åÍ'«]^ËŸ7°¸É”R¬în–yar½$`âÚeÞ Yés^ßø5GÜ·MÚå½ýHÝÉxÚíõ|ù«sÖS|›&7¦L;åǧÅ>¥TÚÍÝ݆Ѱé’P¦:gži[Äš~4_ æ 29› äMÁVŸ½Ú É ÷œ:W'Å_o~?oŒ ê {‘Ç(Á„ìh%£nÂ}4RZ}'óIøR=P zJpçØ`af²ÈhI´ÑÊó„qUÓ–,ÚX <ü?Cð£äBt*¸³ˆUxÈ#! ù ö⃲´/ ²±DQourbm;@føBïyÙà8tjW¢Füç^/`£Wý rÚÆHs)tã+Eă0š†i~~})óÃ>”õNXHçˆ>éç–3„r‘g.Àù~ÿ;¾PΨPÍz¦ Lh(d§‘b šQðï?¸d¤|”€¾`YÇ|þ¿qúláM©ñìX*XäkQè $œõ&H¡® ñhÒ rà›d¡½^é’»F ±%Å{ÁEXJ|G¸=ÙÖšêr^3$ì“ú¾©n¿¤…Jpürº‘Ó˜çùšë಄hjŠS¬+0µ f¯Q¡²Ç´l¬a(cÇwäô £Ò‡; Â{ýÒ†1Ø-ÙY“zx-b•肸øvMY‰äÏ>)·¶°0íÿcÆÕŠ£À·†õó‡(ΣÁÖmN©MöíVœNÓð]™€À{âDq–,ÍL÷Wz¾Ëô‹¨Í?²£T¿÷’¥Õ®pÍHHx ý|÷EÇãÌ®Žå`Áކ!™Q½¾Û&£·°‚ÍSI‚œp˜‡JƤëðXÛÌó!{’îŒxun9ÅmÔÌšm‡nGæEóIº”EÈu»A‡Á~0ÐÉmÿn¦bŠê;¦Ä“Ž/T€aªËÌ d/ཆ¡öúNü-?x÷.b…é<ˆFö7î¨ÉÛæ6ò ëÏ\ñЧø©:…ò²;®ß‰b¿9슠|3+«(G þ zÞ$y­F—˜rÂJJs#%-Ä11ÚE[W7'–{vŠ–>ÏͬÖȦ™wek4‚ÝÒǩͳ7R£&E±£)–@+‰°•ÙlzŽÛ˜Ì¢»º¤Ž«bWFÄ@n£~ZM tÎÈ•¡=èý¶ ç­ÛDC&}ãBÉóãŸw¢(xtÒ€×h”cµZZ>‘2Ø~Óµ>-³Ú•–ø–µ¼©¶æ‹M$P¼¥Gô;NCõ3ÍBlâÎ[I©Fùxw´)¼ü™»Ðú+9â>˜Æî…F‘vnøñJð9UöÐ\”o",üqEì,;qÞ¡ÔèÊìê¤{Î7Û!hcˆZÕUÖg1ƒdžß•YópÈ¿"×yºÛÐC)¤ÛWÎrÜ“áù®:Ω¿T(DVT¿ 2•yéÅu(T8‹s?\i‰h)Ž0Èý@ Ü#ì?©u{4wæÞ‡¦Ë — þí&·ôYX°^hžså9²aUàÛŽž†I]æÍƒ×€5üÜ£²o„žgZN[+$ŸopNç±g¤Ü[µkö«gÚÙÀHáîþ>£Ú8–I{ÿý©UžJ^Øy+”»ÛŸ?1´_´yóc©¾;}>–¹©k Ã+Ý}†Ógç)7Ó`8š'û8ºK‹¥¥ENõù¬‡a÷l‚ëtfŒ·@„´Ÿ4ôªSª‹©ˆ¸È*›æ³©¦ÂÉZ¾œõ»º] a¯%ÛO–OÖÅÉÕpøCäžöÐŽo® ºˆ*£ÔmŸhðkR‘È"¸'Õonð²,WÄB.lG>,I8£*dqˆoäÇOéY÷0“!|l¿+‡–>è{& [¼‚õŒcÙFìSg.ïÕK›²I©°wAÏñÚªd?¾øEZ÷莨UÈ¿óµô6,ûc³õºX \:ÈÃäÕ>qÎãÑ¥OɤÖs÷NéÌodŸIô„ôÏÕç/†L¾÷-—·ßeP¥S¦zÕsB£«÷£vÓsHIÚÂ,$waÞËî©Ï2˾Ü-€.p„£•.^àýÔœ­îÃ_½^Ã¥îÇMC|Æ\RJcŒ2ß©‹_!1¢Ø¡Ê&$øCjrý€(2AÊÍk`?¢4%2˜¼ZØ ƒÎ@‰IçÿÃ$ãâVÛP~NWëîN%¯4kDc6•’僄۴É.\/$ò;l_ÉZ}—¤¥zº«=Ù–Å ã­³“åwZÿo}[Ö«À£u½·1¡€xRZŽšýÉW­©¬ì¬ºì‡y6*×=/‰D4\Ý©  Ñq^š¶;—’_؉n–‰?æÕD°°¬3xõðWƆc~Ù¹’«ÇO¯Þ·€è\a:Œ×\|Ì{BE&Oå•bËh3—ÚÖ9ˆBˆoÈsˆÙY`Ÿ”y®ûM­Ðó‡<ÐFÑK‚”|=x@mðŠ,?6mKªz,W´¡~ô¾¿á¦ %ÐÌ:ww»FŠ»@Âk~ßÓ~ú5Æu€Ý­08ÒöÚÚòa`þ‘âÛw{¤Aj°R´Ýœ*yéÄ%Lö[S{#Ýü6~â$þÕq 5¯ùÊYh‰d._9qN²—sÜ-(áðE*˜žaH7µâ@€P)Ù · á{ègY1i‡T>]ªéË EjúÝxeR©wÎ&›C³R;!H D ?+ÒIdªþ<û«àŽºïgôñ/ë#k¸ o–G+Aç mù"2!ç¹¹û0·‡ùK³ö^è­fQarÞô üBŠ럎¾ kÁ)Hl»é8ÌKvÔì»ÂD$΢ ‘ 5Y]FET<1¨ääã2_ˆŸ$:®þN”ÿ©Ãƒ¤¼äLâviSø]¤Í3éåZK½çÓ/—Xz­8YE1ƒ²%r¡*ýšç·/†Ýè¶6`ré"ÈŠ²+zÓ°Yû‚vœ¤ä—ÊA(ñ.(Õå0Q{¢˜€M”u÷¨8à\z*!sÃ|ÆÀfôŸ¦>ŸÆ Æš‚§ßûñGÎä’d„Z°‹b^ò’X¢_÷4ÏÜyœ ·CNö¤rFäKò$Ô“øã°7ZDƒ|%ËÔ¢Ð{Õëü}¯|H­¢øþlUU CïÉc¾8ÃeoµÜ.ñ'{Iý°3”lg¬‹¸”Eƒ=å}KM¡i ÚÊ‚nÔÉBásSø‰Ó8Ì2’BW󻿠"¼+qÉ}Τ¨ÅõÂÂËBÛÝ ë×!.VQ"ë7o»âª¥¨y Yõä'%ÊX{¸ˆþ!e;šã¿C |ã`1Ós õÁ*¬òjJj6ÎýRø‰–:….¼¼Ð†LÄȉµf vΊš~CM–‡,ѯ=…ŒÇ‹`²N¨ßÉÔñIu@÷€Ü4yN‰Ø¶$Þn»¾Ž'FÞ‡9{†Nb´ëûÐ×°Q²e»`åv.DRM¡ß£à‰ ÎŽÌ#š¾q?i4»¹iïÈEÉÐ"Í`h}{‘»·Ð\ì­ršp,¦d¨ìAŒÀÁGûݱ²Ú… ÚVö²úÉ=ƒ0¨a]©·È7¯° `#•Y»RãMþ¾Å%G/Ì'ÖT䨠+Lÿ$õ_¯ˆ>sů:Ô ,r`‘°L=z+L#D;±ܤ輦ŽÃñ÷Z…ŠŸq`c¿û\ø ˜±»¡^çêÅ*U¼?ÚŒ}ùáÓ`^QBŸE||HÆÝE±×ÓjaL¾jóuD: ‹&úŠ«[¿sè³~ÓȰjmâ¶nrX·©¹2xÞþ¢&…ëQËÆáaP—BóÓ×ëô¤¶¬¥.JüY$éëh©÷à± 8x‰Ž¼+!3xÔ—fäuvÄ.ÓSQLIÏ—¼Ã{ͺbåA‚Ó”ÅÑš¦`ãæ®J’ÚÁ•ÓKŽ÷C‹â¥Œ3ósÔÅÕœ%Ѿüi†®È)É)~2ß»ût¨Ì]• U˜«ŠÄLœdê=pˆš#ޞݢã•Þ‘’ø<„–“šd0Œ>\¾ÜÒ^;Lï%ÿÛJ¡µ;­ÃjQÑÁÑ`ˆžtý*Ù®b»lK“·LN ç7ÁZBøåν…ý¼…™vÓ1¢xõ‘U¹œVaMv,Aué’¯ øBò^¬ê9)Ô}<²heœxKM&¾Qù„Õý¬É‚ýŽi,p´›Dh(ˆ3Ü8Úœø‹\ZPô„¸fî÷ãtPäôéfdzÉúÊî°àR £hB"¶§³œ×iw ™'IÃÜt´-©¸Š#üa¢Pst}‚â][}Q;±f,o/dr¦ ’WSç9B ­#:‡¿À*{«úŒ¼šÔ%6\ïbô -$£5Á¢g7°¥œÚ‡|€ãÔã­èvÙúne#ºÈægà¸mï„9³Œâ–xï&sIŸo¨eCB`@DˆÎjÚ=š"I˜†ö“F0öåÇ5J ‘`zÎ);]ëÅÃÒÉþf˜8hÀ\%|çÏ“Ÿ©JZÍ=Lž¾øÅAgYßÎɽ™·kbÍCýIåù˜Q¾ÕŒJE¹Ö{Eâ4Gh”Ñrþ/nÎÖs”q:Svbt*F ×£ÈD<ˆëŒ#8¶™L™þ0òn1®ŒÆß7ÂÎê·â³ p…cl»pGÕÞyrÒZ­T°~uúÁWK>ƒ»Íøõã- ‹ëë<âÈQ)óbSÚ€,î¾þ´Þ4&/¾Î²ÊãËù-B©x,'·t`«‹ùDÒ½âøì3›Ç®•`f‡o\áÞ‹½VÍŸî8ëZXÑ_8€Î²öÏÔ>@¥Y oÙñD ðó–“p½¢‡É‚¤Œ g½#Pç“’6Q\›^ŸÂ¿ÒrªBÓ W´t?Ê~t…šËÞƒŒMöKŠô·g–dÉ;»¶¿žb­ Ðx êu†ˆ±¹g~üìz²Ë^m¾¯ÌžpObNqöË‘®]ýÁ*Ò„YLs#Ç-·ÔÒöâchȨ@×&<(@Ï«éª0µÎp$:¬Qõ ÛþÿËŸ¼×¸0¬¨ô° !S×–{ö£7À|ªc‹Zºº¢FõÖpØ›úi}Vìóîv´p.‰ŽôzV ë£5íê °N=r’mbû»6Ð$”Ëì#óEz‚ŽôÝ@n¦£&¬B‰Uµô·‘z²–u|´ñ@\¿ÍÌhUå…„¶ µ˜Ò‘ž‹õšØ|¹ìîÂ{ŦܬH(ŠÉY™iæÖàꚣïOÓ;ñZIÇ<¾ÀkBëCô‚ŸäJ@/7–µÆ¦bV¤ÆCµÀíÍ2YgK‚ÐY¡dýŠ?–9“a¦¦du~A BIõb3¿ü$r°1™A[˜bæÛk„’V¬wPÆ×éIzV®“U*³Þë.Ñe¾¨ÂG\4â»àw-f¸MpËcë­XÀ÷¤â*žÜ =ŒÓÄÌ“[xoj R KVÓFs=jPDu:¦L ÖO,¼Ûz̺¬åÍÅWÇïˆ*Z‹³)Ò²lõávTÐ _¨º'EbÓ!XýTukέ>•bP9+\}‡Ñ¸C(c:MøP žbVÞAn™yõ¡,»•gº=‡ ‚N°š¦¿j°Ž_ïN0·Jc¼CÆÖPâš\4Äû´§¢u¢cü‰JA{ÐÉÔt¢¯¡_vÏïÃó ùQá’ção·ÉØ-eOj8Ϫ+&ètìûÎ1`­-Ëd<ùµˆ 0¥éd­ ×ÞKÌj1!ö³hÆÎ!»ñ鈻ø}¿D—áezËÚ0`oyô~‡z ±‰>—ÿ˜kn‡Y÷¼ÿzjö‡0ÓçÕ¡ïNe+¹âš«»±['e&^¡ÿݼÏ[P,ÎÝEï¤ÖíÉìÝ*bÕ³ÚKò‡Úðâ}SºrDaGHêÜΩ>Ç‚¾ÁLSi¶µÐÞ¾æT4ı\æÉ}ÔÞ›^OÜ–?|]£ú±Wž#âÝ[hi¡ Ãv¬Fîkº1]?‚ûytñ¹ï³®Wš~"{@Ÿ6…N©Šå¹Š69â¾aUg8riH¶ì)mÄPௗA>áѨ‰wéc*"‹Xø6óþ3œ“gªý+îpYµÍÐC½cà=3YoÎý)rªí‹f¢2ª„å EïD.Ê8äÃ"ípÄ9™;ªüa¡]ê#QÅû'ŒôÕd¥W?Û¸ò9øJÖÍd.Î-ã»5´Ÿçq¨u´ ï‡z¾àü¤LVVu»™öÕmc‡»_N4}_\¦*œžn²ƒÎÚSZ«ö “d~÷i¹z³ÌZ¯» ™+K_ë^^Ëà¤?5=7ËèV6ûU^¼†H@ë~DŸÓ?øT%¨–H^\O†~‡à t0kj°ÒȨމZ°ðÜËÕ·ZWÚ]‰™?I8I óÚxüî£9ûá]RBµB81MV«üe¨ëË ÷EŠÈb¦h;𾩲](¿^äd•3ÊùÖh‹v$ã‚%Æ(úÔƒ¦;ÌÝeØŽilèZ‹&ÉìkƒåšMûI÷îÞÆçÄœÀH”ã9ý‡ËÝuºYÅ—Ù%U³ ºrñí/Fh1ø„xáÌTÎmN›u`Â0}ý?cš¦½^1vFÄ#âÆjZ³?WºøâË—‚Ž|hy£my#Eë+z(—ªl Y0+)bÓ­åhÖàœ#fÅ}á~¬Æ;?”:ºkb‹b‡,é+ºýÀ§KOü…R«šWØ”?T…fÈ0sE «Éú›“û%Z´ã˜7ë <ÜŒá*hãKðرÃ`¾‹ÿöã]n]TE*}åpËIàaõã6{.r‰z‡ÕÍ×D"6Y»µJBôÙ;4Ì©Ž~)yr]ÛÒZýKúÚ@=ÄÚHõúõÕrW!=$Zµ8ÃKȘ´J,‚ï´É¨àȆt£Iœ)eyN/Ù/?èÄ×%NxÞu'J0wÕÂzeú’g2~`Ipýß[ùÿ`tû‘#E*D;Q~£ç:Ru,ùdñøe³@Iü?~ô—û‚×ԇѥãË56:Ea û4«Àªô6î÷aQ›f¹ñÑXiáC6=ƒÖŸXÆ‚'¿)ŒÄ<¦ÀÑê%ü‹Ÿý6)¹´ ÑÃKéÆý…÷.&„0ª¤¤mku–JCÔoRð (ŸŽ4zmé‰_ø6†vœÞ‚·ž›Þ"º ë\“g"û¶=0Ò¸BÄ/‘ŸÖ|ÙfpØ8~CŸ6ÜØ¼N-B±ÛgJ¯°xÊÖ ú¼¼á+$kO´U=.L-³ÈÜ ¨göNÚtØç¨ïmå’Ù,9?›®Šþ•Ž–J¼RQVgm¯#HBƒã£¼ª[ÆEž^ÝR^éHà­Lå+}„NëëÚ)?‘÷÷j„SG^@ ðOŒU«<Üq¤Ê¹²£J Ð.m‘ÀT·ûeÈ­eRF7B*€Ú;íP¨Ý‹¼ ±ùdÃ4cú•+­5|V¿‘€§?†XúÒ{“@ 7`£hCÊ9…±)šEEÂ~`)æAŸeÈëÍh…Ŭ]€åÞ/ºWDa¥}´]ßºOSÎF–wˆSl~Dâ]¬úδŒøËÜ5?ݹ׎*¯|9ÇÐ=ÖÚTd†_´j:Þø–2"ÔõXj¼ìKr˜jÃ5Tª6â® ÊWȨÀû!ÉJ/SQs‡ª87—쀟7®õx:„º<Ü&ï™WuýšZšXßz;&ZDÀê Á_ÕÒìSÐpì(¸uÚSûZm©ÖÖáÖ«Þðq,.°IA;ñ¹wô‹¢óãû^x•Z]–º¸cÞüÔ§Ÿxéx2ü}ó¢ Ðz½}TªêÏ¿¶uŒÍtѤÊ} ¤;ßߦe3ÓÜ9]û®&·ÂH´É¿Ñ>ÂKátÉVKk:#Ÿr*ʶ±‚|b›ªjK¨|¹$Û\NÄÈú;¡‘Hƒ@ÎIðkn1s_Џ3é¦fÍ¡Í~ßDàe„ÔY›¨:$&cr3™KöwWÀ!þê)ÿÚ_} C­Ôì¬v/ìž`ðýð³êD„"Ί†;É~ýÄ+|,WÙG¾¡Éåý^$Š´qí°rè•–œ;$šm2Wv¤d„é:Œ©8Ö7mPê\°4‡Æ£èN`Z+ê]-o^Þà¶$†OèèŸF¤¾ÓG–ˆŸVÕK–VòhšN EѰâÚ‹ö™}!&Yª^GŸ£xl§¯Zw:;†G™ASâEšŸ†é;géî M"K”HNHî“ Äæ°Ã>ˆl àÖ¿ïó Øâ“^t̺+ª™y;<7™èwLÈßo’BQß¾ëÜf÷pS’ŒsËÝ9Í"ª³>h´¸Ì,Ÿ òV²ßs ÂË]cÂXG×~‚fºUUò¬T]Þ°ütïÞÒÒÌŨ³Ò«·áö/¹²{ý翌Á3ÞÇïQ,‚™(y(ÊO“b.º]°´®ÿÙC‡mDƒy~à%€EWmïbßð’?¡ÊõLÝ}Ûì )6%Üû"s°Úÿªò'†@Š9£òù)0n,THÞ–Ôø2ÙçIÏàUŠºo´öÝŠz\BàOuŽNöâ÷Ra„Ÿ˜!oúí(îþ°ì\¶iÅòŸŸÅÎQw3#û»ÐiÅ+tªs51¸- ­Šz(ÈKªâˆ^±ÊÐ~Ô¥Åül_Z2kxõ  º»,Rò¾Qô²ìð©Ät5âmSšùlö>²’˜fÕ¯ÙúOIÅs,ÇžVô)XZ„­‚ ío8spLòP<¯ð>÷&A­c.+Ògl8Äm3¿c¤“¸¯È‹´]€X5Óè¡è¥çy&g²P…¦c²Áøkkí¹ø«ï¦“ª” ØD¡zã=ÊSÎjÌΠÚðÇž2b”¢÷çêÔ¦ïž\T¦ç»$] B|\å€^ sµ2îžó”öÊýÙÞÿ' _øÈƒZˆ¼Öy&õä£÷:C Ã><Ã2•.m»è²álÌ^ýëñBõÛ†Ë4˜ë|º´¡ÈµgÄ=¶e$ytjùï%*ÐÑøŒÐ?<¡Ö¦°óV™ë®è—©&ÃùnâóE§ä¿ËWÍWÖIìu€[ìÿÖÖJ¥êPì!süïTYÁÝKŒe2¡o–ú1%´C$«ÑŽ;{ÏGúAITjs`oh)FÓ¡ò9Ý‹ÄÀŽ¬Ë†á383í»2Ù¢ô%ìl§œ¸‡˜+f‡DRf3€8‰KuãûÚ6Òû‚ÈÍþŽ’K¹$Cü+¥¾¸.h¯K¿3ˆ&:F> +ºqæZz€™åk$*ÞÛ*w~³ Nu—¸í?ÆC ñ‰öOZ•&Q#»½Ã€.r•9ócYTãO*ë¥PÿžÚ%¨ì$䪹X?,{¼9” $çÇ’ç,ë4?¿äÎ^ßçJb¼BaÊ?䂈·tQAã¸|D'QÔ?`ô³æÊxÛü¸•©¹ãÐ?ÓKjPl Ì“ úÕhN©¸‘]² Q`ÿѳè’ìa¡ìª¯äCc¨½>Õ:ûŠFþs¥QiRiw•ù"ÛÈ7J~¯!•xo<$âo„Þñ‚q«xÉ'l»\ë6â"“ppöЭšZ5z›äœÁuÒñ_ BÖ Œ·â‰oêþ (ˆ-9 nG“òß&Âo}")—¢³LVÇMû â„B*®‰ÄCô,²¶% õ@tU´íÆ[ŸÉ£„a5t‚SÝ•À«–‡3ïzél<Âå™ÎØl|ò3$ÛHÓŠqýù¤7¬êÞvfuIÎiꯟ;›ÓVPV™àqNOÖÃÒ]ÃÍ„9>ÌÏ ›µƒ¨Åž¾!xtW\\Ohg᳿öŸÔG›v¥ž~ÇH5$?ÞL«©ØlJ5²­;dgêÉ}Ùey¶L»Ïæ¼—ð2àUª\HìÌuY/ã-4Ì—i¢~BìäûÇš¬‘å¶Üt»?Ì¢ K¹)àæÏoÇN$B3ÿõè]Ö¢Ñ]W«ƒma«i­5M¥…’¯tK®u‹GŽÁ‹Õغí¾pÏÚõZ˜ªÝØ> stream xÚ­TeX”í¶é’NIAI)q˜``˜ºAA$¤é”Fé‘îé’’Tâ ßÙ{Ÿë;û×9ûÇ{]ïŠç^÷Z÷zNV]A%(ʦ†B: ‚„„eÚp{K'0RKP…€n✜*Ž0°3…T;ÃdF0(@ˆˆ@ÒÒÒœÚÃnmã à1Ô7âåçø—çw ÀÒã‘Û“Npk$€ëödž@¡íaHç[ˆÿóA àlXÁ0€ŠŽ®±†¶:€G]Û CÂÁ€®‹%hÁ!0¤Œ`…r þ2 ÿÝš“Ð-–’ pBà ðÛc0w ý;$@ÃíáNN·ÿ¸ÀÚŒt¾3 GB.ÐßnýV¨?„ÐŽ¨Û ûÛØ-˜.ÊÉÙ âG;n«êªªýÅÓÙìü»¶ü6 @YÝfBQ—ß-ý‰ÝÂÜFÁp¤Àæîü»–% …;¡`ÛÚ·`hGø.Np¤õ¿aÖ`G(æät s‹ý{:ÿêð?º£Ñ?§Q²þÉîìCX €DnkBœok[ÑÀß‹¢´B@Âù¡.èÄ\aŽÄó{gxoI€¡($Â…YµQη%<ÿ7•…þs"ÿ$þü‘÷ÿ'îß5ú—øÿ{Ÿÿ­æ‚@hƒíoà¯pûÂ8´¿ß˜ÿ• ¶‡#<þMöß`1üw ÎàÛ1(!­o¥þË wRƒ»Ã ºpgˆ À Œ¸Ñ¿! sDÀ‘°[-ÿŒ ÿ[ì‰ b‡ü=t é?!úwæ·òüá Ôzl £®Åÿ÷×ôO–î­êÎO<зÄþ»Ç(è?ßÊÊ(w€— HR (*,y{Ù„EÒbÒ>ÿ¦Þ пìÇ`gG¸;Àô¶iaПÖÿûû—eþ7˜H ú{O œÁHèíjýÓñ; qqt¼UôÏm¿mùöŸ%‡ÁÜa‚™IDöµmBr¢sMzW¿ªi{+³+Wù$;ëe ªÅ/!xIºèÅei PÕ ÌuÇÄ6újõßZw+5‚»å=l/“ч·-‹ì+Wƒ$ÿš?ðyqâŽQ˜×þ¸Ö"–‰„ðÓµoýzúÏs/q˜DñöÏx_²»f½¤ä8Eßó…ÄWDR5’VÝ!/û°½Ã»yvÊÝÙó¥ësË!vÛ*Z$>§,˜Æ7n›õ³Ç ÇãJÈ•›`‰Ljlà+¤½G袔ƒ°•kM‰A‘ÉfÏí:¢úüÌ,H´§ ÏCì¯î‚†Ü(}¾ü–…¿mBä6;ýNÖ‰Ö®ÍóN=,ÂT{%Êýd!Aó_¦rÊŸê0ðAÏ †ÑP>’Ê/’ÃLß‚;ÙNº¼¨eÔkÆý¸jYœ¸“NìÏüµ<"!¨Ï7Bf©yV¬X9TªSùÍ`ãÚ¾æÎÙ©ö÷Þ ø0Ö¨Šàw6Å‘‡ôöyÂF‘ê ƒ€ÜÇKÄ–Îì5GžÈ§ù0^“—N¶˜°ãªñR®OP-få–ÓîéÍV5ïë d¯I†¿IÁä´‹ÞlÙ‚òNR´ï# „)±[ê¸Ì{¸Ä–uˆ7lß’89TÜúëŠV@›?bùdÎtRO±w@†-/˜.ªÕñPÿ !ƒ ÍWnÿlærÇWz_ÆÞûrݨû2‘ÅN¢¿0Xp{ã dôfS>Ä €¾ $¶ä9•5dZÏŠ)?”~JÈé‰ä—@&à,‘Æ0žŠðµÕ—0)‡³EbÓ·MŠ Ï+ŒrzG}‰@ÿwO‡ÕÝ/×ûùJÜÐók¤+©ˆÎ¹$a¼ˆMÊÜšX0­†è—û®¨¬’Lq?ýƒtƒ² k<šŒJ xíÞ>? ÐÎVÈx#ùy$.Ó)Í;‹¯Ü©ž†‰aNE†öSO Q=§a9ËSü!DøÍäÒèQ{Éž½~=ºØ×4ôðÃx}`ËÔ¯Mv£ÐÎA«¦N޾1Û`-P»Ö…Í«;ÖÙ²ò½DOâÃü™D—ŒCº FÙ¦µÓê#†1ÌXO úsâÞÃVIVØ9m%ly_(öhVÂɇ¬Ïû;Õhz·Ç£Å6¦í y5›; ­9²%_=‚I°…1z—Cªy‡7³|o¸ì8ûYH¦T’ü»³Bº‡·²Är^Ñ’NÔšSR({Êw€Â»€ Õ7:%êHFÒcõ3eé1uYˆ³„X{GÃÀOÒiXZ÷ Žq©ø•ÈfÅqÄSâ/ œ±&TF"[ÕŽX‘Ö[ü¢ hBÅÁ÷Û¤’©·néZà Çíã¶TÀ¯&Y}Cù‘Œ:E ?¹nè )B%æ9³áöeeÃ÷‰‹Ì|H¥á®[ööX²¼nì›B14…ûU‚’ÁÜÂtÝ/|kÇ+ßóÍÍp=9…˾wÕñª_ÏAo—U¿|´Z Ç’vxʉßhÚ÷UÕÖ&kVŒöÜjâŸãQ+æá¸­™#›ÑåïÁâî×msº¼”=Y˜åó÷>’ùº›øô«Ú§£Ä *UÑEÉN’fÁ+e6Ö;Å%¸‘e5]* L)j¹­Ðdܘ #²ËÌÑ»ñc±ì#{ú:¡q£_#d‚þlég¡(Z Ó|Ò$âùÏÐqŪ—ÂE™ð¥æQ2zBm>Šå ’Å3­ê'i3‹y…ÞåKÂá£óȱIùŽÎØ'ra ]§'']3Ùþ0áTKWeœ"S‡èüiä”;™<«ù Yý ç«%0­´=ÂÀ'‚)wÌÏ;|þ¡â#ê^ûð” a9ýù Á8ulmëھȋ@Œ}“»4åÄõL§Ä.V§61>zƒ ü Üð(ù R _î”ì+ŒYÏXæ¤K º‰»ªÍª{Z×~õYM[µ-éâ?5ó;™œÙ³''Æ„6›n˜¥Ò¼Œ}øÔæäü~_sG~Œ&Oú.™š¥æâŽž°Õ+q›ðÑ£Íû#¢I ­ç0ƒ½¯Ï'ìiÞd¾BOìË}çÂy—Ç¢Ô2׍·>ÖÑWÒi=êö ñ1£ ~8OOo9ß³äÇ:ŽF3Ã^t>±ò¤—b9uTå³ÊÅX 8ÁB—*W8ßßfC) •pæ‘>Ù— 8•‰+t/m0ï~Že³A@|ÝK™ •*Š,ôx:¦ÕW,>WUr„­Êºe`¾~NÂ'ú­¥p4 Âjd=$áø6Ù‹¦©CGl6ZÔ÷ ¼R m$H«úPŽÂøùÏ–å_ë / 1ž¿œHÙó²mÇJaº£ÚBÃa¯¦4ê=žå}ùóÜçê.Δ ¦÷bNq‹8Ϥ¿¢ÆB’íÂ%Á>èÉŸG®FÞ¬ÑáQlGƒ8Ñ&Ûæ1À ˜¸ÄŒs•Ï@³à^å#ü×UšŸìEU€QŸ‚È'¾ê6pÓ{‰õÐ|4Š$‰xöºð Cæ3m({Âûºú ëì­{]-­ûÇâî"ÔG­31¹Ék¿£jõ&ÂDyeDo&ã„©µS2·C–é=Í|ãN«Pßa׳ ä:a-¤âµyA/×XhïÜ”•o'<ÀQP+ا»çßT¹Þ7Ðq™uœ'»¢,kÞ,gá:ñ°jœe§”™Áç¼ÉT]ü!3ðÄ—E'ôšj7“κKDQ]8Ò/Æ~2ã¼Q˜[æb§»ûŠnN{áJºfàñ»í”û¢JÀyä‰úÝÑ‹‘lÓѲüÁȼËÁ†¢Ñ>)â)V¤`~¹LrIÑeUèÑqéS§dãª*ÆÿfiÕ÷Eº¥ÆfŽõ%<ÿBº^ˆŒ~‡à³žBh1©J|½~Œë6+>Î<œ»…³bY{3²÷cÙ~*\ã³µzí‚ù©c™ë$[èóóöZ±Ÿ˜nH¢ƒ#Öïáúp6þ^}9sSa‘—®Š¢¬’$âÁŸ4^è{“@ãe1$Ô5èÇWž®q-ž¢*[ñIp6’Þ®×íŠy}÷l3M’%*uýðk°8‹NÇkȳäiÊ>•Ý®»ªÿeþ+6ßhØ' t§äþåôV†ÅXfÑF{•-ý&­sF1°úN¾-HN5‰+²mÖ«´—£ÉaíìfMôx.CŸˆÄ®lRa†ébfpx}'uW¡•5ª 2¥![ªS>Kýª¥Zñ1v+÷¯@ZB¶¥·*ßlô´ÇÚÎÛC*¼b•»èm2³•ܡнWiëê D0?WÃ\ç*þBwÅ–ÄVâvëÿç™r õûÓ–“|PÇ»wã뤪|Ž¥ Ã>ɵŸŽñ˜í¡ÏJgG±pQaCìøàæÐÚTA8QÌR‰N¨T#çY~¸² ™„Y¸ž¯9Q·Ä¢Å~wÖâŽ핌Qè€ëêØ;ØÛ(Ë -™S¢Az·Å"Çà`g‰Üq¶þ]ÁØ}K0_3¿ª¨zç—p"I¢Üó÷»ÝÒï”ÒIr+ ç?Ž©ê¥ ùu"eõ‹G^L¨¥VX.`¿4ïÛ¾œqzc b-*¿™iæ ¶Fšieyôš ôP|½š)Û8««Ô°S¬’“yq1y`a-ñ gêü ™Æëûcž¿DlðÅ&fBÎëŸI¦ìË,кZ…ßÕ µ^$QÒ>þ²$'Kå.Lh²Æ²!áå¿‚ޤ¼&™:šbQ<äêäfÀ¹ìa+^êFƒaÃ5 §Ó eV`qË!ÖÅ_ŠªV×Éw¾¶‘°•°ÞAûõÏœÐÈÞàrÇ{EÝëä$1š ×\fºâ)juåb…ŠÆØš<²ò°>|Nk!WÿíëB½¢G¯ÌŒŸÏ@êæw„‡'> ¬)‰šEÐñJô·‡0ÿÈÊÕ!PãXX{õóŠE4?f‘Õý`§â‘ÊK ßÌë¥C&…ü7öòÝúî’sSyx&ZíºYû="1z^¬â¾Ô]¦5±éì;,©¼Ð I,)vh`?ŸÏUö$öÅjú÷ÀZªVÞLó_'çIâóö7%Þ¯œ¤žM ›ÑímDï©ð/ÆŸ4ÀÑ=¸¬™‰þfŸæ,i"Àú®ÅCk„þ:ïðdï ¤Fεî4;¥uK?âî”ë©a¯»¿—ag¼¸ym ÎËÿpÐË(Z¥{ÿ¤V̆ëfŽïŒÀUcNH€çï—£òÞÏ¢ÀË¿V®D§a×ÐXm«Rî½c‘'Í]ÿ<:f)n{j¯B8Ê „gTò5& ¸áת-Yðêu!>È‹ô,õÍrÖß+¥Ž}£ ™YÁj7ªbok7XÄhplök/¬ž°ìöˆ3(ÇÜ—z‹Þèdp›]™nõÅŽ‹02QLûU¸6CÞTCxžß¬`-ÚC÷ò$£‰ÑˆŽKá2ß5ŸŽr<ÍE7S³ÔfŽðÃw5W÷¶÷ÆŽ·U&z¾²v23eÝÐÄMŽAWÒR˜”»ŒûúÌa0£]¶úüì_¦„rîéèëYrO)¢’Leçí¼ÅIó‘S±ü¡GéŽÑÏŸ§Ã¥ E]•|_»¥ Ø!Eª÷ý(q‡Ú¤¨^/ÓÉíÍ“= eè7¬µIˆf” åÐJìö_»ä.kÎÛ~eÕ(Z,î]¥V- ºÊZW\óÜj9¼·¿«7\SŘ%ÕNñ¬éZó …nŒ-,„ófŽ¢l‘…ŽÒ%°—!PP Wí 8o»Q@‘T©`Š»¼Þ9 !¡ÀûÚN¡ç4î°8~ÝÎ,)O×é_õåºL{tÄ3C­@Y|áÕ'»%\xôÉ`ï†P>NݯMhF#oq(~âs?ùü)q,ÿ£mrv—B(rÄoïS®•¡õŠ 3KÈ<)™õpÕ¨SÛ»ù¾îœzΞ’X³k¸‡Ã>Ê‹’ïëË­n_êíl55)¤7ÝóÎa¸ÿžfLâÔ\÷@7 ב“›1ˆ·xkÔîæµžKØÛÝ+ªŽ9ýV°~.V0¥ÚÙ‹}ßñºKƒ÷sß6ÞÂÙ9®ƒ¿ÊúŽŸ}Ôx(n]¼QË1_í"l‡ÜK­Ìb´˜xÞ'öÇøÂ¼fïGAP¼” MÍtN›Hóɾ&”Ô}Ùê˜âŸœq‘’ª¸À-¡ó¹Ah9€Û#_“æ0ÛÔÎÞ¼$G—¦×î=fq`Æ®¦¼•Û1qÙ$HY_sªN‹Ú^ž}-¡‘¶uàÎY0ZŒ¯Ôâ‘Éð|ˆw‹xÁU` òòŽ?×˹ÔâpFÊBÚÅg^b»ˆŸ&D 6Éu&fš”àéŠv¡Óå`p¹å¼At€¾œ§[fd¿+æ(¶ž|AÝùÉñTü¢2„™‚¥DS´HH] ®}3(å®S(Õf¶Š¶¾¿8÷¡1´Èöòƒ1ýSw¦¼ ->nu]¸@º±û¯+ê0¢! S+iOm)ó¼dÇ,·pâÇWt?W¶‰¾?#Þ‡žÍ“T"¦hVó-…ÑSWóŒ7pÉÓ ¾Ú|ma§tÜÛ÷Çb3IN;‚svH½É*§®Ì —\ÍÛânozt˜SJ`¾„=Ó=Ò@>eÓ~°W]ôª > stream xÚuSw<œÛº&¢D/£—h£·è½÷N #c0¢‹=¢F'ˆÞ[tDïDK½EÔhWö¾ûì{ö9÷÷ýñ­õ<ïzÞ²žÅ £Ï-kçbQr#¹A<|â@-¨³‡»>®Á­qðÞB`<(ùúŽG@ÀH¨ \Œ¼ã =€š`ŸâçÝ­ùþ tAˆuPgo  AÀ ð;JÁÅÖÃGê{¸ºÂ ;=ˆ»‹Ââ.´¿«ì?³å]\Q¨ƒ#Èn¨gÌñø1×ßHLL hƒú‹*@Ü¡p ëÝÂsqýéNB‡ û«cV´ƒ"· dwD"]Åyy]íÁ;ŒÇÝžAòrܪ·“wqþ-àŽ÷{f PÄö®)ï?çö îâ÷ùØ ·û£%;W^C8ÔÍ¢ªð¿ÁwÞߘ âãçããB܀綎¼¿S \! ß0nçëãêâ ´ÃÜ!¾P{ÈÝÏÇì "_ŸÿKüûÚAm‘@ˆÃÝ5ü­~CìÿÜk‚‘ès 9È÷ûû×ÊòîBí\à0ÔßáZ`g×ÌXQKÃìñ?{ÿW”œœË$7HDÈÍ/*tç”;E1!*ꀡÿ[ß߇Uáö.@±? ¿›Ø_Å{Bîw.²ÿaXà¿+i¹ ¡¶ ûß&±àâ»óÇÝô_ÍóoüµÐ?s(yÀ`ôÏþgãÀ»ÎÝÀß½ÃÀˆÿ;Ca¨ÿràŸÆ?}þÿè¨"Á0¨­,Üö¯1AÝ• Ï!v:P¤­ãŸÆø7„Ûýñâ :.îÐßoÈ ýƒ3p„Ú>ƒCÜÝïÜ÷Ûý#¥"ÜÖÅ wê#ïüFØý øMÛz wãùã‚îÎþµ·‡Þ<‡ØâÍM»ØJ„8U‡´œWÊR{qè6<½õ Ä‹†¡¯òÜëÒ¢xöžZ0çD41CAgÀQªÜC=4ŽZ1ZÄ뙘\+61ÉKâ{*T»<5’Zâ€CöÑ|ÝTñQÉY[ò¨O* %§¦,RòCÄú¡.üiÏÍ66Ý´±¨éJòÊpµ7§9ÄÈ~ík«Àütű&ûÛøœ‚Â’ñÕÚëÇ.ØÔÌðëwÏHÊZ‰­§¦{ä„ü'C•ñÕ‡6Ô¦ïEÄÛ†Úù9¶ªË´¡wp½{•Ͷñ“wÿæk?ç$‹"!žv@HA1(¤á,1g‹C6•ÛÓ:ÆÞå–…[ïØTx1¾Zò~Ÿ™ÍDá¡­üueþ¼q`¦uÖÅþ§ƒeTH/iKcÏEšÑ´3ùâ¸åÀº§|W›ú·ÕA´* :4]—Š„ Ï'.õÛ/TõŸvæ¥ +Ç6 :‰ÉæKÔZ“@ýÛÊã2^ãÐogÒnŒèXY±br锜öøÌP­^• ‹¹hä·,±çܪ(ÏhÁ§kK5 _:ä¸é5#éPM0›ÁLІþÅA«([`õéË.<ø©9 ³Gwëþž¢XÒ¼ÿB¯(„Õî1ãÔ͎ܺ۾—zDi0:6c»ˆè|Œùlå­©•ÈóËý¥ð:ƒÂ©E`@vT8 —M -¿"Bpã¦\ªË_Vbü†%6¼?8€úÉgDd¯tUÚ#õOâJkµcï"›”'ZƒZFlU¯¯—Ûª?¹©ùÀæ‹6öÈOºm´ rû#óæû®××ã¹…LÓƒìU-猫g÷MÅçºË¤ÜÛãê÷ÉžZÒ¾ø\š6¦Zo×_ˆu–XQqZ̸h~-_ šY,cе-\Ùz=™öšíS bÛíÅVæèaå|± Í«7%ãXʱùA{ï¼×˜ê‹i»hçÀ±+¾¬$3fÔpЃ']Fê˜Dßf3¨ikq/ò.{™žÀ&‘’Íï3M#¹ËQ.-Â9<‰|³¿_‡½s> Us§Ü´M°®ËWĪ‰Ü sóOeÆYÝlIˆVÁ)I<×ô”RJ°CîêJ„®É0î•Ø•Ò±’§¢Š>êÔršG–Ên‰Ê°úúR%RÄs?ßs—Š;ZgêxÒ© ¼ïf0=U¹pÑ×$C Aÿäs{¿ªA\\._³‘"Æm͹ŠI%õ–Ç7þª.ÀDÐNÌ.G€ ;=î1kkËòɺ„wpâ)K³ð‰öeÄãL¼%çéÜÈÄ‚‡Éh ‡Ó·Ùc– S´iyÍ<Œ^é$ ªo,¬õ$:Äcâ'Ê´®QÊæ]Uòâ`rõG4K‘4™t,›UÄŸ¤=+qeKSà¨Nˆ3Õ²ÐTÓ†´S!½¢øz±dS=Q½®]ØŽÙ¶Oåå®ß/4 è5ÍZð–<©¯`ÝÈ8´£"С)I©ún1;ë{v“ÉþÒNVgRÍù˜Ô|•vhçLCû©œD–¹ãƒ-¾ä9ÑOW×6L( N®ÜïW…Ú÷´C¢¥Sõ* 2…b×µ’J/wï­÷‰l[¿b6¡ Õ5ù¶Ó´õ™ZÏ00Cùù žzŸÁS‹,y‘å‡D”[Pæmª„ u‚®ZJœÉKYú¡‚û?,ý «iB<[Ф…™„ Ó±„2ü„ÂŽ'€M7YÏ …3n<¸SÚ–À ÅtÂN£F9j^ÕIêK[Ÿt:Åù_è~y £™Yòºö6÷o¶§Ú‰…xÜV­Üpjt4-éš 4ÏRMʽø5ŠÁ6’sü²¡ðZy‹£T*ö× ³Ññ•·ÓÁCvðDÙh½z+¬vèa˜h7Æ/ÆX7ަg½‡¢Ÿ7 Xßòê]}]ÃzKÿY[,»ÏÕÅ=¾©M:ìU-$¥ƒ©™äŠt¾À09r4±î»—ãrúÆô‹ÅZÈôͯgoÙ”æZõ·8±[{ZE„B’•x {¤)Лî¿wòKÅëqCeÒy¯$Ð3$ÍM)ë \ 6ÒçÉY¿ÉcÜÎ6i¬:]ׂÉxZ…¡¾JüMÎë„¿ž]%%H” •¥ÈÖûR¯ïÿPn7õ \')Y 6›HËò/Mý¨‰¤W»èKI×åζŸ^°WŸòU»L¬Ú8#äGÓU¦úö#Ù­áÃYF@7¹ßÛ¼2=ÿ£­óÌG¥+ˆ¢<ºNíÔ–°†¬Æ!Dô¸Ï–rwsŒ˜ö•¥{Ugý—¸(2.^G‚Î}€ðmü‰aF)O`™=¦—Ñwð}k(:ümÔɉ*?Tb-ÍÛé»î¼a²6õpÍ5ñ@™|ø!©aéÀ/ucb¾rç£dÎ! à†çÚg¢Ò3–fVÊ{v.滥<Žë¥âqCMTŸ2×_¸±ŽsÅr k´‰ö ;žE|é°3«s÷2Ù—põ®¨­ÓmþÖÿ“ï"‰ sêëúFYœšA4 ^‡´(v/*TGаõÒ0Ü×(”ãa£Û#+µÕA|„£Ÿ’ÀN–Báâ’±ðò©àW> KSäez¶2OÌ@^苲ÍñžàiŽ^»”.M”¼&„cÓÒ‹.xØ\Õ'q¬:Êy @3¼åÊ3Óã/9öq™ 7Øn|ÕéñÕ¦YÄ  C ^ùÀdÙàuteÎ7—¿¨`kÏ‘Ú2,GÕGå〷v89¨«? Ú¨x>te[·‹“L ×sލÐꬾÊ74]Vlh0l[£7˜¾¨µj›ë}·k¥b2ø6Œ)R1N fPõIèc>ø^¹ßÕ°r1¾š\Ë×VîÒÈHÝ%WñL‹.÷Ó’ñè‰÷‘Ž”<3Uýì ì«h[¸%¥W…°cšôÅæ3–f¬ö(Ù2ê}á¥Þ¼×É|j"ƒvSW¼N{2aEè3KÉJ¤ŸuÉ×:“í–Òô¹Õ º/å4zÐÅÉ3.‡K2•zW]µìX9ØtvÐv³Ièvá@äBÛÑÐA´ñ6'™¯ºK{“|9&vÇs%=±$¬¨|Ròsw¥tR]#ÊËòÛ–ªUÝ ­…„añUÚ4Y¯"„Üq´«eé§Ë:¦——D²{§ôuK´“¸Ò]{‘a|†%3/›p}³¥¶:[9Éü ÔË**)Ëõ§w'ÙÇ÷Ti(‰×ãþ MÄÿ.͆U>é3Ù‡©OO4jàõ…M÷*_ŸëG™Bþ’YK:ü^G¾”ÙÞtÍÌÒ7oÔ¡â<ý#R-Zžz 2c¯J.vžïä´¨ gªÖÈ“[¬wN>Ç ó´õ/öXص¨ˆ½­Kˆ½2@å¶Oü&Ô\µÙPXÚ£ õï6Ø*:MÛßÌN ¶0>’H-î¡’™îIª·É¼ŠéôB eÎáæ’q–ÙUèÊûÖ¨v¬%X+®“V—±MOˆraˆéø€¢ÐYž_’5cL{\{EFFO—ä&ñŠ%)¿A´i›Èa‡÷Cûy»Dsâìñ6Ø@”Pöùˆï–{³ø°±9–©pãæ+—JN}Γê§Àè1Û<ƒØ³n¬Ç鑆Õä M?\  ±“×>Ú´Ûv‘ŒÔØ«¦Òôú®D-±žH&¤pmàÞ¾St°¾ÔÖ34õŠtëOøÉ‹ °LùO>‹š Ò¸‰[¶kM~–Ìû\º"âƒè%V£{Uüã}'²½P%-)¶©)ùÚ¹Êbš6ðñ§}—|^M]ŠdöÁ3ÛÕrB…ÂK–¸†:^Ùp›¸±öäÐÕ¹Cý¼Æ°Çïb wƬÆ1пŠÄ!Ì+ä%Þtâºö«…sJ|ï…¦ Þu¹I·Þv‰M%>êÀ°÷_›ø5=~ý '8Ïa±@¿èè=¦¬ÑÛ"ªwY ý&Ró{ljt}F‘žØÚg,uû‰1ð+MÖu­)[.Iñž ×ë)ãë™Í%¥²2XOèZ@Oî«LQ™‚¤+û¯&Xø&”‹ØýÐx @-’ˆNQˆº#·ðSGD±Gñæ¤R WE˜á¤Hž«ž¦ø‘LÌäØy:Ñm>Ò§/ˆÆœuJë‹+ÿ¬šÓCášÜ™r2M`#í‚Ù8ĈOIOsi ³ËÉ –~ಎöÀd[˜Q`àãbþÙ·•0\-àÒSÅvbÁ³Ó>ãz.NqÍŠá^") †€’Åžn< sQ__…]:7§nÏ“ÒÎ+BûˆÔ ›kD‘ì͆?î;+¥qiÿsÇMÝsÍó.Œ¬¼ ÆÇó1VÕW ç"T=â~öÝõ†È††¥Ð4[üÑÆ_t I´&ß ²l®âU¢˜Ó jû´…VsHÁ,èI³rø€;É©0FΔ z6;Í>š'ûåPãõƒÐÄusQ¾bûÎeuHûíc.ŒPwóÝ™ÒÓËY<ŸF§8%ÈË'¸@¶Ô!2‡îŠ7íûÄúdŸ/â2³&•ÂÄòné«…ü\¬“ï°Í…³þZÈkòkó[ʉړN/òÒwp¡ 2Ñ;OdõOv{å6d¢¤ÅÑDª\H¹ñµÅb¹{Õ-í^jÅ >;³Ðˆ]UÅ2/òDŒÓ/VUJ4|µæ|pÏF¹/ÚjUA59¥³Ýý†<…Ý\¡‰gÎS)Ž¿„¥¦¼Ãùòóto_úí;…á4c~,ðýœª¥Éq¦Öûd¡-õ+ ·…¨¢3¸$ríC{êÿ†tynI]yeñUhp«¦èéO#iÅØ”G;©˜¿¬3Q¥N×ø±à¹qj,¿Àe¬^_ ÖýÙÓ9¾7ù¹þýpŠÑ!~Hæ{¯ø›¾ÆA>랬N { ovÛ³7dcìʇ*\U3¬MÓx×a<èxúáãg|?¯iøa.Ú_B1P4Ûc!û^£$Ê^›Î_~ž§/ÐN o˜Ç§\“µþtP®**0ªØ^ß*Ø=µ?˜öë`å—cX,錌 fmÈ<ï3æ¸WŠ–E8ú˜ƒ6[¾)ABn“›«°yÐ!^óË·ªÖ5…EäDz£Â΂¢Å9ib†â¥Ç:öë]&]êýxYo±•°¥5[kŸÆ(\·º£ Šn7&Ó¸SúºÙ|tÓÔ³FÀV÷Ígb¸ß|uN±£Y úzD“\”à°3f}@¾ðâ;åû“*¹Q/U¸F%uãG–iörás=†I—û÷…Î<¼/+®)F0XºfƒdJóÉ©G†Þ`Jôaª×4ÜZ½\Ó²Ðwul¸¿Füõ˜_U…M1Ëì;¬ªoâÿ¢ lñ¦~ˆ¬Pì¼éf½­¹YÈîÖâñÈ'Á_¢çÚN)eá4Š¿_,WÉE½ÕQÐê$&ñúÁЃÖ9õ8¿ÎzS¹¶›ÖÛ¸ï‘Sµ÷ÝYóí.äÆfÉT²¾¶n§âZ7åj˜¦Ü(³‹‡ß@\µÃbdOn€ý}’ /æ?ßc|¡íËëm$ÄF„.qSri“áâØ|¿›gž/¤ý'Ó’ARß{?®£rm²ìÏ}›L¸w Ö;_ Ðí—…õs6Ššè+͸àÛìêmL…ùö_ÂÈAIêžD‚6W®úT ì·ƒ¹9qBÅçDse©¡"ÒSâÈV“ >`QL†/šNÐ~‰7€›Ëi©-uÓXÏ¥yb±è¯T¾t½« ìÛZMØÛ|z H²Pr•JžõóDÒ×`Ç»ÿؤ)^Å.±;È>Ûb<ˆ0 }7}–Ù@¥d±|cdxXá–³ÈÒ ­cˆî§ò®Ií® <™|4WE%š¡.RLM4nôÈØÙ²†1 »‡0ò}ƒ ÿ¼žMã%uØY¡³Ïùbž_ h'!¯ù­èBl½na”¯<R6o’pƒ½ÖšºÝgó'hŠ·NËerºnÀ/µ¤šÈ.”AŽãÖ _7˜îº½ìÉ«Û3,b~­ÖÊÜgsį«f¦¹?ã?ô±]â~Ò1±¹Ÿ—‹1BºHdX _Ëmþ¹¨Czð‹Mû]<@í>÷9i/íæ¹¹USº»Â½­ºïõ1]ù¼â·ù$‘-£¹+9{0/Ïï$û ïiÓ›¦mUZ¯>Ϛݦ·¢Ž­Q.ãQ‚ŸOÌê>süNdȈ=BcçæÁžÿJÔRL¯p1sù&m챜–©DjN‘ž^*M®Ë¦lc–5pÞµ,Æʬ/ZÛ ã¼eŽ0ùµØ«HϜдU)E+)–føÌ¯a²%ÍýÜ:á³Ì*'5ŽäG«Îõ‰c|DAeÿƒÜèÙ>QX Ô$©Ó÷Œ·7¯ã å!FBÿ¦†Íµ”{rÒÝ-©sZ8éfyF’ãšè à_ipüiõ6‘#å"x]òlgîÇ/-²¾÷õ“Occf÷gÏÛ•Œ5:›sê&ÒJéØ<¯ T°}bÏ›?ÆÉP‰&£Ð_‡êÂa*s~LLw½îÜ ™)Ü5F7J.Oâ5ìñ£ÏÑãe±ö 'Ì/ãqT¶],¦™½ÓÅ÷’E’XžÔ¬J€ŠK×}G¼iΞ™OpeˆýØŒéY]&®ª¼\‰}è(Å H#=¸I]ž®‰Ú&éV Átˆ„vƒP{Ã_¬††]¶õL/ÒØ²ðgyúÓ‰vEFx©Ï|H=Û)5p·’Þ°ý Ñ)“ endstream endobj 82 0 obj << /Length1 1614 /Length2 14210 /Length3 0 /Length 15044 /Filter /FlateDecode >> stream xÚ­¹eT\[´%Lpw ^¸»kpww( pKáîîÁÝÝÝ‚»»{° Áá˽¯_¿¯ûWý£Æ8{É\s­¹÷猢"SQg5w4I9:¸0±1³ò4Õ´U€vv@skG&1G;sÀ_3"•8t±vtº€øÚ s€È ÀÎ`ãããC¤ˆ;:y‚­-­\´1èÿËòOÀÔó?=3­-ÔÜ@vŽNö —¿ÿ׉ê ÀÅ °°¶Ä•Ute•¤´ÒJši ´¨¸šÚY›¬Í@Î :€…#`÷ €™£ƒ¹õ?­93ÿÅuÎN 3ë¿i 3Ó?.F€loíìü÷`í °\þÎÀÅ`í`fçjþ¿v Ç 9ÿFØÿõýSqtvq6[;¹þVU‘úž.V@—j;[ÿu-þFš;š¹þÓÒ¿¾¿0½.@kg€ ÈÃåŸZ¦ €¹µ³“Ðóoí¿`N`ëi¸:[;XþFd ›ÛœÿÂüÅþg:ÿÕ'àéèädçùo¶ã¿Qÿ“ƒµ‹3È΂‘ýoM3—¿µ-­YþÙ*²Ž6Öÿ°›»:ý§Ï þw@´ÿ캿$€æŽvžs"‹’£Ëß’Úÿ;•™ÿ߉üÿ@âÿ'ÿ?‘÷ÿŸ¸ÿ]£ÿåÿÿ=ÏÿZÊÕÎN hú7 ðŸw @ðÏ%ó¿í­í<ÿOáÿ=RôÿO(².À¿ƒu°ü++3ë­¥¬=@æ*Ö.fV  Ýß)ýk×t0í¬@Õüw&6VÖÿæÓ°²6³uøgì\ÿá9˜ÿwêú—8‹¶””–¢ Ãÿ~£þ§òWy O§¿ÔþG'ŠŽæÿsñŠ˜˜£À›‰‹ÀÄÁÊö÷ÀýåÃÇÁåû¨ø/Û­.`k€þß¶ÿfþÓüÿøý×Êð¿ÁH:˜9šÿ³WÔ]€æ·×ÿ4üã6sƒÿªúï‰ÿÛô®ÿÝè È quÉÑL Ä&ýÇw—Z¼œ¡ ýþ^6¨¡P§’Âü€jÇÿôˆ¾ “ךPæÆ)þ÷6ÏÅ3§·9úÑ^\;šžo Ë<"_ º¾|ŒMê†Ã £”ï¿´c¼¯¶¡õ¸Yµw'TÕŒŠ_a‰§:8ÀðWtnùØ”œPýÌÒêãq:Ñ!0k Î~Q'Ÿ<ü¡úÙó¦ï€!;Jˆç—zF–ââi¾k0{‡yvãJ,CP"ò æ`ØRS9ŒR8…Ê9Ñ „fk }!«>)#,ñoö꣜Úç9Dt¦µõzSþ`Î⺉bšß‡£Šý‘iiäÕ™ýú¥¶pÏmX' :ZIƒ OqÙn['ÃWLø–4Í0›2Æï žœÑ…\G @œï‘ÜS–º3þŽu¹í1h½U4ÌÅ` мŠõѽwFBÄ}”1;‡TL*ôiº †6­CÂU ÔQÒ)œ x(´ݚ̲އl½Î·ë§i6êŸÎ¶¢l\Ö¨°æ¿¯$#ÿ‰ j·_6ž ¼6!­çL`•‚¶¨K¸ýG¨ßýœa$8FÔò3…"£Ô¾‰Û"Es_í¢ +³'ª œ§y±s±¢Æ¼‘×ÔÓƘlš³ˆ‚?zWnäyQ’-Œêg‰ùà{%㬜¤Ô\,c½f-09¿Cm>ŒùEDÉç%ÈqsôX«Â,BÖ’Ž:Ž«óÜ:ÁûZ¶KÊmYâ\Ôsv‚ò®‚Ý®ÞL?P󽒘ƥ¥Ðý?“<¶”'3¨ [Ù•d}ù™—K8Ç0IÌ©ã4 ™ö*ÝšçEË«;ýá4ø(rE®£s˜Cª59Šléä´DxPÃèå%Ø–9öRs«ç-“S§zºsm‡4¬ÊJ˜ÞyL¡nÛ@€Ç¶&çÏ%{2+¬YËmždaï¡ À:ñ¸ìñ¿é mãŒ!/ˆ^ÒL•œ‘ALÿ¶YPvä"…g¥óí| ‘¯÷µ$#Š@F¥ÿ3} Ç[™y¹‹iÏE Wµ£G Ä)èCÏÈ~Õ¥¾b¢QìðPQžôu$,±<µ±$¤½öбÊî|Æü÷@‰>{´èl廼EƬ@ðtrùºÔõi9EˆqÃ[>ÜrwJêÀô²â}£Üyã¹ RGgqÚ䂟É÷]+Ú&qGª”0æ«ÜIÒ4– Ïæ+¯:XÂ{BóÇSÿ:vât¬ŸïÍ^ˆ‡q"‚u4SsL6]P±Åð˜ ò™çÕ|0ÚæøswÊhÔ’R ¨0gòW±_S¶Yx¸ª86ïê”9 ‡¸ ”þÈ2ÿÝu fÅÖ—f¨²®Š˜¨ÔFcýd„-Žñ/ú­þ¬­h8¹ðLĺ«§,—–;ÛÒ2 ?ºÝæé8z>ð?êj䙿µ8—~ܧ4¦'+½·Æ’¬Ðá51YAP‚<»#ë´C6ûEèç#¥tL¿FÃ:ïêjŒoŽ­Ô£‰¯j ë?w‚óv(‰jÊ/P1²õ&??YY•vŽb?µ2½ ”žF"—N…Õ½yÊ*}gIRqéaÍ¡Ï}Ä(fÔH«ǶíÇHµwôKWè¶¥BÆ]<4yªqe5|Ù€}|´æŸ¢™t¼·Óõ—UÜ-“FÁ;¥é‹¥–ë ærüôœsk۳Ǻz+îVŠIã%A3ð¶bÍ_É|›Gnn¯àúÞnñË×É™gháV‡Ký#Y×ðŠŠY¬|2Qi*4~•Bƒç?Ò#‡=ÐÍÍ„7DŸ‰´‚Ó1š.U,ÚÇf¿÷£V ´ ©ê KHnŸ>Õ5­¬¸Ž€ODWeÒEh^¬·O'ƒt”W“×ëŽÜ’±,jq3×iç÷ÁRµm ¡œòóP×ZéÔ/Põ‹I?(ä¡p¼îXÖInG<€W8h2;!‚ŸùD@œÛ¥F‰IukF¦°/ÎôÆÉ¶uÊ7ÑšûŠsÈH c 35ïüGfAÉ)•Ä/ãý¨Ò.gæÍøZ *ÈÚÆ@ÀÞŸ»N§Èe$–~¼½«@K¤ŠH8«±È÷Æ÷K:%x³ ²3ñÅÜ[E÷oëp9GÁsŸeÌf-¤ÊõIHÕúר1¿=ÍûŸr'й]Ÿ… ™-°h™§¼ëH­­œü çþ3]¶ïK_C1kRO*ôjK¤y%¾›4:¹\d;Ýô—qÑ„ F-¶†¿!ã}ýâ¯uø>„A—ÁÈ|Fðí$®?a·wžÍÐŽÉÀ†ñúˆ_ޤx\¶¶’"eg_ÂöåvãeóÂ!ÎQ~ÏŒJãWvœg¯H¯@ZØGÖzˆ¥nf_ƒNKÒ¼sL7®M•ɇ|JŠ+ØûJ³;‰AFîC0N&ý‹V½¨Ì¦šˆiZ,þÛÅŽ‡Èʼ‚>ó¥‚,9‰¥]ˆ©üìjSBßFõK ·KéÝlê…€ H1†ÇŸNX™÷Vå !-”Lw2%Ï¥õM®‰ Å• —H(a­†ÐÑñÂ"®Ê…¤€Ob|8¼·Ò4ÙÐ)”°íÑ*ߊóK~oN¹V˪ò º+uÿýöZ¯)È[Í7¾L‰sü4ÁÛMަ˜Úî0ÓÄ[œ“¶hÚKÿlÅÄXÙ§5l.jâÎe{£bÎÀ5Vì“úú:‹cè(ÎÒHT1lG¿6$ýØõ;¿%¦®º?VS'ì1¡ñZä ãÓèEñÃØkVi§-P;%õRoˆÖ]ýI|Fc¼&øÞb“Hi· Ékd^é'HÜ˲±ñQâ¦Ç˜ÆöS@G›Îif)Y\H¿â~§O"ùÅðâÏ®° òUDdyÓqf~+|ÿ.ÅïTÓÙMç¥j¼!Áq¥tž#Ç/Â_Lk¡yW©Ú®ô _}Ø/ôdlw&%æwÌ,˜µƒJmki=çe稳‚öËY)bÜt@3‹ZÊ}qŸMüÃ4£Ïë±ämêó{Xö=>±&*¯ºÉ£Jú˜ûRi®à—*ã]Y<¶‡êëŠ œõÝpêØÖĹA~¹tóâçÐÄPù1|iOfE÷Á.m•½ôô Øc{î2‘$%'¾Ð—ç—U™å`µr¶¦§y.ÞÜKŸÄlßšºÉžâ¦2{ÌóPªÌÕ¢¬Ü\EÅA©^crM?Sd79#McÁÓ"£„sÒ§s¿C³v˜-?¹]¶¹4ýÊ/¾9++¿äÂ㩊b’PÐ>–^Ì­A²þ™¼èÛŸÀ(õ ‚Bæè|* üÍw¥?‹‰{eØ .TôDœ+PJQs6Ç>ÿ ­Ý¬M(b͆sÐèáóF\ü £·ܘӚB§|{vOÛ©þêœvoš¿¡FÒé8]ùû†¿å·»¾”'Šå‚VQqHþ)âëæ&òŠé`°;èò««âÈY°Èœ= EdðÞ'ô–ÃÖàƒŽj$­Ü¾]rg½, />–ÏÏð™‡Þ˜¿ˆàЙ¡Ö;¯é÷N¥÷ŸŠñï©¿@êH¹çB´V:87Ø¡¡ _ÐnëQ7O÷2ÁÁqõ¢¾™ÂÅj…zÉÉɇ›^˜ °:–Ëc„Ï;¾Ä¦zû‹Ä_¶¤p¨åþ±ïɺË8óC¨v$繊i—¾æêšz‘[¤šfõç_ÑO“ΰüŸy]\Ãz«•!ˆˆÜ4ÑNÊL²D'µHÌ-LS$Î…âÃ0åjŸŸHæ Â0É9Y7}æêÀ”š¸á½MyìÓü¨‹¶|M¡äÚp\˜Cdòv;ÚŒŠ¯^pËžºLÿ!Ó&áRQï9‡!.äF÷…i-*Øô-†uÃ_dËKìJ«>Êâ–(]£ÝFkFÔ;¥sýJ5UÈÖÄÌr%ѳ›éX~wMÑ#›Û_å–pMå ™cN ï€b~ÇP®Æ#Ç6ÊÌê¹^qÒàf¾ ²sù0ٿ܈“â©¶½&†¼øMÁÏáw:#$¹áÔ‘ü.6^‡bµÞØŠ[.{ÐêÀ‡qý5çj=zzzÅ×Ɇ5 }aٵЭ+«læ-òG^E=Žyˆu†wùëʆ-^P~jCõ¸ çÈí9U½/ùÆê.òÎs‰N²šp}t¼åDλ¨ÓÌraÁšnv°xè7ë‡ tüPõV•Z½é¼FHs<.pK¹÷/8îð;yªo7º!w3V-Ù*W3õªñ´QSEþÛñ´ºôÉ ´ši›UFù”IAÚŒU®Mt˜ÞøïWoMzÖes”r’9Ë4–‹7ºr‹¨5<ÒXFCºD~2-™½$á¼ùo¯X[î™ÌÕÖ†. œ º2^õ‚õLß,§dè%"¢MÚ`LÑ ¶Êðöi'צUG9ßßãX+—³M ‡ú7èãqwRÌÉ–¬çÕæÛ·Ø|æâ@yΑˆ"‘±æ¸5Äè©BÖäË<ÔqßÙ0í ‚p¶Nþò“»„/:·b“`‘Ô›.äÈoñ zðЇ¤ {üb¡ù<­ôfŸç’&Õ„Y—-é½,yqûc–×›'oà÷û¨ÇîæŸ™ÝE‡|ùC±Í¦u²`b@ë° ‡OôrádÊI/&œ 2(ÌÍç—HÓS/†§¾Èó znuô‹r‘½ñ‹-½Mó2ï»O”ÈýÏÚ$¾gPo»—Gç´r>6PK`M#gºv"Q ê眄µ¿‘¤éã\­jFZ¯Sù‡óQ˜Õ}ç4lÁa¸hЂ—öúÏr v<ó=°£Õ¬XÈ!|ÜR’Aw…FÂÌU/Ÿ#ÄiÌ–‡Z#xvaB·Jadܶ¢½Îˆ 9êxF{iK„´¡zÆðùÔÄõpj´à þ:åzQÞ¸’…ž5C&ÿ!^lÝ•“®˜màûŽ‘ óþé&Ÿ%ô((Ñd7’$)¥deVž,Aæ\*}¹ìs!çaŠÄhņ<¶×®B-O‚à7Ÿ‘×ù¶ì_qpë »{„êñ»]ƒÕŒقÕ£ïBÜ©ç:”´C.¸Ö˜ŽÎxcÈ~?´=“͈Ÿ¿þxÀîsS–’…ˆþ…yÕâçU1à¯Ý“ßµqI}O>—~ý«„W§p%±aZvvúhIÒ4ì83$Ÿ½S‚_²ŠáÉK 4•8ÄÇià4xæ,(°YZ¬Õèð9_TWmw{Ùì0Ë•Ë&Ü粪6ôR&7õuûXí?>×°4š}‰‰È†º ÑòOÚ5n"Yõj\û=¶œÉ뀜l‰ sa–ŸZ»øUQ¶Ÿc/m­tge† ƒ­ñ«(“r¶Qa‰ãÇÑ`èѤ3É.3 Þ¶ŠˆÏÔxJA®<ßžyHüĈ 7@´òÁ\ýD‘AŒMZ¨çZÜÛLIãQÆ?SÌ1¶K¤ÖŸU(ðˆêN4¹:dÓ ã“xðp¸¨_¢%Ý}‚´š¨6Ér¡^V?çÆŒ{Èzq¹°Ñ(€„o]$ø™Hmuc«¡\™ÍÍ`'†ÔÇ}‰ kÖü®k¯V¬ E•ÖV“×ðÁŽlIƒÓü:¥©”‰s|P냙µ#p(x•žrÙ1/™•ÿ{²ã;Ô@Ãà¦k=TI­,Ùu×ê ÜÅ*¸Ö§Y¢qwÌÍÿmmù{–|OÅB+ÄbÌ+;O€9çÄiQx@¼(ŒïO)q ^)[i6)éL6ã¯,î )K’e{vt¥l˜AùÛEž¡SWf—+nI¸檯o›Â,éÌÝ€è²])öènX1&"8ÃÍýŪü¯X¶´E„;`ð¯û^ºïX¼ÙÍœÚ×? }ß(:¿Ï+3ƒÂ¶Øüö;9)ä.Þà|T¯vú€;ßôÉQïÑ•>ötzµµ:¾¯–…*ÀèOîê|V… §p½væ/Ï(çÿ/\‡Åt‚2ù¼ ïK~ N~ض|U¥þ&é÷EÖYA¤KÆh9Ü&ø³2Zòèl‘EI‡®CØyXá£UŒú }¡Ðê#Ìù:LÙfûœÏæ”@c"²@e0ÑO¡÷¤ŠŠ¤Í7%<Ö¿€j³%÷ØÓ©Ÿ¬îbMNìŬ¤ðœ Yड[ûl2ccÎîyœ2>0ª[úÁG‹ú§.ïƒæO­†Ø`× <,kPã«FNy?MÅ!EŸ€„l=”Ûp¥U󠫸@þ³"ö­VÚîai£åŸÜ4ïÇž çÀ6Qƒ¶Q:BÊPØ —ð/èòãŠnø.3ØØÝãv±ßÊ¿]qïãΚ ø›’ñ\%ñXÌë8ejž+-:Wé`·¬ÅbŠí >³)i¡cÔ­×8¥ýÄ¥ÅA=êý8*…†LAà ADë9†ìi¿y¥é Û³*è,U¹Ùf…Kep½Ùî6KK¬>ã׌íò¤¨oëÀ“±WyIÝ‚oÀh90à¼ÚÎXõvùȦ†ªJP­ü®ÌlkåØ~cá©0°Œ”߇T?ö­¤cùÖj)¸³Wâ˜2|J…e¸ßjÏç nÓ n!6RÅ®r…]€‹}A„’”%Ó,3\lËè¦Ë#€¢ö<·-÷cûº Ïš@kðŽC¦çæB¿@ã3ö­ru$´Ó%…ª²[M¼a„àI‰!–=kjg1vêv—^ŽÒ:âÄFéJ¹3:5΀w:ý;{ôK}ÿ’ni µ»ØtfY¸ñûPç‡EÅ'Ä-±½MEÍ’lƉ¥m¤.¨ïóšˆ,¦w±Èäñv<%e/í¡Ôû±$j¯ÃU„|aWòo×Fä*Ï,ùÜO¿deNH jâÙêê¶Ó‚˜#欽õ>¢óê»O§å†Yâ£8hA˜Cð²!yÉiÔýý2Y€,c%½odp=QŸ±2?Ž+dö’°æì¿²>PpW&šn*4u9¤cžÑúK²RbfçëbE”›“JÐ]É3”È}˜OrÙ!ÓàKYhD5¶g…·½[Yœ©¸«>²þ¬¦%GMÉÑ¥úÌ2 Jü´AV¾ô›»õIAŒ—VœHdw^ë/xc”=xŽðCÇ;0–­©Ÿ?šèž¡¨†¬„ϯ&4¸|ö+Nû’ËE"“Žžù‹ËE*©Lw¸èvÕ°6ŸÛÆd´Y3o¯k%hlï†O¦NÊAî ½²xñ\–´íB‡Ÿ ó$ÌâÅàdÖ·º²¤èûjõ•qþÀ÷¸íHžÊɺyçÕéæÐ‹#:qÑ2Àè³J8ü`.} $ƒ¢ßø”3CïU3Ý'2ĉë–ÒRÒqÈL©®œ›»»Ü*V¸©²ëøœŽÏªâÂê³¾î®íU%ÌH*ú¹1¾I!Ó,¸§Î}‚gozÓõ–ÄCh3‹úµº¯IÆÝì –·2SÌ‹_XYié¹”ÜÌÈ3­µ,R2§JÆ|ÍøÍî9§ß¶°æÓs5øÀ†F/ í‹«…£ÏŠ|’bônQ¿)œÿ6,ãÄ3,*2Pö}Ú«.E©uÛñšKíÆf³lÑJ¿@„#7Õׂ½WéЛõÖ´Ù“™ÄâtëÖ²¸9 7‹»¡6oùØusm€í"à—9;Ë7¦Ã¯³VÁ쩟“…º ºɯlr+ê‹í±¡Ë§‡¿ñgä¶–º›~µÐX¶t„Í¥¬úKàW7¤æß@÷6™p÷FÅ@…¤0E·1߃µ®ŽàD§*Ù©2ç\=š†Øåñ€3(ØiEܬDÓ^¤tœ·Et•8¡š'"×—L¬ÑøâZM”×4Ò¡dAaq%:¸­j<ÝúÁÝzê|þ~ºAn´#Luæ1™ç„o+?ÚU:­`yè óåKñUÇ·” ÍÂ¥¹ÄIî¿úž¶èìð q¡..„ƒ@àR©«‹tú´Z zƒ7”Bp;b@gÉq³TfÚDzZd”ñ×uëí€T‰{:B u|PˆÌ/Ïcx! …U’™¼d̓¨¢ZfB“(W¾×›éñÑŸ_^teo´(ÒÐxù>уî#K=jŒ+̸„XÁêzRó_~Ÿ½…{&tðü¶6ªÚOu¨"ÛÆÜ¼Øh½OlfÕ1âé:tßå#xçÌ/,¼L f´^¸€½Cìu),ï_´Ö.¼ €E"79‰ììNŒ+›ÜÝÍs±âÃ+ߘöVšÑ¨¿ÔXš$tkÜ.°±~erä+ØrvÞù;"i³ôr(Š{÷uwï¹D–ºí‡r! Œa!G.«ƒ{E ŸMJ€›»+áßWÀn%÷V\Û½÷ós§øùÙJZÒóµ ðI¾4¨ä–_ÊÊV‰,#£ài;æyðo•Ý’e1W“‚MðѪÆ~ôÆžFZvÝRMà²Ìá#šü%\HRjн~ÎÊÖô™TÙW%©âälÕ9—Ñ=XØîB}ß2~%Ó9ãp7 ¢òÃo¼+ÿÎ×6üµ¾Ú"ÏM ðle”ƒŸªvm ÆW¸†±-iv6=‡ñMHE#ðh]…Zq¦ö\LQµÞ³ºÁŸ8Éj×0lœ<› b5ú A²•Äd}ŽA`fèZ~¾Jw§ÂÚØk¾´øŽùemâ|ƒžÄŽ4Ý€ƒPAǶíù €D;Ŷ±Ã{1X366.5µÎÛ‚ƒd‘a%¼™µ—çáÐ%ÀbK>’6Ëi 4? Ò¾cD0¿ßÓ­ ‘c"i˜Ï¶ЕôwOÿÑtœv3ÀˆÀ ¹D>gv ¥Õi£æ¤;¼\Íöˆ"„{™Öù7²|±˜±ÿñ ™ã7s¬åë×Ð,%ð‚ ŒÒ fŽvPþfŠ0‚žtýöMÖ-øÛ¦±ƒøßwëD¥×J,ñKÙeÔ‘Å_{]¬ˆ»z-uŒ3ø?[Mù`ö·ñMå™VÇëa–²Ç^ìØë=¾cÄâìLs 7î9pÆyo±4¢Ok3j­Gó;WÕ$é$Á<3²âNÕ5$ªº¶Ç‘©. ¨ã¿ÖÃÔ>­£@WêÓ2ˆ.o÷ö0 ±¦,û”Bþ²]e#f¹ýFŸü„âƒN¸¥0Š0züŠx§)ð˜ü“† ÿçjƒ²†wÙ‘5º5 ½Ífð’JXjþµéŸɪ2'ö*|?^Îó|Õ%‰ ‡~kÊr6`òÚeÏ/Ø*®#»ú¼¢KV¾#CCÁ¿Û-äA!1ø{¤¾;AiKûh:þÈQ¤ û% äüTŠŒ 5N^¶ 0èË/»0EW tú‡½Ïô×-I ™«¦éDaîåæýâjêÑÏ”ÆÆc!·’±3þ„æ²ðû07¹I<÷á?«i›n¥ó""û ‘Ó„¨¿s°ò{J²¨V¬Õ-Hœ1”³‡ÃkZÌ”¨A÷ñ²ÛüÊ0»ú³œÝ²×6nøå<õÙ ›|ùO~*Ð+©üçVÛGcV·‘·‡›8<]nü ÷ Î=ã]¹Úa\õw˜Ü~Œ;qÓE{2*7kÙy YÖx’Vï¤ÂÔ—“ˆ æ:íÁîØ};sy ö¬‚L_ /V™ýߣ"ÓKä%J¼?Š–„£$õ¹Ìg \#a‚~Ÿ%¯§û« üÚ™ô.sžutu^r÷hȲvyÊaåV‘py9[Šï²´ÜAB¦Wn bUdÙÍÖ Ò™Ee†ßŒXs™ëGûa•% - ¡Ýïä.zÌÉmÅûÖ÷„§¨”1œ)—« ë§èëÄGz霛÷à_BÍ8žã {¸ï\ËE²ìþ%ùV,è\0DF©NZ&x³†§‰ûRF¤(C`åäß\BñipºóDåÔJ ãm­þä1u¬ÚN!ç“‹†kݾØ8nr¿$ Þí#{å­õ'ª¸ÌÃþ@)¬À|æIÿ ˜#ŒX .mÛÑp¬ß‚kHû•*N‰š´ÛZÁ@˜°Òî´Kz,ÿ3McÝ¸Ï {\ Üó¾lé64¸}¿F—ºs#£zT_àG‹~€¨éÙ¨¨Ql[½Éš+6îäõyn'pPð®m³ýëÓËìóË5÷5¸ ‚û¯âôÖÍ4&Ïcÿ¾Ö N‡ï\L¬®½‘BÀWú¹ÞK@¶âjz³Iº—©òflˆÆÃ½ÂgÇ) "þŽlkñhµÑÿ™5Ÿ+âš}Úн¬Q,”õ™\GïJЇZMŽÉ®[=ŸÕž6ÐQìØÁó ‡D¤´´*À¥\¸Fœ†ýù{9¡màé•lÃ×ÌŸ£Êai²Vš¨£=^m~/ºqsGDË % ½$^¥™íjñk¸ëIm2ÛÒ Å;·“3SN‹ð–^Ž—œE*K@'pÒáÏâ3è×óŽ]n“EîO|·!«‰y}5êy¶Ä“>†¿Õ¿Ž³·8ï~1cäûz¯æU‹:5´3ô]JQ,j®êæØ h¿¶“nÀ†‘ê`72Íö„9±˜F×Uø[Mó`®™ÓOŒK'yqø°¿9Ÿ0Kóëq-ì{5AƒÈbŽbjKö£ˆË­Ê½ï×®¬µ™ÛŸ5‘KÒ«×(­¿MÕúÐ|?AY»‚ÝÅ‹¿Ÿ€ß+Uô$­ôÚõ}áµý°),[뇓îèÎiz·\"!ˆY±0x*ÈéU}ÌÔ×UC%×IÃT®Jµ¿<|žºÞ;“"yr™ëA\›?Ih!:‡¦Y|†­ÏQó¶¡°Û³D0&KuF|Å‘~<¥†˜i§Ÿû2©ÏHÂF~ÿþùa$sg¯_ågæ&æµpMÞvb—*ÃxÕ>9°ô©&ð „¢¤®ºRk¤téèí"žU_òŠË=ÔÓúõm\ó“$ Ø’]wIǘñõR¦K'pÖMÚ™Šá¢NímÌ)-‘̶·ˆQâäy ,fÈQͧ•¶çKKQòö${¦6Ñõ*^ŽbLsÜq1ÄÛuºkøvîü«OA%àz°'”-xâÏÆn¯r¹b¤¿D«}ØäéÆ-ß:OɪɵÒê‰}½²ÿ…¾82w×Á&Ü´î>-ê%…,…S=æ¶ÄOñ†‰‰e‹—ϵéÎ K?µïQrmYP¬'7DíÇY~iÉÀgœ5«zšc{CŽ)Ãö«=–&–F³¨&Íâ7‰%©èÞ%æØ |X/êŒiL”÷¢?$q4TCZøð¾Üi5 ²÷\]’Ñ}ðê½–·\z”æz†Ý%Óÿ4sÌ#Y¯ÏV•Ò]ÐÇÊh§$tÜQPþÈÑççCv iWr@ñ¨Y·¦orææ<&÷ë|4(ó˜"u»Ó0À¸ŠWˆk_™´K|ÙÙÞàW{´´ÍV‰Pëã–’‚òëuœÙjÙã)Ò4qѲÿóëtK…²ÔÜNè «pÒòYÀ1çÔÍ”;t†»º;©¼É`=Ód†ôm{ &J¬paÑB˜OØàû¸+sÃe£µ…0yã&¹0….k1¼¥rœZ8…2ÂÀkw¾Üuȱ†b”ެXåÔ ¿{èJüyâHØnâÊJe^3Ú˜Èãr¼œ_ØvÒ¬kí äƒÓÜò ÒºÓ°¼…@p)­]{qâ÷´^Ä<Áë’Ì™Žôr5„Iù•—)–Ÿ“™¨°6§V …#Ÿì…¨_ÕÈË£ÔÑI,,Ž(èòý¢:j¡• Z/P=ëMj$f0¡ÂM‹÷bOí¥¢3Rƒí8O»e9æ©V¥·=ºÖêëð€ÍxßÌ=§Y»{ñìÓtQ] Sc¼d´åqu¾ú¨Á°MÒ'·J-kÿÚ•¿Jìh‡òIRjwðØMÓ»ºœ)Ê»¶diЀÕPɨ^ü¦Þ¥âÛ\áWíË#HÐ3î Ç¿žÊãz¤Œ£_ÌŠYV…Ÿ\”Fÿº_ì†_ÿXOëzÏ„ó›ÞÃ??Uäw~{Ç\ù釃ƒn0´DeŸŽÂ’ÀÂ|t Y-e‰“P†ÑÐ4ôìFà·Ø’º"bº‚RÀˆ²°¼NÀ½›¹IÃV³ +Ñ2c]á[ÈĬÅ-™ÔiüåÜï'TõÔ@u´®R?‹÷“Yy”GKgRZˆ¶Ùð³q_éœAU ³¾OAgHam®÷ÉGt¼2’Ξ‹tÇ8ίßs3>X ô8ü¨ðDhß Iÿh[nvÇ[ãœàÖW2pO=j èàñŠqUñkG 4É<½_Z¸ÕMYù»1èQñªE¸=iUí£¹••H|´&êðmÉI*Ö¥#Äjó€í§‡úÑÃjƧ$ØE6òµž$0ÄO‚3c¢Ü,±o§m¶k¥»,×ËÁF„v%}øÊ¨XÇ/Z­Üê26\`¹#bú~ÊJÒ›65”+²IÄ\F!;ÛNŽl%>q²ÉØç_ýÖ{ntùú^Á hî´Ñ +NõeR¾R’§!ŸøÖƒñxŒ¨8où 3ÑVâ#2 T)nšš<×°Óê­>Ö›?ÁªR%Qðá–nì¹Pc„e`‡1«dζ¯Îg; ôo?44°÷ŸpËhû}_¥ÐÂʈU1:;ŒÛùôHÝHùar@ôíF¸géauÈ–ªôã'kíuë竺E3»)JˆèÞ˜Tg5™“0ëÄñ†Udzóì—äZR•Tjëz¥é—1äuAóß[NSIÖ+ì<,|ýDÊG6d$Ö»?;;˜ÂU\NFš×9ð™Sê°±EaZ‚ ý§G×*_å{½:ÃüE(†ë{Ͷ¹ ÌcoLµ`é5™Hë…úŸš¡Ï´›´í£ßÁæHS1á+ö’^1[+žÍDnö¯âù-o‚T‡j á¾Ávê6+QO‘fySl‚(<2 xý4áš4΄¥2—¢6W:ÃèÌnv´èìeOBÁÀd6‚HBßçÀÛøGnÏ©éÃP…ZŒAb/NÿiÓ©†ÌÌð†c‘¯æ$rh/kÒ8PËô\Ƹö½^-]I#Ñ<Ž˜…[¡™Üpììᫌ3„\pCé˜ ktç}k‡Âç›+¯Ä]£ã3hžd?¦K%kÛ&U ]½Žún ¦N¼t¶ª— ë?uÆV&{›¨p[Ì$—¿!xø t«êB5Ç äÊí£¤áN5¦Y]3(÷ŠzaÏh-/Q'´ŽE›ÇW¬*@r Ä q–ך–è?³C=õ°§ÍjŒçÿ0É32„/ɸžÃþ|•0’ "šôO9ð!ÞÄœ¬P¶ )Ö¢$/s{b!jm# ÁKå+Z!öYSlÚçÒ›Óþ€™c”îö"o·Œ~›‰x#¬Y®‡[ûvZãÚÛq¿JiX*Ÿ:U5Gj)~™Ðã?}¢ÓƒQ’cÏÙµVã!u?„Ž%U¨†Ù½Ï@®º¿A€ è=??ä$Àb“0.–ó¼^‡—×¹×ß#ÉW¸L±ŸñÒ|ÿCŸÿ˜¾?®™gbçâU™òê] ß¨ôb×4Wy†Újð´j®#’,=ÅÃÈC-ã3|#L¡,­:¨ÐúÏ?ú bÎþYÛÖ.·[çd±v´dVà6f þ\mP’ƒuÊêò^aðì»ÃÆN\>ÞÝvz¸4FÙ®îOtjÞž„!(/iõˆiTÌ_m—æfŸýZÏ0 c°5Äv¬=þ]çpÙs¶_ñ‡ ¢ô.½Ýa™ó¢xn³-™1Y¥Óͦ² Û7˜h¼“Lý-;²X&áA¡¥1*ÀÐ ‚mïöxÌcCôšº2x>¡þuåà³D-Ž"[³ú®XNëU;í1‰9Dè±þé0©e¡z„U77ß‹+;ÄHß)–ÆÈ¤öD_}öˆÔœf'q}ËVL•)aj*ÞúÖØp«înN|‹X5•¶~̾7»T+H ‘® ˆè„4VˆvQï?Ëh͵(U–è°Êà2ÃíNo ˆ_AˆÚò;-"þIYb2ÈRÚú^ؽVt?Hœ0L~qå Æd7ÃÓ¹) ˜NiŽ…fY`Z?#iat+¯,.\i’æ§²ÇÃëämÕø†a‹b Ù‹åóWhù8Ù¬­Žûùø¢›ôÚ¤g×Eb„l+âÀtêˆQN‚†¸Ñy6¿ÐZª1+òÁuµ·Ny•uÓ_k‘ecVeº9ýÛø2ÎÌxí~2ÓúXÎp1“a ö½þ1²ü¬üÊפòó~%˜(1)ßrtÜ|ñ—†s6Ó^Â¥'ÞNÖ“ëîvçáÈC¨ÍÁÿÒÓÿ}grFDlµö&—økàO‘ÕPÄûlýÁIQÉ&3äêØ8މ²åϼÕRêOÒŠ±¹ƒ;pÛ)ý‡Ú‘ß–|Ù¨²VÔWÊ @—+œR¬¼ž0°½|d2i’<øøfU%‰UEmþsÆ6M ~¡Ï±JW»¶ŠÀ&ƒ?¿À?b£é)Zº`à[»‘5[´Lw£ÞTL¢u:6Ñsx²‚üm€¤èž`+×9J±.(ÁöjM2¦\<±Ù$]zë£IÜ3u3Çe[¢AƒÉt½ˆç#§Øœ˜<lóS:e+ÉbV7 Ê$¤è>h¦ÅØ}ªÞ;¢ŽŽK•—4œ/:e˜k ^I!ú_!É{X¯¿­éOÊçñµ5É7–$W›žMÚ]Hã<Ð4d·Ic’š”—¥’’CX¨ú~ù`Þ¯F·P{(4h‘Às1¹«þŽØXs;CE±ü""qY«›mÛ®ÈyíàWæ=œ±“Y=®¢Ã d:Úd45Û}9ôQ¡z?˜j¢ëù†žac6ÆçãbfÂ1aÁ ÷(F9³2ƒ^,²> stream xÚ¬¸cf]°%\¶ízÊU]¶mÛ¶mu¡Ë¶í.Û¶ºlÛ¶ëë÷½sçNÜ™_óÍqvfî•+såÞç)(Ó šØ™ŠÙÛ¹Ð2Ò1pT•Ô ml M,íeh•ìm ͬ0ddÂN¦†.–öv"†.¦\uS€ˆ©1€‰ ÀÈÉÉ C¶wðt²4·pPþÅ ¢¦¦ù/Ë?!#ÏÿôüÝélin ÿûâfjcï`kjçòâÿz£²©)ÀÅÂ`fic –WД”PŠË©ÄMíL m ®F6–ÆKcS;gS*€™½Àæ?c{;ËJs¦û‹%è 08;˜[þÝfêalêð‹à`êdkéìü÷`é 0w2´sùÛ{€¥±«É?þÚÍìÿ%äàdÿ7Âö¯ï/˜‚½³‹³±“¥ƒ àoV±ÿàébaèòOngË¿n€½ÙßH{c×Jú×÷æ¯×ÅÐÒÎàbêáòO.#S€‰¥³ƒ¡çßÜÁœ,ÿ¥áêligþ_ hN¦æ†N&6¦ÎÎaþbÿÓÿªð¿Toèà`ãùïnû£þ'KgS3:F¦¿9]þæ6·´ƒ¡ÿgT$íÌìŒ ÿa7quøOŸ›©Ó¿ ¢ügf¨þ’04±·³ñ˜˜šÁÐËÙ»üM  ü¿S™îÿÈÿ$þ"ðÿyÿÿ‰ûß5ú_ñÿßóüß¡Å\mlä mMÿÝøÏ; øç’±ûߢ m-m<ÿOñÿ=RÝô?Hþa$] ÿ¶BÐÎü¯ t ÿa´t³ô05Q°t1¶˜ÚüíÓ¿vU;S'K;Ó¿zþÛJ-#Ãó©XX[ÛýÓxÖÿp™Ú™üwî%ú—9½†† †õÿ~§þ§ðW{O‡¿ÔþG)²ö&ÿsñнÀ›–‘ @ËÄÁü÷È118Y˜}ÿÿbü¯µ¬¡‹“¥@ûoÙ Œÿÿ?žÿZéþ7Q;c{“¦EÙÅÐÎäï€ýOÃ?ncW'§¿ºþ{æÿýŸëGÝÔÔÃÔfuÉÞ˜;È*-3Ý¥3wxRD»¿—t8Ø¡´A¥¨À¿Ú¾Ç/-l‡³Âà£&˜®qŠë«ÍsñÌáó@êÇáh/† EOŠéU>ž/ U_ò&y;õa ½^)|ú¹z”÷õ‚Ì6˜ƒÚá’^ÉþT³Ôõ3•?‰[?é“ÂOãÔúXôN¤F ”Ú³sòÄ“ç'ŠÁ±‘ᡞ[ð¾\êœXh2nCÌŸÉgDI.žN Æ_àon¬q/Fñôê¿ÛÒ½®¢ëIÌ·}Ì@wBa&°·”•k…c:™•ø2åìú(fò(çþöl’¾¡;Yy.»`ÖNÚ¹j45 äºölÚC‚ùETÅëfN#^µP=Þwjçhî¾NÔámamÈÙ<±ÌØ#VBYpV¨nJ—>î‡Â%çf]ø”Š’{TW^”#é:aÆÔ¸rý44H7n ¸b¿ù˜F k†ÍLq9™~Ü<½;QIò7ºÕ¶JƯwÃתÎM©c‚á½ Gí«BfwnõÝ?¼l|È. çt¥"ÑhH œŠHÖ¬ìT.‘øÜ6[fdÆ5\‡5UiIž™Z BЮÖNNŸ!äÀXÀ‡Ù¼ÇŸˆC!FÀübŠîâx,²ß8bV2W¨ ê;‘ÓfR‘ûj<0mZ /ªiE]žàTˆã¾Yoךô½xÇ'[Méj ’ŠÇöN &ÛRhÐêözm%Ûá¾®2fªIÔ‘£¥ðõT•îlT¯ÙÎ[0äÞ½M;lòŠ9("ÜÉ"v0mºr'’S…Þ%Ôm;ËS$ÛÙ§þ9”Bè}B`ó_Ðóö{½Ž­›7Þø×öŒ+Œþß”}'ˆéà­-aûqÓ);ð¹ÉÚn‡°é¡]]x–É×XóÝõwPVÄ¢¤É“-Á¸ƒ3iÒ%µ–ø£FkWVçÞ~ ¦2»ýª6®R 4Ðû–«fÃ;ëå¹cìy™° Õ¤l{;\fáê]<ëlð´dT:;ÓÇ'¦_Vxã×›†©Û:Äyï±ßœDYæá#ðâa2¶oýÎ ]àúR¢v>ñä¤Ê}Á¹-o3£: ¶'åߟ<+¡ }®ÕZŸ¼]ºù¶8þVð‰G{¾–-eº“ ë­a(ºÁ;þ¯2`Å‹ï¾]Óš|å Ü`Ï·1&Àû5£ˆæ°¸È~eù˜ï~ö6zÖe¡ày–{1¢FmM35‹‚n;C¨—šŽ¦¾u+x@v1© [ ‚°¬³ºº†•W´SG·[û@ºÌS8“ ™'StXÉRDÒ¬ Fä|ô½Æg½%é•é÷"1l.H6âîpã%@¿ðK~Ñ¿N4«u0Mx/vw yF«.èH Á‹ ¿´Ø§îWÃEülXqœ% Ø»JoAêtÝA²×OêúÃ@îèæahµm7÷¥õù¢l´o*ˆÃ­Ò+\KSöõ$NEñ»#%º7Òµ—ö‡ÓKuI9q;ëἌñËi»i°0|qý‡ª¹;Ù·2Ä|x€Ïc3m†š8’õÈ+ý0 ¸iF½;#¢Z*Ÿbk`;„EUTÍ2БòJOiV÷H‘'â®$½þ Ó' ‚‡žA rWEaÏ»3ÿeàzV/TV‘oû?Ë{ÍÃìÄé«ü1åN^‚ýÓÚö»ô… 6"÷)N/ŠCƒ,]dq; — ` P5‚B{&ŸUÕue‹ÈˆSÕãŸz‘UëM};ud¡ã÷ª M«Û+úÚ»i›%ÌÔ})2èàð@#ó…tjíÇSòm‰)ëzº*ЉùŸÉx¿ß`Ž©”jiQ¬[ýî·5iǼi4a~iÙò˜Aø}½Óÿ23ÒOÝíðÝ»8d*ÌŽhzû(«HˈŇ Å©à¹5@ß«óЛÂ,Ågë~o¾ý}j—€òŽ}ÓO#çáñÐêMEs6Ï1ˆ–LàO|ì G^ ýNù­hê‘5C³ó$9“D ø¾@š8·!`«rÌ_Íl¤µ³ø!|ùÌÇY:M0»;8JjÞ˜íñ n"a¿}*ø—>e1ý.zt úáµÝž—ù°=%z–({Ž—, ™9—êÔfde¡¼žö:±#No‚÷dã6Fuhf‡‘{Ý[¸’+é ¢ÛxJjL…C6®f#¼è.•_…ôˇi_Ü( õ,¦4 娒§Mi3 ZŸ,|Ø©'~/ªIšÝT7}W;#{øb]¯•U-ýíi¢?ÒÀ0¸ÛM7Íîä²<÷¶0Ú$U,‘”‡iVjñQa¯§$$kz¸z ^q`@9/bî%óUU ½wÄnuhz3z‚¸;&© ¶wô¦½)”µÿ™é ÍRihq¹bKVÍÆ"p_ñ$¬á-ñ1æº ™xCk©Ù­ÒT “”Z%XeÔ]×nœ>hIìxO`6‘ÅŸ~ï »0×rF¤+ÞŒcÅ‹Òó¨dÙ”^h¦ÃVogOÉf" ¨`iJ°&ȳãò@™iœÎãXÙ·=BvSΪsì6v$uê dž¤$Ðê† ÌO[Ëcë’a½Çñ-Ìŵ÷ôÒÆ¦’õDá ¶7¤ÎÆŸàU×Ûà ÅÍ…g=JWpùƒ·¤Fè]P¿‘Ž.7€9&qð¥ÙAìŒ?‚S€\~Ѳ¾I`^α¡}%@œ­éÆ7dd9D¡/ÎÞ¬NGÐOÿ)Ç#A¸¢•+€r3¡—G@aâ9°3÷4cáUUj¡”# Îóù…J2Ž»˜F6¡ >-Ûf†Éž‰e@+xFÐús‰\e$ôl>ãü<î¨ZøÈvð&Žìœ5‰ìÖVúøÀÍ?`¿¸ªjx™PÁÖm K>ºzŠœ ¯ýެ܀Ouò–¢ÌI¿ÖIÄëØo¹Û¶f÷~nò#8ÃÐi°Ÿ´âç:¿=Hêø²ù>r £ „13§‘å÷‘kçTPºlúSRAïÚ¡AÑ«‹¼ÅIVÒû´ãě̵vOMGûÌW8t2Ô°þmÿi‘®¶+#‘ž—o¤¤YºÊqæÆ…„h(!1Z« Ÿll~£°kvƒÐ—²õî£$‹Ýw+b$ÙÒFF<[ªrþå Çä1¯œ]aÎÖ¿]Ãõ±Ë0UZÑ¥žOuíÍÚÅîкj'¸8Êà ԟ%4ÕñŠšÕàð›ŠÕ nê“„³6h ˆâ‡ú¼î…¦Ö`²=NÜvb»ÐMÆQ&žP9êÀ OûaV¤œš2_“»xËüjßiQ5*_X¨ÿyß¹ŠÇžeðÙˆp^¾ª¸råé€d?Ï’n0¶d~¸§E2ùIm‰Mœ=êá!{š DiI–^Äm^'.fÖz ƒ¹¼ä¤ï fտӆ툭~‚¶(çÛƒ8kmC5¦ù./9ÖÒ˜ ºOASRtÂæDZFiÕäV..…ØkʶË`A¶o äWfn•$Ž8ZñÉBm QÌ™Fv&óQŽb Ñç7‰d©äâ/[àº2ü|F:ò6þ‚<÷‰ABå,ÁÇH³Ög“g ”š4ª½z“-.æ9)xÍלÌÌ.l‹\¯˜üƒõwCk™ƒ þ(¶³^Åcg¬†®ã'š ß“…ü*”T¿ç£TðㆶÁîôæÝ×RÕ„Çj×Á8"_t²1TCw?¾ ê}8MâS6CGN˜›î ›ï)Ýx·áµm Žƒ{ž<7xó‰‚ÄIÈZ1Æ{`ëê™õÑ2„JØCÒ~>ëî¼ßüôlyz·#È×~vÒ‡ äE•öº”ó!ã"(k¢Ï¦ï·²ØŠÖ鬙W§HÉÙ¾@¼zf÷Ñû «€ò]‚¢7ñô|ž;w±>¢5‘/þ²Çÿ>QÔ;^RÃX”Ÿ|š1IMbºŸ¶V*‡ø‘Åwß”ub6sˆCë¢HŠtŸ:þi6»ú»MQôW†šÌ…¤˜KÖFR® -»VL/› p¶—X¡Þ†.8í¨–ÄÉÈ Áfp¬Ë–„ V‹K:åîY†ê:"7š ÏÄĽ¤&»ŸÆ.Ç«s+#¾‡Õ˜‚XAçþކ,K¢€òá,WGè¦Ê͸rV;ב4ƒ ¦ÿ|þ5Ý&*ÚÕiµXÎԑ⻢,âuÇí#D«Áý’à!¹ rØŒž5¬M#ík¯]2ì-­É Ï#Ñ·CðIМ$Å™Z œ_J¹Ñ#©²£Ù©|¨=¡<]`­Œ:a©‡h®éܼåŒÒñû™Ä˜öÞÁèŸR É2õ抃vÏ—ÑôX¶ùâE¦°I5{¯‡E0Cv<9™ íuóSýN0–hâ ýè$ýFbîMÛ¦ `”i\øÎÖêÙVuçŒ#I_`‚²z‚2ÍÙkFÅùa5·5‡„õ³“X›ŸâÝ ÀÍË_ùÀÙ›8òoëC‡MxTÀP¤û.ššÈ‰~ÙŸ œœ!º/r±NÍÁ:á5&:,9gŽ#¯º‹’<×’œÉø%•‹ç ýI©Bëj¦Ô{­šSfxZÄTŽÓ¶æN‡ÇžØË‹Ÿ?v[/ùƒ~‚Æé-XýidÈ+ßêþ=[4€¨xÚà:' •s-¿@a²4—u&%¥¾ûI1ê]ÓfSHOP„{su.²8aF½Ó¼ñ™P%6òEf+†Þ¢u@™ÌŸFP54E¶q®Ö `]ªZÆ ã„”w~ý4„•Kp½ Rcº[‚ëÖÛ:<¹«4ÊäL²ÓÚvMÒíBÜ’XÿéŽ .=3.ÔwpEr·Fpàm^cz7©wSÊVHÉ "‰ªÈ \¦°¶UÅY( õᯓљVÆOÑ’ÂDî%±ùe¹ðôµzå0öq¶[Þ’ÞÉk#¬ ¢rEÍÛëVÚ•ðD[÷;Üõüí!hüN\SÛž,÷kßtÞJq(à‘XB‹n´Ÿëh¤H’jrÐ2;¯fÏéÐêÆô," 6xQT ÷+ëø(ûYº±}æñÞ4«•£àwÃ~'KÅôkÁ#® 5W6â¥òù­7õÛÖ÷èøtº‰-Tò‡ÅšÊIJÀà«YæÑ̦Ÿ ¾ÿ>MäϾ©ä,ѽí¾wå”°¬"3*'½X³oÙí…AÆI¸”±á4#éÇFpù fØT* ¶é·àYÌ@-ôd1Û…|j—åÒ9k_n=zvKúaw@ÿ³LÂlðl4¿B5´ÈY³XRUCS4©äžÆi=d“·?²Ð•Âf^OŸ¸ˆ´ ì™3éK‘L¯ÓÔiô(ƒf2Ȳ‹¬…'o‰‹½ ìKÿ-éFŠ@ÜÞ|n&†uJôsþ„·÷Z_8É^ ðŸ?Ü•ÊMUpq>ø2—r¨WÕK 5Nënç›Ü¶?°m·-G›³x‹ÜÇý†‡ØÚeBìðé!ua¤6W=…0" C0hÄ<<„(“/º“*yõù<Çp’A”?ƒ^Ú^Þ¸PPNá>¿>¥ 3]@¬b³úŸÀຎ–†P¶ê8Ôúwξj–fÞ]«+QÏ?®aŒPèÓÝÂ0φáÎÝvþ~ewgIZŸ!ÔEë²ñ‘ˆÈÛ^º®°¢,Oh‡…œ!^±uup…Ô]ÐG¤¬”592EÔ| Òþ*W¶=ÙûúdKXÄ´ƒ¯3N§xãA¥šÛD·²£mÇýBH+Qãh®ûª_nVZJ?U{2ÈÆ[éêì7Kû-×ÞÑ2YRéÆiNd·ªØµ™DŽF×ÈÝÁ;ÛGP~”-K×^H‡£ öïå¡¥ÐTitþ³§V/êýýifSJ¸Ÿè‹ç6+¼­¨"«°iæðÿ5àpškG‘…,‹t…×îYÛ`·&J†ÄUç>⸹z×öËXÔ¸DVø-ÈÅû±<»lky "Ú¨¿fîc¾†o—@[AùMU‹II_ŽZ¤*mvE»Qž óžIÀjõÐÑ(’ÿ0U+Ö\\´€hÀÂh—«/П*—l Àƒ§j\Å#"ƒÛ}¬ó {8†e¥¼JLÈë dæÔ÷Ã|\d>ïÆ<¢x;V'Lú€èØßw.Ûó}¶ Q³ïùœ‹w'Ï,²­PÔh̉‰4áØüãæAµ¡rù½ÖrýÜ ¥DÌ…-JDjH”56fî-Þ-Ä*FqXÎ;>ÌȆÌ+ï{TValÆaò™“Ïš+iÑ•0ævŒŸ€Ö jˆø“´¤ÕhÁ)î&yMâ‡H9òÖäÙÕ/ºr_mkqÚßö‡òC'Dð½èn¡%ø\Ì£½¬‚x±a s6xÒÑ2Í{àU¿}ܰ ñ8²Õáö£"¯²·Hä–Øæcš.´6'§•¾ "rÉ©'º*Þ:Q0Ú·áµ$‚ÔºFT$K!4ïê ‡Ÿ¢Ñ‘+=+¶¹ðm¹åûkÒ%øi§ãv1è]{;ҵöÇ= sà—Ù÷Yý5zPÒÃ_ ¬¨'êÑ×K¹Ù_‡u­Û£à÷xBB ‰u\K…{á$߈95šü6)ð÷n/\¼ÇÇ~bWø,q=ŒCå«‘49c=½ð|Ÿ©)¡*ÏF—iê%ždHZ¶ÞÙíCÏ?¹‹ÿ°ª vR™˜õPŠƒNéoAƒÞ€–ôÿb®NÃõü‚E³ƒmÉ%h¨KUYf^JNà°ŽWñºtÙ Çôk"c¬’½]€’ Îâýiò®x ¼QoŠ ÞLͯæ p̱1÷»c$ð|š•ᬔô½Ó ÅÜgRqFÛ\+ñ¦ ˆÉØK‹'á@Cã÷Ò.GHÍ·aà(:''Õ´÷±;–Þ (ù|u¤—ÌáúOAÃû]ôïêO¦&c3”*T¶5÷‰lbG—u='©ªáx[o £õúµd‘»ub4'Þ)-{öä 4ƒá‘ðƒÆg!ÐÙû>u÷»o¨%é "»Uá„I¼zÞ(M‘×´53 8¨–8¤éýBÁ‚(ø@ö£ÑE>wQá•Ê›‘NRRÏ·.U!’ËvP>8Omô§Ôã¦ûzI±÷@b«–&¼•sÀÝ%*ÙeúÀCëR-ñÝšRËΟT¦Îv”ÖŒ‹±žcÂrdò¥•y’)#¦¸ o9¥Ø -[¨¸/ ÖO‚v‘t«¬3ij+²æ÷™ßó—&ìПIø5)™Û(Ò€ãUÑ“u"Q \RM¥…× ’ z*—ø.ìÜ/+iÜf r_&š¾Ì×ÀÀëíÆ)aÈ…´÷2p¦l¢GçWçWLo©Ð‚ŽãYeÀŽäŒÌg*|žõ,CÁ`„”xéÉE–]E ›]@ü\ Cµdê>5ãvÄ‘ëâøafS—4-‹AAµ,ÒVÔÑÃÃ͘TÞsfÈ‚§ÙŒ‚… ‡çFšfN'¾æÓX±ÚˆÔý$Î߈b˜ð¥ÐçXŤ?¸{Ð+¤Ç%_I)½Ÿ=AK“¬jÙ8r6Û@Aµ~àj{M•îÒÔ¼RðjÆŒ«TY ß:,쓤‹ï3^Ÿ&KFx„jì‰ø‘6-((O$KsRƒª­!Ÿ¸›ìŽ)¨´§v>ŒIú~3Uæn&G‰ 9bv§ßüØ®†Òf•—òd^¢V͘Ϥ»¨Œ•~'3Zñ¶Uv[Bеɨ°Ä2`¸iœtLÖ—}ƒèÛûKRœ¦Â×p–1Is÷å‡Q®A7-èÈr9ÖŸª-¥ø-úk,ô]ÊÖAñ¼ÞÙýÏõL…~»_“ßõËsÚuUy{¿x[Ò2n4¤¥°o¡»—Æ28Ì.ã»î7ëÜ-V–BvCÒ ¤¤¦êðÔ7—¾Fëè®,ûìï õ陹Bro!TcÌôhQ\½ŠœHU$¸ÍAS€Š/°H€ž[”îüm T ”GìFÒ°]ÒãV>k£~œW9Y}‡rt0Š®¸»½3íäZ A½Qk™ïg:—ˆµÈÅEè!ÇÔD ºIÕª? »¾þdŠ0d +x2˜mᆱU†ÁN™|A)Ö|[9Û Q@Ø£ãÅ;.ŒÀk|A9OÁ%,Âø¹“ÛRÈÉ#VVËOC´jªúiã—öý–Gj·9NòäQtº0¢^Bèô™Ó>Rz?«¾RMóê‹ão×ÀÌ[ss¼ïmp‹{׉Oµ¦²šüÜÕ–ãzÒˆÿN%nÈO} è ¿Ü²—M†CmÀkiôl_ 04/½ž€+¶êÄiÜHæ½î'78°ƒèà,UÙè ü ˜OÔÜ.3ÿê&ã¤w‚ÓpOI¤YXªD1K8tpå‰?è$¬4w¡ýÆ).N Cuê­ ½| ß~ªnÔ0_Ì”æf‰ëÆhcº%“o?<þñ^·^C^û”6XX$"*²¬z§¶xå}³>åIRÿÙF]g?cm‰ýƒh[[ÒpX†Ê2»Å©ˆ0|˜©uÆ-ð…(›š¾h^è¶ÍyÖ1€ê˜®ûÅ•>2›"´´7u ¿à‡¡e`Gþžfó3ׄ‹­!8D¸¦qp½24‰ ÅXé¬J¼CQ5ø‰÷zy›Qn« û–Å8H*zÙ¢;.£JtH<—žØ6T=WÀJ©ðr ¬wjÆ Æï•zü}¬mFƒM&eC¥ø¦(ÿIjQÔ¶õ+Ò`š‚N1P—7†Û–CàOÌ@!ÉÛ[ãö‡ó,˜œ«n2ùÁŸNöoÕ5ïƒy(ÑæpÛr -wã­Ã~cAë S’™—7«WJ«Þ}:ÿ®ïØr!¤Z©•[7/ÙTù…6lÿÒº½ÍúN”•}ŽSŸ¨èÒu8І‡¶y/š4œo^gãÂYOõ‹AÅC¸kå©bDOƒÆ¦äöÞp©ÌÜàêÐæ¹›ùa—ëÉ©€üLÔý%D™CåÊ`w¶\ôá¹è‹ ÈÙòú¦ lxQSço†CL)œf¹œDA’r MÒAA¢H‰CþJ+¹¨'0 }é;Î}úJ3è`xG…yÖ¸!=<ùµpA£âÖh7¡-JI{1R;¶Òtæk %Dˆ_ÅüBú#Cë×z Ÿ!¥ÍAÎïÙSIŽ(Zâódzݴb¤ú:ÆgÜ4{vK?ês¸¾§C*‰nšhÈÍù“H¾UÀ´Bái€o[yï@mÑCSÿã>ÙÓ•uKS„g‹Ç¬‘gÌ¡mªGz÷wr@‹êp·»Æƒð»ˆV%'„ôI ˜¦p”ìwã–`©›ž·Æô²›ƒ]‹Ÿhæ–ºûaô&Ç„Ý4 ”%øaŒÀzVÓiÌ'=ü’ÕÞn¬B%vSptWZɦé‰éEHdÛôø”Ýá>(ˆý[›ÊšWÄËÃýɾòaÍÿ´Ÿõ9ôãдEãö–äNÈvDvÆð² &ù‰´Öî·Ìír§¼,áÈü(˪™`_ùà’⇀¢ì¹¶q–l¡–}Â"{j–î¼wiÐ6[+v­3Ä ¬[I2KƵá`ö±\ øž»)ìÛMÖè@ 8Ø÷3=Œí>„îdÐÞ2Tx»˜ê±ÉvðW‡2(b7[ Ñ¥ M==!Ç­:\}ÞÒÑ,š]D¦íÐÖg2‘×ç°m¢·/£=GGý@–º'c'=„o©Ø“P/⎹-ó/r‡¾È=å+ÜÖç¯1'«s6§;ë^mÏ[Ä_ÊÇ`ÖlUÕe¦3v¶î»]³º‰JÍ[0è°4ä®ù4À½F¥U÷Ô: ¾LtszÜs;R£v爙•ÏeøÄç7}-ÎúsÀìý6@-[¶Ä QØ{4~)êŸØ\ý.S¬0ŠÄ`] áØ)íð PCðóöÃN;Z?va¯?ˆ Õ«Bô’FžÐ²ãPËï§ åÃ{ñ²°óÄ€c´ímÙåè¡tÑú(…“ÌcÄ·<Ž!¾ø•·£ö-bH•Ã\Üþö k»¼h`94ŠÍ ­ì—|ó/ž|Ö¾2ràÉàIä1¢-ü"òø©Õ|ÿûAEöÛ ¶P5C5uµ¬C°»N#÷ð[D¾#žCÔzKˆÓ£Î”žô,3®Ç7{[ÆÄÆ“X…·ÐŒ¹/ñ}¿ Žë Ë&ËYñ]±¨™áø½ÞãØ¬d–p†»$ouWì´¿9ŒËÜQO¥/ ñÞX¤ñݵ>D7ŒFи£#—â¾rH­¡à2ckzÑpu¦zÁ;½ŸžØ…mr!É”\‹W4, åLø Ü‹ c„-íùÆ9e(ÁÊ­±Œ¸.²ÌöØË¯:Ç™&¤B¦¹£Ðƒ©S Nv\š]Ê{ÇÅó—~*ÀŽvÔeÞ¯ëüòGbƒpUsMR‡ËAc¡µŸX™%?+Zí±J»$¨$?iîÖöp_Z”ÿcËÎ$æ/MÎ×ʾ¬vL–íÂA g.DO#9òÆ2án%é6ÐâÀ-pýÒ ?ò¶ø.®ÊhCÿæ[‘%éÈö¨Ì¦Ï#%6dÂ=“}Çóq D*]Dòy´#<.a|º{Xæz+§g1˜p;Ò.sJÆ´$}C Ø&8‹U…Þq#-½h3É:ž¯~jãA™i\YeíRNΡ¡ •¢úÝÑig;èmrpWub¥Ch§V4 ± •šÖÝöjè§µ]@¯¯[:cBöîty<ü ³‹==Z=§ôÆ£¶¬—xqÔåe;¾œ>.@4”ëÉæ…L¹S¡ÚÈGriX¸ì¹Ùãæ­ÆÊ±,œRM÷{\ö ÖÕä¤#*CË3Vˆ"W¸Í,ÀÆC§ò‡Ç`Æ+ƒ^éH“ÙáAvïîqÌ-ÄœP ­‰Oí\×zήÓè4b™x˜°_e¬äÕ÷Èã¯G»dð=vð¤"?QŸZ"ŤcCÆÈþÍFÑÒ?þ9ÝMГ«q¾š¤ÞÞÎíóÒ¥-Î*A@+N¦tžHœß½­)éäÁ˜‡:Íœ§…¢Ý•D=_£µ7N8q î{½_ìj´å<§$͆¥zl(@)°8,OÜ›6GÃ(æ®l4÷æÀ=uzì¢_ ªd6Œ¯øšcykdk˜G’BD©¼½xG®ü¡0{®-¸ò›;qP¦g aÀ‘HÙa¢aßö3ô÷â%Ø{«V›Ä@o±†Û[H ,!sCu4á,鋸۟Ÿ»ç®ÑØ)ŒP@mOzî”EA"RŸõ÷YÇN8Ð5!rÆWMJ™Bókº\P^)ê\B"ö&²ÕÀàlµK_׊¬ú yw q‹+|PÖÁšœ „-VT“=gÀ”|UJϵŽ*ù3®ÛøE”êUHˆv;µ:12kÆÝi,"}I»ß–Ü¢Û'¸££lW{†AKÑú@ƒßHKC¾Ô¡4àm”Ûáiš`Þ&jšG]ùZ”þYŒæ@·ÞæGç¨C]!á‹tä60ü#ƒvÆ.d„ÍœœVEƒß¿Õ;³ýdÅž÷Ã1™3ŠƒJo1°!80mÂ$wäñT!ÁpÐØ>qðª"×gð£dj¾u˜ê_žù’Õòbiq98&Ÿ<¨l9;¡ÿìÜ\þº©Ü®€CONˆ‰IοӣβO2\±~Ñá%= 2¶xB¿ï “½]Ÿé|A_ØODª9Üü(¥!hÕȃ» ìÁÅÞS\ŽÄ ‰Zí% Y!"¶°0ßÏBÀQkž|Ï>ô:ž#¢ó† è¡£:¯_GѨm‚bÕËì±®èíÁE'›j |eÔ¥bþ8 ­w§M–Ë´†zóô_Æ7?0!¨2Ê Ò%SïšQ¥ Òà$á²õü&Xø52Ô$áœÎ ¿ïb¹}ØÊoªS.Ù3EqJ)ò^:/ úYDÈÒâ¾æè2ð€¡ôFn±ü¶(¾0NúC!@k–’tVò1?_˜|Lñð£WoþO' ù¥Àn{ymƒç™)¸*g×Ý®ÓSŒ†,„‰%ŒB絚µèËİH$‹ÍÖ'3ÿÇ®ÝJ^Sÿ‚=N JÀ §A&r%Ž¿“áèÊÅï4¡Y‘6\t^8›A6‘YPK¡ßU;p‡‘|ƒ^,@?„ìÛÑîkΫ»0fDƒ‘T‡>8¬«½©vÖè9GzˆÞDˆ<Ò–~D(Ä=ľÊ>xO‚ÑE°9{É0I£~þ>6£/¼¬Îa©Ã/”Sî­žçÂJ¨ƒüšDㄹ~8‡ÍH#…•ï¥ñl8=«Œ«`Af8Rº$NÇaíÓ'z¤Fì,NÙ—°ÔVTüqû•h¥šôH„ŠñˆX ÆA“${U/“¬÷Ú³Úôǘe °Ìåü[:ß`Í…a;.̧Ðm‚WÆ’<Xå~î»Xs4¸lÑù®36ðÁìô¬YàpÅE‹2kÞÔ‰ñÕ° &5Ž"‚}Û#«ˆ§Sxld~Æ ­ªƒéݶt‹¤ï:¹Ü‰«-ñk0–:X‰Ž2ˆ“SÅãuááðçý٘Ȫ;*ú)ú¬²ºeK`÷(1§W³Òž?­r~ŠÒ')|RGoùp$ÉX¸ ×ÇÅmšgÈÎ4ЧëÛOØCÞ<*¨Ç f{Ëóo¬AòŽ ÀBžŽ}1RHdWÅ,Qb›½ÙRBÕ—³ô…i3Áô4³>ß^½&ö$ú™›>'[Z²3¥Â/7š í6n8þÅn‹v(ýV¸Ûì»=;Mzv<®}¢<¡#(C•Zg‚§̃Tƒ™W©ö©¼^éV–üî­rëoðüÖÍï% –zз—`Ÿ¤o}憰³z°†úRKæºß@–9Ç_&HËÐÌ"ÒÞAœ`a „làðÙ…E­[LX=Ǿ´‚™Ñôx•N¿ªˆËüÈ ÒÊšÅ^õZ/eÙÚ‰j¦y¡ySƒ3;Q?=©Ä£]\N ”4½AÔì1 1äßm¶$ƒî!ŽY‡¼˜ûÓ1Š˜«íH’ä/=c˜b»GSO¡E”÷IoKe€¨åPÚKŽBl«Žƒ«ðŒåµÿãã”ò]'DêT»À*æ%²«ô`å>:leú–6ŒÓ‹e¦Í½°Ã=ö™'@ Š“ŠEYÀa·)&TÒ„(LþA–ÕC6ïuNr• cBŒÞìHvZ•±ÇŸ†&$]øS;Žy±­cµNn¬Â#xމå½rÞ Í#ù+ÀH£©ÇÑA…¹6® 'À:HöÆÎ|ƒ0¶HyÉT}#15èL˜ ‰®Ë:y «Ž‡—JtÁ àbÉÒ'Îø¾GZë©]éêÔö€@ÿy9yBLVÕ—Ž©,›$Á¥Ù:hž³»‚?pVºÚ!\agm|ÚÎðZrÆ4½1­Ci«W+§å›Lçh»² Ës¤$Ó£FÌb1ÚÆíbÅ”q‹¢‚Rüá'[/ÐL)qnÈ&F–ôÁL¢n¥ÄËlLR>¨â5ŒÝ‚Î ôëZ†+Ø0TÔ) Œä´p_̓ˆµº6ÈâáŽaýx‚êÂÎ\H´ÂM¡Nn°Ý™…k¾i®ÌD2DqÈA› ÄOø,i v„˜»ÃØõÌ«þÒ0ö~±4r]›èÍzFÛeg®4¤ôÐfš-*EýÃ…ýfâbð("€äMù—ž¾ÿÆ‘…æ…©‘2%¸ƒs´ç‰Ç‚âK1‚=œDÜ,|¥ìL-8q"nŠÍKÓ¼¿ÐŠ-÷¦Ü3¨òc‘ËXË'(!¡vyVö†fž„2Ùæo.ŽWnªÕ‰nëÉ´º­ø/4ý—ANߎ֛1À4?:>òIY½úc;û°Û.Q9ótÝ]1‰ÆåË›tš/gêi$®1å,zÏŸìh“³ºâ‡Á2Ð? Ew9V•6£®q@ÃÌ©E¸{áÉÓ‹‚í9 …,ß¾!d¸šÃVîl£ÒIš³C­F,WQüvbb†âb9q Cž—ÏÂwƒL³ŠÙX`nÆ79 aû*Œìó?ÊUNI̺l‰}VH„‹t`³yB*™pãúî gÐ~UÄ3æOÓÇ”P ã²Pa¶„ž5ð!5½’²§ü® r!m4åy­ÒWA†A’Æq$¹ë›\ò\M„7(çN¿+ãy ”Ø,Ú€$õ¢vô‚º‚̵^}EÚ+ ÏEí֘Ć9Àä‡i¬¥£AÜý}z¿Ã@‚W™>±$1/+à+uVy¾Åkz6½/ Óàn˽¡óΊ^L¦Ö;‰‚kK¦×®™lÎÓJv¨+Ïqy¾»÷›hÚë¤ßV ìõDôO…å3Yw×IPÉ Åê`V‘ÜçnÖö8s*ÔÍÛJåãXEG;â-@%ç (˜ÂÊêkåŒf$w©‚>Y70Å m¼+h9ƒ™{%zFsnm°Û/[žm­JF𸂒«cÙ—ùÆqb6å`Àíe¾yä[ô¯usOk>n ÈRE«cäY¾ ‰–iâL• ßh"°Ûc£‚´æ‰äA1Ý÷]Ùáqq…Û¥'§‰:BþóW?žTÌX$Ÿfl,vL4QlÅ)5sëj§wrí€nß3ÞX÷Žàò)ÎÑâÕ6‡J):!'!¦"M¯ek+ßéƒñ²€¶•à¼ÞïêKhõú|žÉÈÄoï¡/öjp’«‚l?,W (Ù¬¨k¿=~1­ò˜Š§"ÏÙLB°§]“þñ\µN]9>c^+†EÕRÁDâ_Â…ß$ü !˜‘Þ°™çG«sòY›¹þ ÑìcæÑ‚'^š[ ànjFõ”™+àÛnêéÓ¤Ý|ˆ¹”JÔêŠ}#×y½”}ó%ÑÉ"%{Ú#Ìe+»RØ|¯xãÂxÚnך¸9OÃgÕðêC8fç¤~ßk”'¶©I5Ý›$n? @ çÈíÚ]’Sä9•?[U—“ÚO¾Ëèšñ4†q%î³Eê"fÜ»ÐQå´_VH}nÁ‰ª-M†›Øù¤ÃºùºÓÈë Ž'PÍ3õÕ³WbÇ;NàZû}"ÕŸ PhA¥ý·û°Ë’^ZµüüçÔ½VðÌõ²¨ ×%óçeÞ‹ƒë.ÝÀê3£áÙ,‘! ÈjéàfÖ7bû©9¡£ì³&qAßï½áQlUlJîZ7¤ˆ)?E^.ç_*†ŠAOhÕn£ƒŸÏc%æ¸~pÆSºQÅZ¥t÷˜Ï¶›oíÑ9¼í|¤Û«w“sQ\Èl)¤P¡½•Ò åJ$‰ç‰(‰ñ{¿ç±TåRÎ èU¦‹gÁ‡âöEŠ«*¼\áI&*Eëx Ü2ƒì®FßazÙU˜Óv«ßŽþ{îìÞ¼Ã+ÆPt-µe6Ê!ÇJ ýÃFwN&’xö,r2¬nèpgGk"ì3>íå5õ=Ä–3^Û”¸ZÇïøÔ+±°…þŠ5jr œ=;ßZH¼È³yj_xÁ1mµvëœ4Áx“•ÖÁßâÇ!%êÎÈ1<‚v‘D×§‚Ê*M= dc]P`j{'y^Óš¸[EsFV0K¯åÜ’è’°Ìã”Z¾3/gæ£ýc›8Š@aÊGß_ÍoÂ’ùþ3,ã´®¢ní%Ëü¯Áɤ‰·«Âc»\垤Ŵ”Roq‚”q×ó »6§Ç?ˆe2.(2·kÆ )¥d…ÌQc?ÆÃÒ„¥³.{Åo¤ní VýJ»ñ·²~*í›Å‰.vêh)ÔQYˆ÷ïG¡ ž£¹/+ à/JRßO©­É÷á 3Ø!*oâɪ‹";V7•÷2Ƚ¦´™&ÌB£eÙ C£È?8ð£Cñ£½glÌÉ 5úòÍÉÓˆ ë!޷屫š…"§ºQÞÎH 3³K¯f “áIžŸ¨ehi”îußÜVº(ë71ú©U`çö7ú} ©Á‹ÿäÂï_ùír×ëQª½ÀLÛ?balu•Nbêz…ö"l?Ðýí×ã1¼ÂïFضŸ½lc‘Šô×ÌÈ8 îáQ7"q mYþ Ûwëx˜Eb  xáöÊ/Ž·1Ù‘æ-øšžËg¨¿±B˜, ½T¯vÇÅÞ5`™-C‚‘%ð:|Á·mÀ6kÖkFAë¼19‘ÙÎÄ•FÄœ ÷dþ€‘>úfÚ& A”Ö9~·øPŽ@(0om©l½UÁZ5d ÓZP…þà³§ ÜA`ƒ)aÖ—ƒ;læKŽ`ÉIæ+£RÕå|Ã|‰ÂÌ…ßâÐIuî~D/Òt·5£#©f«(]Õój²/³^ÛDºpÊ;m!½á‡` A†ÔuX–÷ŠSJÁûŒíÞÔw…wxÍ" ÑU›Ú °gB8‘T()–<êÞ_xŠÏ¯! ®Ã míÔyÌ5i‰[ÛŠÖp5Tçì€Ý+È…Aÿü#oü`èTËêJ8nWˆLeU¾G“ˆžP# âñ·†•ã2±6hÎHºýê«·!¦TÛ"TÛOÒ B-“3§èªHP†™rÃÊ 1ºÄZ$¹=ž5êÒÌЋjäŸÐ½kÌtŽåËçâ鉞zã™#Œ©ãÍÇ}?e†ô‘Á#[. cd‘Ì= ˆÉñêˆöy-¬Ÿp…O—ÖQ†ŠþóVœÝ©:‡C䫿2ŒŒÓQ˜æiô'ªŸ©¥Cë.ZRà•¿¸'çÃÒßDѪ£‡ƒ½Þ“•Wò~ß/— ?Sç¬,^ÈÆI1ŽØQ¶™o€¢ÊîuÎk|a1Å9OÓȰ†/Ux!ËÕƒ9udhNïtNp$õ8©LûÉ{` vûg%)š¡>¿¤®JÌPjCò6¢ÂF„¾iÃÃFA~©c¥Ê‡¥Üîäzð㉘Jùb‰´]¤•`‰ŽA&&j¯ß #oU¿f˜ fî·W+lIÞ%²hŠÿ¢ •iMàì/‚TUM'á*­bs£…Êþ¸‰Ì„¹zC” Èw†’¦«-~sOwy‡ØãAcLû¥}ºüù^ðÎ`ÜÒ£0Ôl¥!ìxåQé[”d Ž"¤N^1ÔÊóȬðc; j1f=á­\$ôya•ã§'í”+Ñ8ò0¶NMíP&ý±ò ¨z¦ðäךRF%þÙ†!œJ4ºËÛ}¿x–ƒ7+-Ì:‰yÎÍצlœ©$fCU0x8Öz1ÿ¬Žhv0c'¼V¡<`»køŽk¾·>\îm…l,öÎ*yR~&E8’ž …qæÀöšv“jmQ-G+%g¦ý@ñGÑ|0÷á-$,ùa#t:©ãdY™·Q¬%Æ1ê0+Ö˜.Ú¬î¯óÌ„1?EZÛ#¾ —/>£(ȵˆ£È¬\Lk.RI‘Ñ·y©âExùfÌU ›æ˜Zئ‘9LLj´á"bQhÍ“ûA:tpŸú‘jÆ„À °Š8j•ïܹŠÒب`Q–à-óçX=ÿÇ \à×nåQƒ"êßüÓ8|ð‘ÇÐkZÛwéüüÒ"í) x9y‚Y\ì°P×jJcM$Ñû ¢×ñ4Åîʤ±pûË^×̬öDlk>øe¯)m^åù¬ï£ ÏÓßhp”ðáæÑy_8õôt›Y†ÙQS€;‚˜ÊíÇ—w ñ%„Œn0ÄÀwÎ\Ú< [­LuÐ㉕–Wsÿ¨TT̬Ş—pëõQý¾{Q³=`j¤ñ0Ô‚žäû|ÉÆ(Ã9 ûÅKževBaûåÚjlÈ>Žƒã뻚xrÕ¬šŽ.oFöæ¯+6IÏ)ll½åÀzB»6¨7zò2§’˜ÇJY'N¯œ™ø–œÊ0x¡È☸87ùiý4Õk=2¢ENÍ`fîðpçÉ­0q-ãeîd<[mŒ•ðæ­ P?W/˜§únâYÓÖŽ.¹'¥‰Cp5ìê´6Aýyšã½ÇþÂC°,ƒÿKêÆ{`š-óœUj…è²w  w âÄ'Z¶r£BHÜå§Ó»§g,×1(»ó%ë§VK0"Ö¤X O#á;5mš<¦Î·Ûdhð,Ï‹VÛ~l‘>ïµ>”!ÎÆWt%¥Àš÷<Å{ÊÐþñü¡pš8dî°×Ò2²5Á0„ ÞÓÞÖ7ƒ®§ô¢þd“¯ˆ?ZBþ\Os]¶$ü‹èV•ùß±a 3¡68L›Û’s%Lû!U(-° ±Ðª§Ñ´DÓ¨HéÝ¢ýòJ@õÈ+Ý¢i:ךÄì÷Ç-á^!Gìj'‚½ÎPÒ^ýDS32õ\Œ»çRP´”ä3 ú¶:ÏiMØ3‚Laj™ ÷VŸ¨@Ù(ö×FªÓåÍWø2 Ù鮩÷Æ1®œ)¨³lxïBjÓÇMw¯ÖJýôÆ&»°c2Õ]%NMFYÁ6üëxÚ‰2ÙZ3•|“/Õñ+“ =‰S”Ð#Þ¢qž¥ ‰âJ‰Í³Ìû˜gŒÄ²¹“Ÿ×¢Úóûai‘jTªõÅêÇ~zì™#¢j㓇R{2£2¨c%¡E™Aw«v,TpU=êHŘñÞ,Ô­Ç…^iP½]»]RqÀ2MƒÓXi0ü'l:ŽñŽ[Ë[È—±ßÄUWnyynëá—#‘t'-ì‹qñ« ’4ªÃ0t;x%(nÒÝ]øº€3ö‘ýÊcFHr+\Rõ%v{JL'D3ªdÜ5‘6:á‹÷I6i+ P} (^´W®yÒJgBí|}lÀNÖ"À$©RÙx=K —×âèý2„h˜ˆO ) õŸF‚¹eÄYëµÉ¥ÿÂi¸UÜ <Zũ;³Bü¹/¥P3c¬±F6Öîi·?™À¯R8ÄlÁƒ°§A#y¬½³üÖìç€W"оÂbÃf¬Åvšó曈šûŠ{ ò_è¯7ÝMs^ñ a®¯K<‘88+¿èèNØÖce£—nJhÞÚQ•/t—r­«Âé¨dŒS`!9¨Á"b œË² ýÄÈß—ï8ŒÈ}±© ©ÉOì|t0Þmбq ’®P†EhúnPFWï¶¢¥ôÕ©EI l¾¸UdùUâWø^>P¢éÏw3o°•s쓚ëÐ"¯ýìøŸe®™Â9r ñÀ&“6 !.Ã=GXMùNóìRïCg*³.Ðî{Åa8•’N¢Th.m˜Ûsè׬å±bR†çk×EDšm­(iItÏ(òwÊ©~¾Ò`oœ-ZЋ‹aš¸9cæ!âØù55öfjÌ“•à ‰GM¥Áß`ˈ†L¢•ÆÄ5ꨖz2dö" AŸÁ×^†cS_Œ#vy;“O>*ô+hõJ±*úþ¢ù±ÿ_9Æéq$NpÕgm¢½Þ79``˜ÿ p,ÃŽkîj>ä´ 8:`ÁòÔÌlì™l¹!­¥P5Ðí¦¢…ì¹kUFÖ†”8TS°¶‡Î2Û¬<•Ÿ"¼eó5@‰‚ù+¬^攵z*@ÿûüe«Aqªh2\‰Ä7ÍNÒB†Û€@SŽNA'Ò`ìU×-Ù©¯™Ùã1jf« ô±B¡ç¸¸)dkÒäMéœÝê¥´å¶ ’}Ñ ²M¬‡¾Që7KfÖûŠA¶žÌ «Þûœ å·[’ëglBÌÍäjÛzÅ?f)¢Hb) h^X•¤µí‹Îó¸ìz`0•ÃxÓtРPœbÞ0›¡ÇòöýG°6Zs£nV~jÚCÍÑt–º°kµ,¿¼»(εØ£»W³¹P)÷‚5Ù¯]äXÅ?¼·Üã@v#Ãýœ§©ÒGuÿ=ô»c~Lv¯ êŠ=É Ïžþ}¶°KjšÅîÌÒüvùçkÏ7áš®Ô{R”`ÿ|§„¾_„þŸÿµi!´dèÏú¬ùò\ÓÔq‡H× UUF £¢;–Çx_M±çñEow„OÂt8_²'NŠ T±Uàt„Cò>rfá—Z£‰ŒfNÌ÷±íºRC±Q˜\è•Þ.÷í8üØ þ¡¦ì¤ -½ Éðç™vž*+?þ¾$ðΜŒç×öMk×+äLí‚Mw‚tÙB˜ÃíbXG¿p&¸tpÍ´TÃ4ì(ù#ý‰)msk_qÊKS_âQÌ ™á“¿»IS fGÑ«l86t¡ÀÛ” Õ 'oKߤ¶ÑîûC­|몊Sv¬Ä|£2gkä(Õ(Ë´á=Ó®ra¤Šñ˜$‹­P÷›ašCešYf^¿jê±4Ø×ƒæwÅ+%ˆ¤S>™»+šŒ›Ú|âüÜÓgÄ£®TÛÃóŽnrX›gˆ}؈óÄ2æÙXN‘öˆR'ôã<»Èºµ±“pzîüÎyÿ6 †m‰¢(0Ž7¸ä vŒFfƒ´‡³‰C%Ž•Ž|ABüÒݳ¨ù†l³øÂžõàÐ*„qÈÇ›0ê](¦';ÞF‹1Ëï¬{kè$•z ñW« y)k?Æö”dæbõ©ô©ª’åI¥gÛÚÄ> U A5e+í#<‹B…Ó·Ç€^b}8__Ý^Ð#o]gfº ÿy óAé?€&—‹‚uà&}#wÆr5jwM»}Òóÿ±¸têi™ø> Cäî)u¨ð4ŒÑF;!o­DpZ¤†þxFvA²2šMoˆôœ³ÈÝ oXpIL¨kåkª7¢cø"š«t.foù³<Ü· •X[ÇJý§Œ@´Fsþ·²ùØ11‰rÊjU±úzÇoŠãK‚³šš@£ÖyU2f|xuA‘þjoÊYŸË‡èÄ›`ZÊÉAñ½¬Âì…ÏÄ•õ j–ê\ XÛs²Á Â6t…Zñüg+&cy¶¹6Óý=SÕÓê§¶DÕ4ï„é.åÀ¸Ê/\ß¶Œ=”5¹ 2dw¤ÓÙ7{õèJ‡¹†ûÕ÷.nù¼z‰2ŠÆ”—¢p5’°¾„÷Ø·9+XvyÔ®}Ÿ6@—sõçpãÕ¤¤D¶©ƒÇOD!}@ƒÚóîšÐËõ;fó­•ñ‹b/i)¢!<ÔdR»È†jÏaòј@\û’5xgåœ 59I ] 4Ý®œ{8ož5(lãÑò…Ûp §mrñ¬é˜U e]z%Çq­wºŒ¶DWÞh‰Ÿ è<Å4Ü1Ã÷oåÇœ#©)›¦c¹R‰ÍzFRîÁ¿MÍ<:wr¾ˆÃF\r²Á2°Ô_…¸Ãr(À¿{˜µôºÐ.%íÜ=ОfÑzÙÕŸ!§#£w¥-{V˜ŸÛ—Ûð±]þÔð€C)‰QÃk¯^n?µ‰@#{¨ÎÂROnM‹ ¯6Ó‹—ÄõWY³’Å4TsÐ’ÐÊÙIðÏ&LÏ„&9nj¿­ðò4Kö6¦T‡ßôp Þo_Ï[*ê/Å_4½‚0µ«þÆt6»jÿ¹#¼ N޲v§+Äîî ÿßqx\°ÈöpS=Ü3_\’Ç…kMJÍøØ½@.lD¿¾þ‹¨REì HÑŒðYÓúdSP(ÀtÚ‡ç…1{‹™+£Ïá<:ÇÙ契–ÂÄ€COP.Ý‚8€1³ªõ ÞZÇÓhzÛÑýÛÓr î09 %OÇIõ›ˆ~Där#ruèq2ÅòÁv+k;;僭ò¿þqí­aÅE‰î, ¸ñ;*N»\ôg°S¾9\‚û¯ûbl®`î“aïj¤G&òLÍžE*“LG5ϲG¼aÙ†B‘´¹š(pº &ã^hë&*ˆì%ìŸi7Êr?‡ ÌJlj"/}Ìe”«ŽCa­›&ÍÿQ”UX 'ŸË>TÑ–~²€‘Ÿ0½d²ÙEI¨ÓV¢JP.òÕܧb™×²BÌ\â¸ Ú j-µYуíöÿÕFç›M- luXð‡hkÄRJ•DÛ‚—¶Þ%DMj/`Fƒ5‡í~:J58ÎåsGsæs©³u@¼©ˆO—ºÒË`Þ>^$q}#f‰§0BíÍ,‚"oÛ[ä¾e2 b›~±_T<æ áYÑ©ÔWº‘–æƒÝt…ézkԦƬäy$‚®¾”\¬"ÍQqØö¨už^âÁ‹æý¿Åào6Rö)ìÝdè%¾ÝpU/åß¹å_O=ê ’æÙø¯L’Î 6-ýgÓôñû†&xÁ B“(Íœ÷ž]øc_éaz}›;ÈòŸ‰hËO5x…ã±:«‰£ ê½}îk PÚ8„ÎÐÝ´Þ)ð®XÜý‰ë[Dñ2Á¦ž$ŠXWˆj¬S)¢Ü‘¬*âܬe7õ¾üYµAQ<Öý—hÛm“­x ÎM¤¤tHõ˜¸ûk@†­ôJ&Ëű»„­5&dÅéY}ñðá†Ø冬?º— D ò•åÖ:å´VÉ%Žñ|Ø#Ø:q|6qF™ü‡Ê[å5„܆tªH¿Ù D¥„ÅNøÖ¸×ÇÌ¿TÚtøÿ)î‹¿G—o Ñ;»%¢ĊйæßèukÍÂUX@E£ˆzÑdûW…–ˆ|EëZ++oûˆ cB]“„ ¥b¨VëäQÚdJì^ŠÇƒK .ßGÆO?pYŽ‘›¦E›ÉblöáºMÈãƒÀÔp­£¼<NÀ¿¨R—‡Ñ #t Q`2³ÓIâ¶§Rسßöz vœ‹Àá‚8Xúš5¢k±0ÐG»SÚïÖjÃYûùìÐý07OàKº¯ñ™4OD®G< „ÅšCŸÐiHîOÒì‚Bz£¹}?‘´mæ>Ñú§3‚ôò9x„1/eÖ®Y[»p¼1m£yð²Ë?v†çBSäúöG)œô§\8» ÓnIâŒÒs¹%§`z8R9Æ«I¨ÄÖ63­RO?†Ë;r'{äc«%ü¿ž‚4³î°þ?±Ó¿Ld£¸röì1|ÃÙ>v”7§é}†s€ÍEá­”•À¹Å;ýÚïVJ“€Ú%æ2È—, 7(2ü]%‡#íÉò$¾ÄKŠwäîw•×Jl^—faƒ˜Îâ/5^Ê ƒý.ꦸžÅ-|B«¥T ‡ñ5VÂä)ø ð®#x}:.ÜJö€Á‘z¾_=?¿êÕM =$Î8èú~ãV°^eœ¥}acÀÈÔü(¼§{½Üî“ ‘J%÷ý ¢ôx Ám´õñŽ5 Klp˜M×¶2æaÙ§rJV.P¯+!`¦%Á©ÿF~Ûeí!:†œåõi(ßÔܤ,)ºÂš4Pø&¬öA»M ƒP®s,ð: tx„Pf`aQ"Ž?(a@Í+ ×J¶"Âÿík¾BÑŠ‚ot£Æ”«Á¡ø²p´stól¦š˜©¤×ñ×râQÜ´PQqÙV¹­ã8y]5úãûÄKÕŒWãø×ÅfÈðÌ‹ Êƒ¸¯3•éŽcÞp^·¤©²xÔî”Ú Ç77;*Ô¯±° eÅ´÷)P 5î¶Çj„ô]iÐO5éçuËÊ„‚Js2î‚4ýñf1VB %ÚºŽ¨¹nóÒG¼S£Ä¢U’©*À(W²Z¦í·¤PQád5û‰>7‚šˆZë·Úÿïú z©“'É]àË9Š™6Á_ù>ÚFúå“T't60KDÛ‹Ø~öÈ[=Ô>ÇÚwÇ9!éÉÆµlø{Û\†¦ÀáI%4E‹Û2ý`ò¼‘ª\uª7¢\ÀÂêm5a£Ó¯_{ ÒCþòö;Ý ‚µ8%o*>¬áÏךxz>ﮆáí»ØØ9€7Ï“•Ot-ÙtÖ œ´€¥Q\\_=t wZ`Ù–eÐ'ÚÂÜ ¶«)}¾î³FZ†òH gmqzýÇíëMÙG¶ú!§íµ¶j¯“ÔŪ²°ŸÉ¦ðÞíŽÓßxƒÓ*Ü©U­ö‚Ý鑬‹Ç’]¯.qÉÄ¢\çÁ"5¢O· |lï.¿LKƒâSrD10•‘{àænÌtgÿ®ø|Íz¹¹ `E„Šãn3¹¾¸>>Yœuµ; æƒLõ’°~´dþö´}É3,+˜;V£tí~’`±f*zþ!c5”<ñ Qê¸H¡…G_ïM3’²€o¿³×WÍðˆ8 ßó³Îzš¸%ƒBŽà ÇM8LyˆvGy~.–ÛPiéÚ6Jø‡q£Vöäσ±?(Ô¶é QqÒ$Íœ§/š/ÊróØCNÔŽñ 1 p. öZ¿œ†rž±[o° ×ónº ©Q®ô–€\º³^À‘:´š©Æ;¾> O©m"¡Dç^Y…Ðëh‰E*>#±z-m!ëÜi==ø¿C¯ºù†ÿè‹*àµDj–dléQ c¿ ô¤È$Ÿn™g9ˆ~áµê¥¦xnªãÛ´ƒ½£W!øÊ ö­Ä  ®xôžãÔ‹ÒX¾í¡…Õ¦!ºá t·J•vt±¹l©…õÐßš%ÌÊ_ï°½d|~*÷ì­È'ó·ÑÝýÀPÜÄD5‹œC©ªámÖ ‰'­òsþ.õIú€%æÌHÑ@ªHaŽ Aꂜ9ë4L˜G<«ÐíwôØDDâ;’™ÃÜš’ä¦=Ü 1•Sgëx)K&Ø@PÜ×)še›½pº•¯0‘oè™< ÀýÙ° ½l¥¼ Æ;2„ùö ¸ôQ4E]_™ÔŽ“Šo =è³Ì°K#aö`c•˜[ÍÜ0-oõ>"L›ÊD þ ¾¤yàôŽ2È-²…k¾&ž{!ñ{uŸÏ¨ÿò¸k¶k˜6¸§&"Ba‚!wÅ}›‡"†‰ÏGˆ-ë¶Þq¼òpb.9ÎÇà_´Ëì';Û\r!m–ÉËQ&é:…Îp3`ýÏ)Nj:þ\‰*ò’•% Õ£¤ª;2Þ׌ةnõuƒ%|>w÷7- D²ASìå\LbÊ¥îɬ€uajE¾-€mŠÓ·ÑuæÓ#dß¶¾ 1|Äüãj246ó·¬7ôýêΔz+½ÒÿI-¨C²šB¼¹W(¡ÎæüzGá'Ć7lC­x ŠíûŽãçU1ÿíœ4zŠw£º(¥~öqY˜îâ"üõæ­‹Œž¶$J©mÛ3$*»%UxW ‰ö¬Àm¶£§Hü½æžwÀô¢µ,~X½Ä™º%»Ê¡Äñœ®sŽK‘ŠTy®ÓI“Ô¬ü,ïòf˜Ac–ÀùT“É!cøe€›‰Ðng÷±ÜSÈÅ©t³1 ‡$êä’ó‰<²à´ÇZÄ*éíW)¶˜Hè/æ#®~—M*&S¦:ó»MªÓ5IîˆÐ,µŠSô ´Í˜A ÔÛB÷û˜(‡ªˆÑhÌ=Ìäã\^~ǃÔ#_묃^UßdïpþýþÅÁ±çéç)7^àP YÜ/è~aÿ±Ã«<í¼kïƒï5^?jp[áH®Cœj“Ðåá æ²„º×Ìuޏ»àÀRû¹P5zÜ", ¢å‚èBƼVœâÒ`LÃd?¹ ññàØQfY…é”Ϋ4ÀÞ QŒÔ€ŒTSÜ~¸ $µYéÐ<ì''²6-³Þ/Ùmž@@8Ë×w.ê ~åA_èwŽ>Õ¦. £¡løÜÄ)±LŒ~4¥h¢’I¿®‹Ûjø$(v±¬õ¹føÐàJ.Eœ—c¸u< Í`èâæužÀŽý?ýýž1ßô‹FE\ŒwÁþÃKIBÌÕçA§÷¦.bøI€5¬ nc„I£_ôÓ7~02°T’sÜw‰G;Íñ·õW˜©®DåMðÒ{-ý˜M*DÏ+ÈvY*—¥7 8<¤#}¢SSNsJÒ€ „½ Á̹ÿÿ:)€CË) 4Y¥*àõ/(ÏÚbÿ_X&sݪU-dí/b)ë´ý ÚËië{]PYgîºF÷óeÎ'ö–%ªˆlïêæÏ»y”3ÜuA›¿ƒ3SmkiŒ¯.¨¤’z 50>Á‚8¸ŸTFwµ¾DÊ÷ù¼ð:B6úÍÿiú˜gˆãc·áŒ‰ Ñó²™ôlysóSH›‰é/UôVçúû.ÿø0ðî¡y,=âZüšÛ td7µ #hxïâOÀÁK7À&±`7‘è°S¶qv+S_;϶ÉqàBP ÆA=j»ÁEy‰‘nåÊãš O%gf¼>Éÿõ¿rt¥d‰9–m"ù¸ã#ÜDtHdÞ BÃ:$™våÁËýï×Ëç5c³^ò6×uíµÇżDˆˆìöF¤g®!/¡SlZÿ„¦°oûš¸•t«‹–íõµuó*ë)¤!a¯£æ&ðAGeŒ ÇO>É#ž/^N“wþ˜–¹`nÇ[ƒÙõ:eJ :«¤×·8Çý:aR±Y8Q1„+•·º š¿©±ÌYV¸-I¼ÿÕù³æ„{cäÀ¯dÃŽ»_Ù8BÒ=‡38„»Ým|ö.³›ÕàhDtaf¦ÅÐô endstream endobj 86 0 obj << /Length1 1620 /Length2 14657 /Length3 0 /Length 15476 /Filter /FlateDecode >> stream xÚ­xeT\Û–5ww+Npwwww ×ÂÝÝBpîîî4¸»; þåÞ÷½~=^÷¯îþQ5Î^s­¹dî½Ç8‡‚TI•^ØÌÁ(á`ïBÏÌÀÄPWÑT2¶µ56³r£—v1¶ü1³ÃSPˆ‚€Æ.VöbÆ.@€&Ð 4°°˜¹¹¹á)¢Žž + Kõ:º/ÿ²üå0ñü'ò'ÒÙÊÂ@ùçÁ hëàh´wùCñ?T.–@€¹•- ª¨¤-­  –TPHí ?M(¹šØZ™ä¬LöÎ@€¹`ûÀÔÁÞÌê¯Öœþp ;ŒÎŽ@S«?a@S ã_Ѐ#dgåìüç`å °Û»ü™‹ÀÊÞÔÖÕì¯þØÍþ.ÈäðÇÃîö‡LÉÁÙÅÙdåèø“UILâuºX»ü•ÛÙê p0ÿãiæ`êúWKchþ .ÆVöΠ‡Ë_¹L€3+gG[cÏ?¹ÿ9‚¬þ.ÃÕÙÊÞâ_|€€Æ 3[ ³óš?ÜMç_}þS÷ÆŽŽ¶žG;üíõ5X¹8mÍà™Yþä4uù“ÛÂÊžñ¯­"moî`fú‡ÝÌÕñŸ˜ô÷€¨ÿÚ34Š06s°·õ˜Íá\þ¤PÿÏTfø¿ùÿ@âÿÿOäý߉ûïý§Cü¿=ÏÿN-ájk«`lü;ðÏ; øë’±2ý/îÆvV¶žÿ]À¿{jÿQ¥ ÐÂÕÖôïð?è…í-þ(BÏÍÀþ«•³„•ÐLÉÊÅÔ`nlûgVÛÕíÍ€ [+{àMÿ'€ž™‰éß05K+Sû¿†Ïþhoöïåÿ‘éïâ¥4TÄ%%èþë½ú·ŸÒý]Ô<€ÿŸDSÞÁì?±ˆˆ8x¼é™9™ô¬LìŽÝŸƒÇÍÆìûßdü›ˆù_kyc•@—‰‰‰ðçÿŸ¿­ôÿFÜÞÔÁ쯣êbloög“ý‡á/ØÔú£íßçþOÓÿ\ÿ½Ý@ )üÊ¢ƒ)oˆuZfºK-Nîð„˜n/3Äp¨cIƒZa~@µCZÄ6w…ÑkM(CãÏ{›ç©ãÛ¾ íÁh/¶-UO ð2Ð÷3M_>Úe'ÝA£A Rú™fŒ÷ռܤ“ÆÁ΄²ŠAñ+4ÑT+öê‘&à³[~&ùƒ#²Ÿij}¡K϶Ycý«u+¡™¶ñ€zçB,­-«$MðšîË- +·Pª´ß×5ƒf†æÓt4 ¼}OØUZé™á=º®â´xX×ÎÊ,Ôò¹G9ó>ùïûD=Ë`ñ ý;:|CaÓƒÐ;¾ÎžWÅtO3ìƒÅ‘{SfÄYyüýMǬâ^JƘ¶)g©äà¡`V÷®}ƒúwZaA›Uî›+»°‡Õfòþ¯w)w;s-#d0hnã{xº-°Laˆs¦b7P/" Ñóš¸KQÏltJéÎ…‰õþÂÊ›™­CütcÎgVí©UàÒÙÏl‚5!Šª`Ko㇠ɘhÃw¶·$sÊ^)L9Ÿ~n oµ~´Wã7È—¿±”;™‚3á?Ä ù<~ÄÔ¸Æ ÓZ+Þ^Ì iä!'‰X_Ñë‚ë)§L¹?'1Gõ+ÎÅR×_µîpªÁ …L3ECúÌó8[ƒ ¾í,îT÷ˆ£ŽW°Ø-7ÇxûÖY0A¯¾¢Î–7åOAAMRì· Ì)=jJ'#Î^‡ƒo®tgÛ@O't,QϽÕ)¹îß)§jb1ýhŒ ÓËêêˆ!þßûlî`-l|¨-˜s/ÞVM;ýÂ)" ’áS³“Е‘ûjâV¯ÏðÙÊwhëwÊy öçÝÊíÅ'\Í[>ü©·/§Öí^}ŠìŽ<꥕ÅßÎà¶jÛ4†ç"‹_Û#H¥ò¸á <m$Â\Юp­YN'Xv^º:›]؈Ý1ÖÏÆþ¡b'’œ®|•Zð伟XnG¡ÇÍ)EÜÎÞ"*n.îzœ3k·é¿ŽìWî¿ãòg(Y<¢˜fxaïñ Ö+ð,®\}ËõÌS)­jÝ•†úÕ§WéVBgL¾+Oû^ÿ&êm –¤o×ß›ÂÒŸ,g™Y+ƒ^Þ]hû½J®²»~gÃ_òS–g1ÛûãÒæHù5VÛïÚ¼ïðCã¡`Õª"ÇáIæfÚ“êí¼À;“;œW¬KO2š{…²Ï2¸Ìðlglw–òs KÅ“ ¾ò™§ùב"ŪY{$¨÷"5ösõ‘i¨PZ[zûUµðÑÇlÆ\ADS5•±ÚS¡"{|4_wšÈ>áºE¢ÕÐÁŽ|¨L-¡åšuÝeÏZ*+w> -þTSXÜÄæòÕåOL(å2i„Iƒ©Ž6 ÁfÕe¯Yûú ³[4Äwx ò„±ðŒ0“ÉŽjL+²nUŸS Æ”¿Ó÷¬P@JäšT¾à8»ó'f¬>“’¥š ÍÕ64S4ö†Ã65yÊôv+~»xAIåŒTÀ€à)$¶c‹ÅP¸™½2Âv>8Ö%Þ¦}fâ4!­ìOÛåŽx@nÁñËl8¶T9GX|H£I^.¡¯Á†H*4rd†˜¢8ÉŠnäÓÕ߃¡üb ªõéÁe|FUÏë!Qímv|+ TŠ sÔÁ¾×Ô1ß²²bÌ.å%è™Áë¯ìA5Ö(§×õ„»zƒ¬•iȘ@2’bU&öhØBù¥'2@ŒÌåÓÃßÀIÍ-aÏ|“vÝô4ŠÎ‡Wúdòž ÍðˆÊQ–èØ/‹.Šñh*A¼dÖÄ4Ûh·¼ÿÒ & l*Y]+xÅ‹¾R$9­Êâä¯G]œí‚±}ö=}êcUP%ê¡i¦Xq+‰,<%¨ôç¬ôd{†øá95?“¾0‹'ßVl-ŽÒÝVKºëéÏÃãuÚµ[>v‹Î´›Å9œy«;‰N{¬,&‹_'ìr+!Bˆ÷xJ…ŒÜ…‰¨7å=†åå’Åúl,hz³$ÎC˜¦uWÀÔÆ„Ʊº•䯽•ÌøâÜ”FW`%ȳ+»îµOKéBä3,j[Ô P¾Ñ{ËÞhú>Iô®ô™ÚÞÛñ8í(üËØ^\6ï´+@焞Ø&„¦g_2ZMYßDï53f>npæJK©Ä¶dÀ’¤Ž(-µµµV ´àà±iÃ!dºHpI\Q=4ʯP^ïÑÕ\¹^whϰ½Ô•·1Ëêë.|lÜÈ_¬’ Í‚ƒIFCÊqVɤ 4Ф aDà!wÉvܶ%™Úþ‹èÄ~Oaxýn!º”4£šä×W“ÆÅü(Z1Û›‘Ý;ÏŒÕÈ$Ý{î±;Q’M ¾×oÞ`Sˆ¤®§ VGÝ¿ Àá@|òÞ›ùL!GzW04Ūvw`˜¢©6’Oz¸Íþ:~ìn?´\Ò¦<šT=䃅?ñÖ‹ãž—ÚMöÿþñùX‘Ú›õ,§ ½G\¥\Ç.4>«„â¢Ïµi¤¦a¹Y—W‘aÔz®ßnÆ[k‘x#q)-+ä Á¾ëZDåcîÚCFÓ‚…E†AoNZêaYªMFÝx—¼^C¦µÆMýk[×<Üo\)†É¤¥£Î8¢Ö„5Ë®$¹·ƒ6ößy3©¦,H”|€×òJЊ%'é(øú0M!¤‹æ‚¹ŽC%´ÿ2ø¯[ ©ù8© Y梌JDDæ ÂI|x*FÍ{©%žïNÁT;¿žßÕº¯<\”(/ÃÛV´1›‡î¡f‰zèÊ¥ ÁÕõé‚8{>>µ¢½)lq ¬OüK÷™  VáÇ?n+ ©äŽo4 ÍÛû~Tn$kûÔlõTDP6YÛ㦾½ƒt}bFÔá¨éuL½ÁWöœƒïØåb­K$sH>[&£ÉS¨¢nËtcÚEuÃÌÑ.ütœÄQ°]θr^„þqÆ×rö¦È5@x÷2oß(‚µx(qÎYO¿tK¶ˆ¯–‹T}ðuz“ϸ½†[vKñöËP{ÐVõà¨Çô¢„‡½?¦¦;ÔÕÕ¯Q7âudó¢mÊ?Md…Ql—º”ðÚËÍAû¤¡¤ùܪK~Îc3¢cðTû‚þ½9Jc†/aš ¿“ì›ôÃÚ5“íEÒf’®ŽÅ¢/áp‘ÌÐi—í®·d§Ð”2îYUìÃ]/7<"kÒMÃ@,¯ž›_ 2R‡8H€KË‘nEEñ*ÀâGï…_Ñ/ɯ`UR% Ïþ3•Žb…àФFKÊ8óLÝ, 9=yU‰Ðç—8Æ6)qÓÇ¢ØÞ¹{†²¼‘InÁ´!¨í\Ç-²²É½ËÍ9°"¹lp¶Û ß2'ýø96ÆÂ_çÖ$ï/,%ÝÜ|´§ÏK$u‡¾Ëh˜ºD5}Ôÿšª‰YÕað…–æØ²ߪÛ$Î 6;¤öÔÝ K¨½QA‹U#±6N˰Õò|îi8_çÉ{¦qW†]ƒ>lIYþxÉ2¤éV¦%¨ÔÙ4Yâ媪@”ET$€3`(èŠÇóǵE]ßÂ,mFÿŠ7ÅÙ”W2D3ìp¼äSJ*ŒU¿ájs® >/?*òÈV›{Ù­úú;Û–ÌûC‘íP;Fè¢Ø]sâ™Uã6X ¢L;˜5dî\ƒ’˲îj†±¾‹(ø³°«±æQ1ʱ1¢ ØY>@~f2ë ­ã²éB샥£÷\¦TŽš¤NK_/ÄSPT—¯H/øÊ ¯°¢FíkªáâÉOÑ÷Íí‚s-ɹÃN÷>&f—•Oèµ^?_#ÆžÓƒSh†â?—C)i8ž ˆmÅp;i·{ÉÛh>$aRL`’Ñ?{Öit:{¸)IÍB8à:°, êÚ•ÅE`¼#b»D‹/d¸Ò°„i½¥}‹®¯Û²¨r1¼¿þ2˜³¸.ÛžáÜ6Ÿæ²WPNPSj€R‚‘]öóm¬ËÅÖÍ]ŒÓ<¦V¼¥å‘¯8⋞ K®§»ô8Ñæ»¬=ú£ÀWNõ1h_L6æòj ÅK‘rÁÚÏx„Òã¼äŽLÌ´?¯ ïˆÙ*°>÷ýg 3þ MG.¦ Ýôx¯_©»Û9¤;+ûÙI$ë5mxR¤NÅ„éÊË…š…7ãlbîKÅÊÆL908ŸOÆj’Çâ[—³”ò?RáœyG¬¾óœŽ[TfÈìai«£“\®;¦èƒ#²ïJ ËÆ}~=ì!©8§`ÐZ)̕Ɗа‹ß²ì_7º*H rFÙÉ\bs€¿|Dk3†|è3}{KºîŽ3•k‰£.aôC]ÄΦ3_íçÚϸzPhàR:¦ãJü0ŠF·;&›âÏYzÁí՜ƆȈ˜·ý‘­ûÑEh}AÿêQÄí¶ö³Tg°]†5$S΋^–[6è˜ËýÄÎðñq@aù¿*wå¹?-o–d+þDØI·¥Ùcí3ƒs¬]˜³³¥¹´’‰®óÊU›þ‚gixžndެY%ü®„G‘¸ô×6ÅòTúïêµJ™š >àr6´ÞÈSAcÊù‡Ù—iêA)[C<4k?Öó¥´³üQ ÚÈ„ÚqBc­ E[<ÔþÂ%9(• õ+z]½ÄaOšÍ¨\:éþóîÅO=Ìõò5o~@H.ê«EêÅaQº?oFE(Ç¿ñH6ç¹-¶-lÕö­B<{ÚÐ{&åâÔ?_ýÀæ^¯Åª9·m»ñ¼%iù8Rˆ¬>ГËJ*ùÇf¬û$Õ8ìO·åÔü>qs$íï8ŠK‡’|Vs©»óñýº½~ìw$£mKlÉ…³6‹÷y¬ÊÐ@á4–tÚrTkÖô±ÿÙr¨i8R¼G6ü˜nA P?ã·å†3á±4–œê ¨,Éâ¡£ã²@’'‘÷áƒ#ÙXBúäm=ï9ôUŽl¨Ñ­þÇ ëä¶,dªå €Òa÷ÚÞ7Äs?ÑROnÄfå#®Å×lg?ë\5næ½î‰Ù~N½cMƒZ?hdS³”ê ;oÓáÀðÿ£è'vÃÿ¢]b.iz —B¤qª“çÇAmŸ¹²ÕisE˜I+ʶ„»êûrü²¿åln’‹ò½³70ýæs^C\¡¾Í/“É›+ÙÎ4¤¹ÉÜ ÁäàwY¸ ©Šõ iöô+4Ò¶$Ù±rƒ1›Ûú²o÷¥“»@Èð§"ö}«q²§N|êŒ0ý¯õ R–‡/ݸ|«&©¾æÍÁ#z`Ÿ[ˆÄ”¸=b¶`p¨7ÏÛͺ‚”11œüø“bÖ}k#P/±’Oô‘ÍoÂ!¬ 8£'{ïhÂsÓ¶^:½ø%Õ?´Ã)ŸºxEÁ¨‹Ì¬dr¸)vÛ,%˜Ö(gK¶¾Ê7agö•\®öä5 Èîz×ãjÔÝŽð”;ܰh:Ù†€+d«w˜êýúaÂ:ý»E¦5¼ºîa¥0ùQ]œ:ÇðÒÚ]w3»ÒŒO  RÍ6Øõe_•܃Þmþ‡Z€GÞ,QãS^“‘Zÿ’–÷ ³ª+Ê&mNñ%¸À'âpÍç£òLöþÓÎjçIIyÆàä_íšò ê‹–ÏwñÂ|× 32òê¾MG5VÒ™-ïIåc`€9=ÿúçÌ‚#Æ£ŽÀQØš¯‰áIü–ǺO–­+êU³±Õ)ØßÆi^_ØÂÛ£hÖqŒ5;§?(µLâ¾E@Ã긮ÅÁ—߇ÐËÊ×ÏqU ¹?äŸÐÝkn|ZE5!ž•Î÷&.%€Šw›¬e*ýÉõdoc•ÜŒËÊöL–n¶ëÊòMdÍÏÛjÀƒ#D=^ŸÄi›Ç o­íÝœÛAä-ÈX¬ïû€!Ëáÿ|DP_aÅÌßäÑ—ƒê{÷L;‹UÊeT-‡"ïÒz›ãù¤þ®­-“ oöÑdZCt=Uz>ä5Dïù)‹ˆu"9.L[(ê.s¶©rÚoñJñÄáT¤_Z¨o Šé\«§säŠ$ÓMt[1ô§—ÊM^¦i&t:rãÇñìt–šI£ î@÷n œFM!t–}dŒtž¬1èŸyß ÎÙdÉØ'5„îð`2³õs¦(øÏ© ŽãÁZ›ó!8U6UM 'hp¤‚§Ûž\a‹¶ONx sØéó×Á'Dä:ŸÂ ù¸Ìæ­«0gl‹b¸ÁªU˜ @ô]q«>jîXÒTOnÔ‹¨jº¾Þápdi[…¯MÃLË6.œ¤µSßìf† ÝÓ _SFƒR•ªIÐ>³œR‚«‹Æ–&Á I‘·å¸ù&eØ™++m±¶àæn<š˜ÛÅqxR"¯GŸ¼,»<û†\ø®‘l%”§>'Ú…64;,¦2Äl¼ x¢$uhãìÐw¶èð#l`†>ßM–>{]g@cÍ«%z„Î}_J¯O hxЉ*/OÁÁr»kAþˆ<"·{_RÌȰ/M/§Ç·TvHŒ,,×EÝ…‹{‚?ºôÁNJYˆ‹„vÇ Ë Ë,d÷Q•P£¿‰Y ”•x6Jýø!­º¢¾zßlOe5¥n¥¸_Æ A,™Ë–Ô•ÊêDƒg ; Ò0)Ú…µ ̤hO¶±Ð*¼ò—¬AáŽr ’®dãN‰\ê°½kœ¼¬6óÍŠS}/žéŽaÕ%ÿâ\Ì\IýC5•Ž»ãU*¡1‡qÒbêíâ’¢ ØÓRxÞ¨[e·j+g°4y{½Í7Û'EÚL‰™°§œ¢¸.DÞD µSFÒµÓ'DÇôÔ’‚ê.[À²š¯# ­·¸õN{.Ê•ò×=œi†´…€#É£Ó±”š(ðñ&?…ýÍØ-Å–üH…… jd™:xZx%Gb¬­>½c`"ÏÜ$D©DyWG°~†¢Kömçx|lê{d:èø¹Ðêþ{ÑM‡5bç\þ*[?ý]§ÖíÇÐ.oÔÏ Z¡h°VL†ÍÞË0Aœ¾ÄjªÀÙÏ\¬¥#ƒ}ºG2ɬÔR€uôÄàñgÛÞBYE±ÜõdrðÕÑá÷Wë-Pòÿ¯„S±7²YŒò(5é„'÷ ›Ú%Ñòɲ\0Q D9®NC®¬4qžyàà-ÛlÎò¡§o[ãmP|ŒQy]$žÉXÅCõrBˆC¾@ð =={`¦ÞÚvìì%˜‹©3RwQ*ÎÏ ¸&G]Ãø°±&Q¹'G¾ØäjÑV0“²“-M˜¹)åœêYâÆxªI¹%<}š\2BöîhCU¤•N.:‰ˆg>N’£†äþ±¨ê…Záä+iÕ·ôçù'ªzÕ{ܬÇýçV Ô-D¶¶-‡£á@ÛÜ·rÑ«¡r÷™Ûmy„` 0÷OöܦMóFÏHï–]QïdcK­BÔ¿Ì_sÝ>paðò  Ô}âXM?µ&î§ÙgŽ©øxáÁã }îà0vnø¥Ã² /ÆÄ‘ú`Éè•J¡Ö\!ñ£3}àM‹žÉÃäòTÍ’Ú“Gdø–qÅÀVxкÆ`ôµÅøÛ]ñSÑô e—TBš¾åôR•»4¸Ì™öw‰™ê‘¯LÕF]ܺ¹Ó‰ZÌ£€‡oxTípƒ²ñÄ–Ý=\þ}²Cb!OV;æ‡E|Ï-†®ÔElÁÓÌÊú˜²-p÷±^2?.ƒаeUËQóè¦>+úÂu+b»Z¿ë(Súù°‰bŸ’yp8Ë-Óì}5xú<¢RauŽûæPé‹éVê9•dg ®#šw¦û]”0!*< &yš®$VA·œ`EaÑÁâ=¸ 3À5þ¹´Ùc sÀ.8¤±Cº t—]<ö¬rPÈ}аťSFiú°ß© بòT]uÃ×÷Œþ¸É»®{n…Q•‡~a¹n¬ù³™m •©}{®n‹+V½Kò®=êüW"ß³¤,}evYg( Rï¡Ìšé@‚©…˜âgaP*ò?ÂtSÃŒØà9‡Rµ‡Ð_LõZ¨ˆ"-žU,“zdØ^gK-ä 3±ÕùªØ×víï0‘©Ä8¤Ø¦0ÆrÏÛé_V%!§óAót‡ë7„bq•ÄÖ¾oËlißÊeïÐ>NàKžó£S¶1¹16ÞIFá!ŸLkÙ©8×ðº¿`ÇÖCŒ0Ý&•v?B––¤É,Zˆ¿[%QØ=c {2Þ_/„·+T÷Á¤»Œj \À„™ÿ^ÙyaáÀ«ã­œÛþLj–ÝËC—CˆDVˆrOQí;±Ç© Ö÷Aaz<~ô¡ ÓO½l»š¯ð†Ðt<‰¯ùDû#Ú n‘ðÇA±‘S¡]…d¼éc<›ÑÅüƒ¬<­®€9ìtØ÷$²<'òÚ´³Ú_ÚIÊ–&1Ý´íª:"¦ªŠtnAubÆ@¼˜bÜ“å€ì³8ÈüShã6{|aPÛ¼8=c¢ðÔ×¥sÖq)¢>ÔWÌòÖJEƒýd^`šHIJ4)PˆÐu»9»ï®k‰Ù¦\ëÔL:ë<­‘"ãS-‡úñZº…+^Þý`+4ÍRЫH5Š‚ˆ±QûHiúy%vf ‚_ÅЮžõ‹±‰àw[Km‚ÏE‘7É% Ÿ*Ý Fµèéc„S˜žò¢W^'AûYkd/ ï.àœ'[ò¿ùÜ¥Ìô;ŸþÜåDÂê×Þ)¯™Ú&Ò2•åèà7("䃋Å¡a …ÖôâXãš>§"µ»˜|Sý¥áXðU¢wnŽø|I|ºâÁµÇGÔ4Xk=6\\ÅßÔ‚NÇ:öC$‹CÅw®…µ¯ÓÖ–î¡tÍÍh³ö½Yð†±¨\J6c’n_ð)}^<7øÎÏ×ÕÝ|ìGÆz¯‰‹ërH&ÂÄÂe”qOM"ñç7FøI‡)¼$¦ÉÏaKŸ?KÍ:Í–ÊÕTà§f‘ص«íàÑüBõ¨ÀŠççD×T&Ožô _@„8‘+VyŠ„Ž'*þ½G?Ô®»ö³ÊUþÊùÛ’·„X¨¾6Ï"6Z4¤ò³â#ºZt6¶lxÝ©zó‡]Òá')lµΘX ?žp*Õ‰åD‘ÝxÃO°³¥5Pó‰EÖ8¡Çαu2jÆm_ذ!{D'ܼ‰x4ªé4$Çõ~"+ö´ûr{ïzfôÁ’Cgο¿3R,È>i±ÿÀnsƒLЂRC' Ø#cBnu„Û ¤è5}• -ôBÛ¼¥fyé-0æIBµÄR ` ‰¯ì£¸›spò¶ƒøÈÈÔB[À T¥š1°âù$êø¶uúÁØçöYžO:dáYê4AG·„‰tñò ríÅŒKü~5"£ÿ9£ýoïh^85ŽkqÒõh&÷^™n’d¬ç¬óY0`ËÌÇ¡PÏ}Œ…-rdëLÖë î&*ŽôS˜s"»ðÎük€¹h$¡tR|»G;¿²sá\*ªncB¥ôvÔÊÖ'+…Z‰·ü¡œ|÷›»L û·æ–TMÜ®\÷[k]åê©¡mYƒ¶]¥GU´îïp:±¡ï)gó¶á<Çê°A÷@®«¸xÒ‡_¦gŽçË´²+f¾QQ<æ5ab¡YM4øfÁ÷„§ùØÕ^’ê2O±åªõNA`á;]?âm–v¹Ê»VY_Ï„.¢ïò‹™ÞôÔqIu}Ê®Å6xÔ9Ǿ ¯¬f:Ç•u‹(/A8¾Éa°*f‹XV”=Äì—$¹Û¯GúLÚÅ,÷b°t]?ØÖB³ìˆ„¶A-˜_EFØ¢¾DhÄ.ÏÜŠ¶Ûc)’¯ÝïbõÄ_*‹ÓÛ;nóóÇÏÊv‚Òaøøi=&•ܘ«{#.+î†x›»SÕÖûnDS³Jw.EÉ$Il$N¿Ðb òZý9PÃ|Ž»3KŽ ñ‘àò*häÙoâ`<¥ª–(4V[ø¡sNLÙ¯dÞ ß¶/«ùI65s lmS@³êN:]¬êèØ-Äóÿ6“ž(#ûÕx¿é&)‰ø­Tï)oJ/[ iôlÙíAÒOóÜ£³~ÚCè³á$okR V-C¼âñ­1zô%=,v@±±¿T{í ÉL:• z~*É%||ž>˜&›,;CE+§t±Ì`$ÉNL*=NÉ6âÉiÓ cúÛatñ5BÛü+_êi@ß­ñA×G<îÎÓÚ µ¨fPË]“‰DgómívæB¹4%‡î‹Îõ0bÛÞî©Eôúmñˆ^.T¦i’ó—ERyôÔ°÷Ë5{˜aÑ)~g1þûn¢Ï+ܤ5ËD_ Ä‹ífÀP¾nPPÅ”„ëpñ7}ÐO,¤K-˜gå™Og¡˜ªÈŽÌ¤*ÃszÙWYy?%C¨A ,fö<w1ƒJŸÁŸÙ¿¨™3¼$—:ôúj+™šNù%.PfÍ|tztÄÀðœ¿CÅÕ”4A:ÙŽ¹?ç{¡±Šscq®>ú‰£–ÁÙ$KÕ¢²wÒAH³‹ :é¹ä²oá0- €ÁS…ÃǬ4ÓÿʬØ'O÷õ7Järû-…HV÷Ø+ÈKk-žaɳ¿Hst®6ø!§³˜–·&.ݬpH°&ß^Tgfш—=SÄT™d B€–Âv‰7)ô¬Þ4DSa•ä U„+q2ýìÂW5êz„[9UßTv¥ýêŽê¥E½›Ê\ ÉN T…u'~„¡ÂWû•SûîŽo§Oe«$×{øfž\Ýæ´«¬ßÛæôRÍ™ŽU6¦1èmn¤–¦N}#øý;uZÅ5à&%D@[2ªè¶ß’™’O·’µËQ2‹>½£Á´#µqQß¶QÕÄK£{e¢jãÛ«Í! ŒWFQZþR GDZý±¤6ÜBõ’âin•XóbŽ0‚"·OeáFI×Û\|Ó2ÓªäqøÕÒ=6jÈä‚Ù¼ZšyqœK#t‚ÙÁ„˜ öµ1nzülóŸØ¾]“%™« æÿÔ`m¿úÅ´½'ÏÎA¡Y¡kª&¦Ž'ï‰zÖÃ1z7‹åOµ CP™^ßå½b„Í!AŒ¾ ÉÕcWeÞîs+ô³Wý´˜/`Q$ñXÊnBÚÞbÆ’;¤Ùr—å–I4ÜöýÚ‘ËðM¸¸¡É„k¾I24zY5yávŒÀ×Z]Ò„ƒmÙ›ûq£,w/CåΫQ³wˆÌ]Þ¢¯wƒ0@Òu¿155È?í–{xPÖõm5I‚ƒ·4UÍR°ªòèjöì9ñÇkí>õ˜dñn…nn&- U‡ù @Ðà™ÍÞOmçB©Á×üÀ¤bªð¾+ÆX¡2T´E4wHc«›IpAœÞÈEÄ;l€ô‰¹½ñ:Äa3 LS¸Ü; fFë_jíÚ‚;–FüòůvËbS_ëîR怢•¥Hfî|Èr’/$náýº¹YÐÀùD凪årFy‚6§ T‹üÞÓ'Aµšjt{…GèdY¤WÙq|“ZSüá˜{ÁÇ_Ö¡7Ø‘ÚQb ¸aíh’ k°r”Á·O7ж–÷”Q’ëªTØ"‘±â?X»aÀéî»9ä‘_8gAŠ]SÎÑÉ݉¸•†cm¤÷È™)݆^{<},Ë÷/Ÿ "E)ûù´Ãóyõ`92¤gC´b¤ßMç?ëº×|Æë{é ‰¢½s2y»t=:÷ê°’ô 7"rÖqaž$ѵ°äx4¢¼‘4ó]PC)Òïc.x¼B½.ÐÒ½Þ=ðÖ)yÖE•\ÔBàʯ|[‚ˆš#aOÄìƒl#ÄÀ zx^µÅ쇫×Çá3 ÕD=ÊãÅ…T*ß&õA J‹£Ì<‰-ÌŠ T*ôÃ@e¶bÕž¤ôIa¤%I©‘Kã´|ç•q„wS‹K]]Úõ¶ø׆+ð‹“Œ`E[›Þµ(V{ÔòzKÅ}¶‚ÔáÌÝ·5ž8óÕ‚ÑSï³8â×EóxƒŽ<¤µÃ3Ç{ð€ˆKç_5lpo('2j*W]øUÜo¨:{RxÂÁ’²™™X6ÄXED©L–Á‘¹åfJøew«–6´g̼·é+R¯·ûX×ÃOƒàúÏ‹ELlµI†*îctRåä«´¾Þ(±–¢ŠöAà: .™_>Þ®«D7ægl7ÛÏýk› CSxŸúEÞ†Û± ¬™W•Ù¶¸yΩ0åðÇѧçÑÅÔða\² ™\ì¶*K¡¢FmŽ»çÛcÉ?—Öb^z%gy?²£6¢G`n·Øƒ¡Û ±-ჩJ=TCK}ów‰Es£äªÕãxØN°ág‰¥ölª8ÄòxCŽÐb…K§^þºµ &~ìnkýA¢”ÏÝnp7ð 5­Ͷ½ë«Äqìïvâ­ÊI5?â'àrh„Ïrb44Uf5ÞP-N¦Œ×¸=­¢­€±Ývx EÓåñá^NvžôÖI¢»óPû„Z‹†I½B¬ŽòTžé@¬:R×">+úúïCrÙ—šAŠ–+”}ƽ‚¢ÿAà0ýË–'ËÔ«%W~_fíñô‚Äž¹uˆË©®ü‚ÈJ¢°Èaj"w‚êxVTWc N§îG#íQüÁT~¡ëû¤HžÁºe¬d—ù5ô0Íi㙾bæï’6°`&ƒÎào`‚Ì|¾R_–OOð±mÌ&j¾M?ë&[ö2_2ˆ©s.{/Wnm7Ä4,©s«y ?‘‰pâêÉ«ú k‰-¨Ï6²îb¨×}Ec@Eðòûѧøtïhÿ­JãÁÄ1¯ot¢JÖQBJyŽP.jí>ísBÀ`Hà­%Jœ5èóà†‰ïµÏ>W:¥ùPe<›ðX1ž=º<@Ùœêåü½dÕÁæaÝôC=øÔÜËŽ-v]lvÜxœpU8Ô›¤üUœŽ(ïÑ)¦íEÃW#bÇ—`o2'OAxD-T7)ÁV€Þ¹60k7½Z¾kÑgs]ÇÌ7é´â¢³à“2Ô$€ÿÎfj¿õšFùEËKjoÉ@ fÞš¤´ûþ³mÖxmùì-9—†‘Þ»äŒFʶÕ4­¦wQ‹áźDŸ'^Ö—epŠBö¯Ã7®Ùãr.ë²ã¨#Þ¯dÃüO&eÁï }ìè¨?Ñᚣš¦ëXî/„Ük¦W"Yv\1cÃÝ{«¤¬«X€õ[ßÉc§ý¶FxË<ØZÚN¾~çÁÃN¼8Î}°ðûƒáì¢Î¥´B„žwdg¦ž˜H¯iå”A_Ü¡‰ñX¥À&ýngŸT` =]!™Üãû9õ&ytm—F%‘«šÎ¾#´¡|œn¡Úc®'d¯%&"¼’¦ÙÍ™ëQ#ƒÓz%¢x‚û žýÌrrРÚi—"z¸é¨ßu̼ô›íV€×²¨W°íMós¢°gwBD}جŽc6§6™'Ňç²e.b¿ÈF«2£«é“)¢Š]&„vÜÂÂ\ë)öÑt, µ‘y_tâªPÜ»Çó}™=“.§˜*V+›â¨¸Õ#˜‘±¼ÃtV¸ÈiÈi†vƒî“ÈÉ–4˜gકÜÃù ¸Ò“¯É"ýmXÈŠùüAk?+-p·U|ëpÕ¸§ßß©^Qæ+áø×¾×£)Øï\‹à¤£ªþàžÐtöþH%ßÕ Ân}kŒÑÂ]¿î„2ÏiŽÈû«îõ.ýRn):èÁ¾ÈãddÀÎ(w[Ù—iŠ} Bå‘V4a_×vu“_’•\³´~ç]\þ¶8u‘Sò ¯”Ñ_'KzSrKÔ#Fù8êè9ê"á4ôWÅÌÈ=r…Ô2 MKåÿE†ý endstream endobj 88 0 obj << /Length 699 /Filter /FlateDecode >> stream xÚmTÁn£0½óÞC¥öƆ@LE"¤¶­šhµ×œ.Rˆ$‡þýΛ1i·Z)Aãç™yoÆ7?ž·“¬î^Ý$º×êźËP¹Iþsß77EW]Ž®=?:W»zÜ==¨ç¡«¶î¬nóM±i›ó%oÚêýR»1ëÿI+÷Ö´Ÿ)àQ·;÷{ÒWÃ`‡ ý4òvÍùö¿o)Z«ëZqê/7œš®}Pæ^kMÀº­óîݧ`ê¹ÕtTshÚzðÔ+ä&TuSýŠŸÕ‘ @ñöãtvÇM{è‚ÅBM_hót>XÙ]0}j74훺½ª"t{éûwJË¥ªÝšÑ¬û£SÓïC]·w½S!¯¨©ºÚú}å†}ûæ‚…ÖKµ(ËeàÚúÛž‰¥äõ0æ&”«çx˜™Y°F\20/0–b“Ò# “!Ú‡\§)&q)€% 1Ϲ‘NÐÔ"Û‚%”’4¢81`rÈH%ÃDdè‘åÜ#C ýйk Ю%£íºÀÜ"l é%²Ë€ìR„Q ƒF'b=:SýÙäøuX¤ð$”Qúó:ú\C¼–AfpGÇR~m%^!N%ί$†h³³&„ÕšñR 󛣿#Æ¿p'XϾ¬½>ÿ‹A£Iä Â}3N¸h2Ž5ó¯gNÑE'b«£œkýkåØ¿sè ý»¢%Æ|Vâ ¬áž!ü°¡äÀË3™¬?Ðfc91˜ÓŠ—9Ç|u 6ãZÖcW‚Cƒåƒabî ýd1×®eFæ-9žAg깟ú÷Æ3•ZÆ=üI=ú¤ž ç6-Ä7p¥Ìçœã?)pe…øÆgT<ôŸ«?}øpq¹\¯ƒê2 tSð Ä·¾ÿ¦u×KªïzTñŸo·ñþÄê© þ…çr{ endstream endobj 89 0 obj << /Length 700 /Filter /FlateDecode >> stream xÚmTÁnâ0½ç+¼‡Jíb'$8B ‘8l[•jµWHL©$Q€•ú÷;oÆÐ.Z ¢ñó̼7/Žo~<¯GYÝmÝ(º×êźÓP¹QþsÓ77EWö®=>:W»ú¼{xPÏCW­ÝQÝæ«bÕ6Ç;J^µÕÇ©vç¬ÿ'-Ü[Ó~¥€Gݾºß£þýÏÖ#úiä½6ÇÚ¿ÞR´V—µâÔ_n84]û Ì½Öš€e[çݺÁØs«ñYÍ®iëÁ P[È L¨ê¦:ú?«=€âõçáèö«v׳™¿Ðæá8|²²»`ü4ÔnhÚ7u{QEèúÔ÷ ”æsU»5£Y7{§Æ×C]¶_?{§B^QSuµ;ô›Ê ›öÍ3­çjV–óÀµõÕž‰¥d»;ç&”«§x˜‰™°D\20-0–b“Ò# “ !Ú‡\§)&q)€% 1O¹‘NÐÔ"Û‚%”’4¢80`rÈH%ÃDdè‘åÜ#C ýŠ©K Ð.%£í²ÀÜ"l é%²Ë€ìR„Q ƒÎNÄúìLõ¾Èðë°HáI(£$ôçuôµ†x-ƒLàŽŽ¥üÚJ¼@œJœ!^H Ñ:ggM«5ã9¤æ7F7ÌFŒãN°ž|[{}&þƒF“È„ûf*œpÑdkæ_Μ¢‹NÅ0VG9×ú×ʱçÐúwþDKŒù¬Ä4XÃ=CøaCÉ–g2)4X( ÍÆrb0§/sŽù4êlƵ¬Ç.‡ËÃÄÜúÉb®]ÊŒÌ[r<ÎÔs!?õïf*µŒ{.ø“z.ôI=ÎmZˆoàJ™+Î9ÇRàÊ ñϨxè?Wúðáâr¹\Õiè¦àˆo|ÿMë.—Tßõ¨â?ßnçû«§2ø Ý7rX endstream endobj 90 0 obj << /Length 700 /Filter /FlateDecode >> stream xÚmTÁn£0½óÞC¥öƆ@LE"¤¶­šjµ×œ©D’•ú÷;oƤÝj¥Ÿgæ½y_ýxÜN²º{q“èV«'wìÎCå&ùÏ]\]]u>¸ötï\íêq÷x§‡®Úº“ºÎ7ŦmN7”¼i«÷síÆ¬ÿ'­ÜkÓ~¦€G]?»ß“þíÏ`‡ ý4òž›Ó;íßR´V—µâÔ_n86]{§Ì­Öš€u[çݺÁÔs«é¨fß´õà¨È L¨ê¦:ù?«€âíÇñä›vß‹…š>Ñæñ4|°²›`ú0ÔnhÚWu}QEèöÜ÷ï ”–KU»=5£Yïw§¦ß‡ºl?ôN…¼6¢¦êjwìw•ví« Z/Õ¢,—këo{&–’—ý˜›P®žãaffIÀqÉÀ¼ ÀXŠMJ0Lf„hr¦˜dÄ¥–€ÄP<çF:AS‹l –PJÒˆâtÆ€É #• ¡G–s =2ô+æ¬ (@»–Œ´ës‹°5¤—È.W PL²KF1 ˆõèLõ¶Èðë°HáI(£$ôçuô¹†x-ƒÌàŽŽ¥üÚJ¼BœJœ!^I Ñ:ggM«5ã9¤æ7F7ÌFŒáN°ž}Y{}&þƒF“È„ûf.œpÑdkæ_ Μ¢‹NÅ0VG9×ú×ʱçÐúwþDKŒù¬Ä4XÃ=CøaCÉ–g2)4X( ÍÆrb0§/sŽù4êlƵ¬Ç®‡ËÃÄÜúÉb®]ËŒÌ[r<ƒÎÔs!?õïf*µŒ{.ø“z.ôI=ÎmZˆoàJ™+Î9ÇRàÊ ñϨxè?Wúðáâr¹\Õyè¦àˆo|ÿMë.—Tßõ¨â?ßnãý‰ÕCü_er¨ endstream endobj 91 0 obj << /Length 698 /Filter /FlateDecode >> stream xÚmTÁn£0½óÞC¥öƆ@LE"¤¶­šjµ×œ.Rˆ$‡þýΛ1i·Z)A3Ï3óžÆ7?ž·“¬îönÝkõâNÝe¨Ü$ÿ¹ëƒ››¢«.Gמ«]=®žÔóÐU[wV·ù¦Ø´ÍùŽŠ7mõ~©ÝXõÿ¢•{kÚÏð¨ÛW÷{Ò÷ï{;Lè§Q÷Úœßiýû’¢\]sÅ¥¿ÜpjºöA™{­5ë¶Î»#tŸ‚©çVÓQÍ¡iëÁ P{È L¨ê¦:ûŒŸÕ‘ @óöãtvÇM{è‚ÅBM_hñt>XÙ]0}j74훺½ª"t{¡ÌAÒÁr©jw a´×ÇÝÑ©é÷M]—_?z§BΨ©ºÚú]å†]ûæ‚…ÖKµ(ËeàÚúÛš‰¥ekªÕs<ÌÌ, X#.˜K±Ié†ÉŒ€ãCîӀЏÀŠç˜©ô2î¹àOê¹0'õ\8·i!¾+e®8çÿI++Ä7>£â¡ÿ\ýéÇ‹ËåzT—a ›‚o ¾ðý7­»^R}×£‹ÿ|»÷'²§2ø ­rN endstream endobj 92 0 obj << /Length 698 /Filter /FlateDecode >> stream xÚmTÁn£0½óÞC¥öƆ@LE"¤¶­šhµ×œ.Rˆ$‡þýΛ1i·Z)A3Ï3óžÆ7?ž·“¬î^Ý$º×êźËP¹Iþsß77EW]Ž®=?:W»z\==¨ç¡«¶î¬nóM±i›óoÚêýR»±êÿE+÷Ö´Ÿ%àQ·;÷{Ò÷ïƒ&ôÓ¨Û5çwZÿ¾¤(W×\qé/7œš®}Pæ^kMÀº­óîݧ`ê¹ÕtTshÚzðÔ+ä&TuS}ÆÏêH yûq:»ã¦=tÁb¡¦/´x:¬ì.˜> µšöMÝ^Uº½Pæ @é`¹Tµ;Ð0ÚëãþèÔôû¦®Ë»Þ©s#jª®v§~_¹aß¾¹`¡õR-Êr¸¶þ¶fbiy=Œµ Õê9ff–¬— Ì Œ¥Ø¤ôÃdF@ˆñ!÷iŠ @E\ ` H Ås¤ µ¨¶` ¥%(Ng ˜*R©0fd9ÏÈ0#üb.Àš€´k©(@».°o¶†ôÕ劊 @u)Â(†A£±©þìòü:,RxÊVús}æ¯e#3¸£cé¿¶¯§gˆWC´ÎÙYÂjÍx©†ùM„­æ#Æ¿p'Èg_r¯ÏÄÿbÐhyƒpßÌ….šŒcÍü+Á™StÑI Æê(ç^ÿZ9öïºBÿîÀŸh‰±?+q ÖðÌ~ØPjà‡å=™¬?Ðfc91ا/sŽù4êlƽ¬Ç®‡ËÃÄ<úÉbî]Ë™·äx©çB}êßÌTz÷\ð'õ\˜“z.œÛ´ßÀ•2Wœsÿ¤À•âŸQñЮþôáÃÅår½ªË0ÐMÁ7ßøþ›Ö]/©¾ëÑÅ¾ÝÆûÙSü/Arž endstream endobj 93 0 obj << /Length 699 /Filter /FlateDecode >> stream xÚmTÁn£0½óÞC¥öƆ@LE"¤¶­šjµ×œ.RˆCÿ~çÍ8M»])AãÇ̼7ÏÆW?·“¬î^Ü$ºÕêÉ»ÓP¹Iþs×WWEW®ï«]}~{¼SCWmݨ®óM±i›ñ†’7mõvªÝ9ëÿI+÷Ú´—ð¨ëg÷{Ò÷oCc‡ ý4Ÿ›ñ¾½S¨  8ù—ŽM×Þ)s«µ&`ÝÖyw€ôc0õôjz´oÚzðÔ &TuS~ÅÏê@ xû~ÝaÓî»`±PÓ'zy‡wÖvL†Ú Mûª®/²Þžhé Aé`¹TµÛS7š÷~wpjúm®÷Ïï½S!¯è©ºÚû]å†]ûê‚…ÖKµ(ËeàÚúŸw&–’—ý97¡\=ÇÃÌÌ’€5â’yA€±›”a˜ÌÑ>ä:M1ȈK,‰¡xÎt‚¦Ù,¡”¤Å錓@F*&" C,çzdèWÌXP€v-h׿akH/‘]® ˜d—"Œbtv"Öggª?»|¿‹ž„2JB^G—5Äkdwt,uà×VââTâ ñJbˆÖ9;kBX­Ï!Õ0¿‰0ºaþ0büw‚õìÓÚë3ñW M";÷Í\8á¢É8ÖÌ¿œ9EŠa¬Žr®õÛʱßsè ýÞ?Ñc>+q ÖpÏ~ØPrà‡å™L Ö h³±œÌiÅËœc>:‚›q-ë±+Á¡ÁòÁ01÷„~²˜k×2#ó–Ï 3õ\ÈOý¾ñÁL¥–qÏRÏ…>©ç¹M ñ \)sÅ9çøO \Y!¾ñýçêO>\\/÷Auº*øâ[ßÓºkªïzTñŸï·ó%ŠÕCü¢t« endstream endobj 102 0 obj << /Producer (pdfTeX-1.40.25) /Author()/Title()/Subject()/Creator(LaTeX with hyperref)/Keywords() /CreationDate (D:20230412170205+01'00') /ModDate (D:20230412170205+01'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.141592653-2.6-1.40.25 (TeX Live 2023) kpathsea version 6.3.5) >> endobj 2 0 obj << /Type /ObjStm /N 77 /First 602 /Length 3249 /Filter /FlateDecode >> stream xÚíZ]oÛ8}÷¯àc³ ›"EQä¢(Ð4M§;I[$ýÈL&Š­$šÚ–+Ém:¿~Ï%%[²c'nº,°I?Î=÷ðòÒ’` Y(˜™P“QÌDÄdl™LÚ˜Å,Ô3L†ELE¨³HÉž°L+Üi¦ ZHã™TÌDºaÆ¢7ÁlhÐ 4n$!Ñ!†1*&¤ˆzaÏ1¶Bïh"”,TÀ`У`x‚1S€Kƒ…è7¶Š cñí­{ C€¦€ 6Â% à‡€i=“!ÀÐ0Æs Ü02B»H+Y&i¼féHöP$c ®QßÁZ€ Èÿ´ÔÈÁO šM€3 …QØÃ# ‡û)‹~b ‰ CP½]¢8Aǰ CÆcB4QÄ0‹5È)&°º§-3ŠŒ À:Œ³Ì [cf¥•°Y¢SÌjp†Ìš\J¶€…ÜÀHxLB…=pŠ ÜZ‹þ€D 00àˆ€À[jK*‡{¸Æt%UïéSÆO•¿Ï?`ç!”vÂøaV]°gÏð¸Çߟ¥Œ¿K®Ó‘O«tZ•LS½?IË|^ ÓŠsÇé(Köó[v  ²Ñ@‚o£ÄÀØ‹z)М rµ_ù|Fú¥»z¸EšTY>=Hª”=Ù« ò‚=9KŠ„UE:IQ|œUÞùh>L»uØîn0Ì'ì±w‡,½åEÅä ÀŸ°{ÍûÇ –Mf÷rœ¶KßäÅ$/ ©ƒôk6LO^í÷økVsò+»JÆ%.ðø}‘LËY9üÞPç¬lúXr|öÛïä’àc,ˆšÎÇã‹MU…¯*âA€ùÚ©z¿0òå!¦Ž­}‘&Ü5jñ³·—¦C_ëõ_<{ÃÓ´bçð2XâïÓÛŠ-º¾Óýˆ+þú°4Ádii$šÚ]¤´,]˜Ç1±dðƒd¸j2Hʇ{¹[·v³ƒSuƒñˆ(R¯ù¹M?´E–Gk¤˜Ç‘bè嵺ÒÕ•*PÜÞ@JÛø6)K"ºÄQì ÃG1´Cõ(†Âh‡à­ËFÆñ@o–M›¡–õ›õôh )±Æ}C*x¸†ºu½†~pbµ5´ÅehMCj' )»ÊÐRÑ%ôt´õh Er-ÛÅP$®¡n]¯!¥ô@†b×8Ôfîñ¤Äk¤D#E?\6ݺ^6BÛBFüw’¢£URtø¤ðçÓiŽîÎi'Ap´6þä×ë(® ÒÆ¼¥…E\ð_økþ7È·/°sR\Œ < ƒA„Ù¯T0ÐȨ"œ±kB½Óùe…>ùQ6ýÌŸ?}êFàχ”óSþáä5Onªjö/ÎË›|6È‹4¿S¶Ëg.®x Cme€lQ™p0Ê÷€÷qñ† EH ±Ŧo "³ä˜¿}û6˜®’~6ûõsVæý˜ƒ¾ì£þýËùt4Nûå,Ÿ–°sÔO†pmÉ‚=àEÑþYF+i—°#ýßµG™A`iGiãØp¤áΒʇÉdÜ¿ÌóÏ$¨.Ì}­<»u}ðŒŒ„?+‰Û'Î#IÓ ›dÚécAŠè„ظëÐ-Pô_Ô™ÖØ•+¡:Á†¿¦­Œüu„muscY›Î!Êh„¦>%öëívÛWõÑTαTKÄ&á°Ó¸tM6RyÜÂ@Ï©ÜÂ>*oêºsý¬¹§¶®õgºæŽÆmÎê_ !V±+#[©|½æ‚êÉz\‹îé9µ¥6î¨ýãlÃØMOÚã{O´Gе¤Œªù‚H×7²ëкæEï¼è†~À±¨oÔòpBÑ‚/ÇÃ_‹×qù¶ÆW;íêkòGÓ7•7 ·˜1qÖ­mo/® CÍ-MÃyëh4½h·ôÑõÔKuêm¬®‘4ê¥k.•Ѩչ´yH }í)@‡«¸àk‹~/„pˆÜ赆›ù°˜?õ5Í凜ÊQ¶ÐhËÏ—¦þüm‡ÿÛRÃùˆ~Ï5~•0^Ò³âîU¢ 1ôõ¶UBÆëŸ"q,–«ö¥Y%¥þ”yFÑ$ ¹¤–«„¦©D¿3ûK¯j«HÁ¨o¨åÏÈ}# žÀI¥všfQ.¦™Š[áÞHG¶ }¥kcBWNÙ±¦LixH濫òQ†çô²ƒÚˆeÈû‘eBÐRÃè=ƒµw® [\kjea€ƒFFzÝÁV›;Žüóf}غNÔëx;ÐíºN4¹Œ#»^¨š¾Ûq¬‰ûMLk/Štnâ^ûhâd;î×E+¥¬î -‡E6«òÂgyo’ ž¼>;<:>ùç›lr9/óéQÿ$½ž£Æ8¹.™òU÷Ý~­/$ëKHTCÞFPÒû¼ÒnMË{¿döKš]ßT#éLý³¾P¸{]%ãlø|z=NY€$¸J'™=~V·QR£‹›¤ ò Î÷ù ~À_òCþÊeÚ¿ò#~Ìßð·ü?A¢üžàŸx“²J‹¬üÌ“Š_òˤà—E2LÇéUå¯ êß]~N«E1®ýƒ!fÅp>¹§·|˜‘…#Óž$|ÄGùxŒþRî òôË<óôv8N&üŠ_e_S~…Ý-¿æ×ôj$-ø ¿ù>»I§<ãòÏ|ÌÇ´˜ð)ŸfÓ”Oç“Ë´(³ë)ÏyŽ‚w¯(*wå1ÍÒ‚¸£s–øþežWéèrì/ÊŒxä/y™N2ºL¿bÜ2»åå8)oxÅ«›"Myõ-çsŽb“ÿòoü–çñ¿Ò"ßó>Ìà˜X·‰¸O9Gǧo_ÕÊ9M œý|<Ú œ8dý0p¯¾0i•]j3¦­w»ÐŽ›´#Úâ‰BÙI‡„ó¢y‘ áÍÞÉàòF找 Ô|ëP`v¡à÷O/ßýÞ¦`ËäA¼ïKCï Hm¶(] D—‚p&j1 Ã6ËÉCÓ…&K‚ÉáY¸jDKmè¨ÅèõÖ0s»¦ìBϧÃÃÇïþùáäÓ»3i”å[5IÒH]Ú0j˜6A:î¤õ&)‹‹®F¼BŽRš€òÉ)ÅO'ÏÔµÓÌç–jV(r“©ÃÜ…¡³³ýçg']†NòI²!­IBnEÉAGB¬MÐfÈÈMR-‚´Ýÿ½?‚²ßœ´.çãqZ-Øót˜Ï¾û€6ZÑ鈢S+ŠvéZ]ÄÎûf7Púbwç/}°lBd78nŽˆFíâÍ_>ž¼|uØõ&Ѿ) ¤w÷áô®ÄƘ¨mØÑ»èz³owƦåN³_ÂíåÓÇ„fµK½76øàAôwÈ÷Sä^†ïXs^N‡ùkŒÎ®®Rz‡Ÿ–ì\¶í59O#¥ÅÙZdë¼^N‘¹¶q§%M6 ¹&¦æ¢6ѯ­d„レóJrúuJvK°SšW¼So³F7«µË |BQçL+Jaîšv­Ôñeá>Ì>f,ÿYÑNo:;ÖšÖòŒ¹³ø÷g'Æ}é†7ç·VRÕ¤X¾wêV…uÙ¬è  ~âÓˉe\¸XŸY‹H™+„Ô÷“2u¿JnÎU;3’>rï³¢¬h@4=~”Ô7Ü㟲QuSÒ÷D®j£8L5_ð>ÿ0…«F膌`Ð©Ñ P» TGm Â.F÷µ»ݘÀt± Té6P,Š{Ú`w [R‰¨ááÊû¡ŠÝ¡nYÓW F«Pe©ny_ÝTîŽtËzµ‚4ÞŠT™%Òà~¤á:Rz{XÒëÃ9í&omm÷¯Ù¨l¾Áª?Pª?Õ©?N©¿ÀðŸ\lé[mè»~ý^¿c®ßªú—&ÛºAÓÿ<¢~o¹hBy>9ȇýÓ*)ª=æß\>™¡›Ø£Ï?—÷r¾ø\Þ‡{ô…çò^íÑËûh¾àtò£l’U+c5µÖð¸r½Gßw.{‹÷è{Îå½Ù£ï3—÷ÙkƒÉp/<ýOÊÔ½¿ú‡³(ZEԌ֮¶iñŒH+Ýf¥ŒÈWʈÕzd¦Z)#Sí*Ì6‚vÕÍP‰¡xc7¦ÝYvãc½â¬gØzfÝÏ^½yWg˜¥¨gïˆý/Låüºç»Ð»7BõD¥‡Ç˜–üC™¾Wc$+¥+ <2E7D00CFC8082E6E6E4942CA3A7D6E63>] /Length 271 /Filter /FlateDecode >> stream xÚ%ÑË.ƒa…ᵫª´Ž¥UUÇE©ó™:ÆÌ…˜‰¤ ‰„Hq nÇ5™×ÿn“'+Yk¾|’T I!™½\ˆd&;ó5©ÕS`¶¡v!u†4šÂß~ÛëÐ qS¤êE3´ÀlBÚLñ¤OÚ¡v ¦Ä¥·]„^è6¥ã^¤¡ Ï”y÷"ý°94宽ÍÂŒÁ°)ÿæÅŒÂäaŠ0n*nún ¦¡k0³0%˜‡SéÖÏʦ«O‹¦×ÿ',™¾Òž–M?çžVÌ*QO«f7¿Á—Ukw±€ûTÀC6à©à“}¨ÀÂà œš=—ƒ‹ÏGý6v k endstream endobj startxref 107408 %%EOF camlpdf-2.8.1/introduction_to_camlpdf.tex000066400000000000000000000341541477056064700206120ustar00rootroot00000000000000\documentclass[a4paper]{memoir} \usepackage{palatino} \usepackage{microtype} \usepackage{graphics} \usepackage[plainpages=false,pdfpagelabels,pdfborder=0 0 0]{hyperref} \usepackage{xurl} \usepackage{upquote} \newcommand{\smallgap}{\vspace{4mm}} \newcommand{\cpdf}{\texttt{cpdf}} \addtolength{\textwidth}{20mm} \makeindex \begin{document} \frontmatter \thispagestyle{empty} \begin{flushright} {\sffamily \bfseries \Huge An Introduction to PDF with CamlPDF} \vspace{4mm}{{\LARGE John Whitington}\\ \vspace{2mm} \today} \vspace{3mm} \vfill \includegraphics{logo.pdf} \vspace{2mm} {\sffamily \bfseries \LARGE Coherent Graphics Ltd} \end{flushright} \clearpage \thispagestyle{empty} \noindent For bug reports, feature requests and comments, email\\ \texttt{contact@coherentgraphics.co.uk} \vspace*{\fill} \noindent\copyright\ Coherent Graphics Limited. All rights reserved. \smallgap \noindent Adobe, Acrobat, Adobe PDF, Adobe Reader and PostScript are registered trademarks of Adobe Systems Incorporated. % Letter \cleardoublepage % \tableofcontents \mainmatter \chapterstyle{hangnum} \pagestyle{ruled} \section*{A First Program} You will require \texttt{ocamlfind} to be installed on your system. It comes with any modern installation of OCaml. To build \textsf{CamlPDF}, navigate to the source directory and type \begin{framed} \verb!make! \end{framed} \noindent You can then install \textsf{CamlPDF}: \begin{framed} \verb!make install! \end{framed} \noindent To build the examples, navigate to the examples folder and type \begin{framed} \verb!make! \end{framed} \noindent Now run a simple example to build the file \verb!hello.pdf! \begin{framed} \verb!./pdfhello! \end{framed} \noindent As an alternative to compiling CamlPDF yourself, you may use the \texttt{OPAM} package manager, if you have it installed: \begin{framed} \verb!opam install camlpdf! \end{framed} \noindent Then (or otherwise) we may load CamlPDF into any other top level: \begin{framed} \begin{verbatim} OCaml version 4.14.1 Enter #help;; for help. # #use "topfind";; - : unit = () Findlib has been successfully loaded. Additional directives: #require "package";; to load a package #list;; to list the available packages #camlp4o;; to load camlp4 (standard syntax) #camlp4r;; to load camlp4 (revised syntax) #predicates "p,q,...";; to set these predicates Topfind.reset();; to force that packages will be reloaded #thread;; to enable threads - : unit = () # #require "camlpdf";; /Users/john/.opam/4.14.1/lib/camlpdf: added to search path /Users/john/.opam/4.14.1/lib/camlpdf/camlpdf.cma: loaded \end{verbatim} \end{framed} \noindent The \textsf{Pdfread} module allows us to load PDF files into memory. The raw PDF data is parsed into a structured OCaml value of type \textsf{Pdf.pdfdoc}: \begin{framed} \begin{verbatim} # let pdf = Pdfread.pdf_of_file None None "hello.pdf";; val pdf : Pdf.t = {Pdf.major = 2; minor = 0; root = 3; objects = {Pdf.maxobjnum = 4; parse = Some ; pdfobjects = ; object_stream_ids = }; trailerdict = Pdf.Dictionary [("/Root", Pdf.Indirect 3); ("/ID", Pdf.Array [Pdf.String ; Pdf.String ]); ("/Size", Pdf.Integer 4)]; was_linearized = false; saved_encryption = None} \end{verbatim} \end{framed} \noindent Looking at some of the parts of the \textsf{Pdf.t} record type: \begin{itemize} \item \textsf{Pdf.major} and \textsf{Pdf.minor} - the parts of the PDF version number. Here, PDF Version 2.0 \item \textsf{Pdf.root} - the object number of the 'root object' of the PDF (A PDF is a directed graph of objects, indexed by number) \item \textsf{Pdf.objects} - the PDF objects \item \textsf{Pdf.trailerdict} - the trailer dictionary. This is a distinguished PDF object containing a number of commonly used per-file items. \textsf{Pdf.trailerdict} has type \textsf{Pdf.pdfobject}, which represents all possible PDF data. \end{itemize} \section*{Diversion: A Look at hello.pdf} Here is the contents of the file \texttt{hello.pdf}, as you might see it in a text editor, annotated with some explanatory comments (object numbers may differ in your version): \begin{framed} \noindent\small\verb!%PDF-2.0! \textit{Header}\\ \noindent\small\verb!%%$^@!\\ \noindent\small\verb!1 0 obj! \textit{Object 1\ldots}\\ \noindent\small\verb!<>! \textit{\ldots which is the catalogue of pages}\\ \noindent\small\verb!endobj!\\ \noindent\small\verb!2 0 obj! \textit{This object is a stream, which is a dictionary plus some binary data}\\ \noindent\small\verb!<< /Length 102 >>!\\ \noindent\small\verb!stream! \textit{Usually compressed, but plain here for ease of reading}\\ \noindent\small\verb!1.000000 0.000000 0.000000 1.000000 50.000000 770.000000 cm!\\ \noindent\small\verb$BT /F0 36.000000 Tf (Hello, World!) Tj ET $\textit{The page content, a bit like PostScript}\\ \noindent\small\verb!endstream!\\ \noindent\small\verb!endobj!\\ \noindent\small\verb!3 0 obj! \textit{The page object, }\\ \noindent\small\verb!<< /Type/Page!\\ \noindent\small\verb! /Parent 1 0 R! \textit{The syntax "1 0 R" means a reference to Object 1}\\ \noindent\small\verb! /Resources!\\ \noindent\small\verb! <>!\\ \noindent\small\verb! >> >>!\\ \noindent\small\verb! /MediaBox [0.000000 0.000000 595.275591 841.889764]! \textit{The page dimensions}\\ \noindent\small\verb! /Rotate 0!\\ \noindent\small\verb! /Contents [2 0 R] >>! \textit{Reference to contents in object 2}\\ \noindent\small\verb!endobj!\\ \noindent\small\verb!4 0 obj!\\ \noindent\small\verb!<>! \textit{The root object}\\ \noindent\small\verb!endobj!\\ \noindent\small\verb!xref! \textit{The cross-reference table, listing the byte offsets of each object for random access.}\\ \noindent\small\verb!0 5 !\\ \noindent\small\verb!0000000000 65535 f !\\ \noindent\small\verb!0000000015 00000 n !\\ \noindent\small\verb!0000000074 00000 n !\\ \noindent\small\verb!0000000227 00000 n !\\ \noindent\small\verb!0000000449 00000 n !\\ \noindent\small\verb!trailer! \textit{The trailer dictionary}\\ \noindent\small\verb!<) ()]>>!\\ \noindent\small\verb!startxref!\\ \noindent\small\verb!498! \textit{The trailer}\\ \noindent\small\verb!%%EOF!\\ \end{framed} \section*{Saving the Document} The \textsf{Pdf.t} data type is a record of mutable values. Let's change the PDF Version number and write the file. \begin{framed} \begin{verbatim} # pdf.Pdf.minor <- 2;; - : unit = () # Pdfwrite.pdf_to_file pdf "hello2.pdf";; - : unit = () \end{verbatim} \end{framed} \section*{Next Steps} The objects in a PDF document are of type \textsf{Pdf.pdfobject}: \begin{framed} \noindent\verb!type stream =! \textit{Stream data. Either in memory or still in the file}\\ \verb! | Got of bytes!\\ \verb! | ToGet of Pdfio.input * int * int! \textit{input, offset, length}\\ \verb!!\\ \verb!type pdfobject =!\\ \verb! | Null!\\ \verb! | Boolean of bool!\\ \verb! | Integer of int!\\ \verb! | Real of float!\\ \verb! | String of string!\\ \verb! | Name of string!\\ \verb! | Array of pdfobject list!\\ \verb! | Dictionary of (string * pdfobject) list!\\ \verb! | Stream of (pdfobject * stream) ref! \textit{Stream data (see above)}\\ \verb! | Indirect of int! \textit{A reference to another object}\\ \end{framed} \noindent For instance the PDF object in the file: \begin{framed} \begin{verbatim} 3 0 obj << /Type/Page /Parent 1 0 R /MediaBox [0.000000 0.000000 595.275591 841.889764] /Rotate 0 /Contents [2 0 R] >> end \end{verbatim} \end{framed} \noindent is represented as object number 3 with the Pdf.t instance: \begin{framed} \small\begin{verbatim} Dictionary ["/Type", Name "/Page"; "/Parent", Indirect 1; "/MediaBox", Array [Real 0.; Real 0.; Real 595.275591; Real 841.889764]; "/Rotate", Integer 0; "/Contents", Array [Indirect 2]] \end{verbatim} \end{framed} \section*{Working with Pages} Introduce a command to show the current document, using whatever command opens (or updates) a PDF view on your system: \begin{framed} \noindent\verb!let show pdf =!\\ \verb! Pdfwrite.pdf_to_file pdf "temp.pdf";!\\ \verb! ignore (Sys.command "open temp.pdf");;! \textit{Customize here}\\ \end{framed} \noindent The \textsf{Pdfpage} module deals with PDF pages. We can get the list of pages from a document: \begin{framed} \small\begin{verbatim} # let pages = Pdfpage.pages_of_pagetree pdf;; val pages : Pdfpage.t list = [{Pdfpage.content = [Pdf.Indirect 4]; Pdfpage.mediabox = Pdf.Array [Pdf.Integer 0; Pdf.Integer 0; Pdf.Real 595.275590551; Pdf.Real 841.88976378]; Pdfpage.resources = Pdf.Dictionary [("/Font", Pdf.Dictionary [("/F0", Pdf.Dictionary [("/Type", Pdf.Name "/Font"); ("/Subtype", Pdf.Name "/Type1"); ("/BaseFont", Pdf.Name "/Times-Italic")])])]; Pdfpage.rotate = Pdfpage.Rotate0; Pdfpage.rest = Pdf.Dictionary []}] \end{verbatim} \end{framed} \noindent Each page is a record containing five things: \begin{itemize} \item \textsf{Pdfpage.content} An ordered list of pdf objects representing the one or more streams containing the graphical data for the page. \item \textsf{Pdfpage.mediabox} The page dimensions \item \textsf{Pdfpage.resources} The resources dictionary for a page, which contains the fonts, colour spaces and so on for the page. \item \textsf{Pdfpage.rotate} The viewing rotation for the page. \item \textsf{Pdfpage.rest} The rest of the page dictionary (i.e that which has not been separated into the items above). \end{itemize} Let's change the viewing rotation to 90 degrees: \begin{framed} \small\begin{verbatim} # let page = {(List.hd pages) with Pdfpage.rotate = Pdfpage.Rotate90};; val page : Pdfpage.t = ... # let pdf = Pdfpage.change_pages false pdf [page];; val pdf : Pdf.t = ... # show pdf;; - : unit \end{verbatim} \end{framed} \noindent Now change the rotation back: we're going to work with graphics next, and the viewing roation would confuse: \begin{framed} \small\begin{verbatim} # let page = List.hd pages;; val page : Pdfpage.t = ... # let pdf = Pdfpage.change_pages false pdf [page];; val pdf : Pdf.t = ... # show pdf;; - : unit \end{verbatim} \end{framed} \section*{Graphics and Text} The \textsf{Pdfops} module represents the graphical content of each page, which is formed of PostScript-like operators which draw the page. Let's get the operator list from the page: \begin{framed} \small\begin{verbatim} # let ops = Pdfops.parse_operators pdf page.Pdfpage.resources page.Pdfpage.content;; val ops : Pdfops.t list = [Pdfops.Op_cm {Transform.a = 1.; Transform.b = 0.; Transform.c = 0.; Transform.d = 1.; Transform.e = 50.; Transform.f = 770.}; Pdfops.Op_BT; Pdfops.Op_Tf ("/F0", 36.); Pdfops.Op_Tj "Hello, World!"; Pdfops.Op_ET] \end{verbatim} \end{framed} \noindent The \textsf{Op\_cm} operator alters the graphics matrix to position the text. \textsf{Op\_BT} and \textsf{Op\_ET} mark the beginning and end of a text section. \textsf{Op\_Tf} chooses 36pt Times Italic (which is font \textsf{F0} in the page's font dictionary in its resources) and \textsf{Op\_Tj} paints the text. Let's add operators to underline the text -- \textsf{Op\_m} to move, \textsf{Op\_l} to draw a line and \textsf{Op\_S} to stroke the path. We calculate the width of the underline using the \textsf{Pdfstandard14} and \texttt{Pdftext} modules to get the raw width of the string in millipoints, adjusting for font size and converting to points. \begin{framed} \small\begin{verbatim} # let width = Pdfstandard14.textwidth false Pdftext.WinAnsiEncoding Pdftext.TimesItalic "Hello, World!";; val width : int = 5555 # let actual_width = float width *. 36. /. 1000.;; val actual_width : float = 199.98 # let ops' = ops @ [Pdfops.Op_m (0., 0.); Pdfops.Op_l (actual_width, 0.); Pdfops.Op_S];; val ops' : Pdfops.t list = ... \end{verbatim} \end{framed} \noindent and make the new content stream: \begin{framed} \small\begin{verbatim} # let stream = Pdfops.stream_of_ops ops';; val stream : Pdf.pdfobject = Pdf.Stream {contents = (Pdf.Dictionary [("/Length", Pdf.Integer 68)], Pdf.Got )} \end{verbatim} \end{framed} \noindent and add it to the page, and replace the page in the PDF. \begin{framed} \small\begin{verbatim} # let page' = {page with Pdfpage.content = [stream]};; val page' : Pdfpage.t = ... # let pdf = Pdfpage.change_pages false pdf [page'];; val pdf : Pdf.t = ... \end{verbatim} \end{framed} \noindent and show it: \begin{framed} \small\begin{verbatim} # show pdf;; - : unit () \end{verbatim} \end{framed} \section*{Next Steps} \noindent CamlPDF is a large piece of software. A good way to get to know it is to study the examples shipped with \textsf{CamlPDF}: \smallgap {\centering\small \begin{tabular}{ll} \texttt{pdfhello.ml} & Build a "Hello, World!" PDF from scratch\\ \texttt{pdfdecomp.ml} & Command line utility to decompress a PDF\\ \texttt{pdfmerge.ml} & Command line utility to merge PDF files\\ \texttt{pdfdraft.ml} & Command line utility to make draft documents\\ \texttt{pdftest.ml} & Reads and interprets a file to test CamlPDF's major functionality\\ \texttt{pdfencrypt.ml} & Command line utility to encrypt a PDF file\\ \end{tabular} } \smallgap \noindent The HTML documentation for CamlPDF is built in \texttt{doc/html/camlpdf} when \textsf{CamlPDF} is built. You can, of course, eschew the top level and compile projects using the CamlPDF library directly: this gives native speeds and self-contained executables. \smallgap \section*{Further Reading} The author's book is a suitable introduction to the PDF file format:\\ \url{http://shop.oreilly.com/product/0636920021483.do} \smallgap \noindent For any serious work, you will need the PDF Reference Manual\\ \url{https://www.pdfa-inc.org/product/iso-32000-2-pdf-2-0-bundle-sponsored-access/} \smallgap \noindent For an introduction to OCaml, the author's book is available:\\ \url{http://ocaml-book.com} or at Amazon.com \backmatter \printindex \end{document} camlpdf-2.8.1/logo.pdf000066400000000000000000000041161477056064700146050ustar00rootroot00000000000000%PDF-1.4 %âãÏÓ 4 0 obj <> endobj xref 4 9 0000000016 00000 n 0000000393 00000 n 0000000487 00000 n 0000000669 00000 n 0000000903 00000 n 0000000942 00000 n 0000000977 00000 n 0000001009 00000 n 0000000546 00000 n trailer <>startxref 0 %%EOF 5 0 obj <> endobj 6 0 obj <> endobj 12 0 obj <> stream xœc```e``Rbæ‡ ¨€Y8Z@F¨ +30(0p5ð0Ìvcî"endstream endobj 7 0 obj <>/TrimBox [0 0 56.693 56.693]/Type /Page>> endobj 8 0 obj <> endobj 9 0 obj <> endobj 10 0 obj <> endobj 11 0 obj <> stream xœT»nAÌ-í?LhôN?æ%Y0–@ˆÜ>s’ø|ü=Õ½»$´ÒÞÕÌtuuwÍÎïï~î——óçÃéqŸÎ&¾˜¿^÷X9ìÓ|óõpºÛàÕUzûîúìyzžròçÓíúçø0Í·9=¼LÖh´šµÜÓÓd…zæ„wíéq²LUGbI qÓ”I:'é¤ÝV°›Xp^VˆwµäK­­Àƒ 4¥Á#ŽTäªT¸,”º¡ÝùdÃÆd®Ëˆ3*xZ*™òœEUk²NÝdk¥*’´¢8—rÒ’ØW’¬IªFe™z—„Z W+ÚMÂÔ¸o˜+)Â\uAíwy뮇¨¦5ÒŶ–R¯Ï³ò†Cvå^Òª——×#LôÕõ£0s8ŠxU\#©aH,rwtò•ÆÍC!£ªmX¦„¡šË+R*ØCì‚¡-"WdT´§à‰FÈ@È’eE» sÒuˆÛ¨à—Ç1ÄBÃĉ\ œa1$i­{hI+Ç2bòE†Ú‹Rfvë˜ìOóî¦ï“ùà±ÍTáÇ'7s˜QØÇôSl˜?TfŸ“×+A­-Üàž.BŽQÂ3Lª Æ5xÅRH!(®ŠË|…Ðkeðº¦ÜÝÌC£Ï,a_PùY†]‡;­ÇtÝœ#®¬à^‚àYÜ+àR|*`V 'fECÐw?­¨AÓßÝðþ|{ƒ€üþ³ßÿxn>\ŸÍÿþ¾¤s¹øŸoŒSüôkóšendstream endobj 1 0 obj <> endobj 2 0 obj <> endobj 3 0 obj <> endobj xref 0 8 0000000000 65535 f 0000001662 00000 n 0000001715 00000 n 0000001840 00000 n 0000000016 00000 n 0000000393 00000 n 0000000487 00000 n 0000000669 00000 n trailer <> startxref 127 %%EOF camlpdf-2.8.1/miniz.c000066400000000000000000011515771477056064700144630ustar00rootroot00000000000000/************************************************************************** * * Copyright 2013-2014 RAD Game Tools and Valve Software * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * **************************************************************************/ #include "miniz.h" typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; #ifdef __cplusplus extern "C" { #endif /* ------------------- zlib-style API's */ mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) { mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552; if (!ptr) return MZ_ADLER32_INIT; while (buf_len) { for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; } for (; i < block_len; ++i) s1 += *ptr++, s2 += s1; s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; } return (s2 << 16) + s1; } /* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ */ #if 0 mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) { static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; mz_uint32 crcu32 = (mz_uint32)crc; if (!ptr) return MZ_CRC32_INIT; crcu32 = ~crcu32; while (buf_len--) { mz_uint8 b = *ptr++; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; } return ~crcu32; } #else /* Faster, but larger CPU cache footprint. */ mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) { static const mz_uint32 s_crc_table[256] = { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D }; mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF; const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr; while (buf_len >= 4) { crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF]; crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF]; crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF]; pByte_buf += 4; buf_len -= 4; } while (buf_len) { crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF]; ++pByte_buf; --buf_len; } return ~crc32; } #endif void mz_free(void *p) { MZ_FREE(p); } void *miniz_def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque, (void)items, (void)size; return MZ_MALLOC(items * size); } void miniz_def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); } void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size) { (void)opaque, (void)address, (void)items, (void)size; return MZ_REALLOC(address, items * size); } const char *mz_version(void) { return MZ_VERSION; } #ifndef MINIZ_NO_ZLIB_APIS int mz_deflateInit(mz_streamp pStream, int level) { return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); } int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) { tdefl_compressor *pComp; mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); if (!pStream) return MZ_STREAM_ERROR; if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) return MZ_PARAM_ERROR; pStream->data_type = 0; pStream->adler = MZ_ADLER32_INIT; pStream->msg = NULL; pStream->reserved = 0; pStream->total_in = 0; pStream->total_out = 0; if (!pStream->zalloc) pStream->zalloc = miniz_def_alloc_func; if (!pStream->zfree) pStream->zfree = miniz_def_free_func; pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); if (!pComp) return MZ_MEM_ERROR; pStream->state = (struct mz_internal_state *)pComp; if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) { mz_deflateEnd(pStream); return MZ_PARAM_ERROR; } return MZ_OK; } int mz_deflateReset(mz_streamp pStream) { if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR; pStream->total_in = pStream->total_out = 0; tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags); return MZ_OK; } int mz_deflate(mz_streamp pStream, int flush) { size_t in_bytes, out_bytes; mz_ulong orig_total_in, orig_total_out; int mz_status = MZ_OK; if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return MZ_STREAM_ERROR; if (!pStream->avail_out) return MZ_BUF_ERROR; if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; if (((tdefl_compressor *)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; orig_total_in = pStream->total_in; orig_total_out = pStream->total_out; for (;;) { tdefl_status defl_status; in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; defl_status = tdefl_compress((tdefl_compressor *)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state); pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; if (defl_status < 0) { mz_status = MZ_STREAM_ERROR; break; } else if (defl_status == TDEFL_STATUS_DONE) { mz_status = MZ_STREAM_END; break; } else if (!pStream->avail_out) break; else if ((!pStream->avail_in) && (flush != MZ_FINISH)) { if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) break; return MZ_BUF_ERROR; /* Can't make forward progress without some input. */ } } return mz_status; } int mz_deflateEnd(mz_streamp pStream) { if (!pStream) return MZ_STREAM_ERROR; if (pStream->state) { pStream->zfree(pStream->opaque, pStream->state); pStream->state = NULL; } return MZ_OK; } mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) { (void)pStream; /* This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) */ return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); } int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) { int status; mz_stream stream; memset(&stream, 0, sizeof(stream)); /* In case mz_ulong is 64-bits (argh I hate longs). */ if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; stream.next_in = pSource; stream.avail_in = (mz_uint32)source_len; stream.next_out = pDest; stream.avail_out = (mz_uint32)*pDest_len; status = mz_deflateInit(&stream, level); if (status != MZ_OK) return status; status = mz_deflate(&stream, MZ_FINISH); if (status != MZ_STREAM_END) { mz_deflateEnd(&stream); return (status == MZ_OK) ? MZ_BUF_ERROR : status; } *pDest_len = stream.total_out; return mz_deflateEnd(&stream); } int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) { return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); } mz_ulong mz_compressBound(mz_ulong source_len) { return mz_deflateBound(NULL, source_len); } typedef struct { tinfl_decompressor m_decomp; mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits; mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; tinfl_status m_last_status; } inflate_state; int mz_inflateInit2(mz_streamp pStream, int window_bits) { inflate_state *pDecomp; if (!pStream) return MZ_STREAM_ERROR; if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR; pStream->data_type = 0; pStream->adler = 0; pStream->msg = NULL; pStream->total_in = 0; pStream->total_out = 0; pStream->reserved = 0; if (!pStream->zalloc) pStream->zalloc = miniz_def_alloc_func; if (!pStream->zfree) pStream->zfree = miniz_def_free_func; pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); if (!pDecomp) return MZ_MEM_ERROR; pStream->state = (struct mz_internal_state *)pDecomp; tinfl_init(&pDecomp->m_decomp); pDecomp->m_dict_ofs = 0; pDecomp->m_dict_avail = 0; pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; pDecomp->m_first_call = 1; pDecomp->m_has_flushed = 0; pDecomp->m_window_bits = window_bits; return MZ_OK; } int mz_inflateInit(mz_streamp pStream) { return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); } int mz_inflateReset(mz_streamp pStream) { inflate_state *pDecomp; if (!pStream) return MZ_STREAM_ERROR; pStream->data_type = 0; pStream->adler = 0; pStream->msg = NULL; pStream->total_in = 0; pStream->total_out = 0; pStream->reserved = 0; pDecomp = (inflate_state *)pStream->state; tinfl_init(&pDecomp->m_decomp); pDecomp->m_dict_ofs = 0; pDecomp->m_dict_avail = 0; pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; pDecomp->m_first_call = 1; pDecomp->m_has_flushed = 0; /* pDecomp->m_window_bits = window_bits */; return MZ_OK; } int mz_inflate(mz_streamp pStream, int flush) { inflate_state *pState; mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; size_t in_bytes, out_bytes, orig_avail_in; tinfl_status status; if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; pState = (inflate_state *)pStream->state; if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; orig_avail_in = pStream->avail_in; first_call = pState->m_first_call; pState->m_first_call = 0; if (pState->m_last_status < 0) return MZ_DATA_ERROR; if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; pState->m_has_flushed |= (flush == MZ_FINISH); if ((flush == MZ_FINISH) && (first_call)) { /* MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. */ decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); pState->m_last_status = status; pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; if (status < 0) return MZ_DATA_ERROR; else if (status != TINFL_STATUS_DONE) { pState->m_last_status = TINFL_STATUS_FAILED; return MZ_BUF_ERROR; } return MZ_STREAM_END; } /* flush != MZ_FINISH then we must assume there's more input. */ if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; if (pState->m_dict_avail) { n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; } for (;;) { in_bytes = pStream->avail_in; out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); pState->m_last_status = status; pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); pState->m_dict_avail = (mz_uint)out_bytes; n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); if (status < 0) return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */ else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */ else if (flush == MZ_FINISH) { /* The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. */ if (status == TINFL_STATUS_DONE) return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. */ else if (!pStream->avail_out) return MZ_BUF_ERROR; } else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) break; } return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; } int mz_inflateEnd(mz_streamp pStream) { if (!pStream) return MZ_STREAM_ERROR; if (pStream->state) { pStream->zfree(pStream->opaque, pStream->state); pStream->state = NULL; } return MZ_OK; } int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) { mz_stream stream; int status; memset(&stream, 0, sizeof(stream)); /* In case mz_ulong is 64-bits (argh I hate longs). */ if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; stream.next_in = pSource; stream.avail_in = (mz_uint32)source_len; stream.next_out = pDest; stream.avail_out = (mz_uint32)*pDest_len; status = mz_inflateInit(&stream); if (status != MZ_OK) return status; status = mz_inflate(&stream, MZ_FINISH); if (status != MZ_STREAM_END) { mz_inflateEnd(&stream); return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; } *pDest_len = stream.total_out; return mz_inflateEnd(&stream); } const char *mz_error(int err) { static struct { int m_err; const char *m_pDesc; } s_error_descs[] = { { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } }; mz_uint i; for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc; return NULL; } #endif /*MINIZ_NO_ZLIB_APIS */ #ifdef __cplusplus } #endif /* This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to */ /************************************************************************** * * Copyright 2013-2014 RAD Game Tools and Valve Software * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * **************************************************************************/ #ifdef __cplusplus extern "C" { #endif /* ------------------- Low-level Compression (independent from all decompression API's) */ /* Purposely making these tables static for faster init and thread safety. */ static const mz_uint16 s_tdefl_len_sym[256] = { 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285 }; static const mz_uint8 s_tdefl_len_extra[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0 }; static const mz_uint8 s_tdefl_small_dist_sym[512] = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17 }; static const mz_uint8 s_tdefl_small_dist_extra[512] = { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 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, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 }; static const mz_uint8 s_tdefl_large_dist_sym[128] = { 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 }; static const mz_uint8 s_tdefl_large_dist_extra[128] = { 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13 }; /* Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. */ typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq; static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms1) { mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; MZ_CLEAR_OBJ(hist); for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; } while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--; for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) { const mz_uint32 *pHist = &hist[pass << 8]; mz_uint offsets[256], cur_ofs = 0; for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; } for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; { tdefl_sym_freq *t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; } } return pCur_syms; } /* tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. */ static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) { int root, leaf, next, avbl, used, dpth; if (n == 0) return; else if (n == 1) { A[0].m_key = 1; return; } A[0].m_key += A[1].m_key; root = 0; leaf = 2; for (next = 1; next < n - 1; next++) { if (leaf >= n || A[root].m_key < A[leaf].m_key) { A[next].m_key = A[root].m_key; A[root++].m_key = (mz_uint16)next; } else A[next].m_key = A[leaf++].m_key; if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) { A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); A[root++].m_key = (mz_uint16)next; } else A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); } A[n - 2].m_key = 0; for (next = n - 3; next >= 0; next--) A[next].m_key = A[A[next].m_key].m_key + 1; avbl = 1; used = dpth = 0; root = n - 2; next = n - 1; while (avbl > 0) { while (root >= 0 && (int)A[root].m_key == dpth) { used++; root--; } while (avbl > used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; } avbl = 2 * used; dpth++; used = 0; } } /* Limits canonical Huffman code table's max code size. */ enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) { int i; mz_uint32 total = 0; if (code_list_len <= 1) return; for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i]; for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); while (total != (1UL << max_code_size)) { pNum_codes[max_code_size]--; for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; } total--; } } static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) { int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; MZ_CLEAR_OBJ(num_codes); if (static_table) { for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++; } else { tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; int num_used_syms = 0; const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; for (i = 0; i < table_len; i++) if (pSym_count[i]) { syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; syms0[num_used_syms++].m_sym_index = (mz_uint16)i; } pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); for (i = 1, j = num_used_syms; i <= code_size_limit; i++) for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); } next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1); for (i = 0; i < table_len; i++) { mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1); d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; } } #define TDEFL_PUT_BITS(b, l) \ do \ { \ mz_uint bits = b; \ mz_uint len = l; \ MZ_ASSERT(bits <= ((1U << len) - 1U)); \ d->m_bit_buffer |= (bits << d->m_bits_in); \ d->m_bits_in += len; \ while (d->m_bits_in >= 8) \ { \ if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ d->m_bit_buffer >>= 8; \ d->m_bits_in -= 8; \ } \ } \ MZ_MACRO_END #define TDEFL_RLE_PREV_CODE_SIZE() \ { \ if (rle_repeat_count) \ { \ if (rle_repeat_count < 3) \ { \ d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ while (rle_repeat_count--) \ packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ } \ else \ { \ d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \ packed_code_sizes[num_packed_code_sizes++] = 16; \ packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ } \ rle_repeat_count = 0; \ } \ } #define TDEFL_RLE_ZERO_CODE_SIZE() \ { \ if (rle_z_count) \ { \ if (rle_z_count < 3) \ { \ d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \ while (rle_z_count--) \ packed_code_sizes[num_packed_code_sizes++] = 0; \ } \ else if (rle_z_count <= 10) \ { \ d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \ packed_code_sizes[num_packed_code_sizes++] = 17; \ packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ } \ else \ { \ d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \ packed_code_sizes[num_packed_code_sizes++] = 18; \ packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ } \ rle_z_count = 0; \ } \ } static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; static void tdefl_start_dynamic_block(tdefl_compressor *d) { int num_lit_codes, num_dist_codes, num_bit_lengths; mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; d->m_huff_count[0][256] = 1; tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break; for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break; memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0; memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); for (i = 0; i < total_code_sizes_to_pack; i++) { mz_uint8 code_size = code_sizes_to_pack[i]; if (!code_size) { TDEFL_RLE_PREV_CODE_SIZE(); if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); } } else { TDEFL_RLE_ZERO_CODE_SIZE(); if (code_size != prev_code_size) { TDEFL_RLE_PREV_CODE_SIZE(); d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); packed_code_sizes[num_packed_code_sizes++] = code_size; } else if (++rle_repeat_count == 6) { TDEFL_RLE_PREV_CODE_SIZE(); } } prev_code_size = code_size; } if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } else { TDEFL_RLE_ZERO_CODE_SIZE(); } tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); TDEFL_PUT_BITS(2, 2); TDEFL_PUT_BITS(num_lit_codes - 257, 5); TDEFL_PUT_BITS(num_dist_codes - 1, 5); for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break; num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4); for (i = 0; (int)i < num_bit_lengths; i++) TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes;) { mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); } } static void tdefl_start_static_block(tdefl_compressor *d) { mz_uint i; mz_uint8 *p = &d->m_huff_code_sizes[0][0]; for (i = 0; i <= 143; ++i) *p++ = 8; for (; i <= 255; ++i) *p++ = 9; for (; i <= 279; ++i) *p++ = 7; for (; i <= 287; ++i) *p++ = 8; memset(d->m_huff_code_sizes[1], 5, 32); tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); TDEFL_PUT_BITS(1, 2); } static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { mz_uint flags; mz_uint8 *pLZ_codes; mz_uint8 *pOutput_buf = d->m_pOutput_buf; mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; mz_uint64 bit_buffer = d->m_bit_buffer; mz_uint bits_in = d->m_bits_in; #define TDEFL_PUT_BITS_FAST(b, l) \ { \ bit_buffer |= (((mz_uint64)(b)) << bits_in); \ bits_in += (l); \ } flags = 1; for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) { if (flags == 1) flags = *pLZ_codes++ | 0x100; if (flags & 1) { mz_uint s0, s1, n0, n1, sym, num_extra_bits; mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); pLZ_codes += 3; MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); /* This sequence coaxes MSVC into using cmov's vs. jmp's. */ s0 = s_tdefl_small_dist_sym[match_dist & 511]; n0 = s_tdefl_small_dist_extra[match_dist & 511]; s1 = s_tdefl_large_dist_sym[match_dist >> 8]; n1 = s_tdefl_large_dist_extra[match_dist >> 8]; sym = (match_dist < 512) ? s0 : s1; num_extra_bits = (match_dist < 512) ? n0 : n1; MZ_ASSERT(d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); } else { mz_uint lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { flags >>= 1; lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { flags >>= 1; lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); } } } if (pOutput_buf >= d->m_pOutput_buf_end) return MZ_FALSE; *(mz_uint64 *)pOutput_buf = bit_buffer; pOutput_buf += (bits_in >> 3); bit_buffer >>= (bits_in & ~7); bits_in &= 7; } #undef TDEFL_PUT_BITS_FAST d->m_pOutput_buf = pOutput_buf; d->m_bits_in = 0; d->m_bit_buffer = 0; while (bits_in) { mz_uint32 n = MZ_MIN(bits_in, 16); TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); bit_buffer >>= n; bits_in -= n; } TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); return (d->m_pOutput_buf < d->m_pOutput_buf_end); } #else static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { mz_uint flags; mz_uint8 *pLZ_codes; flags = 1; for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) { if (flags == 1) flags = *pLZ_codes++ | 0x100; if (flags & 1) { mz_uint sym, num_extra_bits; mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3; MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); if (match_dist < 512) { sym = s_tdefl_small_dist_sym[match_dist]; num_extra_bits = s_tdefl_small_dist_extra[match_dist]; } else { sym = s_tdefl_large_dist_sym[match_dist >> 8]; num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; } MZ_ASSERT(d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); } else { mz_uint lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); } } TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); return (d->m_pOutput_buf < d->m_pOutput_buf_end); } #endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS */ static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) { if (static_block) tdefl_start_static_block(d); else tdefl_start_dynamic_block(d); return tdefl_compress_lz_codes(d); } static int tdefl_flush_block(tdefl_compressor *d, int flush) { mz_uint saved_bit_buf, saved_bits_in; mz_uint8 *pSaved_output_buf; mz_bool comp_block_succeeded = MZ_FALSE; int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; d->m_pOutput_buf = pOutput_buf_start; d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; MZ_ASSERT(!d->m_output_flush_remaining); d->m_output_flush_ofs = 0; d->m_output_flush_remaining = 0; *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) { TDEFL_PUT_BITS(0x78, 8); TDEFL_PUT_BITS(0x01, 8); } TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in; if (!use_raw_block) comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); /* If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. */ if (((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) { mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; TDEFL_PUT_BITS(0, 2); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) { TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); } for (i = 0; i < d->m_total_lz_bytes; ++i) { TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); } } /* Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. */ else if (!comp_block_succeeded) { d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; tdefl_compress_block(d, MZ_TRUE); } if (flush) { if (flush == TDEFL_FINISH) { if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { mz_uint i, a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); a <<= 8; } } } else { mz_uint i, z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); } } } MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; d->m_total_lz_bytes = 0; d->m_block_index++; if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) { if (d->m_pPut_buf_func) { *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); } else if (pOutput_buf_start == d->m_output_buf) { int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); d->m_out_buf_ofs += bytes_to_copy; if ((n -= bytes_to_copy) != 0) { d->m_output_flush_ofs = bytes_to_copy; d->m_output_flush_remaining = n; } } else { d->m_out_buf_ofs += n; } } return d->m_output_flush_remaining; } #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES #ifdef MINIZ_UNALIGNED_USE_MEMCPY static mz_uint16 TDEFL_READ_UNALIGNED_WORD(const mz_uint8* p) { mz_uint16 ret; memcpy(&ret, p, sizeof(mz_uint16)); return ret; } static mz_uint16 TDEFL_READ_UNALIGNED_WORD2(const mz_uint16* p) { mz_uint16 ret; memcpy(&ret, p, sizeof(mz_uint16)); return ret; } #else #define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p) #define TDEFL_READ_UNALIGNED_WORD2(p) *(const mz_uint16 *)(p) #endif static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD2(s); MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; for (;;) { for (;;) { if (--num_probes_left == 0) return; #define TDEFL_PROBE \ next_probe_pos = d->m_next[probe_pos]; \ if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ return; \ probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \ break; TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; } if (!dist) break; q = (const mz_uint16 *)(d->m_dict + probe_pos); if (TDEFL_READ_UNALIGNED_WORD2(q) != s01) continue; p = s; probe_len = 32; do { } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); if (!probe_len) { *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN); break; } else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q)) > match_len) { *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break; c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); } } } #else static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; const mz_uint8 *s = d->m_dict + pos, *p, *q; mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; for (;;) { for (;;) { if (--num_probes_left == 0) return; #define TDEFL_PROBE \ next_probe_pos = d->m_next[probe_pos]; \ if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ return; \ probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) \ break; TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; } if (!dist) break; p = s; q = d->m_dict + probe_pos; for (probe_len = 0; probe_len < max_match_len; probe_len++) if (*p++ != *q++) break; if (probe_len > match_len) { *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return; c0 = d->m_dict[pos + match_len]; c1 = d->m_dict[pos + match_len - 1]; } } } #endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */ #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN #ifdef MINIZ_UNALIGNED_USE_MEMCPY static mz_uint32 TDEFL_READ_UNALIGNED_WORD32(const mz_uint8* p) { mz_uint32 ret; memcpy(&ret, p, sizeof(mz_uint32)); return ret; } #else #define TDEFL_READ_UNALIGNED_WORD32(p) *(const mz_uint32 *)(p) #endif static mz_bool tdefl_compress_fast(tdefl_compressor *d) { /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */ mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) { const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); d->m_src_buf_left -= num_bytes_to_process; lookahead_size += num_bytes_to_process; while (num_bytes_to_process) { mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); memcpy(d->m_dict + dst_pos, d->m_pSrc, n); if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); d->m_pSrc += n; dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; num_bytes_to_process -= n; } dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break; while (lookahead_size >= 4) { mz_uint cur_match_dist, cur_match_len = 1; mz_uint8 *pCur_dict = d->m_dict + cur_pos; mz_uint first_trigram = TDEFL_READ_UNALIGNED_WORD32(pCur_dict) & 0xFFFFFF; mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; mz_uint probe_pos = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)lookahead_pos; if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((TDEFL_READ_UNALIGNED_WORD32(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) { const mz_uint16 *p = (const mz_uint16 *)pCur_dict; const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); mz_uint32 probe_len = 32; do { } while ((TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (TDEFL_READ_UNALIGNED_WORD2(++p) == TDEFL_READ_UNALIGNED_WORD2(++q)) && (--probe_len > 0)); cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); if (!probe_len) cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U))) { cur_match_len = 1; *pLZ_code_buf++ = (mz_uint8)first_trigram; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); d->m_huff_count[0][(mz_uint8)first_trigram]++; } else { mz_uint32 s0, s1; cur_match_len = MZ_MIN(cur_match_len, lookahead_size); MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); cur_match_dist--; pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); #ifdef MINIZ_UNALIGNED_USE_MEMCPY memcpy(&pLZ_code_buf[1], &cur_match_dist, sizeof(cur_match_dist)); #else *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; #endif pLZ_code_buf += 3; *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; } } else { *pLZ_code_buf++ = (mz_uint8)first_trigram; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); d->m_huff_count[0][(mz_uint8)first_trigram]++; } if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } total_lz_bytes += cur_match_len; lookahead_pos += cur_match_len; dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE); cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; MZ_ASSERT(lookahead_size >= cur_match_len); lookahead_size -= cur_match_len; if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { int n; d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; } } while (lookahead_size) { mz_uint8 lit = d->m_dict[cur_pos]; total_lz_bytes++; *pLZ_code_buf++ = lit; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } d->m_huff_count[0][lit]++; lookahead_pos++; dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE); cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; lookahead_size--; if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { int n; d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; } } } d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; return MZ_TRUE; } #endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) { d->m_total_lz_bytes++; *d->m_pLZ_code_buf++ = lit; *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } d->m_huff_count[0][lit]++; } static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) { mz_uint32 s0, s1; MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); d->m_total_lz_bytes += match_len; d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); match_dist -= 1; d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3; *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; if (match_len >= TDEFL_MIN_MATCH_LEN) d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; } static mz_bool tdefl_compress_normal(tdefl_compressor *d) { const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left; tdefl_flush flush = d->m_flush; while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) { mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; /* Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. */ if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) { mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; src_buf_left -= num_bytes_to_process; d->m_lookahead_size += num_bytes_to_process; while (pSrc != pSrc_end) { mz_uint8 c = *pSrc++; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++; } } else { while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) { mz_uint8 c = *pSrc++; mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; src_buf_left--; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) { mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); } } } d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) break; /* Simple lazy/greedy parsing state machine. */ len_to_move = 1; cur_match_dist = 0; cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) { if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) { mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; cur_match_len = 0; while (cur_match_len < d->m_lookahead_size) { if (d->m_dict[cur_pos + cur_match_len] != c) break; cur_match_len++; } if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1; } } else { tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); } if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) { cur_match_dist = cur_match_len = 0; } if (d->m_saved_match_len) { if (cur_match_len > d->m_saved_match_len) { tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); if (cur_match_len >= 128) { tdefl_record_match(d, cur_match_len, cur_match_dist); d->m_saved_match_len = 0; len_to_move = cur_match_len; } else { d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; } } else { tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0; } } else if (!cur_match_dist) tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) { tdefl_record_match(d, cur_match_len, cur_match_dist); len_to_move = cur_match_len; } else { d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; } /* Move the lookahead forward by len_to_move bytes. */ d->m_lookahead_pos += len_to_move; MZ_ASSERT(d->m_lookahead_size >= len_to_move); d->m_lookahead_size -= len_to_move; d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE); /* Check if it's time to flush the current LZ codes to the internal output buffer. */ if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || ((d->m_total_lz_bytes > 31 * 1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) { int n; d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; } } d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; return MZ_TRUE; } static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) { if (d->m_pIn_buf_size) { *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; } if (d->m_pOut_buf_size) { size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); d->m_output_flush_ofs += (mz_uint)n; d->m_output_flush_remaining -= (mz_uint)n; d->m_out_buf_ofs += n; *d->m_pOut_buf_size = d->m_out_buf_ofs; } return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; } tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) { if (!d) { if (pIn_buf_size) *pIn_buf_size = 0; if (pOut_buf_size) *pOut_buf_size = 0; return TDEFL_STATUS_BAD_PARAM; } d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size; d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size; d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; d->m_out_buf_ofs = 0; d->m_flush = flush; if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf)) { if (pIn_buf_size) *pIn_buf_size = 0; if (pOut_buf_size) *pOut_buf_size = 0; return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); } d->m_wants_to_finish |= (flush == TDEFL_FINISH); if ((d->m_output_flush_remaining) || (d->m_finished)) return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) { if (!tdefl_compress_fast(d)) return d->m_prev_return_status; } else #endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */ { if (!tdefl_compress_normal(d)) return d->m_prev_return_status; } if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) { if (tdefl_flush_block(d, flush) < 0) return d->m_prev_return_status; d->m_finished = (flush == TDEFL_FINISH); if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_OBJ(d->m_hash); MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; } } return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); } tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) { MZ_ASSERT(d->m_pPut_buf_func); return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); } tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) { d->m_pPut_buf_func = pPut_buf_func; d->m_pPut_buf_user = pPut_buf_user; d->m_flags = (mz_uint)(flags); d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash); d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_pOutput_buf = d->m_output_buf; d->m_pOutput_buf_end = d->m_output_buf; d->m_prev_return_status = TDEFL_STATUS_OKAY; d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1; d->m_pIn_buf = NULL; d->m_pOut_buf = NULL; d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL; d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0; if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_dict); memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); return TDEFL_STATUS_OKAY; } tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) { return d->m_prev_return_status; } mz_uint32 tdefl_get_adler32(tdefl_compressor *d) { return d->m_adler32; } mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) { tdefl_compressor *pComp; mz_bool succeeded; if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE; pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); if (!pComp) return MZ_FALSE; succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); MZ_FREE(pComp); return succeeded; } typedef struct { size_t m_size, m_capacity; mz_uint8 *m_pBuf; mz_bool m_expandable; } tdefl_output_buffer; static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) { tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; size_t new_size = p->m_size + len; if (new_size > p->m_capacity) { size_t new_capacity = p->m_capacity; mz_uint8 *pNew_buf; if (!p->m_expandable) return MZ_FALSE; do { new_capacity = MZ_MAX(128U, new_capacity << 1U); } while (new_size > new_capacity); pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); if (!pNew_buf) return MZ_FALSE; p->m_pBuf = pNew_buf; p->m_capacity = new_capacity; } memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); p->m_size = new_size; return MZ_TRUE; } void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) { tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); if (!pOut_len) return MZ_FALSE; else *pOut_len = 0; out_buf.m_expandable = MZ_TRUE; if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return NULL; *pOut_len = out_buf.m_size; return out_buf.m_pBuf; } size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) { tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); if (!pOut_buf) return 0; out_buf.m_pBuf = (mz_uint8 *)pOut_buf; out_buf.m_capacity = out_buf_len; if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return 0; return out_buf.m_size; } static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; /* level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). */ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) { mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES; else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK; else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES; return comp_flags; } #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4204) /* nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) */ #endif /* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. */ void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) { /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */ static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, bpl = w * num_chans, y, z; mz_uint32 c; *pLen_out = 0; if (!pComp) return NULL; MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE; out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); return NULL; } /* write dummy header */ for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf); /* compress image data */ tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); for (y = 0; y < h; ++y) { tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); } if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } /* write real header */ *pLen_out = out_buf.m_size - 41; { static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 }; mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x44, 0x41, 0x54 }; pnghdr[18] = (mz_uint8)(w >> 8); pnghdr[19] = (mz_uint8)w; pnghdr[22] = (mz_uint8)(h >> 8); pnghdr[23] = (mz_uint8)h; pnghdr[25] = chans[num_chans]; pnghdr[33] = (mz_uint8)(*pLen_out >> 24); pnghdr[34] = (mz_uint8)(*pLen_out >> 16); pnghdr[35] = (mz_uint8)(*pLen_out >> 8); pnghdr[36] = (mz_uint8)*pLen_out; c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); for (i = 0; i < 4; ++i, c <<= 8) ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); memcpy(out_buf.m_pBuf, pnghdr, 41); } /* write footer (IDAT CRC-32, followed by IEND chunk) */ if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4); for (i = 0; i < 4; ++i, c <<= 8) (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); /* compute final size of file, grab compressed data buffer and return */ *pLen_out += 57; MZ_FREE(pComp); return out_buf.m_pBuf; } void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) { /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) */ return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); } #ifndef MINIZ_NO_MALLOC /* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */ /* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */ /* structure size and allocation mechanism. */ tdefl_compressor *tdefl_compressor_alloc() { return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); } void tdefl_compressor_free(tdefl_compressor *pComp) { MZ_FREE(pComp); } #endif #ifdef _MSC_VER #pragma warning(pop) #endif #ifdef __cplusplus } #endif /************************************************************************** * * Copyright 2013-2014 RAD Game Tools and Valve Software * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * **************************************************************************/ #ifdef __cplusplus extern "C" { #endif /* ------------------- Low-level Decompression (completely independent from all compression API's) */ #define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) #define TINFL_MEMSET(p, c, l) memset(p, c, l) #define TINFL_CR_BEGIN \ switch (r->m_state) \ { \ case 0: #define TINFL_CR_RETURN(state_index, result) \ do \ { \ status = result; \ r->m_state = state_index; \ goto common_exit; \ case state_index:; \ } \ MZ_MACRO_END #define TINFL_CR_RETURN_FOREVER(state_index, result) \ do \ { \ for (;;) \ { \ TINFL_CR_RETURN(state_index, result); \ } \ } \ MZ_MACRO_END #define TINFL_CR_FINISH } #define TINFL_GET_BYTE(state_index, c) \ do \ { \ while (pIn_buf_cur >= pIn_buf_end) \ { \ TINFL_CR_RETURN(state_index, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); \ } \ c = *pIn_buf_cur++; \ } \ MZ_MACRO_END #define TINFL_NEED_BITS(state_index, n) \ do \ { \ mz_uint c; \ TINFL_GET_BYTE(state_index, c); \ bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ num_bits += 8; \ } while (num_bits < (mz_uint)(n)) #define TINFL_SKIP_BITS(state_index, n) \ do \ { \ if (num_bits < (mz_uint)(n)) \ { \ TINFL_NEED_BITS(state_index, n); \ } \ bit_buf >>= (n); \ num_bits -= (n); \ } \ MZ_MACRO_END #define TINFL_GET_BITS(state_index, b, n) \ do \ { \ if (num_bits < (mz_uint)(n)) \ { \ TINFL_NEED_BITS(state_index, n); \ } \ b = bit_buf & ((1 << (n)) - 1); \ bit_buf >>= (n); \ num_bits -= (n); \ } \ MZ_MACRO_END /* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. */ /* It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a */ /* Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the */ /* bit buffer contains >=15 bits (deflate's max. Huffman code size). */ #define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ do \ { \ temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ if (temp >= 0) \ { \ code_len = temp >> 9; \ if ((code_len) && (num_bits >= code_len)) \ break; \ } \ else if (num_bits > TINFL_FAST_LOOKUP_BITS) \ { \ code_len = TINFL_FAST_LOOKUP_BITS; \ do \ { \ temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ } while ((temp < 0) && (num_bits >= (code_len + 1))); \ if (temp >= 0) \ break; \ } \ TINFL_GET_BYTE(state_index, c); \ bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ num_bits += 8; \ } while (num_bits < 15); /* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read */ /* beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully */ /* decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. */ /* The slow path is only executed at the very end of the input buffer. */ /* v1.16: The original macro handled the case at the very end of the passed-in input buffer, but we also need to handle the case where the user passes in 1+zillion bytes */ /* following the deflate data and our non-conservative read-ahead path won't kick in here on this code. This is much trickier. */ #define TINFL_HUFF_DECODE(state_index, sym, pHuff) \ do \ { \ int temp; \ mz_uint code_len, c; \ if (num_bits < 15) \ { \ if ((pIn_buf_end - pIn_buf_cur) < 2) \ { \ TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ } \ else \ { \ bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \ pIn_buf_cur += 2; \ num_bits += 16; \ } \ } \ if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ code_len = temp >> 9, temp &= 511; \ else \ { \ code_len = TINFL_FAST_LOOKUP_BITS; \ do \ { \ temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ } while (temp < 0); \ } \ sym = temp; \ bit_buf >>= code_len; \ num_bits -= code_len; \ } \ MZ_MACRO_END tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) { static const int s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 }; static const int s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 }; static const int s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 }; static const int s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; static const mz_uint8 s_length_dezigzag[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; static const int s_min_table_sizes[3] = { 257, 1, 4 }; tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; /* Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). */ if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; } num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; TINFL_CR_BEGIN bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1); counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } } do { TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; if (r->m_type == 0) { TINFL_SKIP_BITS(5, num_bits & 7); for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); } if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } while ((counter) && (num_bits)) { TINFL_GET_BITS(51, dist, 8); while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } *pOut_buf_cur++ = (mz_uint8)dist; counter--; } while (counter) { size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } while (pIn_buf_cur >= pIn_buf_end) { TINFL_CR_RETURN(38, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); } n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n; } } else if (r->m_type == 3) { TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); } else { if (r->m_type == 1) { mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i; r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); for (i = 0; i <= 143; ++i) *p++ = 8; for (; i <= 255; ++i) *p++ = 9; for (; i <= 279; ++i) *p++ = 7; for (; i <= 287; ++i) *p++ = 8; } else { for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } r->m_table_sizes[2] = 19; } for (; (int)r->m_type >= 0; r->m_type--) { int tree_next, tree_cur; tinfl_huff_table *pTable; mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree); for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } if ((65536 != total) && (used_syms > 1)) { TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); } for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) { mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) { tree_cur -= ((rev_code >>= 1) & 1); if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1]; } tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; } if (r->m_type == 2) { for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) { mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; } if ((dist == 16) && (!counter)) { TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); } num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; } if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) { TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); } TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); } } for (;;) { mz_uint8 *pSrc; for (;;) { if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) { TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); if (counter >= 256) break; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } *pOut_buf_cur++ = (mz_uint8)counter; } else { int sym2; mz_uint code_len; #if TINFL_USE_64BIT_BITBUF if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } #else if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } #endif if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) code_len = sym2 >> 9; else { code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); } counter = sym2; bit_buf >>= code_len; num_bits -= code_len; if (counter & 256) break; #if !TINFL_USE_64BIT_BITBUF if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } #endif if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) code_len = sym2 >> 9; else { code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); } bit_buf >>= code_len; num_bits -= code_len; pOut_buf_cur[0] = (mz_uint8)counter; if (sym2 & 256) { pOut_buf_cur++; counter = sym2; break; } pOut_buf_cur[1] = (mz_uint8)sym2; pOut_buf_cur += 2; } } if ((counter &= 511) == 256) break; num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) { TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); } pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) { while (counter--) { while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; } continue; } #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES else if ((counter >= 9) && (counter <= dist)) { const mz_uint8 *pSrc_end = pSrc + (counter & ~7); do { #ifdef MINIZ_UNALIGNED_USE_MEMCPY memcpy(pOut_buf_cur, pSrc, sizeof(mz_uint32)*2); #else ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; #endif pOut_buf_cur += 8; } while ((pSrc += 8) < pSrc_end); if ((counter &= 7) < 3) { if (counter) { pOut_buf_cur[0] = pSrc[0]; if (counter > 1) pOut_buf_cur[1] = pSrc[1]; pOut_buf_cur += counter; } continue; } } #endif while(counter>2) { pOut_buf_cur[0] = pSrc[0]; pOut_buf_cur[1] = pSrc[1]; pOut_buf_cur[2] = pSrc[2]; pOut_buf_cur += 3; pSrc += 3; counter -= 3; } if (counter > 0) { pOut_buf_cur[0] = pSrc[0]; if (counter > 1) pOut_buf_cur[1] = pSrc[1]; pOut_buf_cur += counter; } } } } while (!(r->m_final & 1)); /* Ensure byte alignment and put back any bytes from the bitbuf if we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ /* I'm being super conservative here. A number of simplifications can be made to the byte alignment part, and the Adler32 check shouldn't ever need to worry about reading from the bitbuf now. */ TINFL_SKIP_BITS(32, num_bits & 7); while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) { --pIn_buf_cur; num_bits -= 8; } bit_buf &= (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); MZ_ASSERT(!num_bits); /* if this assert fires then we've read beyond the end of non-deflate/zlib streams with following data (such as gzip streams). */ if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } } TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); TINFL_CR_FINISH common_exit: /* As long as we aren't telling the caller that we NEED more input to make forward progress: */ /* Put back any bytes from the bitbuf in case we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */ /* We need to be very careful here to NOT push back any bytes we definitely know we need to make forward progress, though, or we'll lock the caller up into an inf loop. */ if ((status != TINFL_STATUS_NEEDS_MORE_INPUT) && (status != TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS)) { while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8)) { --pIn_buf_cur; num_bits -= 8; } } r->m_num_bits = num_bits; r->m_bit_buf = bit_buf & (tinfl_bit_buf_t)((((mz_uint64)1) << num_bits) - (mz_uint64)1); r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) { const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; while (buf_len) { for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; } for (; i < block_len; ++i) s1 += *ptr++, s2 += s1; s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; } r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; } return status; } /* Higher level helper functions. */ void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) { tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0; *pOut_len = 0; tinfl_init(&decomp); for (;;) { size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) { MZ_FREE(pBuf); *pOut_len = 0; return NULL; } src_buf_ofs += src_buf_size; *pOut_len += dst_buf_size; if (status == TINFL_STATUS_DONE) break; new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); if (!pNew_buf) { MZ_FREE(pBuf); *pOut_len = 0; return NULL; } pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity; } return pBuf; } size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) { tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp); status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; } int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) { int result = 0; tinfl_decompressor decomp; mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0; if (!pDict) return TINFL_STATUS_FAILED; tinfl_init(&decomp); for (;;) { size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); in_buf_ofs += in_buf_size; if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) break; if (status != TINFL_STATUS_HAS_MORE_OUTPUT) { result = (status == TINFL_STATUS_DONE); break; } dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); } MZ_FREE(pDict); *pIn_buf_size = in_buf_ofs; return result; } #ifndef MINIZ_NO_MALLOC tinfl_decompressor *tinfl_decompressor_alloc() { tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor)); if (pDecomp) tinfl_init(pDecomp); return pDecomp; } void tinfl_decompressor_free(tinfl_decompressor *pDecomp) { MZ_FREE(pDecomp); } #endif #ifdef __cplusplus } #endif /************************************************************************** * * Copyright 2013-2014 RAD Game Tools and Valve Software * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC * Copyright 2016 Martin Raiber * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * **************************************************************************/ #ifndef MINIZ_NO_ARCHIVE_APIS #ifdef __cplusplus extern "C" { #endif /* ------------------- .ZIP archive reading */ #ifdef MINIZ_NO_STDIO #define MZ_FILE void * #else #include #if defined(_MSC_VER) || defined(__MINGW64__) static FILE *mz_fopen(const char *pFilename, const char *pMode) { FILE *pFile = NULL; fopen_s(&pFile, pFilename, pMode); return pFile; } static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) { FILE *pFile = NULL; if (freopen_s(&pFile, pPath, pMode, pStream)) return NULL; return pFile; } #ifndef MINIZ_NO_TIME #include #endif #define MZ_FOPEN mz_fopen #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 _ftelli64 #define MZ_FSEEK64 _fseeki64 #define MZ_FILE_STAT_STRUCT _stat64 #define MZ_FILE_STAT _stat64 #define MZ_FFLUSH fflush #define MZ_FREOPEN mz_freopen #define MZ_DELETE_FILE remove #elif defined(__MINGW32__) #ifndef MINIZ_NO_TIME #include #endif #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 ftello64 #define MZ_FSEEK64 fseeko64 #define MZ_FILE_STAT_STRUCT _stat #define MZ_FILE_STAT _stat #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove #elif defined(__TINYC__) #ifndef MINIZ_NO_TIME #include #endif #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 ftell #define MZ_FSEEK64 fseek #define MZ_FILE_STAT_STRUCT stat #define MZ_FILE_STAT stat #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove #elif defined(__GNUC__) && defined(_LARGEFILE64_SOURCE) #ifndef MINIZ_NO_TIME #include #endif #define MZ_FOPEN(f, m) fopen64(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 ftello64 #define MZ_FSEEK64 fseeko64 #define MZ_FILE_STAT_STRUCT stat64 #define MZ_FILE_STAT stat64 #define MZ_FFLUSH fflush #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) #define MZ_DELETE_FILE remove #elif defined(__APPLE__) #ifndef MINIZ_NO_TIME #include #endif #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 ftello #define MZ_FSEEK64 fseeko #define MZ_FILE_STAT_STRUCT stat #define MZ_FILE_STAT stat #define MZ_FFLUSH fflush #define MZ_FREOPEN(p, m, s) freopen(p, m, s) #define MZ_DELETE_FILE remove #else #pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.") #ifndef MINIZ_NO_TIME #include #endif #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #ifdef __STRICT_ANSI__ #define MZ_FTELL64 ftell #define MZ_FSEEK64 fseek #else #define MZ_FTELL64 ftello #define MZ_FSEEK64 fseeko #endif #define MZ_FILE_STAT_STRUCT stat #define MZ_FILE_STAT stat #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove #endif /* #ifdef _MSC_VER */ #endif /* #ifdef MINIZ_NO_STDIO */ #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) /* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */ enum { /* ZIP archive identifiers and record sizes */ MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, /* ZIP64 archive identifier and record sizes */ MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001, MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50, MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24, MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16, /* Central directory header record offsets */ MZ_ZIP_CDH_SIG_OFS = 0, MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, MZ_ZIP_CDH_BIT_FLAG_OFS = 8, MZ_ZIP_CDH_METHOD_OFS = 10, MZ_ZIP_CDH_FILE_TIME_OFS = 12, MZ_ZIP_CDH_FILE_DATE_OFS = 14, MZ_ZIP_CDH_CRC32_OFS = 16, MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, MZ_ZIP_CDH_DISK_START_OFS = 34, MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, /* Local directory header offsets */ MZ_ZIP_LDH_SIG_OFS = 0, MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, MZ_ZIP_LDH_BIT_FLAG_OFS = 6, MZ_ZIP_LDH_METHOD_OFS = 8, MZ_ZIP_LDH_FILE_TIME_OFS = 10, MZ_ZIP_LDH_FILE_DATE_OFS = 12, MZ_ZIP_LDH_CRC32_OFS = 14, MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3, /* End of central directory offsets */ MZ_ZIP_ECDH_SIG_OFS = 0, MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, /* ZIP64 End of central directory locator offsets */ MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */ MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */ MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */ MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */ /* ZIP64 End of central directory header offsets */ MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */ MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */ MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */ MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */ MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */ MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */ MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */ MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */ MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */ MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */ MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0, MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10, MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1, MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32, MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64, MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192, MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11 }; typedef struct { void *m_p; size_t m_size, m_capacity; mz_uint m_element_size; } mz_zip_array; struct mz_zip_internal_state_tag { mz_zip_array m_central_dir; mz_zip_array m_central_dir_offsets; mz_zip_array m_sorted_central_dir_offsets; /* The flags passed in when the archive is initially opened. */ uint32_t m_init_flags; /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */ mz_bool m_zip64; /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */ mz_bool m_zip64_has_extended_info_fields; /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */ MZ_FILE *m_pFile; mz_uint64 m_file_archive_start_ofs; void *m_pMem; size_t m_mem_size; size_t m_mem_capacity; }; #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size #if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG) static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index) { MZ_ASSERT(index < pArray->m_size); return index; } #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)] #else #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] #endif static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size) { memset(pArray, 0, sizeof(mz_zip_array)); pArray->m_element_size = element_size; } static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) { pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); memset(pArray, 0, sizeof(mz_zip_array)); } static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) { void *pNew_p; size_t new_capacity = min_new_capacity; MZ_ASSERT(pArray->m_element_size); if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE; if (growing) { new_capacity = MZ_MAX(1, pArray->m_capacity); while (new_capacity < min_new_capacity) new_capacity *= 2; } if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) return MZ_FALSE; pArray->m_p = pNew_p; pArray->m_capacity = new_capacity; return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) { if (new_capacity > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) return MZ_FALSE; } return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) { if (new_size > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return MZ_FALSE; } pArray->m_size = new_size; return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) { return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); } static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) { size_t orig_size = pArray->m_size; if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) return MZ_FALSE; if (n > 0) memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); return MZ_TRUE; } #ifndef MINIZ_NO_TIME static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date) { struct tm tm; memset(&tm, 0, sizeof(tm)); tm.tm_isdst = -1; tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; tm.tm_mon = ((dos_date >> 5) & 15) - 1; tm.tm_mday = dos_date & 31; tm.tm_hour = (dos_time >> 11) & 31; tm.tm_min = (dos_time >> 5) & 63; tm.tm_sec = (dos_time << 1) & 62; return mktime(&tm); } #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) { #ifdef _MSC_VER struct tm tm_struct; struct tm *tm = &tm_struct; errno_t err = localtime_s(tm, &time); if (err) { *pDOS_date = 0; *pDOS_time = 0; return; } #else struct tm *tm = localtime(&time); #endif /* #ifdef _MSC_VER */ *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); } #endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ #ifndef MINIZ_NO_STDIO #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime) { struct MZ_FILE_STAT_STRUCT file_stat; /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ if (MZ_FILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE; *pTime = file_stat.st_mtime; return MZ_TRUE; } #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time) { struct utimbuf t; memset(&t, 0, sizeof(t)); t.actime = access_time; t.modtime = modified_time; return !utime(pFilename, &t); } #endif /* #ifndef MINIZ_NO_STDIO */ #endif /* #ifndef MINIZ_NO_TIME */ static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num) { if (pZip) pZip->m_last_error = err_num; return MZ_FALSE; } static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags) { (void)flags; if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!pZip->m_pAlloc) pZip->m_pAlloc = miniz_def_alloc_func; if (!pZip->m_pFree) pZip->m_pFree = miniz_def_free_func; if (!pZip->m_pRealloc) pZip->m_pRealloc = miniz_def_realloc_func; pZip->m_archive_size = 0; pZip->m_central_directory_file_ofs = 0; pZip->m_total_files = 0; pZip->m_last_error = MZ_ZIP_NO_ERROR; if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); pZip->m_pState->m_init_flags = flags; pZip->m_pState->m_zip64 = MZ_FALSE; pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE; pZip->m_zip_mode = MZ_ZIP_MODE_READING; return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) { const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); mz_uint8 l = 0, r = 0; pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pE = pL + MZ_MIN(l_len, r_len); while (pL < pE) { if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; pL++; pR++; } return (pL == pE) ? (l_len < r_len) : (l < r); } #define MZ_SWAP_UINT32(a, b) \ do \ { \ mz_uint32 t = a; \ a = b; \ b = t; \ } \ MZ_MACRO_END /* Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) */ static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) { mz_zip_internal_state *pState = pZip->m_pState; const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; const mz_zip_array *pCentral_dir = &pState->m_central_dir; mz_uint32 *pIndices; mz_uint32 start, end; const mz_uint32 size = pZip->m_total_files; if (size <= 1U) return; pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); start = (size - 2U) >> 1U; for (;;) { mz_uint64 child, root = start; for (;;) { if ((child = (root << 1U) + 1U) >= size) break; child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]))); if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) break; MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; } if (!start) break; start--; } end = size - 1; while (end > 0) { mz_uint64 child, root = 0; MZ_SWAP_UINT32(pIndices[end], pIndices[0]); for (;;) { if ((child = (root << 1U) + 1U) >= end) break; child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])); if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) break; MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; } end--; } } static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs) { mz_int64 cur_file_ofs; mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32; /* Basic sanity checks - reject files which are too small */ if (pZip->m_archive_size < record_size) return MZ_FALSE; /* Find the record by scanning the file from the end towards the beginning. */ cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); for (;;) { int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) return MZ_FALSE; for (i = n - 4; i >= 0; --i) { mz_uint s = MZ_READ_LE32(pBuf + i); if (s == record_sig) { if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size) break; } } if (i >= 0) { cur_file_ofs += i; break; } /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */ if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size))) return MZ_FALSE; cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); } *pOfs = cur_file_ofs; return MZ_TRUE; } static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) { mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; mz_uint64 cdir_ofs = 0; mz_int64 cur_file_ofs = 0; const mz_uint8 *p; mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32; mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32; mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32; mz_uint64 zip64_end_of_central_dir_ofs = 0; /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */ if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); /* Read and verify the end of central directory record. */ if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) { if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) { if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) { zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) { if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) { pZip->m_pState->m_zip64 = MZ_TRUE; } } } } } pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS); cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); if (pZip->m_pState->m_zip64) { mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS); mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS); mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS); mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS); if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if (zip64_total_num_of_disks != 1U) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); /* Check for miniz's practical limits */ if (zip64_cdir_total_entries > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries; if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk; /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */ if (zip64_size_of_central_directory > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); cdir_size = (mz_uint32)zip64_size_of_central_directory; num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS); cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS); cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS); } if (pZip->m_total_files != cdir_entries_on_this_disk) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); pZip->m_central_directory_file_ofs = cdir_ofs; if (pZip->m_total_files) { mz_uint i, n; /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */ if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); if (sort_central_dir) { if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); /* Now create an index into the central directory file records, do some basic sanity checking on each record */ p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) { mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size; mz_uint64 comp_size, decomp_size, local_header_ofs; if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); if (sort_central_dir) MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); if ((!pZip->m_pState->m_zip64_has_extended_info_fields) && (ext_data_size) && (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX)) { /* Attempt to find zip64 extended information field in the entry's extra data */ mz_uint32 extra_size_remaining = ext_data_size; if (extra_size_remaining) { const mz_uint8 *pExtra_data; void* buf = NULL; if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size > n) { buf = MZ_MALLOC(ext_data_size); if(buf==NULL) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size, buf, ext_data_size) != ext_data_size) { MZ_FREE(buf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); } pExtra_data = (mz_uint8*)buf; } else { pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size; } do { mz_uint32 field_id; mz_uint32 field_data_size; if (extra_size_remaining < (sizeof(mz_uint16) * 2)) { MZ_FREE(buf); return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); } field_id = MZ_READ_LE16(pExtra_data); field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) { MZ_FREE(buf); return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); } if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) { /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */ pZip->m_pState->m_zip64 = MZ_TRUE; pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE; break; } pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; } while (extra_size_remaining); MZ_FREE(buf); } } /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */ if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) { if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); } disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1))) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK); if (comp_size != MZ_UINT32_MAX) { if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); } bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); n -= total_header_size; p += total_header_size; } } if (sort_central_dir) mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); return MZ_TRUE; } void mz_zip_zero_struct(mz_zip_archive *pZip) { if (pZip) MZ_CLEAR_OBJ(*pZip); } static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) { mz_bool status = MZ_TRUE; if (!pZip) return MZ_FALSE; if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) { if (set_last_error) pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER; return MZ_FALSE; } if (pZip->m_pState) { mz_zip_internal_state *pState = pZip->m_pState; pZip->m_pState = NULL; mz_zip_array_clear(pZip, &pState->m_central_dir); mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); #ifndef MINIZ_NO_STDIO if (pState->m_pFile) { if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) { if (MZ_FCLOSE(pState->m_pFile) == EOF) { if (set_last_error) pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED; status = MZ_FALSE; } } pState->m_pFile = NULL; } #endif /* #ifndef MINIZ_NO_STDIO */ pZip->m_pFree(pZip->m_pAlloc_opaque, pState); } pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; return status; } mz_bool mz_zip_reader_end(mz_zip_archive *pZip) { return mz_zip_reader_end_internal(pZip, MZ_TRUE); } mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags) { if ((!pZip) || (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; pZip->m_zip_type = MZ_ZIP_TYPE_USER; pZip->m_archive_size = size; if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end_internal(pZip, MZ_FALSE); return MZ_FALSE; } return MZ_TRUE; } static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); return s; } mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags) { if (!pMem) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY; pZip->m_archive_size = size; pZip->m_pRead = mz_zip_mem_read_func; pZip->m_pIO_opaque = pZip; pZip->m_pNeeds_keepalive = NULL; #ifdef __cplusplus pZip->m_pState->m_pMem = const_cast(pMem); #else pZip->m_pState->m_pMem = (void *)pMem; #endif pZip->m_pState->m_mem_size = size; if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end_internal(pZip, MZ_FALSE); return MZ_FALSE; } return MZ_TRUE; } #ifndef MINIZ_NO_STDIO static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); file_ofs += pZip->m_pState->m_file_archive_start_ofs; if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) return 0; return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); } mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) { return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0); } mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size) { mz_uint64 file_size; MZ_FILE *pFile; if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pFile = MZ_FOPEN(pFilename, "rb"); if (!pFile) return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); file_size = archive_size; if (!file_size) { if (MZ_FSEEK64(pFile, 0, SEEK_END)) { MZ_FCLOSE(pFile); return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); } file_size = MZ_FTELL64(pFile); } /* TODO: Better sanity check archive_size and the # of actual remaining bytes */ if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) { MZ_FCLOSE(pFile); return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); } if (!mz_zip_reader_init_internal(pZip, flags)) { MZ_FCLOSE(pFile); return MZ_FALSE; } pZip->m_zip_type = MZ_ZIP_TYPE_FILE; pZip->m_pRead = mz_zip_file_read_func; pZip->m_pIO_opaque = pZip; pZip->m_pState->m_pFile = pFile; pZip->m_archive_size = file_size; pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end_internal(pZip, MZ_FALSE); return MZ_FALSE; } return MZ_TRUE; } mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) { mz_uint64 cur_file_ofs; if ((!pZip) || (!pFile)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); cur_file_ofs = MZ_FTELL64(pFile); if (!archive_size) { if (MZ_FSEEK64(pFile, 0, SEEK_END)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); archive_size = MZ_FTELL64(pFile) - cur_file_ofs; if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); } if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; pZip->m_pRead = mz_zip_file_read_func; pZip->m_pIO_opaque = pZip; pZip->m_pState->m_pFile = pFile; pZip->m_archive_size = archive_size; pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs; if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end_internal(pZip, MZ_FALSE); return MZ_FALSE; } return MZ_TRUE; } #endif /* #ifndef MINIZ_NO_STDIO */ static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index) { if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files)) return NULL; return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); } mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) { mz_uint m_bit_flag; const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); if (!p) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return MZ_FALSE; } m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0; } mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index) { mz_uint bit_flag; mz_uint method; const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); if (!p) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return MZ_FALSE; } method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); if ((method != 0) && (method != MZ_DEFLATED)) { mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); return MZ_FALSE; } if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) { mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); return MZ_FALSE; } if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG) { mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); return MZ_FALSE; } return MZ_TRUE; } mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) { mz_uint filename_len, attribute_mapping_id, external_attr; const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); if (!p) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return MZ_FALSE; } filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); if (filename_len) { if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') return MZ_TRUE; } /* Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. */ /* Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. */ /* FIXME: Remove this check? Is it necessary - we already check the filename. */ attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8; (void)attribute_mapping_id; external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0) { return MZ_TRUE; } return MZ_FALSE; } static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data) { mz_uint n; const mz_uint8 *p = pCentral_dir_header; if (pFound_zip64_extra_data) *pFound_zip64_extra_data = MZ_FALSE; if ((!p) || (!pStat)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); /* Extract fields from the central directory record. */ pStat->m_file_index = file_index; pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); #ifndef MINIZ_NO_TIME pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); #endif pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); /* Copy as much of the filename and comment as possible. */ n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pStat->m_filename[n] = '\0'; n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); pStat->m_comment_size = n; memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); pStat->m_comment[n] = '\0'; /* Set some flags for convienance */ pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index); pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index); pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index); /* See if we need to read any zip64 extended information fields. */ /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */ if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX) { /* Attempt to find zip64 extended information field in the entry's extra data */ mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS); if (extra_size_remaining) { const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); do { mz_uint32 field_id; mz_uint32 field_data_size; if (extra_size_remaining < (sizeof(mz_uint16) * 2)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); field_id = MZ_READ_LE16(pExtra_data); field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) { const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2; mz_uint32 field_data_remaining = field_data_size; if (pFound_zip64_extra_data) *pFound_zip64_extra_data = MZ_TRUE; if (pStat->m_uncomp_size == MZ_UINT32_MAX) { if (field_data_remaining < sizeof(mz_uint64)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); pStat->m_uncomp_size = MZ_READ_LE64(pField_data); pField_data += sizeof(mz_uint64); field_data_remaining -= sizeof(mz_uint64); } if (pStat->m_comp_size == MZ_UINT32_MAX) { if (field_data_remaining < sizeof(mz_uint64)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); pStat->m_comp_size = MZ_READ_LE64(pField_data); pField_data += sizeof(mz_uint64); field_data_remaining -= sizeof(mz_uint64); } if (pStat->m_local_header_ofs == MZ_UINT32_MAX) { if (field_data_remaining < sizeof(mz_uint64)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); pStat->m_local_header_ofs = MZ_READ_LE64(pField_data); pField_data += sizeof(mz_uint64); field_data_remaining -= sizeof(mz_uint64); } break; } pExtra_data += sizeof(mz_uint16) * 2 + field_data_size; extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size; } while (extra_size_remaining); } } return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) { mz_uint i; if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) return 0 == memcmp(pA, pB, len); for (i = 0; i < len; ++i) if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) return MZ_FALSE; return MZ_TRUE; } static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) { const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); mz_uint8 l = 0, r = 0; pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pE = pL + MZ_MIN(l_len, r_len); while (pL < pE) { if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; pL++; pR++; } return (pL == pE) ? (int)(l_len - r_len) : (l - r); } static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex) { mz_zip_internal_state *pState = pZip->m_pState; const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; const mz_zip_array *pCentral_dir = &pState->m_central_dir; mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); const uint32_t size = pZip->m_total_files; const mz_uint filename_len = (mz_uint)strlen(pFilename); if (pIndex) *pIndex = 0; if (size) { /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */ /* honestly the major expense here on 32-bit CPU's will still be the filename compare */ mz_int64 l = 0, h = (mz_int64)size - 1; while (l <= h) { mz_int64 m = l + ((h - l) >> 1); uint32_t file_index = pIndices[(uint32_t)m]; int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); if (!comp) { if (pIndex) *pIndex = file_index; return MZ_TRUE; } else if (comp < 0) l = m + 1; else h = m - 1; } } return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); } int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) { mz_uint32 index; if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index)) return -1; else return (int)index; } mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex) { mz_uint file_index; size_t name_len, comment_len; if (pIndex) *pIndex = 0; if ((!pZip) || (!pZip->m_pState) || (!pName)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); /* See if we can use a binary search */ if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) && (pZip->m_zip_mode == MZ_ZIP_MODE_READING) && ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) { return mz_zip_locate_file_binary_search(pZip, pName, pIndex); } /* Locate the entry by scanning the entire central directory */ name_len = strlen(pName); if (name_len > MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); comment_len = pComment ? strlen(pComment) : 0; if (comment_len > MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); for (file_index = 0; file_index < pZip->m_total_files; file_index++) { const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; if (filename_len < name_len) continue; if (comment_len) { mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); const char *pFile_comment = pFilename + filename_len + file_extra_len; if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags))) continue; } if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) { int ofs = filename_len - 1; do { if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) break; } while (--ofs >= 0); ofs++; pFilename += ofs; filename_len -= ofs; } if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags))) { if (pIndex) *pIndex = file_index; return MZ_TRUE; } } return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND); } mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) { int status = TINFL_STATUS_DONE; mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; mz_zip_archive_file_stat file_stat; void *pRead_buf; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; tinfl_decompressor inflator; if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; /* A directory or zero length file */ if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) return MZ_TRUE; /* Encryption and patch files are not supported. */ if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); /* This function only supports decompressing stored and deflate. */ if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); /* Ensure supplied output buffer is large enough. */ needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; if (buf_size < needed_size) return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL); /* Read and parse the local directory entry. */ cur_file_ofs = file_stat.m_local_header_ofs; if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { /* The file is stored or the caller has requested the compressed data. */ if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0) { if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); } #endif return MZ_TRUE; } /* Decompress the file either directly from memory or from a file input buffer. */ tinfl_init(&inflator); if (pZip->m_pState->m_pMem) { /* Read directly from the archive in memory. */ pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; read_buf_size = read_buf_avail = file_stat.m_comp_size; comp_remaining = 0; } else if (pUser_read_buf) { /* Use a user provided read buffer. */ if (!user_read_buf_size) return MZ_FALSE; pRead_buf = (mz_uint8 *)pUser_read_buf; read_buf_size = user_read_buf_size; read_buf_avail = 0; comp_remaining = file_stat.m_comp_size; } else { /* Temporarily allocate a read buffer. */ read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); read_buf_avail = 0; comp_remaining = file_stat.m_comp_size; } do { /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */ size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { status = TINFL_STATUS_FAILED; mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); break; } cur_file_ofs += read_buf_avail; comp_remaining -= read_buf_avail; read_buf_ofs = 0; } in_buf_size = (size_t)read_buf_avail; status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); read_buf_avail -= in_buf_size; read_buf_ofs += in_buf_size; out_buf_ofs += out_buf_size; } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); if (status == TINFL_STATUS_DONE) { /* Make sure the entire file was decompressed, and check its CRC. */ if (out_buf_ofs != file_stat.m_uncomp_size) { mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); status = TINFL_STATUS_FAILED; } #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32) { mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED); status = TINFL_STATUS_FAILED; } #endif } if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); return status == TINFL_STATUS_DONE; } mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) { mz_uint32 file_index; if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) return MZ_FALSE; return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); } mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) { return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); } mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) { return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); } void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) { mz_uint64 comp_size, uncomp_size, alloc_size; const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); void *pBuf; if (pSize) *pSize = 0; if (!p) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return NULL; } comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) { mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); return NULL; } if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); return NULL; } if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return NULL; } if (pSize) *pSize = (size_t)alloc_size; return pBuf; } void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) { mz_uint32 file_index; if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) { if (pSize) *pSize = 0; return MZ_FALSE; } return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); } mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) { int status = TINFL_STATUS_DONE; mz_uint file_crc32 = MZ_CRC32_INIT; mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; mz_zip_archive_file_stat file_stat; void *pRead_buf = NULL; void *pWrite_buf = NULL; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; /* A directory or zero length file */ if ((file_stat.m_is_directory) || (!file_stat.m_comp_size)) return MZ_TRUE; /* Encryption and patch files are not supported. */ if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); /* This function only supports decompressing stored and deflate. */ if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */ cur_file_ofs = file_stat.m_local_header_ofs; if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); /* Decompress the file either directly from memory or from a file input buffer. */ if (pZip->m_pState->m_pMem) { pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; read_buf_size = read_buf_avail = file_stat.m_comp_size; comp_remaining = 0; } else { read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); read_buf_avail = 0; comp_remaining = file_stat.m_comp_size; } if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { /* The file is stored or the caller has requested the compressed data. */ if (pZip->m_pState->m_pMem) { if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) { mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); status = TINFL_STATUS_FAILED; } else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); #endif } cur_file_ofs += file_stat.m_comp_size; out_buf_ofs += file_stat.m_comp_size; comp_remaining = 0; } else { while (comp_remaining) { read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); status = TINFL_STATUS_FAILED; break; } #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); } #endif if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); status = TINFL_STATUS_FAILED; break; } cur_file_ofs += read_buf_avail; out_buf_ofs += read_buf_avail; comp_remaining -= read_buf_avail; } } } else { tinfl_decompressor inflator; tinfl_init(&inflator); if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); status = TINFL_STATUS_FAILED; } else { do { mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); status = TINFL_STATUS_FAILED; break; } cur_file_ofs += read_buf_avail; comp_remaining -= read_buf_avail; read_buf_ofs = 0; } in_buf_size = (size_t)read_buf_avail; status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); read_buf_avail -= in_buf_size; read_buf_ofs += in_buf_size; if (out_buf_size) { if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) { mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED); status = TINFL_STATUS_FAILED; break; } #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); #endif if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) { mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); status = TINFL_STATUS_FAILED; break; } } } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); } } if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) { /* Make sure the entire file was decompressed, and check its CRC. */ if (out_buf_ofs != file_stat.m_uncomp_size) { mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); status = TINFL_STATUS_FAILED; } #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS else if (file_crc32 != file_stat.m_crc32) { mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED); status = TINFL_STATUS_FAILED; } #endif } if (!pZip->m_pState->m_pMem) pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); if (pWrite_buf) pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); return status == TINFL_STATUS_DONE; } mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) { mz_uint32 file_index; if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) return MZ_FALSE; return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); } mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) { mz_zip_reader_extract_iter_state *pState; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; /* Argument sanity check */ if ((!pZip) || (!pZip->m_pState)) return NULL; /* Allocate an iterator status structure */ pState = (mz_zip_reader_extract_iter_state*)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_reader_extract_iter_state)); if (!pState) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); return NULL; } /* Fetch file details */ if (!mz_zip_reader_file_stat(pZip, file_index, &pState->file_stat)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } /* Encryption and patch files are not supported. */ if (pState->file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)) { mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } /* This function only supports decompressing stored and deflate. */ if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (pState->file_stat.m_method != 0) && (pState->file_stat.m_method != MZ_DEFLATED)) { mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } /* Init state - save args */ pState->pZip = pZip; pState->flags = flags; /* Init state - reset variables to defaults */ pState->status = TINFL_STATUS_DONE; #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS pState->file_crc32 = MZ_CRC32_INIT; #endif pState->read_buf_ofs = 0; pState->out_buf_ofs = 0; pState->pRead_buf = NULL; pState->pWrite_buf = NULL; pState->out_blk_remain = 0; /* Read and parse the local directory entry. */ pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } pState->cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > pZip->m_archive_size) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } /* Decompress the file either directly from memory or from a file input buffer. */ if (pZip->m_pState->m_pMem) { pState->pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + pState->cur_file_ofs; pState->read_buf_size = pState->read_buf_avail = pState->file_stat.m_comp_size; pState->comp_remaining = pState->file_stat.m_comp_size; } else { if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) { /* Decompression required, therefore intermediate read buffer required */ pState->read_buf_size = MZ_MIN(pState->file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); if (NULL == (pState->pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)pState->read_buf_size))) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } } else { /* Decompression not required - we will be reading directly into user buffer, no temp buf required */ pState->read_buf_size = 0; } pState->read_buf_avail = 0; pState->comp_remaining = pState->file_stat.m_comp_size; } if (!((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method))) { /* Decompression required, init decompressor */ tinfl_init( &pState->inflator ); /* Allocate write buffer */ if (NULL == (pState->pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); if (pState->pRead_buf) pZip->m_pFree(pZip->m_pAlloc_opaque, pState->pRead_buf); pZip->m_pFree(pZip->m_pAlloc_opaque, pState); return NULL; } } return pState; } mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) { mz_uint32 file_index; /* Locate file index by name */ if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index)) return NULL; /* Construct iterator */ return mz_zip_reader_extract_iter_new(pZip, file_index, flags); } size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size) { size_t copied_to_caller = 0; /* Argument sanity check */ if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState) || (!pvBuf)) return 0; if ((pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!pState->file_stat.m_method)) { /* The file is stored or the caller has requested the compressed data, calc amount to return. */ copied_to_caller = (size_t)MZ_MIN( buf_size, pState->comp_remaining ); /* Zip is in memory....or requires reading from a file? */ if (pState->pZip->m_pState->m_pMem) { /* Copy data to caller's buffer */ memcpy( pvBuf, pState->pRead_buf, copied_to_caller ); pState->pRead_buf = ((mz_uint8*)pState->pRead_buf) + copied_to_caller; } else { /* Read directly into caller's buffer */ if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pvBuf, copied_to_caller) != copied_to_caller) { /* Failed to read all that was asked for, flag failure and alert user */ mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); pState->status = TINFL_STATUS_FAILED; copied_to_caller = 0; } } #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS /* Compute CRC if not returning compressed data only */ if (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, (const mz_uint8 *)pvBuf, copied_to_caller); #endif /* Advance offsets, dec counters */ pState->cur_file_ofs += copied_to_caller; pState->out_buf_ofs += copied_to_caller; pState->comp_remaining -= copied_to_caller; } else { do { /* Calc ptr to write buffer - given current output pos and block size */ mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pState->pWrite_buf + (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); /* Calc max output size - given current output pos and block size */ size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (pState->out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); if (!pState->out_blk_remain) { /* Read more data from file if none available (and reading from file) */ if ((!pState->read_buf_avail) && (!pState->pZip->m_pState->m_pMem)) { /* Calc read size */ pState->read_buf_avail = MZ_MIN(pState->read_buf_size, pState->comp_remaining); if (pState->pZip->m_pRead(pState->pZip->m_pIO_opaque, pState->cur_file_ofs, pState->pRead_buf, (size_t)pState->read_buf_avail) != pState->read_buf_avail) { mz_zip_set_error(pState->pZip, MZ_ZIP_FILE_READ_FAILED); pState->status = TINFL_STATUS_FAILED; break; } /* Advance offsets, dec counters */ pState->cur_file_ofs += pState->read_buf_avail; pState->comp_remaining -= pState->read_buf_avail; pState->read_buf_ofs = 0; } /* Perform decompression */ in_buf_size = (size_t)pState->read_buf_avail; pState->status = tinfl_decompress(&pState->inflator, (const mz_uint8 *)pState->pRead_buf + pState->read_buf_ofs, &in_buf_size, (mz_uint8 *)pState->pWrite_buf, pWrite_buf_cur, &out_buf_size, pState->comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); pState->read_buf_avail -= in_buf_size; pState->read_buf_ofs += in_buf_size; /* Update current output block size remaining */ pState->out_blk_remain = out_buf_size; } if (pState->out_blk_remain) { /* Calc amount to return. */ size_t to_copy = MZ_MIN( (buf_size - copied_to_caller), pState->out_blk_remain ); /* Copy data to caller's buffer */ memcpy( (uint8_t*)pvBuf + copied_to_caller, pWrite_buf_cur, to_copy ); #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS /* Perform CRC */ pState->file_crc32 = (mz_uint32)mz_crc32(pState->file_crc32, pWrite_buf_cur, to_copy); #endif /* Decrement data consumed from block */ pState->out_blk_remain -= to_copy; /* Inc output offset, while performing sanity check */ if ((pState->out_buf_ofs += to_copy) > pState->file_stat.m_uncomp_size) { mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); pState->status = TINFL_STATUS_FAILED; break; } /* Increment counter of data copied to caller */ copied_to_caller += to_copy; } } while ( (copied_to_caller < buf_size) && ((pState->status == TINFL_STATUS_NEEDS_MORE_INPUT) || (pState->status == TINFL_STATUS_HAS_MORE_OUTPUT)) ); } /* Return how many bytes were copied into user buffer */ return copied_to_caller; } mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState) { int status; /* Argument sanity check */ if ((!pState) || (!pState->pZip) || (!pState->pZip->m_pState)) return MZ_FALSE; /* Was decompression completed and requested? */ if ((pState->status == TINFL_STATUS_DONE) && (!(pState->flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) { /* Make sure the entire file was decompressed, and check its CRC. */ if (pState->out_buf_ofs != pState->file_stat.m_uncomp_size) { mz_zip_set_error(pState->pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE); pState->status = TINFL_STATUS_FAILED; } #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS else if (pState->file_crc32 != pState->file_stat.m_crc32) { mz_zip_set_error(pState->pZip, MZ_ZIP_DECOMPRESSION_FAILED); pState->status = TINFL_STATUS_FAILED; } #endif } /* Free buffers */ if (!pState->pZip->m_pState->m_pMem) pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pRead_buf); if (pState->pWrite_buf) pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState->pWrite_buf); /* Save status */ status = pState->status; /* Free context */ pState->pZip->m_pFree(pState->pZip->m_pAlloc_opaque, pState); return status == TINFL_STATUS_DONE; } #ifndef MINIZ_NO_STDIO static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) { (void)ofs; return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); } mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) { mz_bool status; mz_zip_archive_file_stat file_stat; MZ_FILE *pFile; if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); pFile = MZ_FOPEN(pDst_filename, "wb"); if (!pFile) return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); if (MZ_FCLOSE(pFile) == EOF) { if (status) mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); status = MZ_FALSE; } #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) if (status) mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); #endif return status; } mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) { mz_uint32 file_index; if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) return MZ_FALSE; return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); } mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags) { mz_zip_archive_file_stat file_stat; if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; if ((file_stat.m_is_directory) || (!file_stat.m_is_supported)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); } mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags) { mz_uint32 file_index; if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index)) return MZ_FALSE; return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags); } #endif /* #ifndef MINIZ_NO_STDIO */ static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) { mz_uint32 *p = (mz_uint32 *)pOpaque; (void)file_ofs; *p = (mz_uint32)mz_crc32(*p, (const mz_uint8 *)pBuf, n); return n; } mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags) { mz_zip_archive_file_stat file_stat; mz_zip_internal_state *pState; const mz_uint8 *pCentral_dir_header; mz_bool found_zip64_ext_data_in_cdir = MZ_FALSE; mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; mz_uint64 local_header_ofs = 0; mz_uint32 local_header_filename_len, local_header_extra_len, local_header_crc32; mz_uint64 local_header_comp_size, local_header_uncomp_size; mz_uint32 uncomp_crc32 = MZ_CRC32_INIT; mz_bool has_data_descriptor; mz_uint32 local_header_bit_flags; mz_zip_array file_data_array; mz_zip_array_init(&file_data_array, 1); if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (file_index > pZip->m_total_files) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState = pZip->m_pState; pCentral_dir_header = mz_zip_get_cdh(pZip, file_index); if (!mz_zip_file_stat_internal(pZip, file_index, pCentral_dir_header, &file_stat, &found_zip64_ext_data_in_cdir)) return MZ_FALSE; /* A directory or zero length file */ if ((file_stat.m_is_directory) || (!file_stat.m_uncomp_size)) return MZ_TRUE; /* Encryption and patch files are not supported. */ if (file_stat.m_is_encrypted) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION); /* This function only supports stored and deflate. */ if ((file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD); if (!file_stat.m_is_supported) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE); /* Read and parse the local directory entry. */ local_header_ofs = file_stat.m_local_header_ofs; if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); local_header_filename_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); local_header_crc32 = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_CRC32_OFS); local_header_bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); has_data_descriptor = (local_header_bit_flags & 8) != 0; if (local_header_filename_len != strlen(file_stat.m_filename)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if ((local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if (!mz_zip_array_resize(pZip, &file_data_array, MZ_MAX(local_header_filename_len, local_header_extra_len), MZ_FALSE)) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); if (local_header_filename_len) { if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE, file_data_array.m_p, local_header_filename_len) != local_header_filename_len) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); goto handle_failure; } /* I've seen 1 archive that had the same pathname, but used backslashes in the local dir and forward slashes in the central dir. Do we care about this? For now, this case will fail validation. */ if (memcmp(file_stat.m_filename, file_data_array.m_p, local_header_filename_len) != 0) { mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); goto handle_failure; } } if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) { mz_uint32 extra_size_remaining = local_header_extra_len; const mz_uint8 *pExtra_data = (const mz_uint8 *)file_data_array.m_p; if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); goto handle_failure; } do { mz_uint32 field_id, field_data_size, field_total_size; if (extra_size_remaining < (sizeof(mz_uint16) * 2)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); field_id = MZ_READ_LE16(pExtra_data); field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); field_total_size = field_data_size + sizeof(mz_uint16) * 2; if (field_total_size > extra_size_remaining) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) { const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); if (field_data_size < sizeof(mz_uint64) * 2) { mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); goto handle_failure; } local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); found_zip64_ext_data_in_ldir = MZ_TRUE; break; } pExtra_data += field_total_size; extra_size_remaining -= field_total_size; } while (extra_size_remaining); } /* TODO: parse local header extra data when local_header_comp_size is 0xFFFFFFFF! (big_descriptor.zip) */ /* I've seen zips in the wild with the data descriptor bit set, but proper local header values and bogus data descriptors */ if ((has_data_descriptor) && (!local_header_comp_size) && (!local_header_crc32)) { mz_uint8 descriptor_buf[32]; mz_bool has_id; const mz_uint8 *pSrc; mz_uint32 file_crc32; mz_uint64 comp_size = 0, uncomp_size = 0; mz_uint32 num_descriptor_uint32s = ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) ? 6 : 4; if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size, descriptor_buf, sizeof(mz_uint32) * num_descriptor_uint32s) != (sizeof(mz_uint32) * num_descriptor_uint32s)) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); goto handle_failure; } has_id = (MZ_READ_LE32(descriptor_buf) == MZ_ZIP_DATA_DESCRIPTOR_ID); pSrc = has_id ? (descriptor_buf + sizeof(mz_uint32)) : descriptor_buf; file_crc32 = MZ_READ_LE32(pSrc); if ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) { comp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32)); uncomp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32) + sizeof(mz_uint64)); } else { comp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32)); uncomp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32) + sizeof(mz_uint32)); } if ((file_crc32 != file_stat.m_crc32) || (comp_size != file_stat.m_comp_size) || (uncomp_size != file_stat.m_uncomp_size)) { mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); goto handle_failure; } } else { if ((local_header_crc32 != file_stat.m_crc32) || (local_header_comp_size != file_stat.m_comp_size) || (local_header_uncomp_size != file_stat.m_uncomp_size)) { mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); goto handle_failure; } } mz_zip_array_clear(pZip, &file_data_array); if ((flags & MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY) == 0) { if (!mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_compute_crc32_callback, &uncomp_crc32, 0)) return MZ_FALSE; /* 1 more check to be sure, although the extract checks too. */ if (uncomp_crc32 != file_stat.m_crc32) { mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); return MZ_FALSE; } } return MZ_TRUE; handle_failure: mz_zip_array_clear(pZip, &file_data_array); return MZ_FALSE; } mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags) { mz_zip_internal_state *pState; uint32_t i; if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState = pZip->m_pState; /* Basic sanity checks */ if (!pState->m_zip64) { if (pZip->m_total_files > MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); if (pZip->m_archive_size > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); } else { if (pZip->m_total_files >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); } for (i = 0; i < pZip->m_total_files; i++) { if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags) { mz_uint32 found_index; mz_zip_archive_file_stat stat; if (!mz_zip_reader_file_stat(pZip, i, &stat)) return MZ_FALSE; if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, NULL, 0, &found_index)) return MZ_FALSE; /* This check can fail if there are duplicate filenames in the archive (which we don't check for when writing - that's up to the user) */ if (found_index != i) return mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED); } if (!mz_zip_validate_file(pZip, i, flags)) return MZ_FALSE; } return MZ_TRUE; } mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr) { mz_bool success = MZ_TRUE; mz_zip_archive zip; mz_zip_error actual_err = MZ_ZIP_NO_ERROR; if ((!pMem) || (!size)) { if (pErr) *pErr = MZ_ZIP_INVALID_PARAMETER; return MZ_FALSE; } mz_zip_zero_struct(&zip); if (!mz_zip_reader_init_mem(&zip, pMem, size, flags)) { if (pErr) *pErr = zip.m_last_error; return MZ_FALSE; } if (!mz_zip_validate_archive(&zip, flags)) { actual_err = zip.m_last_error; success = MZ_FALSE; } if (!mz_zip_reader_end_internal(&zip, success)) { if (!actual_err) actual_err = zip.m_last_error; success = MZ_FALSE; } if (pErr) *pErr = actual_err; return success; } #ifndef MINIZ_NO_STDIO mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr) { mz_bool success = MZ_TRUE; mz_zip_archive zip; mz_zip_error actual_err = MZ_ZIP_NO_ERROR; if (!pFilename) { if (pErr) *pErr = MZ_ZIP_INVALID_PARAMETER; return MZ_FALSE; } mz_zip_zero_struct(&zip); if (!mz_zip_reader_init_file_v2(&zip, pFilename, flags, 0, 0)) { if (pErr) *pErr = zip.m_last_error; return MZ_FALSE; } if (!mz_zip_validate_archive(&zip, flags)) { actual_err = zip.m_last_error; success = MZ_FALSE; } if (!mz_zip_reader_end_internal(&zip, success)) { if (!actual_err) actual_err = zip.m_last_error; success = MZ_FALSE; } if (pErr) *pErr = actual_err; return success; } #endif /* #ifndef MINIZ_NO_STDIO */ /* ------------------- .ZIP archive writing */ #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); } static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); p[2] = (mz_uint8)(v >> 16); p[3] = (mz_uint8)(v >> 24); } static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v) { mz_write_le32(p, (mz_uint32)v); mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32)); } #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) #define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v)) static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; mz_zip_internal_state *pState = pZip->m_pState; mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); if (!n) return 0; /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */ if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)) { mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); return 0; } if (new_size > pState->m_mem_capacity) { void *pNew_block; size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); while (new_capacity < new_size) new_capacity *= 2; if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) { mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); return 0; } pState->m_pMem = pNew_block; pState->m_mem_capacity = new_capacity; } memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); pState->m_mem_size = (size_t)new_size; return n; } static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error) { mz_zip_internal_state *pState; mz_bool status = MZ_TRUE; if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) { if (set_last_error) mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return MZ_FALSE; } pState = pZip->m_pState; pZip->m_pState = NULL; mz_zip_array_clear(pZip, &pState->m_central_dir); mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); #ifndef MINIZ_NO_STDIO if (pState->m_pFile) { if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) { if (MZ_FCLOSE(pState->m_pFile) == EOF) { if (set_last_error) mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); status = MZ_FALSE; } } pState->m_pFile = NULL; } #endif /* #ifndef MINIZ_NO_STDIO */ if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); pState->m_pMem = NULL; } pZip->m_pFree(pZip->m_pAlloc_opaque, pState); pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; return status; } mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags) { mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0; if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) { if (!pZip->m_pRead) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); } if (pZip->m_file_offset_alignment) { /* Ensure user specified file offset alignment is a power of 2. */ if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); } if (!pZip->m_pAlloc) pZip->m_pAlloc = miniz_def_alloc_func; if (!pZip->m_pFree) pZip->m_pFree = miniz_def_free_func; if (!pZip->m_pRealloc) pZip->m_pRealloc = miniz_def_realloc_func; pZip->m_archive_size = existing_size; pZip->m_central_directory_file_ofs = 0; pZip->m_total_files = 0; if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); pZip->m_pState->m_zip64 = zip64; pZip->m_pState->m_zip64_has_extended_info_fields = zip64; pZip->m_zip_type = MZ_ZIP_TYPE_USER; pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; return MZ_TRUE; } mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) { return mz_zip_writer_init_v2(pZip, existing_size, 0); } mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags) { pZip->m_pWrite = mz_zip_heap_write_func; pZip->m_pNeeds_keepalive = NULL; if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) pZip->m_pRead = mz_zip_mem_read_func; pZip->m_pIO_opaque = pZip; if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) return MZ_FALSE; pZip->m_zip_type = MZ_ZIP_TYPE_HEAP; if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) { if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) { mz_zip_writer_end_internal(pZip, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } pZip->m_pState->m_mem_capacity = initial_allocation_size; } return MZ_TRUE; } mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) { return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0); } #ifndef MINIZ_NO_STDIO static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); file_ofs += pZip->m_pState->m_file_archive_start_ofs; if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) { mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); return 0; } return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); } mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) { return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0); } mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags) { MZ_FILE *pFile; pZip->m_pWrite = mz_zip_file_write_func; pZip->m_pNeeds_keepalive = NULL; if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) pZip->m_pRead = mz_zip_file_read_func; pZip->m_pIO_opaque = pZip; if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags)) return MZ_FALSE; if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb"))) { mz_zip_writer_end(pZip); return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); } pZip->m_pState->m_pFile = pFile; pZip->m_zip_type = MZ_ZIP_TYPE_FILE; if (size_to_reserve_at_beginning) { mz_uint64 cur_ofs = 0; char buf[4096]; MZ_CLEAR_OBJ(buf); do { size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) { mz_zip_writer_end(pZip); return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_ofs += n; size_to_reserve_at_beginning -= n; } while (size_to_reserve_at_beginning); } return MZ_TRUE; } mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags) { pZip->m_pWrite = mz_zip_file_write_func; pZip->m_pNeeds_keepalive = NULL; if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) pZip->m_pRead = mz_zip_file_read_func; pZip->m_pIO_opaque = pZip; if (!mz_zip_writer_init_v2(pZip, 0, flags)) return MZ_FALSE; pZip->m_pState->m_pFile = pFile; pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); pZip->m_zip_type = MZ_ZIP_TYPE_CFILE; return MZ_TRUE; } #endif /* #ifndef MINIZ_NO_STDIO */ mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags) { mz_zip_internal_state *pState; if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) { /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */ if (!pZip->m_pState->m_zip64) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); } /* No sense in trying to write to an archive that's already at the support max size */ if (pZip->m_pState->m_zip64) { if (pZip->m_total_files == MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } else { if (pZip->m_total_files == MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); } pState = pZip->m_pState; if (pState->m_pFile) { #ifdef MINIZ_NO_STDIO (void)pFilename; return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); #else if (pZip->m_pIO_opaque != pZip) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) { if (!pFilename) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */ if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) { /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */ mz_zip_reader_end_internal(pZip, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); } } pZip->m_pWrite = mz_zip_file_write_func; pZip->m_pNeeds_keepalive = NULL; #endif /* #ifdef MINIZ_NO_STDIO */ } else if (pState->m_pMem) { /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */ if (pZip->m_pIO_opaque != pZip) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState->m_mem_capacity = pState->m_mem_size; pZip->m_pWrite = mz_zip_heap_write_func; pZip->m_pNeeds_keepalive = NULL; } /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */ else if (!pZip->m_pWrite) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); /* Start writing new files at the archive's current central directory location. */ /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */ pZip->m_archive_size = pZip->m_central_directory_file_ofs; pZip->m_central_directory_file_ofs = 0; /* Clear the sorted central dir offsets, they aren't useful or maintained now. */ /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */ /* TODO: We could easily maintain the sorted central directory offsets. */ mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; return MZ_TRUE; } mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) { return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); } /* TODO: pArchive_name is a terrible name here! */ mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) { return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); } typedef struct { mz_zip_archive *m_pZip; mz_uint64 m_cur_archive_file_ofs; mz_uint64 m_comp_size; } mz_zip_writer_add_state; static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser) { mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) return MZ_FALSE; pState->m_cur_archive_file_ofs += len; pState->m_comp_size += len; return MZ_TRUE; } #define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2) #define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3) static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs) { mz_uint8 *pDst = pBuf; mz_uint32 field_size = 0; MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); MZ_WRITE_LE16(pDst + 2, 0); pDst += sizeof(mz_uint16) * 2; if (pUncomp_size) { MZ_WRITE_LE64(pDst, *pUncomp_size); pDst += sizeof(mz_uint64); field_size += sizeof(mz_uint64); } if (pComp_size) { MZ_WRITE_LE64(pDst, *pComp_size); pDst += sizeof(mz_uint64); field_size += sizeof(mz_uint64); } if (pLocal_header_ofs) { MZ_WRITE_LE64(pDst, *pLocal_header_ofs); pDst += sizeof(mz_uint64); field_size += sizeof(mz_uint64); } MZ_WRITE_LE16(pBuf + 2, field_size); return (mz_uint32)(pDst - pBuf); } static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) { (void)pZip; memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); return MZ_TRUE; } static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) { (void)pZip; memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX)); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX)); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX)); return MZ_TRUE; } static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes, const char *user_extra_data, mz_uint user_extra_data_len) { mz_zip_internal_state *pState = pZip->m_pState; mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; size_t orig_central_dir_size = pState->m_central_dir.m_size; mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; if (!pZip->m_pState->m_zip64) { if (local_header_ofs > 0xFFFFFFFF) return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); } /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, (mz_uint16)(extra_size + user_extra_data_len), comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) { /* Try to resize the central directory array back into its original state. */ mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } return MZ_TRUE; } static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) { /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */ if (*pArchive_name == '/') return MZ_FALSE; /* Making sure the name does not contain drive letters or DOS style backward slashes is the responsibility of the program using miniz*/ return MZ_TRUE; } static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) { mz_uint32 n; if (!pZip->m_file_offset_alignment) return 0; n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1)); } static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) { char buf[4096]; memset(buf, 0, MZ_MIN(sizeof(buf), n)); while (n) { mz_uint32 s = MZ_MIN(sizeof(buf), n); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_file_ofs += s; n -= s; } return MZ_TRUE; } mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) { return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0); } mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) { mz_uint16 method = 0, dos_time = 0, dos_date = 0; mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; size_t archive_name_size; mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; tdefl_compressor *pComp = NULL; mz_bool store_data_uncompressed; mz_zip_internal_state *pState; mz_uint8 *pExtra_data = NULL; mz_uint32 extra_size = 0; mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; mz_uint16 bit_flags = 0; if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; level = level_and_flags & 0xF; store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState = pZip->m_pState; if (pState->m_zip64) { if (pZip->m_total_files == MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } else { if (pZip->m_total_files == MZ_UINT16_MAX) { pState->m_zip64 = MZ_TRUE; /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ } if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) { pState->m_zip64 = MZ_TRUE; /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ } } if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!mz_zip_writer_validate_archive_name(pArchive_name)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); #ifndef MINIZ_NO_TIME if (last_modified != NULL) { mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date); } else { MZ_TIME_T cur_time; time(&cur_time); mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); } #endif /* #ifndef MINIZ_NO_TIME */ if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); uncomp_size = buf_size; if (uncomp_size <= 3) { level = 0; store_data_uncompressed = MZ_TRUE; } } archive_name_size = strlen(pArchive_name); if (archive_name_size > MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); if (!pState->m_zip64) { /* Bail early if the archive would obviously become too large */ if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + user_extra_data_central_len + MZ_ZIP_DATA_DESCRIPTER_SIZE32) > 0xFFFFFFFF) { pState->m_zip64 = MZ_TRUE; /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ } } if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) { /* Set DOS Subdirectory attribute bit. */ ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; /* Subdirectories cannot contain data. */ if ((buf_size) || (uncomp_size)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); } /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */ if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); if ((!store_data_uncompressed) && (buf_size)) { if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return MZ_FALSE; } local_dir_header_ofs += num_alignment_padding_bytes; if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } cur_archive_file_ofs += num_alignment_padding_bytes; MZ_CLEAR_OBJ(local_dir_header); if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { method = MZ_DEFLATED; } if (pState->m_zip64) { if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) { pExtra_data = extra_data; extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); } if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method, bit_flags, dos_time, dos_date)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += sizeof(local_dir_header); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_archive_file_ofs += archive_name_size; if (pExtra_data != NULL) { if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += extra_size; } } else { if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += sizeof(local_dir_header); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_archive_file_ofs += archive_name_size; } if (user_extra_data_len > 0) { if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += user_extra_data_len; } if (store_data_uncompressed) { if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_archive_file_ofs += buf_size; comp_size = buf_size; } else if (buf_size) { mz_zip_writer_add_state state; state.m_pZip = pZip; state.m_cur_archive_file_ofs = cur_archive_file_ofs; state.m_comp_size = 0; if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); } comp_size = state.m_comp_size; cur_archive_file_ofs = state.m_cur_archive_file_ofs; } pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); pComp = NULL; if (uncomp_size) { mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR); MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); if (pExtra_data == NULL) { if (comp_size > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); MZ_WRITE_LE32(local_dir_footer + 8, comp_size); MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); } else { MZ_WRITE_LE64(local_dir_footer + 8, comp_size); MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; } if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) return MZ_FALSE; cur_archive_file_ofs += local_dir_footer_size; } if (pExtra_data != NULL) { extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); } if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, (mz_uint16)extra_size, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, user_extra_data_central, user_extra_data_central_len)) return MZ_FALSE; pZip->m_total_files++; pZip->m_archive_size = cur_archive_file_ofs; return MZ_TRUE; } mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) { mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0; size_t archive_name_size; mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; mz_uint8 *pExtra_data = NULL; mz_uint32 extra_size = 0; mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE]; mz_zip_internal_state *pState; mz_uint64 file_ofs = 0; if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME)) gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8; if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; level = level_and_flags & 0xF; /* Sanity checks */ if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState = pZip->m_pState; if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX)) { /* Source file is too large for non-zip64 */ /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ pState->m_zip64 = MZ_TRUE; } /* We could support this, but why? */ if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!mz_zip_writer_validate_archive_name(pArchive_name)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); if (pState->m_zip64) { if (pZip->m_total_files == MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } else { if (pZip->m_total_files == MZ_UINT16_MAX) { pState->m_zip64 = MZ_TRUE; /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */ } } archive_name_size = strlen(pArchive_name); if (archive_name_size > MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME); num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */ if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); if (!pState->m_zip64) { /* Bail early if the archive would obviously become too large */ if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + user_extra_data_len + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024 + MZ_ZIP_DATA_DESCRIPTER_SIZE32 + user_extra_data_central_len) > 0xFFFFFFFF) { pState->m_zip64 = MZ_TRUE; /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */ } } #ifndef MINIZ_NO_TIME if (pFile_time) { mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); } #endif if (uncomp_size <= 3) level = 0; if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes)) { return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_archive_file_ofs += num_alignment_padding_bytes; local_dir_header_ofs = cur_archive_file_ofs; if (pZip->m_file_offset_alignment) { MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } if (uncomp_size && level) { method = MZ_DEFLATED; } MZ_CLEAR_OBJ(local_dir_header); if (pState->m_zip64) { if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX) { pExtra_data = extra_data; extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); } if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)(extra_size + user_extra_data_len), 0, 0, 0, method, gen_flags, dos_time, dos_date)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += sizeof(local_dir_header); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) { return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_archive_file_ofs += archive_name_size; if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += extra_size; } else { if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX)) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, (mz_uint16)user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date)) return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += sizeof(local_dir_header); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) { return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_archive_file_ofs += archive_name_size; } if (user_extra_data_len > 0) { if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_archive_file_ofs += user_extra_data_len; } if (uncomp_size) { mz_uint64 uncomp_remaining = uncomp_size; void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); if (!pRead_buf) { return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (!level) { while (uncomp_remaining) { mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); if ((read_callback(callback_opaque, file_ofs, pRead_buf, n) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); } file_ofs += n; uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); uncomp_remaining -= n; cur_archive_file_ofs += n; } comp_size = uncomp_size; } else { mz_bool result = MZ_FALSE; mz_zip_writer_add_state state; tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); if (!pComp) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } state.m_pZip = pZip; state.m_cur_archive_file_ofs = cur_archive_file_ofs; state.m_comp_size = 0; if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR); } for (;;) { size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE); tdefl_status status; tdefl_flush flush = TDEFL_NO_FLUSH; if (read_callback(callback_opaque, file_ofs, pRead_buf, in_buf_size)!= in_buf_size) { mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); break; } file_ofs += in_buf_size; uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); uncomp_remaining -= in_buf_size; if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque)) flush = TDEFL_FULL_FLUSH; status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH); if (status == TDEFL_STATUS_DONE) { result = MZ_TRUE; break; } else if (status != TDEFL_STATUS_OKAY) { mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED); break; } } pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); if (!result) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); return MZ_FALSE; } comp_size = state.m_comp_size; cur_archive_file_ofs = state.m_cur_archive_file_ofs; } pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); } { mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64]; mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32; MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID); MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32); if (pExtra_data == NULL) { if (comp_size > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); MZ_WRITE_LE32(local_dir_footer + 8, comp_size); MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size); } else { MZ_WRITE_LE64(local_dir_footer + 8, comp_size); MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size); local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64; } if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size) return MZ_FALSE; cur_archive_file_ofs += local_dir_footer_size; } if (pExtra_data != NULL) { extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL, (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL); } if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, (mz_uint16)extra_size, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes, user_extra_data_central, user_extra_data_central_len)) return MZ_FALSE; pZip->m_total_files++; pZip->m_archive_size = cur_archive_file_ofs; return MZ_TRUE; } #ifndef MINIZ_NO_STDIO static size_t mz_file_read_func_stdio(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) { MZ_FILE *pSrc_file = (MZ_FILE *)pOpaque; mz_int64 cur_ofs = MZ_FTELL64(pSrc_file); if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pSrc_file, (mz_int64)file_ofs, SEEK_SET)))) return 0; return MZ_FREAD(pBuf, 1, n, pSrc_file); } mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) { return mz_zip_writer_add_read_buf_callback(pZip, pArchive_name, mz_file_read_func_stdio, pSrc_file, size_to_add, pFile_time, pComment, comment_size, level_and_flags, user_extra_data, user_extra_data_len, user_extra_data_central, user_extra_data_central_len); } mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) { MZ_FILE *pSrc_file = NULL; mz_uint64 uncomp_size = 0; MZ_TIME_T file_modified_time; MZ_TIME_T *pFile_time = NULL; mz_bool status; memset(&file_modified_time, 0, sizeof(file_modified_time)); #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO) pFile_time = &file_modified_time; if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED); #endif pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); if (!pSrc_file) return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); MZ_FSEEK64(pSrc_file, 0, SEEK_END); uncomp_size = MZ_FTELL64(pSrc_file); MZ_FSEEK64(pSrc_file, 0, SEEK_SET); status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0); MZ_FCLOSE(pSrc_file); return status; } #endif /* #ifndef MINIZ_NO_STDIO */ static mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, uint32_t ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start) { /* + 64 should be enough for any new zip64 data */ if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE)) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); mz_zip_array_resize(pZip, pNew_ext, 0, MZ_FALSE); if ((pUncomp_size) || (pComp_size) || (pLocal_header_ofs) || (pDisk_start)) { mz_uint8 new_ext_block[64]; mz_uint8 *pDst = new_ext_block; mz_write_le16(pDst, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID); mz_write_le16(pDst + sizeof(mz_uint16), 0); pDst += sizeof(mz_uint16) * 2; if (pUncomp_size) { mz_write_le64(pDst, *pUncomp_size); pDst += sizeof(mz_uint64); } if (pComp_size) { mz_write_le64(pDst, *pComp_size); pDst += sizeof(mz_uint64); } if (pLocal_header_ofs) { mz_write_le64(pDst, *pLocal_header_ofs); pDst += sizeof(mz_uint64); } if (pDisk_start) { mz_write_le32(pDst, *pDisk_start); pDst += sizeof(mz_uint32); } mz_write_le16(new_ext_block + sizeof(mz_uint16), (mz_uint16)((pDst - new_ext_block) - sizeof(mz_uint16) * 2)); if (!mz_zip_array_push_back(pZip, pNew_ext, new_ext_block, pDst - new_ext_block)) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if ((pExt) && (ext_len)) { mz_uint32 extra_size_remaining = ext_len; const mz_uint8 *pExtra_data = pExt; do { mz_uint32 field_id, field_data_size, field_total_size; if (extra_size_remaining < (sizeof(mz_uint16) * 2)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); field_id = MZ_READ_LE16(pExtra_data); field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); field_total_size = field_data_size + sizeof(mz_uint16) * 2; if (field_total_size > extra_size_remaining) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); if (field_id != MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) { if (!mz_zip_array_push_back(pZip, pNew_ext, pExtra_data, field_total_size)) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } pExtra_data += field_total_size; extra_size_remaining -= field_total_size; } while (extra_size_remaining); } return MZ_TRUE; } /* TODO: This func is now pretty freakin complex due to zip64, split it up? */ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index) { mz_uint n, bit_flags, num_alignment_padding_bytes, src_central_dir_following_data_size; mz_uint64 src_archive_bytes_remaining, local_dir_header_ofs; mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; mz_uint8 new_central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; size_t orig_central_dir_size; mz_zip_internal_state *pState; void *pBuf; const mz_uint8 *pSrc_central_header; mz_zip_archive_file_stat src_file_stat; mz_uint32 src_filename_len, src_comment_len, src_ext_len; mz_uint32 local_header_filename_size, local_header_extra_len; mz_uint64 local_header_comp_size, local_header_uncomp_size; mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE; /* Sanity checks */ if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pSource_zip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState = pZip->m_pState; /* Don't support copying files from zip64 archives to non-zip64, even though in some cases this is possible */ if ((pSource_zip->m_pState->m_zip64) && (!pZip->m_pState->m_zip64)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); /* Get pointer to the source central dir header and crack it */ if (NULL == (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index))) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); src_filename_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS); src_comment_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); src_ext_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS); src_central_dir_following_data_size = src_filename_len + src_ext_len + src_comment_len; /* TODO: We don't support central dir's >= MZ_UINT32_MAX bytes right now (+32 fudge factor in case we need to add more extra data) */ if ((pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + 32) >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); if (!pState->m_zip64) { if (pZip->m_total_files == MZ_UINT16_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } else { /* TODO: Our zip64 support still has some 32-bit limits that may not be worth fixing. */ if (pZip->m_total_files == MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } if (!mz_zip_file_stat_internal(pSource_zip, src_file_index, pSrc_central_header, &src_file_stat, NULL)) return MZ_FALSE; cur_src_file_ofs = src_file_stat.m_local_header_ofs; cur_dst_file_ofs = pZip->m_archive_size; /* Read the source archive's local dir header */ if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; /* Compute the total size we need to copy (filename+extra data+compressed data) */ local_header_filename_size = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS); local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); src_archive_bytes_remaining = local_header_filename_size + local_header_extra_len + src_file_stat.m_comp_size; /* Try to find a zip64 extended information field */ if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX))) { mz_zip_array file_data_array; const mz_uint8 *pExtra_data; mz_uint32 extra_size_remaining = local_header_extra_len; mz_zip_array_init(&file_data_array, 1); if (!mz_zip_array_resize(pZip, &file_data_array, local_header_extra_len, MZ_FALSE)) { return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, src_file_stat.m_local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_size, file_data_array.m_p, local_header_extra_len) != local_header_extra_len) { mz_zip_array_clear(pZip, &file_data_array); return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); } pExtra_data = (const mz_uint8 *)file_data_array.m_p; do { mz_uint32 field_id, field_data_size, field_total_size; if (extra_size_remaining < (sizeof(mz_uint16) * 2)) { mz_zip_array_clear(pZip, &file_data_array); return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); } field_id = MZ_READ_LE16(pExtra_data); field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16)); field_total_size = field_data_size + sizeof(mz_uint16) * 2; if (field_total_size > extra_size_remaining) { mz_zip_array_clear(pZip, &file_data_array); return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); } if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) { const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32); if (field_data_size < sizeof(mz_uint64) * 2) { mz_zip_array_clear(pZip, &file_data_array); return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); } local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data); local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */ found_zip64_ext_data_in_ldir = MZ_TRUE; break; } pExtra_data += field_total_size; extra_size_remaining -= field_total_size; } while (extra_size_remaining); mz_zip_array_clear(pZip, &file_data_array); } if (!pState->m_zip64) { /* Try to detect if the new archive will most likely wind up too big and bail early (+(sizeof(mz_uint32) * 4) is for the optional descriptor which could be present, +64 is a fudge factor). */ /* We also check when the archive is finalized so this doesn't need to be perfect. */ mz_uint64 approx_new_archive_size = cur_dst_file_ofs + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + src_archive_bytes_remaining + (sizeof(mz_uint32) * 4) + pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 64; if (approx_new_archive_size >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); } /* Write dest archive padding */ if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) return MZ_FALSE; cur_dst_file_ofs += num_alignment_padding_bytes; local_dir_header_ofs = cur_dst_file_ofs; if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } /* The original zip's local header+ext block doesn't change, even with zip64, so we can just copy it over to the dest zip */ if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; /* Copy over the source archive bytes to the dest archive, also ensure we have enough buf space to handle optional data descriptor */ if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(32U, MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining))))) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); while (src_archive_bytes_remaining) { n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining); if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); } cur_src_file_ofs += n; if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_dst_file_ofs += n; src_archive_bytes_remaining -= n; } /* Now deal with the optional data descriptor */ bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); if (bit_flags & 8) { /* Copy data descriptor */ if ((pSource_zip->m_pState->m_zip64) || (found_zip64_ext_data_in_ldir)) { /* src is zip64, dest must be zip64 */ /* name uint32_t's */ /* id 1 (optional in zip64?) */ /* crc 1 */ /* comp_size 2 */ /* uncomp_size 2 */ if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, (sizeof(mz_uint32) * 6)) != (sizeof(mz_uint32) * 6)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); } n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID) ? 6 : 5); } else { /* src is NOT zip64 */ mz_bool has_id; if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); } has_id = (MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID); if (pZip->m_pState->m_zip64) { /* dest is zip64, so upgrade the data descriptor */ const mz_uint32 *pSrc_descriptor = (const mz_uint32 *)((const mz_uint8 *)pBuf + (has_id ? sizeof(mz_uint32) : 0)); const mz_uint32 src_crc32 = pSrc_descriptor[0]; const mz_uint64 src_comp_size = pSrc_descriptor[1]; const mz_uint64 src_uncomp_size = pSrc_descriptor[2]; mz_write_le32((mz_uint8 *)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID); mz_write_le32((mz_uint8 *)pBuf + sizeof(mz_uint32) * 1, src_crc32); mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 2, src_comp_size); mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 4, src_uncomp_size); n = sizeof(mz_uint32) * 6; } else { /* dest is NOT zip64, just copy it as-is */ n = sizeof(mz_uint32) * (has_id ? 4 : 3); } } if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); } cur_src_file_ofs += n; cur_dst_file_ofs += n; } pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); /* Finally, add the new central dir header */ orig_central_dir_size = pState->m_central_dir.m_size; memcpy(new_central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); if (pState->m_zip64) { /* This is the painful part: We need to write a new central dir header + ext block with updated zip64 fields, and ensure the old fields (if any) are not included. */ const mz_uint8 *pSrc_ext = pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len; mz_zip_array new_ext_block; mz_zip_array_init(&new_ext_block, sizeof(mz_uint8)); MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_UINT32_MAX); MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_UINT32_MAX); MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_UINT32_MAX); if (!mz_zip_writer_update_zip64_extension_block(&new_ext_block, pZip, pSrc_ext, src_ext_len, &src_file_stat.m_comp_size, &src_file_stat.m_uncomp_size, &local_dir_header_ofs, NULL)) { mz_zip_array_clear(pZip, &new_ext_block); return MZ_FALSE; } MZ_WRITE_LE16(new_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS, new_ext_block.m_size); if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) { mz_zip_array_clear(pZip, &new_ext_block); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_filename_len)) { mz_zip_array_clear(pZip, &new_ext_block); mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_ext_block.m_p, new_ext_block.m_size)) { mz_zip_array_clear(pZip, &new_ext_block); mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len + src_ext_len, src_comment_len)) { mz_zip_array_clear(pZip, &new_ext_block); mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } mz_zip_array_clear(pZip, &new_ext_block); } else { /* sanity checks */ if (cur_dst_file_ofs > MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); if (local_dir_header_ofs >= MZ_UINT32_MAX) return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_central_dir_following_data_size)) { mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } } /* This shouldn't trigger unless we screwed up during the initial sanity checks */ if (pState->m_central_dir.m_size >= MZ_UINT32_MAX) { /* TODO: Support central dirs >= 32-bits in size */ mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE); } n = (mz_uint32)orig_central_dir_size; if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) { mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } pZip->m_total_files++; pZip->m_archive_size = cur_dst_file_ofs; return MZ_TRUE; } mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) { mz_zip_internal_state *pState; mz_uint64 central_dir_ofs, central_dir_size; mz_uint8 hdr[256]; if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); pState = pZip->m_pState; if (pState->m_zip64) { if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX)) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } else { if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)) return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); } central_dir_ofs = 0; central_dir_size = 0; if (pZip->m_total_files) { /* Write central directory */ central_dir_ofs = pZip->m_archive_size; central_dir_size = pState->m_central_dir.m_size; pZip->m_central_directory_file_ofs = central_dir_ofs; if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); pZip->m_archive_size += central_dir_size; } if (pState->m_zip64) { /* Write zip64 end of central directory header */ mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; MZ_CLEAR_OBJ(hdr); MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64)); MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */ MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs); if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; /* Write zip64 end of central directory locator */ MZ_CLEAR_OBJ(hdr); MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG); MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr); MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1); if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; } /* Write end of central directory record */ MZ_CLEAR_OBJ(hdr); MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files)); MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size)); MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs)); if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); #ifndef MINIZ_NO_STDIO if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED); #endif /* #ifndef MINIZ_NO_STDIO */ pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE; pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; return MZ_TRUE; } mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize) { if ((!ppBuf) || (!pSize)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); *ppBuf = NULL; *pSize = 0; if ((!pZip) || (!pZip->m_pState)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (pZip->m_pWrite != mz_zip_heap_write_func) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); if (!mz_zip_writer_finalize_archive(pZip)) return MZ_FALSE; *ppBuf = pZip->m_pState->m_pMem; *pSize = pZip->m_pState->m_mem_size; pZip->m_pState->m_pMem = NULL; pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; return MZ_TRUE; } mz_bool mz_zip_writer_end(mz_zip_archive *pZip) { return mz_zip_writer_end_internal(pZip, MZ_TRUE); } #ifndef MINIZ_NO_STDIO mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) { return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL); } mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr) { mz_bool status, created_new_archive = MZ_FALSE; mz_zip_archive zip_archive; struct MZ_FILE_STAT_STRUCT file_stat; mz_zip_error actual_err = MZ_ZIP_NO_ERROR; mz_zip_zero_struct(&zip_archive); if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) { if (pErr) *pErr = MZ_ZIP_INVALID_PARAMETER; return MZ_FALSE; } if (!mz_zip_writer_validate_archive_name(pArchive_name)) { if (pErr) *pErr = MZ_ZIP_INVALID_FILENAME; return MZ_FALSE; } /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */ /* So be sure to compile with _LARGEFILE64_SOURCE 1 */ if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) { /* Create a new archive. */ if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags)) { if (pErr) *pErr = zip_archive.m_last_error; return MZ_FALSE; } created_new_archive = MZ_TRUE; } else { /* Append to an existing archive. */ if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) { if (pErr) *pErr = zip_archive.m_last_error; return MZ_FALSE; } if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags)) { if (pErr) *pErr = zip_archive.m_last_error; mz_zip_reader_end_internal(&zip_archive, MZ_FALSE); return MZ_FALSE; } } status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); actual_err = zip_archive.m_last_error; /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */ if (!mz_zip_writer_finalize_archive(&zip_archive)) { if (!actual_err) actual_err = zip_archive.m_last_error; status = MZ_FALSE; } if (!mz_zip_writer_end_internal(&zip_archive, status)) { if (!actual_err) actual_err = zip_archive.m_last_error; status = MZ_FALSE; } if ((!status) && (created_new_archive)) { /* It's a new archive and something went wrong, so just delete it. */ int ignoredStatus = MZ_DELETE_FILE(pZip_filename); (void)ignoredStatus; } if (pErr) *pErr = actual_err; return status; } void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr) { mz_uint32 file_index; mz_zip_archive zip_archive; void *p = NULL; if (pSize) *pSize = 0; if ((!pZip_filename) || (!pArchive_name)) { if (pErr) *pErr = MZ_ZIP_INVALID_PARAMETER; return NULL; } mz_zip_zero_struct(&zip_archive); if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) { if (pErr) *pErr = zip_archive.m_last_error; return NULL; } if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index)) { p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); } mz_zip_reader_end_internal(&zip_archive, p != NULL); if (pErr) *pErr = zip_archive.m_last_error; return p; } void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) { return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL); } #endif /* #ifndef MINIZ_NO_STDIO */ #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ /* ------------------- Misc utils */ mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip) { return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID; } mz_zip_type mz_zip_get_type(mz_zip_archive *pZip) { return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID; } mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num) { mz_zip_error prev_err; if (!pZip) return MZ_ZIP_INVALID_PARAMETER; prev_err = pZip->m_last_error; pZip->m_last_error = err_num; return prev_err; } mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip) { if (!pZip) return MZ_ZIP_INVALID_PARAMETER; return pZip->m_last_error; } mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip) { return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR); } mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip) { mz_zip_error prev_err; if (!pZip) return MZ_ZIP_INVALID_PARAMETER; prev_err = pZip->m_last_error; pZip->m_last_error = MZ_ZIP_NO_ERROR; return prev_err; } const char *mz_zip_get_error_string(mz_zip_error mz_err) { switch (mz_err) { case MZ_ZIP_NO_ERROR: return "no error"; case MZ_ZIP_UNDEFINED_ERROR: return "undefined error"; case MZ_ZIP_TOO_MANY_FILES: return "too many files"; case MZ_ZIP_FILE_TOO_LARGE: return "file too large"; case MZ_ZIP_UNSUPPORTED_METHOD: return "unsupported method"; case MZ_ZIP_UNSUPPORTED_ENCRYPTION: return "unsupported encryption"; case MZ_ZIP_UNSUPPORTED_FEATURE: return "unsupported feature"; case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: return "failed finding central directory"; case MZ_ZIP_NOT_AN_ARCHIVE: return "not a ZIP archive"; case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: return "invalid header or archive is corrupted"; case MZ_ZIP_UNSUPPORTED_MULTIDISK: return "unsupported multidisk archive"; case MZ_ZIP_DECOMPRESSION_FAILED: return "decompression failed or archive is corrupted"; case MZ_ZIP_COMPRESSION_FAILED: return "compression failed"; case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: return "unexpected decompressed size"; case MZ_ZIP_CRC_CHECK_FAILED: return "CRC-32 check failed"; case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: return "unsupported central directory size"; case MZ_ZIP_ALLOC_FAILED: return "allocation failed"; case MZ_ZIP_FILE_OPEN_FAILED: return "file open failed"; case MZ_ZIP_FILE_CREATE_FAILED: return "file create failed"; case MZ_ZIP_FILE_WRITE_FAILED: return "file write failed"; case MZ_ZIP_FILE_READ_FAILED: return "file read failed"; case MZ_ZIP_FILE_CLOSE_FAILED: return "file close failed"; case MZ_ZIP_FILE_SEEK_FAILED: return "file seek failed"; case MZ_ZIP_FILE_STAT_FAILED: return "file stat failed"; case MZ_ZIP_INVALID_PARAMETER: return "invalid parameter"; case MZ_ZIP_INVALID_FILENAME: return "invalid filename"; case MZ_ZIP_BUF_TOO_SMALL: return "buffer too small"; case MZ_ZIP_INTERNAL_ERROR: return "internal error"; case MZ_ZIP_FILE_NOT_FOUND: return "file not found"; case MZ_ZIP_ARCHIVE_TOO_LARGE: return "archive is too large"; case MZ_ZIP_VALIDATION_FAILED: return "validation failed"; case MZ_ZIP_WRITE_CALLBACK_FAILED: return "write calledback failed"; default: break; } return "unknown error"; } /* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */ mz_bool mz_zip_is_zip64(mz_zip_archive *pZip) { if ((!pZip) || (!pZip->m_pState)) return MZ_FALSE; return pZip->m_pState->m_zip64; } size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip) { if ((!pZip) || (!pZip->m_pState)) return 0; return pZip->m_pState->m_central_dir.m_size; } mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) { return pZip ? pZip->m_total_files : 0; } mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip) { if (!pZip) return 0; return pZip->m_archive_size; } mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip) { if ((!pZip) || (!pZip->m_pState)) return 0; return pZip->m_pState->m_file_archive_start_ofs; } MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip) { if ((!pZip) || (!pZip->m_pState)) return 0; return pZip->m_pState->m_pFile; } size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n) { if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead)) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n); } mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) { mz_uint n; const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index); if (!p) { if (filename_buf_size) pFilename[0] = '\0'; mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); return 0; } n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); if (filename_buf_size) { n = MZ_MIN(n, filename_buf_size - 1); memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pFilename[n] = '\0'; } return n + 1; } mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) { return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL); } mz_bool mz_zip_end(mz_zip_archive *pZip) { if (!pZip) return MZ_FALSE; if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) return mz_zip_reader_end(pZip); #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)) return mz_zip_writer_end(pZip); #endif return MZ_FALSE; } #ifdef __cplusplus } #endif #endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ camlpdf-2.8.1/miniz.h000066400000000000000000002037551477056064700144630ustar00rootroot00000000000000/* miniz.c 2.1.0 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing See "unlicense" statement at the end of this file. Rich Geldreich , last updated Oct. 13, 2013 Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). * Low-level Deflate/Inflate implementation notes: Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses approximately as well as zlib. Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory block large enough to hold the entire file. The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. * zlib-style API notes: miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in zlib replacement in many apps: The z_stream struct, optional memory allocation callbacks deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound inflateInit/inflateInit2/inflate/inflateReset/inflateEnd compress, compress2, compressBound, uncompress CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. Supports raw deflate streams or standard zlib streams with adler-32 checking. Limitations: The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but there are no guarantees that miniz.c pulls this off perfectly. * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by Alex Evans. Supports 1-4 bytes/pixel images. * ZIP archive API notes: The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to get the job done with minimal fuss. There are simple API's to retrieve file information, read files from existing archives, create new archives, append new files to existing archives, or clone archive data from one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), or you can specify custom file read/write callbacks. - Archive reading: Just call this function to read a single file from a disk archive: void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint zip_flags); For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); The locate operation can optionally check file comments too, which (as one example) can be used to identify multiple versions of the same file in an archive. This function uses a simple linear search through the central directory, so it's not very fast. Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and retrieve detailed info on each file by calling mz_zip_reader_file_stat(). - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data to disk and builds an exact image of the central directory in memory. The central directory image is written all at once at the end of the archive file when the archive is finalized. The archive writer can optionally align each file's local header and file data to any power of 2 alignment, which can be useful when the archive will be read from optical media. Also, the writer supports placing arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still readable by any ZIP tool. - Archive appending: The simple way to add a single file to an archive is to call this function: mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); The archive will be created if it doesn't already exist, otherwise it'll be appended to. Note the appending is done in-place and is not an atomic operation, so if something goes wrong during the operation it's possible the archive could be left without a central directory (although the local file headers and file data will be fine, so the archive will be recoverable). For more complex archive modification scenarios: 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and you're done. This is safe but requires a bunch of temporary disk space or heap memory. 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), append new files as needed, then finalize the archive which will write an updated central directory to the original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a possibility that the archive's central directory could be lost with this method if anything goes wrong, though. - ZIP archive support limitations: No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files. Requires streams capable of seeking. * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. * Important: For best perf. be sure to customize the below macros for your target platform: #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 #define MINIZ_LITTLE_ENDIAN 1 #define MINIZ_HAS_64BIT_REGISTERS 1 * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). */ #pragma once /* Defines to completely disable specific portions of miniz.c: If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. */ /* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. */ #define MINIZ_NO_STDIO /* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or */ /* get/set file times, and the C run-time funcs that get/set times won't be called. */ /* The current downside is the times written to your archives will be from 1979. */ #define MINIZ_NO_TIME /* Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. */ #define MINIZ_NO_ARCHIVE_APIS /* Define MINIZ_NO_ARCHIVE_WRITING_APIS to disable all writing related ZIP archive API's. */ #define MINIZ_NO_ARCHIVE_WRITING_APIS /* Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. */ /*#define MINIZ_NO_ZLIB_APIS */ /* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. */ #define MINIZ_NO_ZLIB_COMPATIBLE_NAMES /* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. */ /*#define MINIZ_NO_MALLOC */ #if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) /* TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux */ #define MINIZ_NO_TIME #endif #include #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) #include #endif #if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) /* MINIZ_X86_OR_X64_CPU is only used to help set the below macros. */ #define MINIZ_X86_OR_X64_CPU 1 #else #define MINIZ_X86_OR_X64_CPU 0 #endif #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU /* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */ #define MINIZ_LITTLE_ENDIAN 1 #else #define MINIZ_LITTLE_ENDIAN 0 #endif /* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES only if not set */ #if !defined(MINIZ_USE_UNALIGNED_LOADS_AND_STORES) #if MINIZ_X86_OR_X64_CPU /* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */ #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 #define MINIZ_UNALIGNED_USE_MEMCPY #else #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 #endif #endif #if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) /* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). */ #define MINIZ_HAS_64BIT_REGISTERS 1 #else #define MINIZ_HAS_64BIT_REGISTERS 0 #endif #ifdef __cplusplus extern "C" { #endif /* ------------------- zlib-style API Definitions. */ /* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! */ typedef unsigned long mz_ulong; /* mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. */ void mz_free(void *p); #define MZ_ADLER32_INIT (1) /* mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. */ mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); #define MZ_CRC32_INIT (0) /* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */ mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); /* Compression strategies. */ enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 }; /* Method */ #define MZ_DEFLATED 8 /* Heap allocation callbacks. Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. */ typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); typedef void (*mz_free_func)(void *opaque, void *address); typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); /* Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */ enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 }; #define MZ_VERSION "10.1.0" #define MZ_VERNUM 0xA100 #define MZ_VER_MAJOR 10 #define MZ_VER_MINOR 1 #define MZ_VER_REVISION 0 #define MZ_VER_SUBREVISION 0 #ifndef MINIZ_NO_ZLIB_APIS /* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). */ enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 }; /* Return status codes. MZ_PARAM_ERROR is non-standard. */ enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 }; /* Window bits */ #define MZ_DEFAULT_WINDOW_BITS 15 struct mz_internal_state; /* Compression/decompression stream struct. */ typedef struct mz_stream_s { const unsigned char *next_in; /* pointer to next byte to read */ unsigned int avail_in; /* number of bytes available at next_in */ mz_ulong total_in; /* total number of bytes consumed so far */ unsigned char *next_out; /* pointer to next byte to write */ unsigned int avail_out; /* number of bytes that can be written to next_out */ mz_ulong total_out; /* total number of bytes produced so far */ char *msg; /* error msg (unused) */ struct mz_internal_state *state; /* internal state, allocated by zalloc/zfree */ mz_alloc_func zalloc; /* optional heap allocation function (defaults to malloc) */ mz_free_func zfree; /* optional heap free function (defaults to free) */ void *opaque; /* heap alloc function user pointer */ int data_type; /* data_type (unused) */ mz_ulong adler; /* adler32 of the source or uncompressed data */ mz_ulong reserved; /* not used */ } mz_stream; typedef mz_stream *mz_streamp; /* Returns the version string of miniz.c. */ const char *mz_version(void); /* mz_deflateInit() initializes a compressor with default options: */ /* Parameters: */ /* pStream must point to an initialized mz_stream struct. */ /* level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. */ /* level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. */ /* (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) */ /* Return values: */ /* MZ_OK on success. */ /* MZ_STREAM_ERROR if the stream is bogus. */ /* MZ_PARAM_ERROR if the input parameters are bogus. */ /* MZ_MEM_ERROR on out of memory. */ int mz_deflateInit(mz_streamp pStream, int level); /* mz_deflateInit2() is like mz_deflate(), except with more control: */ /* Additional parameters: */ /* method must be MZ_DEFLATED */ /* window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) */ /* mem_level must be between [1, 9] (it's checked but ignored by miniz.c) */ int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); /* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */ int mz_deflateReset(mz_streamp pStream); /* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. */ /* Parameters: */ /* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ /* flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. */ /* Return values: */ /* MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). */ /* MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. */ /* MZ_STREAM_ERROR if the stream is bogus. */ /* MZ_PARAM_ERROR if one of the parameters is invalid. */ /* MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) */ int mz_deflate(mz_streamp pStream, int flush); /* mz_deflateEnd() deinitializes a compressor: */ /* Return values: */ /* MZ_OK on success. */ /* MZ_STREAM_ERROR if the stream is bogus. */ int mz_deflateEnd(mz_streamp pStream); /* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */ mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); /* Single-call compression functions mz_compress() and mz_compress2(): */ /* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */ int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); /* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). */ mz_ulong mz_compressBound(mz_ulong source_len); /* Initializes a decompressor. */ int mz_inflateInit(mz_streamp pStream); /* mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: */ /* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). */ int mz_inflateInit2(mz_streamp pStream, int window_bits); /* Quickly resets a compressor without having to reallocate anything. Same as calling mz_inflateEnd() followed by mz_inflateInit()/mz_inflateInit2(). */ int mz_inflateReset(mz_streamp pStream); /* Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. */ /* Parameters: */ /* pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */ /* flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. */ /* On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). */ /* MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. */ /* Return values: */ /* MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. */ /* MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. */ /* MZ_STREAM_ERROR if the stream is bogus. */ /* MZ_DATA_ERROR if the deflate stream is invalid. */ /* MZ_PARAM_ERROR if one of the parameters is invalid. */ /* MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again */ /* with more input data, or with more room in the output buffer (except when using single call decompression, described above). */ int mz_inflate(mz_streamp pStream, int flush); /* Deinitializes a decompressor. */ int mz_inflateEnd(mz_streamp pStream); /* Single-call decompression. */ /* Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. */ int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); /* Returns a string description of the specified error code, or NULL if the error code is invalid. */ const char *mz_error(int err); /* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. */ /* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */ #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES typedef unsigned char Byte; typedef unsigned int uInt; typedef mz_ulong uLong; typedef Byte Bytef; typedef uInt uIntf; typedef char charf; typedef int intf; typedef void *voidpf; typedef uLong uLongf; typedef void *voidp; typedef void *const voidpc; #define Z_NULL 0 #define Z_NO_FLUSH MZ_NO_FLUSH #define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH #define Z_SYNC_FLUSH MZ_SYNC_FLUSH #define Z_FULL_FLUSH MZ_FULL_FLUSH #define Z_FINISH MZ_FINISH #define Z_BLOCK MZ_BLOCK #define Z_OK MZ_OK #define Z_STREAM_END MZ_STREAM_END #define Z_NEED_DICT MZ_NEED_DICT #define Z_ERRNO MZ_ERRNO #define Z_STREAM_ERROR MZ_STREAM_ERROR #define Z_DATA_ERROR MZ_DATA_ERROR #define Z_MEM_ERROR MZ_MEM_ERROR #define Z_BUF_ERROR MZ_BUF_ERROR #define Z_VERSION_ERROR MZ_VERSION_ERROR #define Z_PARAM_ERROR MZ_PARAM_ERROR #define Z_NO_COMPRESSION MZ_NO_COMPRESSION #define Z_BEST_SPEED MZ_BEST_SPEED #define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION #define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION #define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY #define Z_FILTERED MZ_FILTERED #define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY #define Z_RLE MZ_RLE #define Z_FIXED MZ_FIXED #define Z_DEFLATED MZ_DEFLATED #define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS #define alloc_func mz_alloc_func #define free_func mz_free_func #define internal_state mz_internal_state #define z_stream mz_stream #define deflateInit mz_deflateInit #define deflateInit2 mz_deflateInit2 #define deflateReset mz_deflateReset #define deflate mz_deflate #define deflateEnd mz_deflateEnd #define deflateBound mz_deflateBound #define compress mz_compress #define compress2 mz_compress2 #define compressBound mz_compressBound #define inflateInit mz_inflateInit #define inflateInit2 mz_inflateInit2 #define inflateReset mz_inflateReset #define inflate mz_inflate #define inflateEnd mz_inflateEnd #define uncompress mz_uncompress #define crc32 mz_crc32 #define adler32 mz_adler32 #define MAX_WBITS 15 #define MAX_MEM_LEVEL 9 #define zError mz_error #define ZLIB_VERSION MZ_VERSION #define ZLIB_VERNUM MZ_VERNUM #define ZLIB_VER_MAJOR MZ_VER_MAJOR #define ZLIB_VER_MINOR MZ_VER_MINOR #define ZLIB_VER_REVISION MZ_VER_REVISION #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION #define zlibVersion mz_version #define zlib_version mz_version() #endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */ #endif /* MINIZ_NO_ZLIB_APIS */ #ifdef __cplusplus } #endif #pragma once #include #include #include #include /* ------------------- Types and macros */ typedef unsigned char mz_uint8; typedef signed short mz_int16; typedef unsigned short mz_uint16; typedef unsigned int mz_uint32; typedef unsigned int mz_uint; typedef int64_t mz_int64; typedef uint64_t mz_uint64; typedef int mz_bool; #define MZ_FALSE (0) #define MZ_TRUE (1) /* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */ #ifdef _MSC_VER #define MZ_MACRO_END while (0, 0) #else #define MZ_MACRO_END while (0) #endif #ifdef MINIZ_NO_STDIO #define MZ_FILE void * #else #include #define MZ_FILE FILE #endif /* #ifdef MINIZ_NO_STDIO */ #ifdef MINIZ_NO_TIME typedef struct mz_dummy_time_t_tag { int m_dummy; } mz_dummy_time_t; #define MZ_TIME_T mz_dummy_time_t #else #define MZ_TIME_T time_t #endif #define MZ_ASSERT(x) assert(x) #ifdef MINIZ_NO_MALLOC #define MZ_MALLOC(x) NULL #define MZ_FREE(x) (void)x, ((void)0) #define MZ_REALLOC(p, x) NULL #else #define MZ_MALLOC(x) malloc(x) #define MZ_FREE(x) free(x) #define MZ_REALLOC(p, x) realloc(p, x) #endif #define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) #define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN #define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) #define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) #else #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) #endif #define MZ_READ_LE64(p) (((mz_uint64)MZ_READ_LE32(p)) | (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) << 32U)) #ifdef _MSC_VER #define MZ_FORCEINLINE __forceinline #elif defined(__GNUC__) #define MZ_FORCEINLINE __inline__ __attribute__((__always_inline__)) #else #define MZ_FORCEINLINE inline #endif #ifdef __cplusplus extern "C" { #endif extern void *miniz_def_alloc_func(void *opaque, size_t items, size_t size); extern void miniz_def_free_func(void *opaque, void *address); extern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size); #define MZ_UINT16_MAX (0xFFFFU) #define MZ_UINT32_MAX (0xFFFFFFFFU) #ifdef __cplusplus } #endif #pragma once #ifdef __cplusplus extern "C" { #endif /* ------------------- Low-level Compression API Definitions */ /* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). */ #define TDEFL_LESS_MEMORY 0 /* tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): */ /* TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). */ enum { TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF }; /* TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. */ /* TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). */ /* TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. */ /* TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). */ /* TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) */ /* TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. */ /* TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. */ /* TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. */ /* The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). */ enum { TDEFL_WRITE_ZLIB_HEADER = 0x01000, TDEFL_COMPUTE_ADLER32 = 0x02000, TDEFL_GREEDY_PARSING_FLAG = 0x04000, TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, TDEFL_RLE_MATCHES = 0x10000, TDEFL_FILTER_MATCHES = 0x20000, TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 }; /* High level compression functions: */ /* tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). */ /* On entry: */ /* pSrc_buf, src_buf_len: Pointer and size of source block to compress. */ /* flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. */ /* On return: */ /* Function returns a pointer to the compressed data, or NULL on failure. */ /* *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. */ /* The caller must free() the returned block when it's no longer needed. */ void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); /* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */ /* Returns 0 on failure. */ size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); /* Compresses an image to a compressed PNG file in memory. */ /* On entry: */ /* pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. */ /* The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. */ /* level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL */ /* If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). */ /* On return: */ /* Function returns a pointer to the compressed data, or NULL on failure. */ /* *pLen_out will be set to the size of the PNG image file. */ /* The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. */ void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); /* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */ typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); /* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. */ mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 }; /* TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). */ #if TDEFL_LESS_MEMORY enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; #else enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; #endif /* The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. */ typedef enum { TDEFL_STATUS_BAD_PARAM = -2, TDEFL_STATUS_PUT_BUF_FAILED = -1, TDEFL_STATUS_OKAY = 0, TDEFL_STATUS_DONE = 1 } tdefl_status; /* Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums */ typedef enum { TDEFL_NO_FLUSH = 0, TDEFL_SYNC_FLUSH = 2, TDEFL_FULL_FLUSH = 3, TDEFL_FINISH = 4 } tdefl_flush; /* tdefl's compression state structure. */ typedef struct { tdefl_put_buf_func_ptr m_pPut_buf_func; void *m_pPut_buf_user; mz_uint m_flags, m_max_probes[2]; int m_greedy_parsing; mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; tdefl_status m_prev_return_status; const void *m_pIn_buf; void *m_pOut_buf; size_t *m_pIn_buf_size, *m_pOut_buf_size; tdefl_flush m_flush; const mz_uint8 *m_pSrc; size_t m_src_buf_left, m_out_buf_ofs; mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; } tdefl_compressor; /* Initializes the compressor. */ /* There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. */ /* pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. */ /* If pBut_buf_func is NULL the user should always call the tdefl_compress() API. */ /* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) */ tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); /* Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. */ tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); /* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */ /* tdefl_compress_buffer() always consumes the entire input buffer. */ tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); mz_uint32 tdefl_get_adler32(tdefl_compressor *d); /* Create tdefl_compress() flags given zlib-style compression parameters. */ /* level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) */ /* window_bits may be -15 (raw deflate) or 15 (zlib) */ /* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED */ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); #ifndef MINIZ_NO_MALLOC /* Allocate the tdefl_compressor structure in C so that */ /* non-C language bindings to tdefl_ API don't need to worry about */ /* structure size and allocation mechanism. */ tdefl_compressor *tdefl_compressor_alloc(void); void tdefl_compressor_free(tdefl_compressor *pComp); #endif #ifdef __cplusplus } #endif #pragma once /* ------------------- Low-level Decompression API Definitions */ #ifdef __cplusplus extern "C" { #endif /* Decompression flags used by tinfl_decompress(). */ /* TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. */ /* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. */ /* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). */ /* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. */ enum { TINFL_FLAG_PARSE_ZLIB_HEADER = 1, TINFL_FLAG_HAS_MORE_INPUT = 2, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, TINFL_FLAG_COMPUTE_ADLER32 = 8 }; /* High level decompression functions: */ /* tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). */ /* On entry: */ /* pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. */ /* On return: */ /* Function returns a pointer to the decompressed data, or NULL on failure. */ /* *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. */ /* The caller must call mz_free() on the returned block when it's no longer needed. */ void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); /* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */ /* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */ #define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); /* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. */ /* Returns 1 on success or 0 on failure. */ typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor; #ifndef MINIZ_NO_MALLOC /* Allocate the tinfl_decompressor structure in C so that */ /* non-C language bindings to tinfl_ API don't need to worry about */ /* structure size and allocation mechanism. */ tinfl_decompressor *tinfl_decompressor_alloc(void); void tinfl_decompressor_free(tinfl_decompressor *pDecomp); #endif /* Max size of LZ dictionary. */ #define TINFL_LZ_DICT_SIZE 32768 /* Return status. */ typedef enum { /* This flags indicates the inflator needs 1 or more input bytes to make forward progress, but the caller is indicating that no more are available. The compressed data */ /* is probably corrupted. If you call the inflator again with more bytes it'll try to continue processing the input but this is a BAD sign (either the data is corrupted or you called it incorrectly). */ /* If you call it again with no input you'll just get TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS again. */ TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS = -4, /* This flag indicates that one or more of the input parameters was obviously bogus. (You can try calling it again, but if you get this error the calling code is wrong.) */ TINFL_STATUS_BAD_PARAM = -3, /* This flags indicate the inflator is finished but the adler32 check of the uncompressed data didn't match. If you call it again it'll return TINFL_STATUS_DONE. */ TINFL_STATUS_ADLER32_MISMATCH = -2, /* This flags indicate the inflator has somehow failed (bad code, corrupted input, etc.). If you call it again without resetting via tinfl_init() it it'll just keep on returning the same status failure code. */ TINFL_STATUS_FAILED = -1, /* Any status code less than TINFL_STATUS_DONE must indicate a failure. */ /* This flag indicates the inflator has returned every byte of uncompressed data that it can, has consumed every byte that it needed, has successfully reached the end of the deflate stream, and */ /* if zlib headers and adler32 checking enabled that it has successfully checked the uncompressed data's adler32. If you call it again you'll just get TINFL_STATUS_DONE over and over again. */ TINFL_STATUS_DONE = 0, /* This flag indicates the inflator MUST have more input data (even 1 byte) before it can make any more forward progress, or you need to clear the TINFL_FLAG_HAS_MORE_INPUT */ /* flag on the next call if you don't have any more source data. If the source data was somehow corrupted it's also possible (but unlikely) for the inflator to keep on demanding input to */ /* proceed, so be sure to properly set the TINFL_FLAG_HAS_MORE_INPUT flag. */ TINFL_STATUS_NEEDS_MORE_INPUT = 1, /* This flag indicates the inflator definitely has 1 or more bytes of uncompressed data available, but it cannot write this data into the output buffer. */ /* Note if the source compressed data was corrupted it's possible for the inflator to return a lot of uncompressed data to the caller. I've been assuming you know how much uncompressed data to expect */ /* (either exact or worst case) and will stop calling the inflator and fail after receiving too much. In pure streaming scenarios where you have no idea how many bytes to expect this may not be possible */ /* so I may need to add some code to address this. */ TINFL_STATUS_HAS_MORE_OUTPUT = 2 } tinfl_status; /* Initializes the decompressor to its initial state. */ #define tinfl_init(r) \ do \ { \ (r)->m_state = 0; \ } \ MZ_MACRO_END #define tinfl_get_adler32(r) (r)->m_check_adler32 /* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. */ /* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. */ tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); /* Internal/private bits follow. */ enum { TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS }; typedef struct { mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; } tinfl_huff_table; #if MINIZ_HAS_64BIT_REGISTERS #define TINFL_USE_64BIT_BITBUF 1 #else #define TINFL_USE_64BIT_BITBUF 0 #endif #if TINFL_USE_64BIT_BITBUF typedef mz_uint64 tinfl_bit_buf_t; #define TINFL_BITBUF_SIZE (64) #else typedef mz_uint32 tinfl_bit_buf_t; #define TINFL_BITBUF_SIZE (32) #endif struct tinfl_decompressor_tag { mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; tinfl_bit_buf_t m_bit_buf; size_t m_dist_from_out_buf_start; tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; }; #ifdef __cplusplus } #endif #pragma once /* ------------------- ZIP archive reading/writing */ #ifndef MINIZ_NO_ARCHIVE_APIS #ifdef __cplusplus extern "C" { #endif enum { /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */ MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512 }; typedef struct { /* Central directory file index. */ mz_uint32 m_file_index; /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */ mz_uint64 m_central_dir_ofs; /* These fields are copied directly from the zip's central dir. */ mz_uint16 m_version_made_by; mz_uint16 m_version_needed; mz_uint16 m_bit_flag; mz_uint16 m_method; #ifndef MINIZ_NO_TIME MZ_TIME_T m_time; #endif /* CRC-32 of uncompressed data. */ mz_uint32 m_crc32; /* File's compressed size. */ mz_uint64 m_comp_size; /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */ mz_uint64 m_uncomp_size; /* Zip internal and external file attributes. */ mz_uint16 m_internal_attr; mz_uint32 m_external_attr; /* Entry's local header file offset in bytes. */ mz_uint64 m_local_header_ofs; /* Size of comment in bytes. */ mz_uint32 m_comment_size; /* MZ_TRUE if the entry appears to be a directory. */ mz_bool m_is_directory; /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */ mz_bool m_is_encrypted; /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */ mz_bool m_is_supported; /* Filename. If string ends in '/' it's a subdirectory entry. */ /* Guaranteed to be zero terminated, may be truncated to fit. */ char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; /* Comment field. */ /* Guaranteed to be zero terminated, may be truncated to fit. */ char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; } mz_zip_archive_file_stat; typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque); struct mz_zip_internal_state_tag; typedef struct mz_zip_internal_state_tag mz_zip_internal_state; typedef enum { MZ_ZIP_MODE_INVALID = 0, MZ_ZIP_MODE_READING = 1, MZ_ZIP_MODE_WRITING = 2, MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 } mz_zip_mode; typedef enum { MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800, MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */ MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000, /* validate the local headers, but don't decompress the entire file and check the crc32 */ MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000, /* always use the zip64 file format, instead of the original zip file format with automatic switch to zip64. Use as flags parameter with mz_zip_writer_init*_v2 */ MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000, MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000 } mz_zip_flags; typedef enum { MZ_ZIP_TYPE_INVALID = 0, MZ_ZIP_TYPE_USER, MZ_ZIP_TYPE_MEMORY, MZ_ZIP_TYPE_HEAP, MZ_ZIP_TYPE_FILE, MZ_ZIP_TYPE_CFILE, MZ_ZIP_TOTAL_TYPES } mz_zip_type; /* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */ typedef enum { MZ_ZIP_NO_ERROR = 0, MZ_ZIP_UNDEFINED_ERROR, MZ_ZIP_TOO_MANY_FILES, MZ_ZIP_FILE_TOO_LARGE, MZ_ZIP_UNSUPPORTED_METHOD, MZ_ZIP_UNSUPPORTED_ENCRYPTION, MZ_ZIP_UNSUPPORTED_FEATURE, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR, MZ_ZIP_NOT_AN_ARCHIVE, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED, MZ_ZIP_UNSUPPORTED_MULTIDISK, MZ_ZIP_DECOMPRESSION_FAILED, MZ_ZIP_COMPRESSION_FAILED, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE, MZ_ZIP_CRC_CHECK_FAILED, MZ_ZIP_UNSUPPORTED_CDIR_SIZE, MZ_ZIP_ALLOC_FAILED, MZ_ZIP_FILE_OPEN_FAILED, MZ_ZIP_FILE_CREATE_FAILED, MZ_ZIP_FILE_WRITE_FAILED, MZ_ZIP_FILE_READ_FAILED, MZ_ZIP_FILE_CLOSE_FAILED, MZ_ZIP_FILE_SEEK_FAILED, MZ_ZIP_FILE_STAT_FAILED, MZ_ZIP_INVALID_PARAMETER, MZ_ZIP_INVALID_FILENAME, MZ_ZIP_BUF_TOO_SMALL, MZ_ZIP_INTERNAL_ERROR, MZ_ZIP_FILE_NOT_FOUND, MZ_ZIP_ARCHIVE_TOO_LARGE, MZ_ZIP_VALIDATION_FAILED, MZ_ZIP_WRITE_CALLBACK_FAILED, MZ_ZIP_TOTAL_ERRORS } mz_zip_error; typedef struct { mz_uint64 m_archive_size; mz_uint64 m_central_directory_file_ofs; /* We only support up to UINT32_MAX files in zip64 mode. */ mz_uint32 m_total_files; mz_zip_mode m_zip_mode; mz_zip_type m_zip_type; mz_zip_error m_last_error; mz_uint64 m_file_offset_alignment; mz_alloc_func m_pAlloc; mz_free_func m_pFree; mz_realloc_func m_pRealloc; void *m_pAlloc_opaque; mz_file_read_func m_pRead; mz_file_write_func m_pWrite; mz_file_needs_keepalive m_pNeeds_keepalive; void *m_pIO_opaque; mz_zip_internal_state *m_pState; } mz_zip_archive; typedef struct { mz_zip_archive *pZip; mz_uint flags; int status; #ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS mz_uint file_crc32; #endif mz_uint64 read_buf_size, read_buf_ofs, read_buf_avail, comp_remaining, out_buf_ofs, cur_file_ofs; mz_zip_archive_file_stat file_stat; void *pRead_buf; void *pWrite_buf; size_t out_blk_remain; tinfl_decompressor inflator; } mz_zip_reader_extract_iter_state; /* -------- ZIP reading */ /* Inits a ZIP archive reader. */ /* These functions read and validate the archive's central directory. */ mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags); mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags); #ifndef MINIZ_NO_STDIO /* Read a archive from a disk file. */ /* file_start_ofs is the file offset where the archive actually begins, or 0. */ /* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. If zero the entire file is treated as the archive. */ mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); /* Read an archive from an already opened FILE, beginning at the current file position. */ /* The archive is assumed to be archive_size bytes long. If archive_size is < 0, then the entire rest of the file is assumed to contain the archive. */ /* The FILE will NOT be closed when mz_zip_reader_end() is called. */ mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags); #endif /* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. */ mz_bool mz_zip_reader_end(mz_zip_archive *pZip); /* -------- ZIP reading or writing */ /* Clears a mz_zip_archive struct to all zeros. */ /* Important: This must be done before passing the struct to any mz_zip functions. */ void mz_zip_zero_struct(mz_zip_archive *pZip); mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip); mz_zip_type mz_zip_get_type(mz_zip_archive *pZip); /* Returns the total number of files in the archive. */ mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip); mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip); MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip); /* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */ size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n); /* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this field. */ /* Note that the m_last_error functionality is not thread safe. */ mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num); mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip); mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip); mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip); const char *mz_zip_get_error_string(mz_zip_error mz_err); /* MZ_TRUE if the archive file entry is a directory entry. */ mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); /* MZ_TRUE if the file is encrypted/strong encrypted. */ mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); /* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch file. */ mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index); /* Retrieves the filename of an archive file entry. */ /* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. */ mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); /* Attempts to locates a file in the archive's central directory. */ /* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */ /* Returns -1 if the file cannot be found. */ int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); int mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index); /* Returns detailed information about an archive file entry. */ mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); /* MZ_TRUE if the file is in zip64 format. */ /* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 extended file information fields in the central directory. */ mz_bool mz_zip_is_zip64(mz_zip_archive *pZip); /* Returns the total central directory size in bytes. */ /* The current max supported size is <= MZ_UINT32_MAX. */ size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip); /* Extracts a archive file to a memory buffer using no memory allocation. */ /* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */ mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); /* Extracts a archive file to a memory buffer. */ mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); /* Extracts a archive file to a dynamically allocated heap buffer. */ /* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */ /* Returns NULL and sets the last error on failure. */ void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); /* Extracts a archive file using a callback function to output the file's data. */ mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); /* Extract a file iteratively */ mz_zip_reader_extract_iter_state* mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); mz_zip_reader_extract_iter_state* mz_zip_reader_extract_file_iter_new(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); size_t mz_zip_reader_extract_iter_read(mz_zip_reader_extract_iter_state* pState, void* pvBuf, size_t buf_size); mz_bool mz_zip_reader_extract_iter_free(mz_zip_reader_extract_iter_state* pState); #ifndef MINIZ_NO_STDIO /* Extracts a archive file to a disk file and sets its last accessed and modified times. */ /* This function only extracts files, not archive directory records. */ mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); /* Extracts a archive file starting at the current position in the destination FILE stream. */ mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags); mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags); #endif #if 0 /* TODO */ typedef void *mz_zip_streaming_extract_state_ptr; mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); uint64_t mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); uint64_t mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, uint64_t new_ofs); size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size); mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState); #endif /* This function compares the archive's local headers, the optional local zip64 extended information block, and the optional descriptor following the compressed data vs. the data in the central directory. */ /* It also validates that each file can be successfully uncompressed unless the MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY is specified. */ mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags); /* Validates an entire archive by calling mz_zip_validate_file() on each file. */ mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags); /* Misc utils/helpers, valid for ZIP reading or writing */ mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr); mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr); /* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */ mz_bool mz_zip_end(mz_zip_archive *pZip); /* -------- ZIP writing */ #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS /* Inits a ZIP archive writer. */ /*Set pZip->m_pWrite (and pZip->m_pIO_opaque) before calling mz_zip_writer_init or mz_zip_writer_init_v2*/ /*The output is streamable, i.e. file_ofs in mz_file_write_func always increases only by n*/ mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags); mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags); #ifndef MINIZ_NO_STDIO mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags); mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags); #endif /* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. */ /* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. */ /* For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). */ /* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. */ /* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before */ /* the archive is finalized the file's central directory will be hosed. */ mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); /* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. */ /* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */ /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); /* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with already compressed data. */ /* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */ mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len); /* Adds the contents of a file to an archive. This function also records the disk file's modified time into the archive. */ /* File data is supplied via a read callback function. User mz_zip_writer_add_(c)file to add a file directly.*/ mz_bool mz_zip_writer_add_read_buf_callback(mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void* callback_opaque, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len); #ifndef MINIZ_NO_STDIO /* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. */ /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); /* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */ mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len); #endif /* Adds a file to an archive by fully cloning the data from another archive. */ /* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the compressed data. */ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index); /* Finalizes the archive by writing the central directory records followed by the end of central directory record. */ /* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */ /* An archive must be manually finalized by calling this function for it to be valid. */ mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); /* Finalizes a heap archive, returning a poiner to the heap block and its size. */ /* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */ mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize); /* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */ /* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). */ mz_bool mz_zip_writer_end(mz_zip_archive *pZip); /* -------- Misc. high-level helper functions: */ /* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. */ /* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up state (without a central directory). */ /* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */ /* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate the file (so the old central dir would be at the end) if something goes wrong. */ mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr); /* Reads a single file from an archive into a heap block. */ /* If pComment is not NULL, only the file with the specified comment will be extracted. */ /* Returns NULL on failure. */ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags); void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr); #endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */ #ifdef __cplusplus } #endif #endif /* MINIZ_NO_ARCHIVE_APIS */ camlpdf-2.8.1/mkinstall000077500000000000000000000001051477056064700150700ustar00rootroot00000000000000#!/bin/bash make clean; make; ocamlfind remove camlpdf; make install camlpdf-2.8.1/old/000077500000000000000000000000001477056064700137265ustar00rootroot00000000000000camlpdf-2.8.1/old/README.md000066400000000000000000000000751477056064700152070ustar00rootroot00000000000000Some old, unfinished modules from CamlPDF's very early life. camlpdf-2.8.1/old/pdfcff.ml000066400000000000000000001745461477056064700155310ustar00rootroot00000000000000(* Convert a CFF Type 1 Font to a Type 3 font. *) open Pdfutil open Pdfio type dictop = | IntOp of int32 | RealOp of float | Operator of int | Operator2 of int let read_card8 b = i32toi (getval_32 b 8) let read_card16 b = i32toi (getval_32 b 16) let discard_bytes b n = for x = 1 to n do ignore (getval_32 b 8) done let read_string b l = let chars = ref [] in for x = 1 to l do chars =| char_of_int (i32toi (getval_32 b 8)) done; implode (rev !chars) let read_index b = let count = read_card16 b in if count = 0 then [] else let offsize = read_card8 b * 8 and offsets = ref [] in for x = 1 to count + 1 do offsets =| i32toi (getval_32 b offsize) done; let offsets = rev !offsets in map (fun (x, y) -> y - x) (pairs offsets) (* Read a dictionary, creating a dictop list, and parse to (key, value) pairs. l is the length of the dictionary. *) let rec read_float_dict_item prev n_read b = match i32toi (getval_32 b 4) with | 0xF -> align b; ((n_read + 2) / 2), Scanf.sscanf (implode (rev prev)) "%f" ident | 0x0 -> read_float_dict_item ('0'::prev) (n_read + 1) b | 0x1 -> read_float_dict_item ('1'::prev) (n_read + 1) b | 0x2 -> read_float_dict_item ('2'::prev) (n_read + 1) b | 0x3 -> read_float_dict_item ('3'::prev) (n_read + 1) b | 0x4 -> read_float_dict_item ('4'::prev) (n_read + 1) b | 0x5 -> read_float_dict_item ('5'::prev) (n_read + 1) b | 0x6 -> read_float_dict_item ('6'::prev) (n_read + 1) b | 0x7 -> read_float_dict_item ('7'::prev) (n_read + 1) b | 0x8 -> read_float_dict_item ('8'::prev) (n_read + 1) b | 0x9 -> read_float_dict_item ('9'::prev) (n_read + 1) b | 0xA -> read_float_dict_item ('.'::prev) (n_read + 1) b | 0xB -> read_float_dict_item ('E'::prev) (n_read + 1) b | 0xC -> read_float_dict_item ('-'::'E'::prev) (n_read + 1) b | 0xD -> read_float_dict_item prev (n_read + 1) b | 0xE -> read_float_dict_item ('-'::prev) (n_read + 1) b | _ -> assert false let read_dict_item b = let b1 = read_card8 b in if b1 >= 0 && b1 <= 21 then if b1 = 12 then let b2 = read_card8 b in 2, Operator2 b2 else 1, Operator b1 else if b1 = 28 then let ob1 = read_card8 b in let ob2 = read_card8 b in 3, IntOp (i32ofi ((ob1 lsl 8) lor ob2)) else if b1 = 29 then let ob1 = getval_32 b 8 in let ob2 = getval_32 b 8 in let ob3 = getval_32 b 8 in let ob4 = getval_32 b 8 in let v = lor32 (lor32 (lsl32 ob1 24) (lsl32 ob2 16)) (lor32 (lsl32 ob3 8) ob4) in 5, IntOp v else if b1 >= 32 && b1 <= 246 then 1, IntOp (i32ofi (b1 - 139)) else if b1 >= 247 && b1 <= 250 then let ob1 = read_card8 b in 2, IntOp (i32ofi ((b1 - 247) * 256 + ob1 + 108)) else if b1 >= 251 && b1 <= 254 then let ob1 = read_card8 b in 2, IntOp (i32ofi ((~- (b1 - 251)) * 256 - ob1 - 108)) else if b1 = 30 then let bytes_read, num = read_float_dict_item [] 0 b in bytes_read + 1, RealOp num else raise (Pdf.PDFError "bad operator/operand in read_dict_item") let rec read_dict prev b l = if l <= 0 then rev prev else let bytes_read, op = read_dict_item b in read_dict (op::prev) b (l - bytes_read) (* In code, out code *) let standard_encoding = [(0, 0); (1, 0); (2, 0); (3, 0); (4, 0); (5, 0); (6, 0); (7, 0); (8, 0); (9, 0); (10, 0); (11, 0); (12, 0); (13, 0); (14, 0); (15, 0); (16, 0); (17, 0); (18, 0); (19, 0); (20, 0); (21, 0); (22, 0); (23, 0); (24, 0); (25, 0); (26, 0); (27, 0); (28, 0); (29, 0); (30, 0); (31, 0); (32, 1); (33, 2); (34, 3); (35, 4); (36, 5); (37, 6); (38, 7); (39, 8); (40, 9); (41, 10); (42, 11); (43, 12); (44, 13); (45, 14); (46, 15); (47, 16); (48, 17); (49, 18); (50, 19); (51, 20); (52, 21); (53, 22); (54, 23); (55, 24); (56, 25); (57, 26); (58, 27); (59, 28); (60, 29); (61, 30); (62, 31); (63, 32); (64, 33); (65, 34); (66, 35); (67, 36); (68, 37); (69, 38); (70, 39); (71, 40); (72, 41); (73, 42); (74, 43); (75, 44); (76, 45); (77, 46); (78, 47); (79, 48); (80, 49); (81, 50); (82, 51); (83, 52); (84, 53); (85, 54); (86, 55); (87, 56); (88, 57); (89, 58); (90, 59); (91, 60); (92, 61); (93, 62); (94, 63); (95, 64); (96, 65); (97, 66); (98, 67); (99, 68); (100, 69); (101, 70); (102, 71); (103, 72); (104, 73); (105, 74); (106, 75); (107, 76); (108, 77); (109, 78); (110, 79); (111, 80); (112, 81); (113, 82); (114, 83); (115, 84); (116, 85); (117, 86); (118, 87); (119, 88); (120, 89); (121, 90); (122, 91); (123, 92); (124, 93); (125, 94); (126, 95); (127, 0); (128, 0); (129, 0); (130, 0); (131, 0); (132, 0); (133, 0); (134, 0); (135, 0); (136, 0); (137, 0); (138, 0); (139, 0); (140, 0); (141, 0); (142, 0); (143, 0); (144, 0); (145, 0); (146, 0); (147, 0); (148, 0); (149, 0); (150, 0); (151, 0); (152, 0); (153, 0); (154, 0); (155, 0); (156, 0); (157, 0); (158, 0); (159, 0); (160, 0); (161, 96); (162, 97); (163, 98); (164, 99); (165, 100); (166, 101); (167, 102); (168, 103); (169, 104); (170, 105); (171, 106); (172, 107); (173, 108); (174, 109); (175, 110); (176, 0); (177, 111); (178, 112); (179, 113); (180, 114); (181, 0); (182, 115); (183, 116); (184, 117); (185, 118); (186, 119); (187, 120); (188, 121); (189, 122); (190, 0); (191, 123); (192, 0); (193, 124); (194, 125); (195, 126); (196, 127); (197, 128); (198, 129); (199, 130); (200, 131); (201, 0); (202, 132); (203, 133); (204, 0); (205, 134); (206, 135); (207, 136); (208, 137); (209, 0); (210, 0); (211, 0); (212, 0); (213, 0); (214, 0); (215, 0); (216, 0); (217, 0); (218, 0); (219, 0); (220, 0); (221, 0); (222, 0); (223, 0); (224, 0); (225, 138); (226, 0); (227, 139); (228, 0); (229, 0); (230, 0); (231, 0); (232, 140); (233, 141); (234, 142); (235, 143); (236, 0); (237, 0); (238, 0); (239, 0); (240, 0); (241, 144); (242, 0); (243, 0); (244, 0); (245, 145); (246, 0); (247, 0); (248, 146); (249, 147); (250, 148); (251, 149); (252, 0); (253, 0); (254, 0); (255, 0)] let expert_encoding = [(0, 0); (1, 0); (2, 0); (3, 0); (4, 0); (5, 0); (6, 0); (7, 0); (8, 0); (9, 0); (10, 0); (11, 0); (12, 0); (13, 0); (14, 0); (15, 0); (16, 0); (17, 0); (18, 0); (19, 0); (20, 0); (21, 0); (22, 0); (23, 0); (24, 0); (25, 0); (26, 0); (27, 0); (28, 0); (29, 0); (30, 0); (31, 0); (32, 1); (33, 229); (34, 230); (35, 0); (36, 231); (37, 232); (38, 233); (39, 234); (40, 235); (41, 236); (42, 237); (43, 238); (44, 13); (45, 14); (46, 15); (47, 99); (48, 239); (49, 240); (50, 241); (51, 242); (52, 243); (53, 244); (54, 245); (55, 246); (56, 247); (57, 248); (58, 27); (59, 28); (60, 249); (61, 250); (62, 251); (63, 252); (64, 0); (65, 253); (66, 254); (67, 255); (68, 256); (69, 257); (70, 0); (71, 0); (72, 0); (73, 258); (74, 0); (75, 0); (76, 259); (77, 260); (78, 261); (79, 262); (80, 0); (81, 0); (82, 263); (83, 264); (84, 265); (85, 0); (86, 266); (87, 109); (88, 110); (89, 267); (90, 268); (91, 269); (92, 0); (93, 270); (94, 271); (95, 272); (96, 273); (97, 274); (98, 275); (99, 276); (100, 277); (101, 278); (102, 279); (103, 280); (104, 281); (105, 282); (106, 283); (107, 284); (108, 285); (109, 286); (110, 287); (111, 288); (112, 289); (113, 290); (114, 291); (115, 292); (116, 293); (117, 294); (118, 295); (119, 296); (120, 297); (121, 298); (122, 299); (123, 300); (124, 301); (125, 302); (126, 303); (127, 0); (128, 0); (129, 0); (130, 0); (131, 0); (132, 0); (133, 0); (134, 0); (135, 0); (136, 0); (137, 0); (138, 0); (139, 0); (140, 0); (141, 0); (142, 0); (143, 0); (144, 0); (145, 0); (146, 0); (147, 0); (148, 0); (149, 0); (150, 0); (151, 0); (152, 0); (153, 0); (154, 0); (155, 0); (156, 0); (157, 0); (158, 0); (159, 0); (160, 0); (161, 304); (162, 305); (163, 306); (164, 0); (165, 0); (166, 307); (167, 308); (168, 309); (169, 310); (170, 311); (171, 0); (172, 312); (173, 0); (174, 0); (175, 313); (176, 0); (177, 0); (178, 314); (179, 315); (180, 0); (181, 0); (182, 316); (183, 317); (184, 318); (185, 0); (186, 0); (187, 0); (188, 158); (189, 155); (190, 163); (191, 319); (192, 320); (193, 321); (194, 322); (195, 323); (196, 324); (197, 325); (198, 0); (199, 0); (200, 326); (201, 150); (202, 164); (203, 169); (204, 327); (205, 328); (206, 329); (207, 330); (208, 331); (208, 332); (209, 332); (210, 333); (211, 334); (212, 335); (213, 336); (214, 337); (215, 338); (216, 339); (217, 340); (218, 341); (219, 342); (220, 343); (221, 344); (222, 345); (223, 346); (224, 347); (225, 348); (226, 349); (227, 350); (228, 351); (229, 352); (230, 353); (231, 354); (232, 355); (233, 356); (234, 357); (235, 358); (236, 359); (237, 360); (238, 361); (239, 362); (240, 363); (241, 364); (242, 365); (243, 366); (244, 367); (245, 268); (246, 369); (247, 370); (248, 371); (249, 372); (250, 373); (251, 374); (252, 375); (253, 376); (254, 377); (255, 378)] let sids = [(0, ".notdef"); (1, "space"); (2, "exclam"); (3, "quotedbl"); (4, "numbersign"); (5, "dollar"); (6, "percent"); (7, "ampersand"); (8, "quoteright"); (9, "parenleft"); (10, "parenright"); (11, "asterisk"); (12, "plus"); (13, "comma"); (14, "hyphen"); (15, "period"); (16, "slash"); (17, "zero"); (18, "one"); (19, "two"); (20, "three"); (21, "four"); (22, "five"); (23, "six"); (24, "seven"); (25, "eight"); (26, "nine"); (27, "colon"); (28, "semicolon"); (29, "less"); (30, "equal"); (31, "greater"); (32, "question"); (33, "at"); (34, "A"); (35, "B"); (36, "C"); (37, "D"); (38, "E"); (39, "F"); (40, "G"); (41, "H"); (42, "I"); (43, "J"); (44, "K"); (45, "L"); (46, "M"); (47, "N"); (48, "O"); (49, "P"); (50, "Q"); (51, "R"); (52, "S"); (53, "T"); (54, "U"); (55, "V"); (56, "W"); (57, "X"); (58, "Y"); (59, "Z"); (60, "bracketleft"); (61, "backslash"); (62, "bracketright"); (63, "asciicircum"); (64, "underscore"); (65, "quoteleft"); (66, "a"); (67, "b"); (68, "c"); (69, "d"); (70, "e"); (71, "f"); (72, "g"); (73, "h"); (74, "i"); (75, "j"); (76, "k"); (77, "l"); (78, "m"); (79, "n"); (80, "o"); (81, "p"); (82, "q"); (83, "r"); (84, "s"); (85, "t"); (86, "u"); (87, "v"); (88, "w"); (89, "x"); (90, "y"); (91, "z"); (92, "braceleft"); (93, "bar"); (94, "braceright"); (95, "asciitilde"); (96, "exclamdown"); (97, "cent"); (98, "sterling"); (99, "fraction"); (100, "yen"); (101, "florin"); (102, "section"); (103, "currency"); (104, "quotesingle"); (105, "quotedblleft"); (106, "guillemotleft"); (107, "guilsinglleft"); (108, "guilsinglright"); (109, "fi"); (110, "fl"); (111, "endash"); (112, "dagger"); (113, "daggerdbl"); (114, "periodcentered"); (115, "paragraph"); (116, "bullet"); (117, "quotesinglbase"); (118, "quotedblbase"); (119, "quotedblright"); (120, "guillemotright"); (121, "ellipsis"); (122, "perthousand"); (123, "questiondown"); (124, "grave"); (125, "acute"); (126, "circumflex"); (127, "tilde"); (128, "macron"); (129, "breve"); (130, "dotaccent"); (131, "dieresis"); (132, "ring"); (133, "cedilla"); (134, "hungarumlaut"); (135, "ogonek"); (136, "caron"); (137, "emdash"); (138, "AE"); (139, "ordfeminine"); (140, "Lslash"); (141, "Oslash"); (142, "OE"); (143, "ordmasculine"); (144, "ae"); (145, "dotlessi"); (146, "lslash"); (147, "oslash"); (148, "oe"); (149, "germandbls"); (150, "onesuperior"); (151, "logicalnot"); (152, "mu"); (153, "trademark"); (154, "Eth"); (155, "onehalf"); (156, "plusminus"); (157, "Thorn"); (158, "onequarter"); (159, "divide"); (160, "brokenbar"); (161, "degree"); (162, "thorn"); (163, "threequarters"); (164, "twosuperior"); (165, "registered"); (166, "minus"); (167, "eth"); (168, "multiply"); (169, "threesuperior"); (170, "copyright"); (171, "Aacute"); (172, "Acircumflex"); (173, "Adieresis"); (174, "Agrave"); (175, "Aring"); (176, "Atilde"); (177, "Ccedilla"); (178, "Eacute"); (179, "Ecircumflex"); (180, "Edieresis"); (181, "Egrave"); (182, "Iacute"); (183, "Icircumflex"); (184, "Idieresis"); (185, "Igrave"); (186, "Ntilde"); (187, "Oacute"); (188, "Ocircumflex"); (189, "Odieresis"); (190, "Ograve"); (191, "Otilde"); (192, "Scaron"); (193, "Uacute"); (194, "Ucircumflex"); (195, "Udieresis"); (196, "Ugrave"); (197, "Yacute"); (198, "Ydieresis"); (199, "Zcaron"); (200, "aacute"); (201, "acircumflex"); (202, "adieresis"); (203, "agrave"); (204, "aring"); (205, "atilde"); (206, "ccedilla"); (207, "eacute"); (208, "ecircumflex"); (209, "edieresis"); (210, "egrave"); (211, "iacute"); (212, "icircumflex"); (213, "idieresis"); (214, "igrave"); (215, "ntilde"); (216, "oacute"); (217, "ocircumflex"); (218, "odieresis"); (219, "ograve"); (220, "otilde"); (221, "scaron"); (222, "uacute"); (223, "ucircumflex"); (224, "udieresis"); (225, "ugrave"); (226, "yacute"); (227, "ydieresis"); (228, "zcaron"); (229, "exclamsmall"); (230, "Hungarumlautsmall"); (231, "dollaroldstyle"); (232, "dollarsuperior"); (233, "ampersandsmall"); (234, "Acutesmall"); (235, "parenleftsuperior"); (236, "parenrightsuperior"); (237, "twodotenleader"); (238, "onedotenleader"); (239, "zerooldstyle"); (240, "oneoldstyle"); (241, "twooldstyle"); (242, "threeoldstyle"); (243, "fouroldstyle"); (244, "fiveoldstyle"); (245, "sixoldstyle"); (246, "sevenoldstyle"); (247, "eightoldstyle"); (248, "nineoldstyle"); (249, "commasuperior"); (250, "threequartersemdash"); (251, "periodsuperior"); (252, "questionsmall"); (253, "asuperior"); (254, "bsuperior"); (255, "centsuperior"); (256, "dsuperior"); (257, "esuperior"); (258, "isuperior"); (259, "lsuperior"); (260, "msuperior"); (261, "nsuperior"); (262, "osuperior"); (263, "rsuperior"); (264, "ssuperior"); (265, "tsuperior"); (266, "ff"); (267, "ffi"); (268, "ffl"); (269, "parenleftinferior"); (270, "parenrightinferior"); (271, "Circumflexsmall"); (272, "hyphensuperior"); (273, "Gravesmall"); (274, "Asmall"); (275, "Bsmall"); (276, "Csmall"); (277, "Dsmall"); (278, "Esmall"); (279, "Fsmall"); (280, "Gsmall"); (281, "Hsmall"); (282, "Ismall"); (283, "Jsmall"); (284, "Ksmall"); (285, "Lsmall"); (286, "Msmall"); (287, "Nsmall"); (288, "Osmall"); (289, "Psmall"); (290, "Qsmall"); (291, "Rsmall"); (292, "Ssmall"); (293, "Tsmall"); (294, "Usmall"); (295, "Vsmall"); (296, "Wsmall"); (297, "Xsmall"); (298, "Ysmall"); (299, "Zsmall"); (300, "colonmonetary"); (301, "onefitted"); (302, "rupiah"); (303, "Tildesmall"); (304, "exclamdownsmall"); (305, "centoldstyle"); (306, "Lslashsmall"); (307, "Scaronsmall"); (308, "Zcaronsmall"); (309, "Dieresissmall"); (310, "Brevesmall"); (311, "Caronsmall"); (312, "Dotaccentsmall"); (313, "Macronsmall"); (314, "figuredash"); (315, "hypheninferior"); (316, "Ogoneksmall"); (317, "Ringsmall"); (318, "Cedillasmall"); (319, "questionsmalldown"); (320, "oneeighth"); (321, "threeeighths"); (322, "fiveeighths"); (323, "seveneighths"); (324, "onethird"); (325, "twothirds"); (326, "zerosuperior"); (327, "foursuperior"); (328, "fivesuperior"); (329, "sixsuperior"); (330, "sevensuperior"); (331, "eightsuperior"); (332, "ninesuperior"); (333, "zeroinferior"); (334, "oneinferior"); (335, "twoinferior"); (336, "threeinferior"); (337, "fourinferior"); (338, "fiveinferior"); (339, "sixinferior"); (340, "seveninferior"); (341, "eightinferior"); (342, "nineinferior"); (343, "centinferior"); (344, "dollarinferior"); (345, "periodinferior"); (346, "commainferior"); (347, "Agravesmall"); (348, "Aacutesmall"); (349, "Acircumflexsmall"); (350, "Atildesmall"); (351, "Adieresissmall"); (352, "Aringsmall"); (353, "AEsmall"); (354, "Ccedillasmall"); (355, "Egravesmall"); (356, "Eacutesmall"); (357, "Ecircumflexsmall"); (358, "Edieresissmall"); (359, "Igravesmall"); (360, "Iacutesmall"); (361, "Icircumflexsmall"); (362, "Idieresissmall"); (363, "Ethsmall"); (364, "Ntildesmall"); (365, "Ogravesmall"); (366, "Oacutesmall"); (367, "Ocircumflexsmall"); (368, "Otildesmall"); (369, "Odieresissmall"); (370, "OEsmall"); (371, "Oslashsmall"); (372, "Ugravesmall"); (373, "Uacutesmall"); (374, "Ucircumflexsmall"); (375, "Udieresissmall"); (376, "Yacutesmall"); (377, "Thornsmall"); (378, "Ydieresissmall"); (379, "001.000"); (380, "001.001"); (381, "001.002"); (382, "001.003"); (383, "Black"); (384, "Bold"); (385, "Book"); (386, "Light"); (387, "Medium"); (388, "Regular"); (389, "Roman"); (390, "Semibold")] (* Read entries from the topdict, returning a list of the data therein. At the moment, we ignore anything we're not interested in, substituting defaults as appropriate, returning a list. *) type topdict_entry = | CharStringType of int | CharSetOffset of int | EncodingOffset of int | CharStringOffset of int | PrivateDict of int * int (*i (offset, length) i*) | FontMatrix of Pdftransform.transform_matrix let parse_topdict_entry = function | Operator2 6, [IntOp x] -> Some (CharStringType (i32toi x)) | Operator 15, [IntOp x] -> Some (CharSetOffset (i32toi x)) | Operator 16, [IntOp x] -> Some (EncodingOffset (i32toi x)) | Operator 17, [IntOp x] -> Some (CharStringOffset (i32toi x)) | Operator 18, [IntOp size; IntOp offset] -> Some (PrivateDict (i32toi offset, i32toi size)) | Operator2 7, [a; b; c; d; e; f] -> let getnum = function | IntOp i -> Int32.to_float i | RealOp r -> r | _ -> Printf.eprintf "cff.ml: bad mat%!"; 0. in Some (FontMatrix {Pdftransform.a = getnum a; Pdftransform.b = getnum b; Pdftransform.c = getnum c; Pdftransform.d = getnum d; Pdftransform.e = getnum e; Pdftransform.f = getnum f}) | _ -> None let rec read_dict_sections prev ops = match let operands, more = cleavewhile (function Operator _ | Operator2 _ -> false | _ -> true) ops in match more with | Operator x::rest -> Some (Operator x, operands, rest) | Operator2 x::rest -> Some (Operator2 x, operands, rest) | _ -> None with | Some (Operator x, ops, more) -> read_dict_sections ((Operator x, ops)::prev) more | Some (Operator2 x, ops, more) -> read_dict_sections ((Operator2 x, ops)::prev) more | _ -> rev prev let parse_topdict ops = option_map parse_topdict_entry (read_dict_sections [] ops) let string_of_topdict_entry = function | CharStringType i -> "CharStringType is " ^ string_of_int i ^ "\n" | CharSetOffset i -> "CharSetOffset is " ^ string_of_int i ^ "\n" | EncodingOffset i -> "EncodingOffset is " ^ string_of_int i ^ "\n" | CharStringOffset i -> "CharStringOffset is " ^ string_of_int i ^ "\n" | PrivateDict (offset, size) -> "PrivateDict offset is " ^ string_of_int offset ^ " and size " ^ string_of_int size ^ "\n" | FontMatrix m -> "FontMatrix is " ^ Pdftransform.string_of_matrix m ^ "\n" (* Same for private dictionary *) type privatedict_entry = | Subrs of int let parse_privatedict_entry = function | Operator 19, [IntOp offset] -> Some (Subrs (i32toi offset)) | _ -> None let parse_privatedict ops = option_map parse_privatedict_entry (read_dict_sections [] ops) let string_of_privatedict_entry = function | Subrs offset -> "Subrs: offset is " ^ string_of_int offset ^ "\n" let dbg = ref false (* Read the encoding in b at offset off *) let read_encoding b = function | 0 -> if !dbg then flprint "read_encoding: This font uses the standard encoding\n"; standard_encoding, false | 1 -> if !dbg then flprint "read_encoding: This font uses the expert encoding\n"; expert_encoding, false | off -> if !dbg then flprint "read_encoding: This font uses its own encoding\n"; discard_bytes b off; match read_card8 b with | 0 -> if !dbg then flprint "read_encoding: Format type 0\n"; let numglyphs = read_card8 b in if !dbg then Printf.printf "there are %i encoding entries\n" numglyphs; let codes = ref [] in for x = 1 to numglyphs do codes =| read_card8 b done; if !codes = [] then [], true else combine (rev !codes) (ilist 1 numglyphs), true | 1 -> if !dbg then flprint "read_encoding: Format type 1\n"; let numranges = read_card8 b in let encoding = ref [] and n = ref 1 in for x = 1 to numranges do let first = read_card8 b in let nLeft = read_card8 b in encoding =@ rev (combine (ilist first (first + nLeft)) (ilist !n (!n + nLeft))); n := !n + nLeft + 1 done; rev !encoding, true | n -> Printf.eprintf "Unknown encoding format %i (CFF)%!" n; [], false let read_charset b off numglyphs = assert (numglyphs >= 0); discard_bytes b off; let fmt = read_card8 b in match fmt with | 0 -> if !dbg then flprint "Format 0\n"; let sids = ref [] and glyphsleft = ref numglyphs in while !glyphsleft > 0 do sids =| read_card16 b; decr glyphsleft done; rev !sids | 1 -> if !dbg then flprint "Format 1\n"; let sids = ref [] and glyphsleft = ref numglyphs in while !glyphsleft > 0 do let first = read_card16 b in let left = read_card8 b in sids =| ilist first (first + left); glyphsleft -= (left + 1) done; take (flatten (rev !sids)) numglyphs | 2 -> if !dbg then flprint "format 2\n"; let sids = ref [] and glyphsleft = ref numglyphs in while !glyphsleft > 0 do let first = read_card16 b in let left = read_card16 b in sids =| ilist first (first + left); glyphsleft -= (left + 1) done; take (flatten (rev !sids)) numglyphs | _ -> flprint "bad charset format\n"; raise (Pdf.PDFError "CFF: Bad charset format") let read_charstrings b charstringtype off = discard_bytes b off; map (read_string b) (read_index b) type charstring_elt = | CSOperator of int | CSOperator2 of int | CSInt of int32 | CSEndHere let string_of_charstring_elt = function | CSOperator i -> Printf.sprintf "CSOperator: %i\n" i | CSOperator2 i -> Printf.sprintf "CSOperator2: %i\n" i | CSInt i -> Printf.sprintf "CSInt %li\n" i | CSEndHere -> "CSEndHere\n" let string_of_charstring elts = fold_left ( ^ ) "" (map string_of_charstring_elt elts) (* Parse a charstring from an input *) let lex_charstring_elt hintbits i = let b = i.input_byte () in if b = Pdfio.no_more then raise End_of_file else if b < 11 then CSOperator b else if b = 12 then let b1 = i.input_byte () in CSOperator2 b1 else if b <= 18 then CSOperator b else if b <= 20 then if hintbits = -1 then CSEndHere else begin (* For now, just ignore hint data *) for x = 1 to (hintbits + 7) / 8 do nudge i done; CSOperator b end else if b <= 27 then CSOperator b else if b <= 28 then let b1 = i.input_byte () in let b2 = i.input_byte () in let num = ((b1 land 0b01111111) lsl 8) lor b2 in if (b1 land 0b10000000) <> 0 then CSInt (i32ofi (num - 32768)) else CSInt (i32ofi num) else if b <= 31 then CSOperator b else if b <= 246 then CSInt (i32ofi (b - 139)) else if b <= 250 then let b1 = i.input_byte () in CSInt (i32ofi ((b - 247) * 256 + b1 + 108)) else if b <= 254 then let b1 = i.input_byte () in CSInt (i32ofi ((~-((b - 251) * 256)) - b1 - 108)) else (* 255 *) let ob1 = i32ofi (i.input_byte ()) in let ob2 = i32ofi (i.input_byte ()) in let ob3 = i32ofi (i.input_byte ()) in let ob4 = i32ofi (i.input_byte ()) in CSInt (lor32 (lor32 (lsl32 ob1 24) (lsl32 ob2 16)) (lor32 (lsl32 ob3 8) ob4)) (* Put elements on the stack. On a hint operator, count up what's on the stack, and add one hintbit for each pair of operators. If another operator, clear the stack. On moveto, we're done. *) let count_hintbits i = let hintbits = ref 0 and stk = ref [] and hint_ops = ref [] in try while true do match lex_charstring_elt ~-1 i with | CSOperator ((19 | 1 | 3 | 18 | 23) as p) -> hint_ops =| p; hintbits += length !stk / 2; stk := [] | CSEndHere when (mem 1 !hint_ops || mem 18 !hint_ops) && (not (mem 3 !hint_ops)) && not (mem 23 !hint_ops) -> hintbits += length !stk / 2; raise End_of_file | CSOperator n | CSOperator2 n -> raise End_of_file | x -> stk =| x done; 0 with _ -> !hintbits let lex_charstring s = let elts = ref [] and i = input_of_string s in let hintbits = count_hintbits i in let i = input_of_string s in try while true do elts =| lex_charstring_elt hintbits i done; [] with _ -> rev !elts let mflprint x = () (*i flprint x i*) (* Parse one or more paths into a [Pdfops.op list]*) let rec parse_charstring_inner (cx, cy) stk prev thing = (*i Printf.printf "parse_charstring_inner: %f, %f\n" cx cy; i*) match thing with (* endchar *) | CSOperator 14::_ | [] -> mflprint "op: endchar\n"; if prev = [] then [] else rev (Pdfops.Op_f::prev) (* rmoveto *) | CSOperator 21::t -> mflprint "op: rmoveto\n"; begin match stk with | CSInt y::CSInt x::CSInt _::_ | CSInt y::CSInt x::_ -> let cx = i32tof x +. cx and cy = i32tof y +. cy in parse_charstring_inner (cx, cy) [] (Pdfops.Op_m (cx, cy)::prev) t | _ -> Printf.eprintf "bad rmoveto%!"; raise (Pdf.PDFError "bad rmoveto") end | CSOperator 4::t -> mflprint "op: vmoveto\n"; begin match stk with | CSInt y::CSInt _::_ | CSInt y::_ -> let cy = i32tof y +. cy in parse_charstring_inner (cx, cy) [] (Pdfops.Op_m (cx, cy)::prev) t | _ -> Printf.eprintf "bad vmoveto%!"; raise (Pdf.PDFError "bad vmoveto") end | CSOperator 22::t -> mflprint "op: hmoveto\n"; begin match stk with | CSInt x::CSInt _::_ | CSInt x::_ -> let cx = i32tof x +. cx in parse_charstring_inner (cx, cy) [] (Pdfops.Op_m (cx, cy)::prev) t | _ -> Printf.eprintf "bad hmoveto%!"; raise (Pdf.PDFError "bad hmoveto") end (* vvcurveto *) | CSOperator 26::t -> mflprint "op: vvcurveto\n"; let stk = ref (rev stk) and cx = ref cx and cy = ref cy and ops = ref [] in if length !stk mod 4 > 0 then begin match !stk with | CSInt dx1::CSInt dya::CSInt dxb::CSInt dyb::CSInt dyc::more -> let xa = i32tof dx1 +. !cx and ya = i32tof dya +. !cy in let xb = i32tof dxb +. xa and yb = i32tof dyb +. ya in let xc = i32tof dxb +. xa and yc = i32tof dyc +. yb in ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); cx := xc; cy := yc; stk := more | _ -> raise (Pdf.PDFError "CSOperator 26: bad operands") end; while !stk <> [] do match !stk with | CSInt dya::CSInt dxb::CSInt dyb::CSInt dyc::more -> let xa = !cx and ya = i32tof dya +. !cy in let xb = i32tof dxb +. xa and yb = i32tof dyb +. ya in let xc = i32tof dxb +. xa and yc = i32tof dyc +. yb in ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); cx := xc; cy := yc; stk := more | _ -> raise (Pdf.PDFError "CSOperator 26: bad operands") done; parse_charstring_inner (!cx, !cy) [] (!ops @ prev) t (* rlinecurve *) | CSOperator 25::t -> mflprint "op: rlinecurve\n"; let stk = ref (rev stk) and cx = ref cx and cy = ref cy and ops = ref [] in (* rlinetos *) for x = 1 to (length !stk - 6) / 2 do match !stk with | CSInt dxa::CSInt dya::more -> stk := more; let cx' = !cx +. i32tof dxa and cy' = !cy +. i32tof dya in ops =| Pdfops.Op_l (cx', cy'); cx := cx'; cy := cy' | _ -> raise (Pdf.PDFError "bad: rlinecurve / rlineto") done; (* rrcurvetos *) begin match !stk with | CSInt dxb::CSInt dyb::CSInt dxc::CSInt dyc::CSInt dxd::CSInt dyd::more -> let xb = i32tof dxb +. !cx and yb = i32tof dyb +. !cy in let xc = i32tof dxc +. xb and yc = i32tof dyc +. yb in let xd = i32tof dxd +. xc and yd = i32tof dyd +. yc in ops =| Pdfops.Op_c (xb, yb, xc, yc, xd, yd); cx := xd; cy := yd | _ -> raise (Pdf.PDFError "bad: rlinecurve") end; parse_charstring_inner (!cx, !cy) [] (!ops @ prev) t (* rcurveline *) | CSOperator 24::t -> mflprint "op: rcurveline"; let stk = ref (rev stk) and cx = ref cx and cy = ref cy and ops = ref [] in (* rrcurvetos *) for x = 1 to (length !stk - 2) / 6 do match !stk with | CSInt dxb::CSInt dyb::CSInt dxc::CSInt dyc::CSInt dxd::CSInt dyd::more -> let xb = i32tof dxb +. !cx and yb = i32tof dyb +. !cy in let xc = i32tof dxc +. xb and yc = i32tof dyc +. yb in let xd = i32tof dxd +. xc and yd = i32tof dyd +. yc in ops =| Pdfops.Op_c (xb, yb, xc, yc, xd, yd); cx := xd; cy := yd; stk := more | _ -> raise (Pdf.PDFError "bad: rlinecurve") done; (* rlineto *) begin match !stk with | CSInt dxa::CSInt dya::more -> stk := more; let cx' = !cx +. i32tof dxa and cy' = !cy +. i32tof dya in ops =| Pdfops.Op_l (cx', cy'); cx := cx'; cy := cy' | _ -> raise (Pdf.PDFError "bad: rlinecurve / rlineto") end; parse_charstring_inner (!cx, !cy) [] (!ops @ prev) t (* hhcurveto *) | CSOperator 27::t -> mflprint "op: hhcurveto\n"; let ops = ref [] and stk = ref (rev stk) and cx = ref cx and cy = ref cy in if odd (length !stk) then begin match !stk with | CSInt dy1::CSInt dxa::CSInt dxb::CSInt dyb::CSInt dxc::more -> let xa = i32tof dxa +. !cx and ya = i32tof dy1 +. !cy in let xb = i32tof dxb +. xa and yb = i32tof dyb +. ya in let xc = i32tof dxc +. xb and yc = yb in stk := more; ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); cx := xc; cy := yc | _ -> raise (Pdf.PDFError "hhcurveto: operand problem") end; while !stk <> [] do match !stk with | CSInt dxa::CSInt dxb::CSInt dyb::CSInt dxc::more -> let xa = i32tof dxa +. !cx and ya = !cy in let xb = xa +. i32tof dxb and yb = ya +. i32tof dyb in let xc = xb +. i32tof dxc and yc = yb in stk := more; ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); cx := xc; cy := yc | _ -> raise (Pdf.PDFError "hhcurveto: operand problem") done; parse_charstring_inner (!cx, !cy) [] (!ops @ prev) t (* vhcurveto *) | CSOperator 30::t -> mflprint "vhcurveto:\n"; let ops = ref [] and stk = ref (rev stk) and cx = ref cx and cy = ref cy and starts_horz = ref false in (*i Printf.printf "At start of vhcurveto, cx, cy = %f, %f\n" !cx !cy; * i*) if length !stk mod 8 > 0 && (length !stk - 1) mod 8 > 0 then (* dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf? *) begin match !stk with | [CSInt dy1; CSInt dx2; CSInt dy2; CSInt dx3; CSInt dyf] -> let xa = !cx and ya = !cy +. i32tof dy1 in let xb = xa +. i32tof dx2 and yb = ya +. i32tof dy2 in let xc = xb +. i32tof dx3 and yc = yb +. i32tof dyf in (*i flprint "vhcurveto-A\n"; i*) ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); stk := []; flip starts_horz; cx := xc; cy := yc | CSInt dy1::CSInt dx2::CSInt dy2::CSInt dx3::more -> let xa = !cx and ya = !cy +. i32tof dy1 in let xb = i32tof dx2 +. xa and yb = i32tof dy2 +. ya in let xc = xb +. i32tof dx3 and yc = yb in (*i flprint "vhcurveto-B\n"; Printf.printf "a = %f, %f - b = %f, %f - c = %f, %f\n" xa ya xb yb xc yc; i*) ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); stk := more; flip starts_horz; cx := xc; cy := yc | _ -> raise (Pdf.PDFError "vhcurveto: bad operands") end; (* {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf? vhcurveto *) let add_horz_start p q r s t = let xa = i32tof p +. !cx and ya = !cy in let xb = i32tof q +. xa and yb = i32tof r +. ya in let xc = i32tof t +. xb and yc = i32tof s +. yb in (*i Printf.printf "H %li %li %li %li %li\n" p q r s t; Printf.printf "xa, ya, xb, yb, xc, yc = %f, %f %f, %f %f, %f\n" xa ya xb yb xc yc; i*) ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); cx := xc; cy := yc; (*i Printf.printf "Point is %f, %f\n" !cx !cy; i*) and add_vert_start p q r s t = let xa = !cx and ya = i32tof p +. !cy in let xb = i32tof q +. xa and yb = i32tof r +. ya in let xc = i32tof s +. xb and yc = i32tof t +. yb in (*i Printf.printf "V %li %li %li %li %li\n" p q r s t; Printf.printf "xa, ya, xb, yb, xc, yc = %f, %f %f, %f %f, %f\n" xa ya xb yb xc yc; i*) ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); cx := xc; cy := yc; (*i Printf.printf "Point is %f, %f\n" !cx !cy; i*) in while !stk <> [] do match !stk with | [CSInt dxa; CSInt dxb; CSInt dyb; CSInt dyc; CSInt dyd; CSInt dxe; CSInt dye; CSInt dxf; CSInt dyf] -> (* Two curves, last one free ending *) if !starts_horz then begin add_horz_start dxa dxb dyb dyc 0l; add_vert_start dyd dxe dye dxf dyf end else begin add_vert_start dxa dxb dyb dyc 0l; add_horz_start dyd dxe dye dxf dyf end; stk := []; | CSInt dya::CSInt dxb::CSInt dyb::CSInt dyc:: CSInt dyd::CSInt dxe::CSInt dye::CSInt dxf::more -> (* Two curves, entirely unfree *) if !starts_horz then begin add_horz_start dya dxb dyb dyc 0l; add_vert_start dyd dxe dye dxf 0l end else begin add_vert_start dya dxb dyb dyc 0l; add_horz_start dyd dxe dye dxf 0l end; stk := more; | _ -> raise (Pdf.PDFError "vhcurveto: bad operands") done; parse_charstring_inner (!cx, !cy) [] (!ops @ prev) t (* hvcurveto *) | CSOperator 31::t -> mflprint "hvcurveto\n"; (*i Printf.printf "cx, cy = %f, %f\n" cx cy; i*) let ops = ref [] and stk = ref (rev stk) and cx = ref cx and cy = ref cy and starts_horz = ref true in if length !stk mod 8 > 0 && (length !stk - 1) mod 8 > 0 then (* dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf? *) begin match !stk with | [CSInt dx1; CSInt dx2; CSInt dy2; CSInt dy3; CSInt dxf] -> let xa = i32tof dx1 +. !cx and ya = !cy in let xb = i32tof dx2 +. xa and yb = i32tof dy2 +. ya in let xc = i32tof dxf +. xb and yc = i32tof dy3 +. yb in ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); stk := []; flip starts_horz; cx := xc; cy := yc | CSInt dx1::CSInt dx2::CSInt dy2::CSInt dy3::more -> let xa = i32tof dx1 +. !cx and ya = !cy in let xb = i32tof dx2 +. xa and yb = i32tof dy2 +. ya in let xc = xb and yc = i32tof dy3 +. yb in ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); stk := more; flip starts_horz; cx := xc; cy := yc | _ -> raise (Pdf.PDFError "hvcurveto: bad operands") end; (* {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf? hvcurveto *) let add_horz_start p q r s t = let xa = i32tof p +. !cx and ya = !cy in let xb = i32tof q +. xa and yb = i32tof r +. ya in let xc = i32tof s +. xb and yc = i32tof t +. yb in (*i Printf.printf "add_horz_start: (%f, %f)\n(%f, %f)\n(%f,%f)\n" xa * ya xb yb xc yc; i*) ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); cx := xc; cy := yc; and add_vert_start p q r s t = let xa = !cx and ya = i32tof p +. !cy in let xb = i32tof q +. xa and yb = i32tof r +. ya in let xc = i32tof s +. xb and yc = i32tof t +. yb in (*i Printf.printf "add_vert_start: (%f, %f)\n(%f, %f)\n(%f,%f)\n" xa * ya xb yb xc yc; i*) ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); cx := xc; cy := yc; in while !stk <> [] do match !stk with | [CSInt dxa; CSInt dxb; CSInt dyb; CSInt dyc; CSInt dyd; CSInt dxe; CSInt dye; CSInt dxf; CSInt dyf] -> (* Two curves, last one free ending *) if !starts_horz then begin add_horz_start dxa dxb dyb 0l dyc; add_vert_start dyd dxe dye dxf dyf end else begin add_vert_start dxa dxb dyb dyc 0l; add_horz_start dyd dxe dye dyf dxf end; stk := [] | CSInt dya::CSInt dxb::CSInt dyb::CSInt dyc:: CSInt dyd::CSInt dxe::CSInt dye::CSInt dxf::more -> (* Two curves, entirely unfree *) if !starts_horz then begin add_horz_start dya dxb dyb 0l dyc; add_vert_start dyd dxe dye dxf 0l end else begin add_vert_start dya dxb dyb dyc 0l; add_horz_start dyd dxe dye 0l dxf end; stk := more | _ -> raise (Pdf.PDFError "hvcurveto: bad operands") done; parse_charstring_inner (!cx, !cy) [] (!ops @ prev) t (* rrcurveto *) | CSOperator 8::t -> mflprint "rrcurveto\n"; let ops = ref [] and stk = ref (rev stk) and cx = ref cx and cy = ref cy in while !stk <> [] do match !stk with | CSInt dxa::CSInt dya::CSInt dxb::CSInt dyb::CSInt dxc::CSInt dyc::more -> let xa = !cx +. i32tof dxa and ya = !cy +. i32tof dya in let xb = xa +. i32tof dxb and yb = ya +. i32tof dyb in let xc = xb +. i32tof dxc and yc = yb +. i32tof dyc in stk := more; ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); cx := xc; cy := yc | _ -> raise (Pdf.PDFError "rrcurveto: args not multiple of 6\n") done; parse_charstring_inner (!cx, !cy) [] (!ops @ prev) t (* vlineto *) | CSOperator 7::t -> mflprint "vlineto\n"; let stk = ref (rev stk) and first_is_horz = ref false and ops = ref [] and cx = ref cx and cy = ref cy in (* 1. If odd, do the first one *) if odd (length !stk) then begin begin match !stk with | CSInt dy1::more -> stk := more; ops =| Pdfops.Op_l (!cx, i32tof dy1 +. !cy); cy := i32tof dy1 +. !cy | _ -> raise (Pdf.PDFError "vlineto/odd fail") end; set first_is_horz end; (* 2. Do the rest *) while !stk <> [] do match !stk with | CSInt p::CSInt q::more -> stk := more; if !first_is_horz then begin ops =| Pdfops.Op_l (i32tof p +. !cx, !cy); cx := i32tof p +. !cx; ops =| Pdfops.Op_l (!cx, i32tof q +. !cy); cy := i32tof q +. !cy end else begin ops =| Pdfops.Op_l (!cx, i32tof p +. !cy); cy := i32tof p +. !cy; ops =| Pdfops.Op_l (i32tof q +. !cx, !cy); cx := i32tof q +. !cx end | _ -> raise (Pdf.PDFError "vlineto/odd fail") done; parse_charstring_inner (!cx, !cy) [] (!ops @ prev) t (* rlineto *) | CSOperator 5::t -> mflprint "rlineto\n"; let stk = ref (rev stk) and ops = ref [] and cx = ref cx and cy = ref cy in while !stk <> [] do match !stk with | CSInt dxa::CSInt dyb::more -> stk := more; ops =| Pdfops.Op_l (!cx +. i32tof dxa, !cy +. i32tof dyb); cx := !cx +. i32tof dxa; cy := !cy +. i32tof dyb | _ -> raise (Pdf.PDFError "rlineto") done; parse_charstring_inner (!cx, !cy) [] (!ops @ prev) t (* hlineto *) | CSOperator 6::t -> mflprint "hlineto\n"; if even (length stk) then (* Even: alternating horizontal and vertical segments *) let ops = ref [] and stk = ref (rev stk) and cx = ref cx and cy = ref cy in while !stk <> [] do match !stk with | CSInt dxa::CSInt dyb::more -> stk := more; ops =| Pdfops.Op_l (!cx +. i32tof dxa, !cy); cx := !cx +. i32tof dxa; ops =| Pdfops.Op_l (!cx, !cy +. i32tof dyb); cy := !cy +. i32tof dyb | _ -> Printf.eprintf "%i items on stack\n%!" (length !stk); assert false done; parse_charstring_inner (!cx, !cy) [] (!ops @ prev) t else (* Odd: Horizontal line of length dx1 then alternating vertical and horizontal segments. *) let ops, cx', cy' = match hd (rev stk) with | CSInt dx1 -> let ops = ref [Pdfops.Op_l (cx +. i32tof dx1, cy)] and stk = ref (tl (rev stk)) and cx = ref (cx +. i32tof dx1) and cy = ref cy in while !stk <> [] do match !stk with | CSInt dya::CSInt dxb::more -> stk := more; ops =| Pdfops.Op_l (!cx, !cy +. i32tof dya); cy := !cy +. i32tof dya; ops =| Pdfops.Op_l (!cx +. i32tof dxb, !cy); cx := !cx +. i32tof dxb | _ -> assert false done; !ops, !cx, !cy | _ -> raise (Pdf.PDFError "bad csoperator 6") in parse_charstring_inner (cx', cy') [] (ops @ prev) t | CSOperator2 34::t -> mflprint "hflex\n"; let ops = ref [] in begin match rev stk with | CSInt dx1::CSInt dx2::CSInt dy2::CSInt dx3::CSInt dx4::CSInt dx5::CSInt dx6::more -> let xa = cx +. i32tof dx1 and ya = cy in let xb = xa +. i32tof dx2 and yb = ya +. i32tof dy2 in let xc = xb +. i32tof dx3 and yc = yb in ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); let xa = xc +. i32tof dx4 and ya = yc in let xb = xa +. i32tof dx5 and yb = yc in let xc = xb +. i32tof dx6 and yc = yc in ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); parse_charstring_inner (xc, yc) [] (!ops @ prev) t | _ -> raise (Pdf.PDFError "hflex: bad arguments") end; | CSOperator2 35::t -> mflprint "flex"; let ops = ref [] in begin match rev stk with | CSInt dx1::CSInt dy1::CSInt dx2::CSInt dy2::CSInt dx3::CSInt dy3::CSInt dx4::CSInt dy4:: CSInt dx5::CSInt dy5::CSInt dx6::CSInt dy6::CSInt _::more -> let xa = cx +. i32tof dx1 and ya = cy +. i32tof dy1 in let xb = xa +. i32tof dx2 and yb = ya +. i32tof dy2 in let xc = xb +. i32tof dx3 and yc = yb +. i32tof dy3 in ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); let xa = xc +. i32tof dx4 and ya = yc +. i32tof dy4 in let xb = xa +. i32tof dx5 and yb = ya +. i32tof dy5 in let xc = xb +. i32tof dx6 and yc = yb +. i32tof dy6 in ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); parse_charstring_inner (xc, yc) [] (!ops @ prev) t | _ -> raise (Pdf.PDFError "flex: bad arguments.") end | CSOperator2 36::t -> mflprint "hflex1\n"; (**i Printf.printf "cx = %f, cy = %f\n" cx cy; i*) let ops = ref [] in begin match rev stk with | CSInt dx1::CSInt dy1::CSInt dx2::CSInt dy2::CSInt dx3::CSInt dx4::CSInt dx5::CSInt dy5::CSInt dx6::more -> let xa = cx +. i32tof dx1 and ya = cy +. i32tof dy1 in let xb = xa +. i32tof dx2 and yb = ya +. i32tof dy2 in let xc = xb +. i32tof dx3 and yc = yb in (*i Printf.printf "Curve one: %f %f %f %f %f %f\n" xa ya xb yb xc * yc; i*) ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); let xa = xc +. i32tof dx4 and ya = yc in let xb = xa +. i32tof dx5 and yb = ya +. i32tof dy5 in let xc = xb +. i32tof dx6 and yc = yb in ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); (*i Printf.printf "Curve two: %f %f %f %f %f %f\n" xa ya xb yb * xc yc; i*) parse_charstring_inner (xc, yc) [] (!ops @ prev) t | _ -> raise (Pdf.PDFError "hflex1: bad arguments") end | CSOperator2 37::t -> mflprint "flex1\n"; let ops = ref [] in begin match rev stk with | CSInt dx1::CSInt dy1::CSInt dx2::CSInt dy2::CSInt dx3:: CSInt dy3::CSInt dx4::CSInt dy4::CSInt dx5::CSInt dy5::CSInt d6::more -> let xa = cx +. i32tof dx1 and ya = cy +. i32tof dy1 in let xb = xa +. i32tof dx2 and yb = ya +. i32tof dy2 in let xc = xb +. i32tof dx3 and yc = yb +. i32tof dy3 in ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); let newdx, newdy = let dx = i32tof dx1 +. i32tof dx2 +. i32tof dx3 +. i32tof dx4 +. i32tof dx5 and dy = i32tof dy1 +. i32tof dy2 +. i32tof dy3 +. i32tof dy4 +. i32tof dy5 in if fabs dx > fabs dy then d6, 0l else 0l, d6 in let xa = xc +. i32tof dx4 and ya = yc +. i32tof dy4 in let xb = xa +. i32tof dx5 and yb = ya +. i32tof dy5 in let xc = xb +. i32tof newdx and yc = yb +. i32tof newdy in ops =| Pdfops.Op_c (xa, ya, xb, yb, xc, yc); parse_charstring_inner (xc, yc) [] (!ops @ prev) t | _ -> raise (Pdf.PDFError "flex1: bad arguments") end (* hintmask / cntrmask *) | CSOperator (19 | 20)::t -> parse_charstring_inner (cx, cy) stk prev t (* hint building *) | CSOperator (1 | 3 | 18 | 23)::t -> parse_charstring_inner (cx, cy) [] prev t (* Obsolete: dotsection *) | CSOperator2 0::t -> parse_charstring_inner (cx, cy) stk prev t (* anything else: stick it on the stack *) | (CSOperator n | CSOperator2 n)::t -> Printf.eprintf "CFF: operator %i not understood\n%!" n; parse_charstring_inner (cx, cy) [] prev t | h::t -> parse_charstring_inner (cx, cy) (h::stk) prev t let parse_charstring lexemes = try parse_charstring_inner (0., 0.) [] [] lexemes with e -> (*i Printf.eprintf (Printexc.to_string e); i*) raise e (* Given a op list, debug to letter.pdf *) let debug_letter ops = let page = Pdfpage.blankpage Pdfpaper.a4 in let page = {page with Pdfpage.content = let trop = Pdfops.Op_cm (Pdftransform.matrix_of_op (Pdftransform.Scale ((0., 0.), 0.1, 0.1))) in [Pdfops.stream_of_ops (trop::ops)]} in let pdf, pageroot = Pdfpage.add_pagetree [page] (Pdf.empty ()) in let pdf = Pdfpage.add_root pageroot [] pdf in Pdfwrite.pdf_to_file pdf "letter.pdf" (* The undefined glyph *) let notdef = {Pdfgraphics.elements = []; Pdfgraphics.fonts = []; Pdfgraphics.resources = Pdf.Dictionary []} let parse_cff_font data = let get_bitstream () = bitbytes_of_input (input_of_bytes data) in let b = get_bitstream () in (* Read the header *) let _ = read_card8 b in (* MAJOR *) let _ = read_card8 b in (* MINOR *) let header_size = read_card8 b in let _ = read_card8 b * 4 in (* OFFSIZE*) (* Wind forward past the possible rest of the header *) discard_bytes b (header_size - 4); (* Read the name INDEX *) if !dbg then Printf.printf "Reading the name INDEX\n"; let fontnames = map (read_string b) (read_index b) in if !dbg then begin Printf.printf "There are %i fonts in this CFF:\n" (length fontnames); iter (Printf.printf "%s\n") fontnames; end; (* Read the Top DICT INDEX *) let topdicts = map (read_dict [] b) (read_index b) in (* Read the STRING INDEX. - strings for SIDs *) let strings = let stringnames = map (read_string b) (read_index b) and fst = length sids in if stringnames = [] then [] else combine (ilist fst (fst + length stringnames - 1)) stringnames in if !dbg then begin Printf.printf "have read %i non-standard strings\n" (length strings); iter (function (sid, str) -> Printf.printf "SID, string = %i, %s \n" sid str) strings end; let parsed = parse_topdict (hd topdicts) in if !dbg then flprint "Have read the first font's topdict\n"; (* A. Read encoding (codes to glpyh codes) *) let encodingoffset = match keep (function EncodingOffset _ -> true | _ -> false) parsed with | [EncodingOffset i] -> if !dbg then Printf.printf "An Encoding was found at EncodingOffset %i\n" i; i | [] -> if !dbg then Printf.printf "This fonts uses the standard encoding"; 0(* Standard encoding *) | _ -> raise (Pdf.PDFError "no encoding offset") in let encoding, encoding_was_custom = read_encoding (get_bitstream ()) encodingoffset in if !dbg then begin Printf.printf "Read %i encoding entries\n" (length encoding); iter (function (x, y) -> Printf.printf "%i -> %i\n" x y) encoding; flprint "\n" end; (* C. Read char strings *) let charstringtype = match keep (function CharStringType _ -> true | _ -> false) parsed with | [CharStringType i] -> i | _ -> 2 and charstringoffset = match keep (function CharStringOffset _ -> true | _ -> false) parsed with | [CharStringOffset i] -> i | _ -> raise (Pdf.PDFError "no encoding offset") in if !dbg then Printf.printf "Charstring format is %i\n" charstringtype; let charstrings = read_charstrings (get_bitstream ()) charstringtype charstringoffset in if !dbg then begin Printf.printf "Read %i glyph descriptions\n" (length charstrings); Printf.printf "numglyphs = %i\n" (length charstrings - 1); end; (* B. Read charset (glpyh codes to glyph names) *) let charsetoffset = match keep (function CharSetOffset _ -> true | _ -> false) parsed with | [CharSetOffset i] -> i | _ -> 0 (* No charset offset = ISOAdobe = 0 *) in (*Printf.printf "Charset offset is %i\n" charsetoffset;*) let fontmatrix = match keep (function FontMatrix _ -> true | _ -> false) parsed with | [FontMatrix m] -> m | _ -> Pdftransform.matrix_of_op (Pdftransform.Scale ((0., 0.), 0.001, 0.001)) in let charset = match charsetoffset with | 0 | 1 | 2 -> if !dbg then flprint "***BUILTIN charset"; map fst (sids @ strings) | o -> if !dbg then flprint "***READING charset manually"; read_charset (get_bitstream ()) o (length charstrings - 1) in let gids = match charsetoffset with 0 | 1 | 2 -> indx0 charset | _ -> indx charset in let allids = sids @ strings in let names = map (function c -> lookup_failnull c allids) charset in if !dbg then begin Printf.printf "Read %i (gid, charset SID, glyphname) triples:" (length charset); iter3 (fun gid charset glyphname -> Printf.printf "%i -> %i -> %s, " gid charset glyphname) gids charset names end; let lexed_charstrings = map (fun (_, c) -> lex_charstring c) (combine (ilist 1 (length charstrings)) charstrings) in if !dbg then begin Printf.printf "lexed %i charstrings\n" (length lexed_charstrings); iter2 (fun i s -> Printf.printf "GID %i -> a charstring, " i) (indx lexed_charstrings) (map string_of_charstring lexed_charstrings); end; let parsed_charstrings = map (fun (_, c) -> parse_charstring c) (combine (ilist 1 (length lexed_charstrings)) lexed_charstrings) in if !dbg then flprint "Parsed all charstrings..\n"; let paths = map Pdfgraphics.graphic_of_ops parsed_charstrings in if !dbg then flprint "Built graphic paths from parsed_charstrings\n"; if !dbg then Printf.printf "WE HAVE %i names and %i paths\n" (length names) (length paths); (* Now can build paths from names *) (* To do this, for each thing in "names" with .notdef added, at same position in charset, at same position in parsed_charstrings. *) let path_name_pairs = let charset_gid_pairs = combine charset gids in map2 (fun name charsetchar -> name, (if !dbg then Printf.printf "Starting with name %s -> charset SID %i -> " name charsetchar; match lookup charsetchar charset_gid_pairs with | None -> (if !dbg then flprint "not defined - not in charset\n"; {Pdfgraphics.elements = []; Pdfgraphics.fonts = []; Pdfgraphics.resources = Pdf.Dictionary []}) | Some gid -> if gid + 1 <= length paths && gid + 1 > 0 then (if !dbg then Printf.printf "converted to gid %i\n" gid; select (gid + 1) paths) else (if !dbg then flprint "not defined - gid found but no charstring defined\n"; {Pdfgraphics.elements = []; Pdfgraphics.fonts = []; Pdfgraphics.resources = Pdf.Dictionary []}))) names charset in if !dbg then flprint "Total:\n"; let differences = let gidmap = combine gids charset and charsetmap = combine charset names in option_map (fun incode -> if !dbg then Printf.printf "incode %i -> " incode; match lookup incode encoding with | Some code -> if !dbg then Printf.printf "encoded %i -> " code; if encoding_was_custom then begin match lookup code gidmap with | Some gid -> begin if !dbg then Printf.printf "sid %i -> " code; begin match lookup gid charsetmap with | Some glyphname -> if !dbg then Printf.printf "glyphname %s\n" glyphname; Some (incode, glyphname) | None -> if !dbg then flprint "\n"; None end end | None -> flprint "\n"; None end else begin if !dbg then Printf.printf "sid %i -> " code; begin match lookup code charsetmap with | Some glyphname -> if !dbg then Printf.printf "glyphname %s\n" glyphname; Some (incode, glyphname) | None -> if !dbg then flprint "\n"; None end end | None -> if !dbg then Printf.printf "incode not found in encoding \n"; None ) (ilist 0 255) in path_name_pairs, differences, fontmatrix (* Make a CharProc stream from a graphic. We need to filter out ops we don't want. *) let charprocbytes_of_graphic g matrix = Pdfops.stream_of_ops (Pdfops.Op_d1 (0., 0., 0., 0., 0., 0.):: lose (function | Pdfops.Op_q | Pdfops.Op_Q | Pdfops.Op_cm _ | Pdfops.Op_w _ | Pdfops.Op_J _ | Pdfops.Op_j _ | Pdfops.Op_M _ | Pdfops.Op_ri _ | Pdfops.Op_CS _ | Pdfops.Op_SCN _ | Pdfops.Op_cs _ | Pdfops.Op_scn _ -> true | _ -> false) (Pdfgraphics.ops_of_simple_graphic (Pdfgraphics.transform_graphic matrix g))) (* Calculate the maximal bounding box of some graphics *) let bbox_of_graphics gs = fold_left box_union_float (max_float, min_float, max_float, min_float) (map Pdfgraphics.bbox_of_graphic gs) (* Convert a Pdftext font in Type 1 format to a Pdftext font in type3 font. This involves calculating FontBBox, FontMatrix and CharProcs entries, and removing certain entries from the FontDescriptor *) let to_type3 pdf = function | Pdftext.SimpleFont ({Pdftext.fonttype = Pdftext.Type1; Pdftext.encoding = original_encoding; Pdftext.fontdescriptor = Some ({Pdftext.fontfile = Some Pdftext.FontFile3 fontfileobj} as fontdescriptor)} as fontrec) -> begin try flprint "***inside Pdfcff.to_type3\n"; let parsed_cffdata, differences, fontmatrix = let str = Pdf.direct pdf (Pdf.Indirect fontfileobj) in Pdfcodec.decode_pdfstream pdf str; match str with | Pdf.Stream {contents = (_, Pdf.Got data)} -> begin try parse_cff_font data with e -> Printf.printf "Error %s" (Printexc.to_string e); raise (Pdf.PDFError "CFF Parse failure") end | _ -> raise (Pdf.PDFError "CFF data not a stream") in Printf.printf "parsed_cffdata returned %i things\n" (length parsed_cffdata); let fontdescriptor = fontdescriptor and charprocs = let scalematrix = Pdftransform.matrix_compose fontmatrix (Pdftransform.matrix_of_op (Pdftransform.Scale ((0., 0.), 1000., 1000.))) in map (function (n, g) -> "/" ^ n, Pdf.Indirect (Pdf.addobj pdf (charprocbytes_of_graphic g scalematrix))) parsed_cffdata and fontmatrix = Pdftransform.matrix_of_op (Pdftransform.Scale ((0., 0.), 0.001, 0.001)) and fontbbox = bbox_of_graphics (snd (split parsed_cffdata)) and encoding = let existing_differences = match original_encoding with | Pdftext.CustomEncoding (_, diffs) -> map (fun (x, y) -> y, x) diffs | _ -> [] and new_differences = map (fun (x, y) -> x, "/" ^ y) differences in (* Prefer existing differences over the internal ones we generated *) let final_differences = fold_left (fun acc (code, name) -> add code name acc) new_differences existing_differences in Pdftext.CustomEncoding (Pdftext.ImplicitInFontFile, map (function (x, y) -> y, x) final_differences) in flprint "***All done, CFF font produced\n"; Pdftext.SimpleFont {fontrec with Pdftext.fonttype = Pdftext.Type3 {Pdftext.fontbbox = fontbbox; Pdftext.fontmatrix = fontmatrix; Pdftext.charprocs = charprocs; Pdftext.type3_resources = Pdf.Dictionary []}; Pdftext.encoding = encoding; Pdftext.fontdescriptor = Some fontdescriptor} with e -> Printf.eprintf "Failed to read CFF font with error %s\n%!" (Printexc.to_string e); raise e end | _ -> raise (Pdf.PDFError "Pdfcff.to_type3: This is not a type 1 CFF font") camlpdf-2.8.1/old/pdfcff.mli000066400000000000000000000003311477056064700156560ustar00rootroot00000000000000(** Convert a CFF Type 1 Font to a Type 3 Font. *) (** The Type 3 font is not necessarily valid for inclusion in a PDF, we just intend to use it for rendering. *) val to_type3 : Pdf.t -> Pdftext.font -> Pdftext.font camlpdf-2.8.1/old/pdfgraphics.ml000066400000000000000000001774111477056064700165650ustar00rootroot00000000000000(* Structured Graphics *) open Pdfutil open Pdfio type fpoint = float * float type winding_rule = EvenOdd | NonZero type segment = | Straight of fpoint * fpoint | Bezier of fpoint * fpoint * fpoint * fpoint (* Each segment list may be marked as a hole or not. *) type hole = Hole | Not_hole (* A [subpath] is either closed or open. *) type closure = Closed | Open (* A [subpath] is the pair of a hole and a list of segments. *) type subpath = hole * closure * segment list (* A path is made from a number of subpaths. *) type path = winding_rule * subpath list type tiling = Tiling type function_shading = {funshading_domain : float * float * float * float; funshading_matrix : Pdftransform.transform_matrix; funshading_function : Pdffun.t} type radial_shading = {radialshading_coords : float * float * float * float * float * float; radialshading_domain : float * float; radialshading_function : Pdffun.t list; radialshading_extend : bool * bool} type axial_shading = {axialshading_coords : float * float * float * float; axialshading_domain : float * float; axialshading_function : Pdffun.t list; axialshading_extend : bool * bool} type shading_kind = | FunctionShading of function_shading | AxialShading of axial_shading | RadialShading of radial_shading | FreeFormGouraudShading | LatticeFormGouraudShading | CoonsPatchMesh | TensorProductPatchMesh type shading = {shading_colourspace : Pdf.pdfobject; shading_background : Pdf.pdfobject option; shading_bbox : Pdf.pdfobject option; shading_antialias : bool; shading_matrix : Pdftransform.transform_matrix; shading_extgstate : Pdf.pdfobject; shading : shading_kind} type pattern = | ColouredTilingPattern of tiling | UncolouredTilingPattern of tiling | ShadingPattern of shading type colvals = | Floats of float list | Named of (string * float list) | Pattern of pattern let rec string_of_colvals = function | Floats fs -> "Floats " ^ fold_left ( ^ ) "" (map (function x -> string_of_float x ^ " ") fs) | Named (n, fs) -> "Named " ^ n ^ " " ^ string_of_colvals (Floats fs) | Pattern p -> "Pattern" type objectclass = | PathObject | TextObject | ClippingPathObject | PageDescriptionLevel | ShadingObject | InlineImageObject | ExternalObject let string_of_objectclass = function | PathObject -> "PathObject" | TextObject -> "TextObject" | ClippingPathObject -> "ClippingPathObject" | PageDescriptionLevel -> "PageDescriptionLevel" | ShadingObject -> "ShadingObject" | InlineImageObject -> "InlineImageObject" | ExternalObject -> "ExternalObject" type transparency_attributes = {fill_transparency : float; line_transparency : float} type path_attributes = {path_transform : Pdftransform.transform_matrix; path_fill : (Pdfspace.t * colvals) option; path_line : (Pdfspace.t * colvals) option; path_linewidth : float; path_joinstyle : int; path_capstyle : int; path_dash : float list * float; path_mitrelimit : float; path_transparency : transparency_attributes; path_intent : string} type text_attributes = {textmode : int} type textblock_attributes = {textblock_transform : Pdftransform.transform_matrix} type textblock = text_attributes * Pdfops.t type softmask_subtype = Alpha | Luminosity type transparency_group = {tr_group_colourspace : Pdf.pdfobject option; (* FIXME: This should be colourspace *) isolated : bool; knockout : bool; tr_graphic : t} and softmask = {softmask_subtype : softmask_subtype; transparency_group : transparency_group; softmask_bbox : float * float * float * float; backdrop : float list option; softmask_transfer : Pdffun.t option} and image_attributes = {image_transform : Pdftransform.transform_matrix; image_transparency : float; (* The /ca value *) image_softmask : softmask option} and fontname = string * Pdf.pdfobject (*r Name, font *) (* The main type for a graphic. It must be kept paired with the PDF it comes from, since it will reference objects (fonts, images etc) in that PDF. *) and graphic_elt = | Path of (path * path_attributes) | Text of textblock list * textblock_attributes | MCPoint of string | MCPointProperties of string * Pdf.pdfobject | MCSection of string * graphic_elt list | MCSectionProperties of string * Pdf.pdfobject * graphic_elt list | Image of image_attributes * int (* object number *) | GraphicInlineImage of Pdf.pdfobject * bytes * Pdftransform.transform_matrix | Clip of path * graphic_elt list | Shading of path option * shading * Pdftransform.transform_matrix and t = {elements : graphic_elt list; (* Page content *) fonts : fontname list; (* Fonts *) resources : Pdf.pdfobject} (* Anything else in /Resources *) (* Calculate the bounding box (xmin, xmax, ymin, ymax) of a graphic. *) let bbox_of_segment = function | Straight ((x1, y1), (x2, y2)) -> fmin x1 x2, fmax x1 x2, fmin y1 y2, fmax y1 y2 | Bezier ((x1, y1), (x2, y2), (x3, y3), (x4, y4)) -> fmin (fmin x1 x2) (fmin x3 x4), fmax (fmax x1 x2) (fmax x3 x4), fmin (fmin y1 y2) (fmin y3 y4), fmax (fmax y1 y2) (fmax y3 y4) let bbox_of_path (_, subpaths) = let segments = flatten (map (function (_, _, l) -> l) subpaths) in fold_left box_union_float (max_float, min_float, max_float, min_float) (map bbox_of_segment segments) let rec bbox_of_graphic_inner (xmin, xmax, ymin, ymax) = function | [] -> xmin, xmax, ymin, ymax | (Path (p, _) | Clip (p, _))::t -> bbox_of_graphic_inner (box_union_float (xmin, xmax, ymin, ymax) (bbox_of_path p)) t | h::t -> bbox_of_graphic_inner (xmin, xmax, ymin, ymax) t let bbox_of_graphic graphic = bbox_of_graphic_inner (max_float, min_float, max_float, min_float) graphic.elements (* For debug purposes, build a string of a graphic. *) let string_of_segment = function | Straight ((ax, ay), (bx, by)) -> Printf.sprintf "Straight line: (%f, %f) --> (%f, %f)\n" ax ay bx by | Bezier ((ax, ay), (bx, by), (cx, cy), (dx, dy)) -> Printf.sprintf "Bezier curve: (%f, %f) --> (%f, %f) --> (%f, %f) --> (%f, %f)\n" ax ay bx by cx cy dx dy let string_of_subpath (h, o ,segments) = Printf.sprintf "Hole: %b, Open: %b, segments:%s\n" (h = Hole) (o = Open) (fold_left ( ^ ) "" (map string_of_segment segments)) let string_of_path (windingrule, subpaths) = Printf.sprintf "%s %s" (match windingrule with | EvenOdd -> "Even-odd\n" | NonZero -> "Non-zero\n") (fold_left ( ^ ) "" (map string_of_subpath subpaths)) let string_of_textblock (st, op) = "TEXTPIECE: " ^ Pdfops.string_of_op op ^ "\n" let string_of_font (f, i) = f ^ " " ^ Pdfwrite.string_of_pdf i ^ "\n" let string_of_colvals = function | Floats l -> Printf.sprintf "Floats (%i)" (length l) | Named (s, fl) -> Printf.sprintf "Named %s, Floats (%i)" s (length fl) | Pattern _ -> Printf.sprintf "Pattern" let string_of_attributes a = let line = match a.path_line with | None -> "none" | Some (cs, vals) -> Printf.sprintf "line colourspace is %s, %s vals" (Pdfspace.string_of_colourspace cs) (string_of_colvals vals) and fill = match a.path_fill with | None -> "none" | Some (cs, vals) -> Printf.sprintf "fill colourspace is %s, %s vals" (Pdfspace.string_of_colourspace cs) (string_of_colvals vals) in line ^ "\n" ^ fill ^ "\n" let rec string_of_graphic_elt = function | MCSection (n, g) -> Printf.sprintf "Marked content section %s...\n" n ^ "BEGIN\n" ^ (fold_left ( ^ ) "" (map string_of_graphic_elt g)) ^ "\nEND Marked content section\n" | MCSectionProperties (n, d, g) -> Printf.sprintf "Marked content section %s with properties %s...\n" n (Pdfwrite.string_of_pdf d) ^ "BEGIN\n" ^ (fold_left ( ^ ) "" (map string_of_graphic_elt g)) ^ "\nEND Marked content section\n" | MCPoint n -> Printf.sprintf "Marked content point %s...\n" n | MCPointProperties (n, d) -> Printf.sprintf "Marked content point %s with properties %s...\n" n (Pdfwrite.string_of_pdf d) | Path (p, attributes) -> Printf.sprintf "Path: %s\nAttributes\n%s\n" (string_of_path p) (string_of_attributes attributes) | Text (ts, attr) -> "-----BEGIN TEXT - fonts:\n" ^ fold_left ( ^ ) "" (map string_of_textblock ts) ^ "-----END TEXT\n" | Image (tr, x) -> "Image " ^ string_of_int x ^ "\n" | GraphicInlineImage _ -> "Inline image\n" | Clip (p, g) -> "Clipview: path = " ^ string_of_path p ^ "\ngraphic is " ^ fold_left ( ^ ) "" (map string_of_graphic_elt g) | Shading (clip, shading, tr) -> "Shading\n" and string_of_graphic g = "Elements:\n" ^ fold_left ( ^ ) "" (map string_of_graphic_elt g.elements) ^ "Fonts:\n" ^ fold_left ( ^ ) "" (map (fun (name, obj) -> name ^ " " ^ Pdfwrite.string_of_pdf obj) g.fonts) ^ "Resources:\n" ^ Pdfwrite.string_of_pdf g.resources type state = {mutable objectclass : objectclass; (*r Not strictly part of the state, but fits here. *) mutable clip : path option; (*r Ditto - stores a clipping path which is to be invoked on the next path operation. *) mutable intent : string; mutable fill : colvals; mutable linewidth : float; mutable line : colvals; mutable mitrelimit : float; mutable joinstyle : int; mutable capstyle : int; mutable colourspace_stroke : Pdfspace.t; mutable colourspace_nonstroke : Pdfspace.t; mutable dash : float list * float; mutable flatness : int; mutable transform : Pdftransform.transform_matrix; mutable extra_transform : Pdftransform.transform_matrix; mutable text_transform : Pdftransform.transform_matrix; mutable text_line_transform : Pdftransform.transform_matrix; mutable opacity_stroke : float; mutable opacity_nonstroke : float; mutable character_spacing : float; mutable word_spacing : float; mutable scale : float; mutable leading : float; mutable font_and_size : (string * float) option; mutable font_render : int; mutable font_rise : float; mutable blendmode : int; mutable softmask : softmask option; mutable in_xobject : int; mutable opdo_matrix : Pdftransform.transform_matrix} let default_state () = {objectclass = PageDescriptionLevel; clip = None; intent = "/RelativeColorimetric"; fill = Floats [1.]; linewidth = 1.; line = Floats [1.]; mitrelimit = 10.; joinstyle = 0; capstyle = 0; colourspace_stroke = Pdfspace.DeviceGray; colourspace_nonstroke = Pdfspace.DeviceGray; dash = [], 0.; flatness = 0; transform = Pdftransform.i_matrix; extra_transform = Pdftransform.i_matrix; text_transform = Pdftransform.i_matrix; text_line_transform = Pdftransform.i_matrix; opacity_stroke = 1.; opacity_nonstroke = 1.; character_spacing = 0.; word_spacing = 0.; scale = 100.; leading = 0.; font_and_size = None; (*r No initial value. *) font_render = 0; font_rise = 0.; blendmode = 1; softmask = None; in_xobject = 0; opdo_matrix = Pdftransform.i_matrix} let state = ref (default_state ()) let string_of_state s = (*i "Object class: " ^ string_of_objectclass s.objectclass ^ "\n" ^ i*) "Stroke Colourspace: " ^ Pdfspace.string_of_colourspace s.colourspace_stroke ^ "\n" ^ "Nonstroke Colourspace: " ^ Pdfspace.string_of_colourspace s.colourspace_nonstroke ^ "\n" ^ "Stroke colours: " ^ string_of_colvals s.line ^ "\n" ^ "NonStroke colours: " ^ string_of_colvals s.fill ^ "\n" let path_attributes_fill_and_stroke () = {path_transform = (!state).transform; path_fill = Some ((!state).colourspace_nonstroke, (!state).fill); path_line = Some ((!state).colourspace_stroke, (!state).line); path_linewidth = (!state).linewidth; path_joinstyle = (!state).joinstyle; path_capstyle = (!state).capstyle; path_dash = (!state).dash; path_mitrelimit = (!state).mitrelimit; path_transparency = {fill_transparency = (!state).opacity_nonstroke; line_transparency = (!state).opacity_stroke}; path_intent = (!state).intent} let path_attributes_fill () = {path_transform = (!state).transform; path_fill = Some ((!state).colourspace_nonstroke, (!state).fill); path_line = None; path_linewidth = (!state).linewidth; path_joinstyle = (!state).joinstyle; path_capstyle = (!state).capstyle; path_dash = (!state).dash; path_mitrelimit = (!state).mitrelimit; path_transparency = {fill_transparency = (!state).opacity_nonstroke; line_transparency = 1.}; path_intent = (!state).intent} let path_attributes_stroke () = {path_transform = (!state).transform; path_fill = None; path_line = Some ((!state).colourspace_stroke, (!state).line); path_linewidth = (!state).linewidth; path_joinstyle = (!state).joinstyle; path_capstyle = (!state).capstyle; path_dash = (!state).dash; path_mitrelimit = (!state).mitrelimit; path_transparency = {fill_transparency = 1.; line_transparency = (!state).opacity_stroke}; path_intent = (!state).intent} let textstate () = {textmode = 0} let nonzero = EvenOdd let rec initial_colour pdf resources = function | Pdf.Name "/DeviceGray" | Pdf.Array (Pdf.Name "/CalGray"::_) -> Floats [0.] | Pdf.Name "/DeviceRGB" | Pdf.Array (Pdf.Name "/CalRGB"::_) -> Floats [0.; 0.; 0.] | Pdf.Name "/DeviceCMYK" -> Floats [0.; 0.; 0.; 1.] | Pdf.Name "/Pattern" | Pdf.Array [Pdf.Name "/Pattern"] -> Floats [0.] | Pdf.Array elts as cs -> begin match elts with | [Pdf.Name "/ICCBased"; iccstream] -> begin match Pdf.lookup_direct pdf "/Alternate" iccstream with | Some space -> initial_colour pdf resources space | None -> begin match Pdf.lookup_direct pdf "/N" iccstream with | Some (Pdf.Integer 1) -> Floats [0.] | Some (Pdf.Integer 3) -> Floats [0.; 0.; 0.] | Some (Pdf.Integer 4) -> Floats [0.; 0.; 0.; 0.] | _ -> raise (Pdf.PDFError "Bad ICCBased Alternate") end end | Pdf.Name "/DeviceN"::_::alternate::_ | [Pdf.Name "/Separation"; _; alternate; _] -> initial_colour pdf resources alternate | [Pdf.Name "/Pattern"; alternate] -> initial_colour pdf resources alternate | _ -> Pdfe.log (Printf.sprintf "%s\n" (Pdfwrite.string_of_pdf cs)); raise (Pdf.PDFError "Unknown colourspace A") end | Pdf.Indirect _ as indirect -> initial_colour pdf resources (Pdf.direct pdf indirect) | _ -> raise (Pdf.PDFError "Unknown colourspace B") (* PartialPath (sp, cp, p, s) is starting point [sp], current point [cp] the partial segment list [p], subpath [s] and graphic [g]. *) type partial = | NoPartial | PartialText of textblock list | PartialPath of fpoint * fpoint * segment list * subpath list (* g is a [group_transparency] xobject *) let rec read_transparency_group pdf g = let group = match Pdf.lookup_direct pdf "/Group" g with | Some gr -> gr | None -> raise (Pdf.PDFError "Pdfgraphics.read_transparency_group: no /Group found") in let colourspace = Pdf.lookup_direct pdf "/CS" group and isolated = match Pdf.lookup_direct pdf "/I" group with | Some (Pdf.Boolean b) -> b | _ -> false and knockout = match Pdf.lookup_direct pdf "/K" group with | Some (Pdf.Boolean b) -> b | _ -> false and graphic = let fakepage = let resources = match Pdf.lookup_direct pdf "/Resources" g with | Some (Pdf.Dictionary d) -> Pdf.Dictionary d | _ -> Pdf.Dictionary [] and contents = [g] in {Pdfpage.content = contents; Pdfpage.mediabox = Pdf.Null; Pdfpage.resources = resources; Pdfpage.rotate = Pdfpage.Rotate0; Pdfpage.rest = Pdf.Dictionary []} in graphic_of_page pdf fakepage and a, b, c, d = Pdf.parse_rectangle pdf (Pdf.lookup_fail "no bbox" pdf "/BBox" g) in {tr_group_colourspace = colourspace; isolated = isolated; knockout = knockout; tr_graphic = graphic}, a, b, c, d and read_soft_mask pdf mask = match match Pdf.lookup_direct pdf "/S" mask with | Some (Pdf.Name "/Alpha") -> Some Alpha | Some (Pdf.Name "/Luminosity") -> Some Luminosity | _ -> None with | None -> None | Some subtype -> let transparency_group, a, b, c, d = match Pdf.lookup_direct pdf "/G" mask with | Some g -> read_transparency_group pdf g | None -> raise (Pdf.PDFError "Pdfgraphics.transparency group not found in soft mask") and backdrop = match Pdf.lookup_direct pdf "/BC" mask with | Some (Pdf.Array nums) -> Some (map (Pdf.getnum pdf) nums) | _ -> None and transfer = match Pdf.lookup_direct pdf "/TR" mask with | Some (Pdf.Dictionary d) -> Some (Pdffun.parse_function pdf (Pdf.Dictionary d)) | _ -> None in Some {softmask_subtype = subtype; transparency_group = transparency_group; backdrop = backdrop; softmask_transfer = transfer; softmask_bbox = (a, b, c, d)} and update_graphics_state_from_dict pdf resources gdict = begin match Pdf.lookup_direct pdf "/SMask" gdict with | Some softmask -> (!state).softmask <- read_soft_mask pdf softmask | None -> () end; begin match Pdf.lookup_direct pdf "/CA" gdict with | Some (Pdf.Real o) -> (!state).opacity_stroke <- o | _ -> () end; begin match Pdf.lookup_direct pdf "/ca" gdict with | Some (Pdf.Real o) -> (!state).opacity_nonstroke <- o | _ -> () end; begin match Pdf.lookup_direct pdf "/BM" gdict with | Some (Pdf.Name n) | Some (Pdf.Array (Pdf.Name n::_)) -> (!state).blendmode <- 0 (* FIXME: Do properly *) | _ -> () end; begin match Pdf.lookup_direct pdf "/LW" gdict with | Some (Pdf.Integer width) -> (!state).linewidth <- float width | Some (Pdf.Real width) -> (!state).linewidth <- width | _ -> () end; begin match Pdf.lookup_direct pdf "/LC" gdict with | Some (Pdf.Integer style) -> (!state).capstyle <- style | _ -> () end; begin match Pdf.lookup_direct pdf "/LC" gdict with | Some (Pdf.Integer join) -> (!state).joinstyle <- join | _ -> () end; begin match Pdf.lookup_direct pdf "/ML" gdict with | Some (Pdf.Integer limit) -> (!state).mitrelimit <- float limit | Some (Pdf.Real limit) -> (!state).mitrelimit <- limit | _ -> () end; begin match Pdf.lookup_direct pdf "/D" gdict with | Some (Pdf.Array [Pdf.Array dashes; phase]) -> let dashnums, phase = map (function | (Pdf.Integer n) -> float n | (Pdf.Real n) -> n | _ -> raise (Pdf.PDFError "Malformed dash.")) dashes, match phase with | Pdf.Integer phase -> float phase | Pdf.Real phase -> phase | _ -> raise (Pdf.PDFError "Malformed dash phase.") in (!state).dash <- dashnums, phase | _ -> () end and statestack : state list ref = ref [] and copystate () = {!state with fill = (!state).fill} and push_statestack () = (*i Printf.printf "push_statestack\n"; i*) statestack =| copystate () and pop_statestack () = (*i Printf.printf "pop_statestack: %i items in stack before pop\n" (length !statestack); Printf.printf "Before pop_statestack, line and fill spaces are %s and %s\n" (Pdfspace.string_of_colourspace (!state).colourspace_stroke) (Pdfspace.string_of_colourspace (!state).colourspace_nonstroke); I*) begin match !statestack with | [] -> raise (Pdf.PDFError "Unbalanced q/Q Ops") | h::t -> statestack := t; state := h end(*i ; Printf.printf "After pop_statestack, line and fill spaces are %s and %s\n" (Pdfspace.string_of_colourspace (!state).colourspace_stroke) (Pdfspace.string_of_colourspace (!state).colourspace_nonstroke) i*) and read_tiling_pattern _ = ColouredTilingPattern Tiling and read_function_shading pdf shading = let domain = match Pdf.lookup_direct pdf "/Domain" shading with | Some (Pdf.Array [a; b; c; d]) -> Pdf.getnum pdf a, Pdf.getnum pdf b, Pdf.getnum pdf c, Pdf.getnum pdf d | _ -> 0., 1., 0., 1. and matrix = Pdf.parse_matrix pdf "/Matrix" shading and func = Pdf.lookup_fail "No function found" pdf "/Function" shading in FunctionShading {funshading_domain = domain; funshading_matrix = matrix; funshading_function = Pdffun.parse_function pdf func} and read_radial_shading pdf shading = let coords = match Pdf.lookup_direct pdf "/Coords" shading with | Some (Pdf.Array [a; b; c; d; e; f]) -> Pdf.getnum pdf a, Pdf.getnum pdf b, Pdf.getnum pdf c, Pdf.getnum pdf d, Pdf.getnum pdf e, Pdf.getnum pdf f | _ -> raise (Pdf.PDFError "Pdfgraphics.read_radial_shading: no coords in radial shading") and domain = match Pdf.lookup_direct pdf "/Domain" shading with | Some (Pdf.Array [a; b]) -> Pdf.getnum pdf a, Pdf.getnum pdf b | _ -> 0., 1. and func = match Pdf.lookup_direct pdf "/Function" shading with | Some (Pdf.Array fs) -> map (Pdffun.parse_function pdf) fs | Some f -> [Pdffun.parse_function pdf f] | _ -> raise (Pdf.PDFError "Pdfgraphics.read_radial_shading: no function in radial shading") and extend = match Pdf.lookup_direct pdf "/Extend" shading with | Some (Pdf.Array [Pdf.Boolean a; Pdf.Boolean b]) -> a, b | _ -> false, false in RadialShading {radialshading_coords = coords; radialshading_domain = domain; radialshading_function = func; radialshading_extend = extend} and read_axial_shading pdf shading = let coords = match Pdf.lookup_direct pdf "/Coords" shading with | Some (Pdf.Array [a; b; c; d]) -> Pdf.getnum pdf a, Pdf.getnum pdf b, Pdf.getnum pdf c, Pdf.getnum pdf d | _ -> raise (Pdf.PDFError "Pdfgraphics.read_axial_shading: no coords in radial shading") and domain = match Pdf.lookup_direct pdf "/Domain" shading with | Some (Pdf.Array [a; b]) -> Pdf.getnum pdf a, Pdf.getnum pdf b | _ -> 0., 1. and func = match Pdf.lookup_direct pdf "/Function" shading with | Some (Pdf.Array fs) -> map (Pdffun.parse_function pdf) fs | Some f -> [Pdffun.parse_function pdf f] | _ -> raise (Pdf.PDFError "Pdfgraphics.read_axial_shading: no function in radial shading") and extend = match Pdf.lookup_direct pdf "/Extend" shading with | Some (Pdf.Array [Pdf.Boolean a; Pdf.Boolean b]) -> a, b | _ -> false, false in AxialShading {axialshading_coords = coords; axialshading_domain = domain; axialshading_function = func; axialshading_extend = extend} (* Read a shading pattern *) and read_shading pdf matrix extgstate shading = let colourspace = Pdf.lookup_fail "No colourspace in shading" pdf "/ColorSpace" shading and background = Pdf.lookup_direct pdf "/Background" shading and bbox = Pdf.lookup_direct pdf "/BBox" shading and antialias = match Pdf.lookup_direct pdf "/BBox" shading with | Some (Pdf.Boolean true) -> true | _ -> false in let shading = match Pdf.lookup_fail "no /ShadingType" pdf "/ShadingType" shading with | Pdf.Integer 1 -> read_function_shading pdf shading | Pdf.Integer 3 -> read_radial_shading pdf shading | Pdf.Integer 2 -> read_axial_shading pdf shading | Pdf.Integer 4 -> FreeFormGouraudShading | Pdf.Integer 5 -> LatticeFormGouraudShading | Pdf.Integer 6 -> CoonsPatchMesh | Pdf.Integer 7 -> TensorProductPatchMesh | _ -> raise (Pdf.PDFError "Pdfgraphics.unknown shadingtype") in {shading_colourspace = colourspace; shading_background = background; shading_bbox = bbox; shading_antialias = antialias; shading_matrix = matrix; shading_extgstate = extgstate; shading = shading} and read_shading_pattern pdf p = let matrix = Pdf.parse_matrix pdf "/Matrix" p and extgstate = match Pdf.lookup_direct pdf "/ExtGState" p with | Some (Pdf.Dictionary _ as d) -> d | _ -> Pdf.Dictionary [] in match Pdf.lookup_direct pdf "/Shading" p with | Some shading -> ShadingPattern (read_shading pdf matrix extgstate shading) | _ -> raise (Pdf.PDFError "No shading dictionary") and read_pattern pdf page name = match Pdf.lookup_direct pdf "/Pattern" page.Pdfpage.resources with | None -> raise (Pdf.PDFError "No pattern dictionary") | Some patterndict -> match Pdf.lookup_direct pdf name patterndict with | None -> raise (Pdf.PDFError "Pattern not found") | Some pattern -> match Pdf.lookup_direct pdf "/PatternType" pattern with | Some (Pdf.Integer 1) -> read_tiling_pattern pattern | Some (Pdf.Integer 2) -> read_shading_pattern pdf pattern | _ -> raise (Pdf.PDFError "unknown pattern") and process_op pdf page (partial, graphic) op = let ret = (partial, graphic) in (*i flprint (string_of_state !state); *) (*i flprint (Pdfpages.string_of_op op ^ "\n"); i*) match op with | Pdfops.Op_W -> (* Move the current partial path into Clip, and return *) begin match partial with | PartialPath (_, _, segments, subpaths) -> if segments = [] && subpaths = [] then ret else let path = if segments <> [] then (Not_hole, Closed, rev segments)::subpaths else subpaths in (!state).clip <- Some (NonZero, path); ret | _ -> ret end (* FIXME: In NextClip needs to support possibly several clips, since we can do W n W n W n f, for instance? *) | Pdfops.Op_W' -> begin match partial with | PartialPath (_, _, segments, subpaths) -> if segments = [] && subpaths = [] then ret else let path = if segments <> [] then (Not_hole, Closed, rev segments)::subpaths else subpaths in (!state).clip <- Some (EvenOdd, path); ret | _ -> ret end | Pdfops.InlineImage (dict, data) -> (NoPartial, GraphicInlineImage (dict, data, (!state).transform)::graphic) | Pdfops.Op_MP name -> begin match (!state).objectclass with | PageDescriptionLevel -> (NoPartial, MCPoint name::graphic) | TextObject -> ret (* FIXME -- Add it to the text partial. *) | _ -> ret (* Invalid, silently drop *) end | Pdfops.Op_DP (name, properties) -> begin match (!state).objectclass with | PageDescriptionLevel -> (NoPartial, MCPointProperties (name, properties)::graphic) | TextObject -> ret (* FIXME -- Add it to the text partial. *) | _ -> ret (* Invalid, silently drop *) end | Pdfops.Op_BX | Pdfops.Op_EX -> ret | Pdfops.Op_ri n -> (!state).intent <- n; ret | Pdfops.Op_j j -> (!state).joinstyle <- j; ret | Pdfops.Op_J c -> (!state).capstyle <- c; ret | Pdfops.Op_w w -> (!state).linewidth <- w; ret | Pdfops.Op_M m -> (!state).mitrelimit <- m; ret | Pdfops.Op_q -> (*i flprint "Op_q\n"; i*) push_statestack (); ret | Pdfops.Op_Q -> (*i flprint "Op_Q\n"; i*) pop_statestack (); ret | Pdfops.Op_SC vals | Pdfops.Op_SCN vals -> (!state).line <- Floats vals; ret | Pdfops.Op_sc vals | Pdfops.Op_scn vals -> (!state).fill <- Floats vals; ret | Pdfops.Op_scnName (name, vals) -> begin match (!state).colourspace_nonstroke with | Pdfspace.Pattern | Pdfspace.PatternWithBaseColourspace _ -> begin try (!state).fill <- Pattern (read_pattern pdf page name); ret with _ -> ret end | _ -> (!state).fill <- Named (name, vals); ret end | Pdfops.Op_SCNName (name, vals) -> begin match (!state).colourspace_stroke with | Pdfspace.Pattern | Pdfspace.PatternWithBaseColourspace _ -> begin try (!state).line <- Pattern (read_pattern pdf page name); ret with _ -> ret end | _ -> (!state).line <- Named (name, vals); ret end | Pdfops.Op_CS c -> (*i Printf.printf "Op_CS: %s\n" c; *) (!state).colourspace_nonstroke <- Pdfspace.read_colourspace pdf page.Pdfpage.resources (Pdf.Name c); ret | Pdfops.Op_cs c -> (*i flprint "Op_cs\n"; Printf.printf "Pdfgraphics: Op_cs: %s\n" c; i*) (!state).colourspace_nonstroke <- Pdfspace.read_colourspace pdf page.Pdfpage.resources (Pdf.Name c); ret | Pdfops.Op_G gv -> (*i flprint "Op_G\n"; i*) (!state).colourspace_stroke <- Pdfspace.DeviceGray; (!state).line <- Floats [gv]; ret | Pdfops.Op_g gv -> (*i flprint "Op_g\n"; i*) (!state).colourspace_nonstroke <- Pdfspace.DeviceGray; (!state).fill <- Floats [gv]; ret | Pdfops.Op_RG (rv, gv, bv) -> (!state).colourspace_stroke <- Pdfspace.DeviceRGB; (!state).line <- Floats [rv; gv; bv]; ret | Pdfops.Op_rg (rv, gv, bv) -> (!state).colourspace_nonstroke <- Pdfspace.DeviceRGB; (!state).fill <- Floats [rv; gv; bv]; ret | Pdfops.Op_K (c, m, y, k) -> (!state).colourspace_stroke <- Pdfspace.DeviceCMYK; (!state).line <- Floats [c; y; m; k]; ret | Pdfops.Op_k (c, m, y, k) -> (!state).colourspace_nonstroke <- Pdfspace.DeviceCMYK; (!state).fill <- Floats [c; y; m; k]; ret | Pdfops.Op_gs name -> let ext_state_dict = Pdf.lookup_fail "Bad Op_gs" pdf "/ExtGState" page.Pdfpage.resources in let gdict = Pdf.lookup_fail "Bad Op_gs" pdf name ext_state_dict in update_graphics_state_from_dict pdf page.Pdfpage.resources gdict; ret | Pdfops.Op_m (x, y) -> (* Begin a new subpath. Get into path mode if not already there. If the last op was an [Op_m], it should have no effect. *) (!state).objectclass <- PathObject; begin match partial with | PartialPath (sp, cp, segs, subpaths) -> if segs = [] then PartialPath ((x, y), (x, y), [], subpaths), graphic else PartialPath ((x, y), (x, y), [], (Not_hole, Open, rev segs)::subpaths), graphic | _ -> PartialPath ((x, y), (x, y), [], []), graphic end | Pdfops.Op_l (x, y) -> if (!state).objectclass <> PathObject then raise (Pdf.PDFError "Pdfgraphics: Op_l"); begin match partial with | PartialPath (sp, cp, segs, subpaths) -> PartialPath (sp, (x, y), Straight (cp, (x, y))::segs, subpaths), graphic | _ -> raise (Pdf.PDFError "Pdfgraphics: Op_l") end | Pdfops.Op_c (a, b, c, d, e, f) -> if (!state).objectclass <> PathObject then raise (Pdf.PDFError "Pdfgraphics: Op_c"); begin match partial with | PartialPath (sp, cp, segs, subpaths) -> let ep = (e, f) in let curve = Bezier (cp, (a, b), (c, d), ep) in PartialPath (sp, ep, curve::segs, subpaths), graphic | _ -> raise (Pdf.PDFError "Pdfgraphics: Op_c") end | Pdfops.Op_v (a, b, c, d) -> if (!state).objectclass <> PathObject then raise (Pdf.PDFError "Pdfgraphics: Op_v"); begin match partial with | PartialPath (sp, cp, segs, subpaths) -> let ep = (c, d) in let curve = Bezier (cp, cp, (a, b), ep) in PartialPath (sp, ep, curve::segs, subpaths), graphic | _ -> raise (Pdf.PDFError "Pdfgraphics: Op_v") end | Pdfops.Op_y (a, b, c, d) -> if (!state).objectclass <> PathObject then raise (Pdf.PDFError "Pdfgraphics: Op_y"); begin match partial with | PartialPath (sp, cp, segs, subpaths) -> let ep = (c, d) in let curve = Bezier (cp, (a, b), ep, ep) in PartialPath (sp, ep, curve::segs, subpaths), graphic | _ -> raise (Pdf.PDFError "Pdfgraphics: Op_y") end | Pdfops.Op_h -> if (!state).objectclass <> PathObject then raise (Pdf.PDFError "Pdfgraphics: Op_h - not in PathObject"); begin match partial with | PartialPath (sp, cp, segs, subpaths) -> PartialPath (sp, cp, [], (Not_hole, Closed, rev segs)::subpaths), graphic | _ -> raise (Pdf.PDFError "Pdfgraphics: Op_h - not a partial path") end | Pdfops.Op_s -> (* Close and stroke. Equivalent to h S *) process_ops pdf page ret [Pdfops.Op_h; Pdfops.Op_S] | Pdfops.Op_b -> (* Close, fill, stroke, nonzero. Equivalent to h B *) process_ops pdf page ret [Pdfops.Op_h; Pdfops.Op_B] | Pdfops.Op_b' -> (* Close, fill, stroke, evenodd. Equivalent to h B* *) process_ops pdf page ret [Pdfops.Op_h; Pdfops.Op_B'] | Pdfops.Op_f | Pdfops.Op_F -> (* Close and Fill non-zero *) if (!state).objectclass <> PathObject then raise (Pdf.PDFError "Pdfgraphics: Op_f"); let partial, graphic = process_op pdf page (partial, graphic) Pdfops.Op_h in (!state).objectclass <- PageDescriptionLevel; begin match partial with | PartialPath (sp, cp, segs, subpaths) -> (* segs is empty, due to [Op_h] *) PartialPath (sp, cp, [], []), Path ((NonZero, rev subpaths), path_attributes_fill ())::graphic | _ -> raise (Pdf.PDFError "Pdfgraphics: Op_f") end | Pdfops.Op_S -> (* Stroke *) if (!state).objectclass <> PathObject then raise (Pdf.PDFError "Pdfgraphics: Op_S"); (!state).objectclass <- PageDescriptionLevel; begin match partial with | PartialPath (sp, cp, segs, subpaths) -> if segs = [] then PartialPath (sp, cp, [], []), Path ((EvenOdd, rev subpaths), path_attributes_stroke ())::graphic else PartialPath (sp, cp, [], []), Path ((EvenOdd, rev ((Not_hole, Open, rev segs)::subpaths)), path_attributes_stroke ())::graphic | _ -> raise (Pdf.PDFError "Pdfgraphics: Op_S") end | Pdfops.Op_B -> (* Fill and stroke, non-zero. *) if (!state).objectclass <> PathObject then raise (Pdf.PDFError "Pdfgraphics: Op_B"); (!state).objectclass <- PageDescriptionLevel; begin match partial with | PartialPath (sp, cp, segs, subpaths) -> if segs = [] then PartialPath (sp, cp, [], []), Path ((NonZero, rev subpaths), path_attributes_fill_and_stroke ())::graphic else PartialPath (sp, cp, [], []), Path ((NonZero, rev ((Not_hole, Open, rev segs)::subpaths)), path_attributes_fill_and_stroke ()) ::graphic | _ -> raise (Pdf.PDFError "Pdfgraphics: Op_B") end | Pdfops.Op_B' -> (* Fill and stroke, even-odd. *) if (!state).objectclass <> PathObject then raise (Pdf.PDFError "Pdfgraphics: Op_B*"); let partial, graphic = process_op pdf page (partial, graphic) Pdfops.Op_h in (!state).objectclass <- PageDescriptionLevel; begin match partial with | PartialPath (sp, cp, segs, subpaths) -> if segs = [] then PartialPath (sp, cp, [], []), Path ((EvenOdd, rev subpaths), path_attributes_fill_and_stroke ())::graphic else PartialPath (sp, cp, [], []), Path ((EvenOdd, rev ((Not_hole, Open, rev segs)::subpaths)), path_attributes_fill_and_stroke ()) ::graphic | _ -> raise (Pdf.PDFError "Pdfgraphics: Op_B*") end | Pdfops.Op_f' -> (* Fill, even-odd *) if (!state).objectclass <> PathObject then raise (Pdf.PDFError "Pdfgraphics: Op_f*"); (!state).objectclass <- PageDescriptionLevel; begin match partial with | PartialPath (sp, cp, segs, subpaths) -> if segs = [] then PartialPath (sp, cp, [], []), Path ((EvenOdd, rev subpaths), path_attributes_fill ())::graphic else PartialPath (sp, cp, [], []), Path ((EvenOdd, rev ((Not_hole, Open, rev segs)::subpaths)), path_attributes_fill ()) ::graphic | _ -> raise (Pdf.PDFError "Pdfgraphics: Op_f*") end | Pdfops.Op_n -> (* no-op *) (!state).objectclass <- PageDescriptionLevel; (* for now, until we support clipviews, clean up the polygon *) (NoPartial, graphic) | Pdfops.Op_re (x, y, w, h) -> (* Rectangle. *) let ops = [Pdfops.Op_m (x, y); Pdfops.Op_l (x +. w, y); Pdfops.Op_l (x +. w, y +. h); Pdfops.Op_l (x, y +. h); Pdfops.Op_h] in process_ops pdf page (partial, graphic) ops | Pdfops.Op_Do name -> begin match Pdf.lookup_direct pdf "/XObject" page.Pdfpage.resources with | Some d -> begin match Pdf.lookup_direct pdf name d with | Some xobj -> begin match Pdf.lookup_direct pdf "/Subtype" xobj with | Some (Pdf.Name "/Image") -> let objnum = match Pdf.find_indirect name d with | None -> raise (Pdf.PDFError "image not found") | Some i -> i in partial, Image ({image_transform = (!state).transform; image_transparency = (!state).opacity_nonstroke; image_softmask = (!state).softmask} , objnum)::graphic | Some (Pdf.Name "/Form") -> let elts = read_form_xobject pdf page xobj in partial, rev elts @ graphic | _ -> raise (Pdf.PDFError "Unknown kind of xobject") end | _ -> raise (Pdf.PDFError "Unknown xobject") end | None -> raise (Pdf.PDFError "xobject not found") end | Pdfops.Op_cm tr -> (!state).transform <- Pdftransform.matrix_compose (!state).transform tr; ret | ( Pdfops.Op_Tc _ | Pdfops.Op_Tw _ | Pdfops.Op_Tz _ | Pdfops.Op_TL _ | Pdfops.Op_Tf _ | Pdfops.Op_Tr _ | Pdfops.Op_Ts _ | Pdfops.Op_Td _ | Pdfops.Op_TD _ | Pdfops.Op_Tm _ | Pdfops.Op_T' | Pdfops.Op_Tj _ | Pdfops.Op_TJ _ | Pdfops.Op_' _ | Pdfops.Op_'' _ | Pdfops.Op_d0 _ | Pdfops.Op_d1 _) as op -> begin match partial with | PartialText t -> let st = textstate () in PartialText ((st, op)::t), graphic | _ -> (* If there's no partial text, this is an op affecting the text state but not in a text section. Such ops are allowed. FIXME: Deal with them properly - by ops altering the text state so this can be reflected in the initial state at the start of a text section *) ret end | Pdfops.Op_sh n -> let shading = let shadingdict = Pdf.lookup_fail "no /Shading" pdf "/Shading" page.Pdfpage.resources in let shading = Pdf.lookup_fail "named shading not found" pdf n shadingdict in read_shading pdf Pdftransform.i_matrix Pdf.Null shading and currentclip = (!state).clip in partial, Shading (currentclip, shading, (!state).transform)::graphic | Pdfops.Op_i flatness -> if flatness >= 0 && flatness <= 100 then (!state).flatness <- flatness; ret | Pdfops.Op_d (spec, phase) -> (!state).dash <- spec, phase; ret | Pdfops.Op_Unknown _ -> ret | _ -> Pdfe.log "Operator shouldn't appear at this place"; ret and getuntil_matching_emc level prev = function | (Pdfops.Op_BMC _ | Pdfops.Op_BDC (_, _)) as h::t -> getuntil_matching_emc (level + 1) (h::prev) t | Pdfops.Op_EMC::t -> if level < 0 then raise (Pdf.PDFError "Too many EMCs\n") else if level = 0 then rev prev, t else getuntil_matching_emc (level - 1) (Pdfops.Op_EMC::prev) t | h::t -> getuntil_matching_emc level (h::prev) t | [] -> raise (Pdf.PDFError "Missing EMC\n") and getuntil_matching_Q level prev = function | Pdfops.Op_q::t -> getuntil_matching_Q (level + 1) (Pdfops.Op_q::prev) t | Pdfops.Op_Q::t -> if level = 0 then rev prev, Pdfops.Op_Q::t else getuntil_matching_Q (level - 1) (Pdfops.Op_Q::prev) t | [] -> rev prev, [] | h::t -> getuntil_matching_Q level (h::prev) t and process_ops pdf page (partial, graphic) ops = match ops with | [] -> partial, rev graphic | Pdfops.Op_n::t -> (* If there's a NextClip, select all operators within the scope of this clip. That is, all operators until an [Op_Q] which puts the stack level below the current level or the end of the stream, whichever comes first.*) begin match (!state).clip with | None -> process_ops pdf page (partial, graphic) t | Some path -> (* We process the operators concerned, putting them inside a Clip, and then proceed with the remaining operators (including any [Op_Q]). However, to deal with the case of overlapping pairs of marked content sections and q/Q pairs (which is allowed). Currently just chuck BDC we don't understand. *) let toq, rest = getuntil_matching_Q 0 [] t in let _, elts = process_ops pdf page (NoPartial, []) toq in process_ops pdf page (NoPartial, Clip (path, elts)::graphic) rest end | Pdfops.Op_BMC n::t -> (* FIXME: Marked content regions / q/Q pairs overlapping problem *) begin try let ops, rest = getuntil_matching_emc 0 [] t in let partial, graphic' = process_ops pdf page (partial, []) ops in process_ops pdf page (partial, MCSection (n, graphic')::graphic) rest with _ -> process_ops pdf page (partial, graphic) t end | Pdfops.Op_BDC (n, d)::t -> (* FIXME: Marked content regions / q/Q pairs overlapping problem *) begin try let ops, rest = getuntil_matching_emc 0 [] t in let partial, graphic' = process_ops pdf page (partial, []) ops in process_ops pdf page (partial, MCSectionProperties (n, d, graphic')::graphic) rest with _ -> process_ops pdf page (partial, graphic) t end | Pdfops.Op_BT::t -> (* Can't nest text sections, so just get to ET *) let textops, rest = cleavewhile (neq Pdfops.Op_ET) t in begin match rest with | Pdfops.Op_ET::_ | [] -> (* We allow blank in case of wrongly nested EMC / ET etc *) let more = tail_no_fail rest in (* We need to process the ops, and capture the text operations, but state changes inside text sections (e.g colour changes) have global effect, so need to keep the state *) (!state).objectclass <- TextObject; let partial, _ = process_ops pdf page (PartialText [], graphic) textops in begin match partial with | PartialText t -> let textblock = Text (rev t, {textblock_transform = (!state).transform}) in process_ops pdf page (partial, textblock::graphic) (Pdfops.Op_ET::more) | _ -> raise (Pdf.PDFError "Bad operations in text block") end | _ -> (*i Printf.printf "textops: %s\n\n" (Pdfops.string_of_ops textops); Printf.printf "rest: %s\n\n" (Pdfops.string_of_ops rest); i*) raise (Pdf.PDFError "No Matching Op_ET") end | Pdfops.Op_ET::t -> (!state).objectclass <- PageDescriptionLevel; process_ops pdf page (partial, graphic) t | h::t -> process_ops pdf page (process_op pdf page (partial, graphic) h) t (* Load the fonts as (name, pdfobject) pairs *) and fonts_of_page pdf page = match Pdf.lookup_direct pdf "/Font" page.Pdfpage.resources with | Some (Pdf.Dictionary fs) -> fs | _ -> [] (* Find the operations of a form xobject. *) and read_form_xobject pdf page pdfobject = let content = [Pdf.direct pdf pdfobject] in let pagedict = match Pdf.direct pdf page.Pdfpage.resources with | Pdf.Dictionary rs -> rs | _ -> [] and xobjdict = match Pdf.direct pdf pdfobject with | Pdf.Stream {contents = (dict, _)} -> begin match Pdf.lookup_direct pdf "/Resources" dict with | Some (Pdf.Dictionary rs) -> rs | _ -> [] end | _ -> raise (Pdf.PDFError "bad stream in read_form_xobject") in let total_resources = Pdf.Dictionary (mergedict pagedict xobjdict) in let fake_page = {Pdfpage.content = []; Pdfpage.mediabox = Pdf.Null; Pdfpage.resources = total_resources; Pdfpage.rotate = Pdfpage.Rotate0; Pdfpage.rest = Pdf.Dictionary []} in let _, graphic_elts = (process_ops pdf fake_page (NoPartial, []) (Pdfops.parse_operators pdf total_resources content)) in graphic_elts (* Main function - build a graphic from a page *) and graphic_of_page pdf page = statestack := []; state := default_state (); if Pdfcrypt.is_encrypted pdf then raise (Pdf.PDFError "Pdfgraphics: File is encrypted") else begin let _, elts = let ops = Pdfops.parse_operators pdf page.Pdfpage.resources page.Pdfpage.content in process_ops pdf page (NoPartial, []) ops in {elements = elts; fonts = fonts_of_page pdf page; resources = page.Pdfpage.resources} end let graphic_of_ops ops = graphic_of_page (Pdf.empty ()) {(Pdfpage.blankpage Pdfpaper.a4) with Pdfpage.content = [Pdf.Stream {contents = (Pdf.Dictionary [], Pdf.Got (bytes_of_string (Pdfops.string_of_ops ops)))}]} (* \section{Building a page from a graphic} *) let int_of_shading_kind = function | FunctionShading _ -> 1 | AxialShading _ -> 2 | RadialShading _ -> 3 | FreeFormGouraudShading -> 4 | LatticeFormGouraudShading -> 5 | CoonsPatchMesh -> 6 | TensorProductPatchMesh -> 7 let entries_of_shading pdf s = match s.shading with | RadialShading r -> let coords = let a, b, c, d, e, f = r.radialshading_coords in Pdf.Array [Pdf.Real a; Pdf.Real b; Pdf.Real c; Pdf.Real d; Pdf.Real e; Pdf.Real f] and domain = let a, b = r.radialshading_domain in Pdf.Array [Pdf.Real a; Pdf.Real b] and funcnum = match r.radialshading_function with | [f] -> Pdf.addobj pdf (Pdffun.pdfobject_of_function pdf f) | funs -> Pdf.addobj pdf (Pdf.Array (map (Pdffun.pdfobject_of_function pdf) funs)) and extend = Pdf.Array [Pdf.Boolean (fst r.radialshading_extend); Pdf.Boolean (snd r.radialshading_extend)] in ["/Coords", coords; "/Domain", domain; "/Function", Pdf.Indirect funcnum; "/Extend", extend] | AxialShading a -> let coords = let a, b, c, d = a.axialshading_coords in Pdf.Array [Pdf.Real a; Pdf.Real b; Pdf.Real c; Pdf.Real d] and domain = let a, b = a.axialshading_domain in Pdf.Array [Pdf.Real a; Pdf.Real b] and funcnum = match a.axialshading_function with | [f] -> Pdf.addobj pdf (Pdffun.pdfobject_of_function pdf f) | funs -> Pdf.addobj pdf (Pdf.Array (map (Pdffun.pdfobject_of_function pdf) funs)) and extend = Pdf.Array [Pdf.Boolean (fst a.axialshading_extend); Pdf.Boolean (snd a.axialshading_extend)] in ["/Coords", coords; "/Domain", domain; "/Function", Pdf.Indirect funcnum; "/Extend", extend] | _ -> [] let shading_object_of_shading pdf s = let background = match s.shading_background with | None -> [] | Some b -> ["/Background", b] and bbox = match s.shading_bbox with | None -> [] | Some b -> ["/BBox", b] in Pdf.Dictionary (["/ShadingType", Pdf.Integer (int_of_shading_kind s.shading); "/ColorSpace", s.shading_colourspace; "/AntiAlias", Pdf.Boolean s.shading_antialias] @ background @ bbox @ entries_of_shading pdf s) let pattern_object_of_pattern xobject_level opdo_matrix pdf = function | ShadingPattern s -> begin try let shading_matrix = if xobject_level > 0 then let inverted = Pdftransform.matrix_invert opdo_matrix in Pdftransform.matrix_compose inverted s.shading_matrix else s.shading_matrix in Pdf.Dictionary ["/Type", Pdf.Name "/Pattern"; "/PatternType", Pdf.Integer 2; "/Shading", shading_object_of_shading pdf s; "/Matrix", Pdf.make_matrix shading_matrix] with Pdftransform.NonInvertable -> raise (Pdf.PDFError "Pdfgraphics.Bad pattern") end | _ -> Pdfe.log "Unknown pattern\n"; Pdf.Dictionary [] (* Output a move and line/curve ops. *) let ops_of_segs segs closure = let raw_seg_ops = map (function | Straight (_, (x, y)) -> Pdfops.Op_l (x, y) | Bezier (_, (bx, by), (cx, cy), (dx, dy)) -> Pdfops.Op_c (bx, by, cx, cy, dx, dy)) segs and get_move = function | Straight ((x, y), _) | Bezier ((x, y), _, _, _) -> Pdfops.Op_m (x, y) in (* Predicate: Do we need to close this subpath? *) match segs with | [] -> [] | h::_ -> get_move h::raw_seg_ops @ (if closure = Closed then [Pdfops.Op_h] else []) let protect ops = [Pdfops.Op_q] @ ops @ [Pdfops.Op_Q] let attribute_ops_of_path (_, a) = [Pdfops.Op_w a.path_linewidth; Pdfops.Op_J a.path_capstyle; Pdfops.Op_j a.path_joinstyle; begin match a.path_dash with (x, y) -> Pdfops.Op_d (x, y) end; Pdfops.Op_M a.path_mitrelimit; Pdfops.Op_ri a.path_intent] let transform_ops_of_path (_, a) = [Pdfops.Op_cm a.path_transform] let stroke_ops_of_path ((winding, _), a) = match winding, a.path_fill, a.path_line with | _, None, None -> Pdfops.Op_n | EvenOdd, Some _, Some _ -> Pdfops.Op_B' | EvenOdd, Some _, None -> Pdfops.Op_f' | NonZero, Some _, Some _ -> Pdfops.Op_B | NonZero, Some _, None -> Pdfops.Op_f | _, None, Some _ -> Pdfops.Op_S let path_ops_of_path (_, subpaths) = flatten (map (fun (_, closure, segs) -> ops_of_segs segs closure) subpaths) let ops_of_path pdf page (((winding, subpaths), a) as p) = (* Add a colourspace returning new resources and a new name, or return the name it's already held under. *) let name_of_colourspace cs resources = match cs with (*i | Pdf.Name (("/DeviceGray" | "/DeviceRGB" | "/DeviceCMYK" | "/Pattern") as str) -> resources, str i*) | Pdfspace.DeviceGray | Pdfspace.DeviceRGB | Pdfspace.DeviceCMYK | Pdfspace.Pattern -> resources, Pdfspace.string_of_colourspace cs | _ -> let existing_colourspacedict = match Pdf.lookup_direct pdf "/ColorSpace" resources with | Some ((Pdf.Dictionary _) as d) -> d | _ -> Pdf.Dictionary [] in (* FIXME: For now, we just always create a new one. Must search to see if it's already there for efficiency. *) let name = Pdf.unique_key "cs" existing_colourspacedict in let newcolourspacedict = Pdf.add_dict_entry existing_colourspacedict name (Pdfspace.write_colourspace pdf cs) in Pdf.add_dict_entry resources "/ColorSpace" newcolourspacedict, name in let resources = page.Pdfpage.resources in let attribute_ops = attribute_ops_of_path p and transform = transform_ops_of_path p and stroke_op = stroke_ops_of_path p in let colours_stroke, resources = match a.path_line with | Some (cs, Floats vals) -> let resources', name = name_of_colourspace cs resources in [Pdfops.Op_CS name; Pdfops.Op_SCN vals], resources | Some (cs, Named (n, vals)) -> let resources', name = name_of_colourspace cs resources in [Pdfops.Op_CS name; Pdfops.Op_SCNName (n, vals)], resources' | _ -> [], resources in let colours_nonstroke, resources = match a.path_fill with | Some (cs, Floats vals) -> let resources', name = name_of_colourspace cs resources in [Pdfops.Op_cs name; Pdfops.Op_scn vals], resources' | Some (cs, Named (n, vals)) -> let resources', name = name_of_colourspace cs resources in [Pdfops.Op_cs name; Pdfops.Op_scnName (n, vals)], resources' | Some (_, Pattern p) -> (* Build /Pattern cs and reference to pattern, having built the pattern in the pattern dictionary *) let pattern = pattern_object_of_pattern (!state).in_xobject (!state).opdo_matrix pdf p in let resources, name = let existing_patterndict = match Pdf.lookup_direct pdf "/Pattern" resources with | Some ((Pdf.Dictionary _) as d) -> d | _ -> Pdf.Dictionary [] in let name = Pdf.unique_key "pt" existing_patterndict in let newpatterndict = Pdf.add_dict_entry existing_patterndict name pattern in Pdf.add_dict_entry page.Pdfpage.resources "/Pattern" newpatterndict, name in [Pdfops.Op_cs "/Pattern"; Pdfops.Op_scnName (name, [])], resources | _ -> [], resources in let gs, resources = if a.path_transparency.fill_transparency < 1. || a.path_transparency.line_transparency < 1. then let resources, name = let existing_extgstate = match Pdf.lookup_direct pdf "/ExtGState" resources with | Some ((Pdf.Dictionary _) as d) -> d | _ -> Pdf.Dictionary [] in let name = Pdf.unique_key "gs" existing_extgstate and gsdict = Pdf.Dictionary [("/ca", Pdf.Real a.path_transparency.fill_transparency); ("/CA", Pdf.Real a.path_transparency.line_transparency)] in let new_extgstate = Pdf.add_dict_entry existing_extgstate name gsdict in Pdf.add_dict_entry page.Pdfpage.resources "/ExtGState" new_extgstate, name in [Pdfops.Op_gs name], resources else [], resources in let path_ops = path_ops_of_path (winding, subpaths) in protect (gs @ transform @ attribute_ops @ colours_stroke @ colours_nonstroke @ path_ops @ [stroke_op]), resources let ops_of_textstate st = [] let ops_of_textpiece (st, op) = ops_of_textstate st @ [op] (* Upon entry to this, the transformation matrix is identity *) let ops_of_text tr ops = protect ([Pdfops.Op_cm tr; Pdfops.Op_BT] @ (flatten <| map ops_of_textpiece ops) @ [Pdfops.Op_ET]) (* Transform a bounding box by a given matrix *) let extreme_of_4 f a b c d = hd <| sort f [a; b; c; d] let min_of_4 = extreme_of_4 compare let max_of_4 = extreme_of_4 (fun a b -> ~-(compare a b)) let transform_bbox tr l b r t = let (x0, y0) = Pdftransform.transform_matrix tr (l, t) and (x1, y1) = Pdftransform.transform_matrix tr (l, b) and (x2, y2) = Pdftransform.transform_matrix tr (r, t) and (x3, y3) = Pdftransform.transform_matrix tr (r, b) in min_of_4 x0 x1 x2 x3, min_of_4 y0 y1 y2 y3, max_of_4 x0 x1 x2 x3, max_of_4 y0 y1 y2 y3 (* Build a transparency group xobject, add it to the pdf and return its object number *) let rec pdfobject_of_transparency_group (a, b, c, d) pdf t = (!state).in_xobject <- (!state).in_xobject + 1; let r = let page = page_of_graphic pdf (0., 0., 0., 0.) t.tr_graphic and group_attributes = let cs = match t.tr_group_colourspace with | None -> [] | Some pdfobject -> ["/CS", pdfobject] in Pdf.Dictionary (["/Type", Pdf.Name "/Group"; "/S", Pdf.Name "/Transparency"; "/I", Pdf.Boolean t.isolated; "/K", Pdf.Boolean t.knockout] @ cs) in let extras = ["/Type", Pdf.Name "/XObject"; "/Subtype", Pdf.Name "/Form"; "/BBox", Pdf.Array [Pdf.Real a; Pdf.Real b; Pdf.Real c; Pdf.Real d]; "/Resources", page.Pdfpage.resources; "/Group", group_attributes] in match page.Pdfpage.content with | Pdf.Stream ({contents = Pdf.Dictionary dict, Pdf.Got data})::_ -> Pdf.addobj pdf (Pdf.Stream ({contents = Pdf.Dictionary (extras @ dict), Pdf.Got data})) | _ -> raise (Pdf.PDFError "Pdfgraphics: Bad page content") in (!state).in_xobject <- (!state).in_xobject - 1; r and pdfobject_of_softmask pdf m = let bc = match m.backdrop with | None -> [] | Some fs -> ["/BC", Pdf.Array (map (function x -> Pdf.Real x) fs)] and tr = match m.softmask_transfer with | None -> [] | Some f -> ["/TR", Pdffun.pdfobject_of_function pdf f] in Pdf.addobj pdf (Pdf.Dictionary (["/Type", Pdf.Name "/Mask"; "/S", Pdf.Name (match m.softmask_subtype with Alpha -> "/Alpha" | Luminosity -> "/Luminosity"); "/G", Pdf.Indirect (pdfobject_of_transparency_group m.softmask_bbox pdf m.transparency_group)] @ bc @ tr)) and ops_of_image pdf page (a, i) = (!state).opdo_matrix <- a.image_transform; let resources = page.Pdfpage.resources in let ops, resources = let opgs, resources = if a.image_transparency < 1. || a.image_softmask <> None then let resources, name = let existing_extgstate = match Pdf.lookup_direct pdf "/ExtGState" page.Pdfpage.resources with | Some ((Pdf.Dictionary _) as d) -> d | _ -> Pdf.Dictionary [] in let name = Pdf.unique_key "gs" existing_extgstate and gsdict = let softmask = match a.image_softmask with | None -> [] | Some m -> ["/SMask", Pdf.Indirect (pdfobject_of_softmask pdf m)] in Pdf.Dictionary ([("/ca", Pdf.Real a.image_transparency)] @ softmask) in let new_extgstate = Pdf.add_dict_entry existing_extgstate name gsdict in Pdf.add_dict_entry resources "/ExtGState" new_extgstate, name in [Pdfops.Op_gs name], resources else [], resources in [Pdfops.Op_cm a.image_transform] @ opgs @ [Pdfops.Op_Do ("/Im" ^ string_of_int i)], resources in protect ops, resources and ops_of_shading pdf page path shading transform = let resources', name = (* Add new entry to shading dictionary, return its name, new resources *) let existing_shadingdict = match Pdf.lookup_direct pdf "/Shading" page.Pdfpage.resources with | Some ((Pdf.Dictionary _) as d) -> d | _ -> Pdf.Dictionary [] in let name = Pdf.unique_key "sh" existing_shadingdict and objnum = Pdf.addobj pdf (shading_object_of_shading pdf shading) in let shadingref = Pdf.Indirect objnum in let new_shadingdict = Pdf.add_dict_entry existing_shadingdict name shadingref in let r = Pdf.add_dict_entry page.Pdfpage.resources "/Shading" new_shadingdict in r, name in let ops = let pathops, clipops = match path with | None -> [], [] | Some p -> path_ops_of_path p, [Pdfops.Op_W; Pdfops.Op_n] (* FIXME: Even-odd vs Non-Zero *) in pathops @ clipops @ [Pdfops.Op_cm transform; Pdfops.Op_sh name] in protect ops, resources' and ops_of_graphic_acc pdf page oplists = function | [] -> flatten (rev oplists), page | Path p::t -> let ops, resources' = ops_of_path pdf page p in let page' = {page with Pdfpage.resources = resources'} in ops_of_graphic_acc pdf page' (ops::oplists) t | Image (attr, i)::t -> let ops, resources' = ops_of_image pdf page (attr, i) in let page' = {page with Pdfpage.resources = resources'} in ops_of_graphic_acc pdf page' (ops::oplists) t | Text (ts, {textblock_transform = tr})::t -> let ops = ops_of_text tr ts in ops_of_graphic_acc pdf page (ops::oplists) t | MCSection (n, graphic)::t -> let oplist, page' = ops_of_graphic_acc pdf page [] graphic in ops_of_graphic_acc pdf page' (([Pdfops.Op_BMC n] @ oplist @ [Pdfops.Op_EMC])::oplists) t | MCSectionProperties (n, d, graphic)::t -> let oplist, page' = ops_of_graphic_acc pdf page [] graphic in ops_of_graphic_acc pdf page' (([Pdfops.Op_BDC (n, d)] @ oplist @ [Pdfops.Op_EMC])::oplists) t | MCPoint n::t -> ops_of_graphic_acc pdf page ([Pdfops.Op_MP n]::oplists) t | MCPointProperties (n, d)::t -> ops_of_graphic_acc pdf page ([Pdfops.Op_DP (n, d)]::oplists) t | GraphicInlineImage (dict, data, tr)::t -> ops_of_graphic_acc pdf page (protect [Pdfops.Op_cm tr; Pdfops.InlineImage (dict, data)]::oplists) t | Clip ((w, _) as p, elts)::t -> let ops, page' = let path_ops = [Pdfops.Op_cm (!state).transform] @ path_ops_of_path p and clipviewops = [if w = NonZero then Pdfops.Op_W else Pdfops.Op_W'; Pdfops.Op_n] and insideclipops, page' = ops_of_graphic_acc pdf page [] elts in protect (path_ops @ clipviewops @ insideclipops), page' in ops_of_graphic_acc pdf page' (ops::oplists) t | Shading (path, shading, transform)::t -> let ops, resources' = ops_of_shading pdf page path shading transform in let oplists'= protect ops::oplists and page' = {page with Pdfpage.resources = resources'} in ops_of_graphic_acc pdf page' oplists' t (* Build a page from a graphic in the same PDF. *) and image_numbers_of_elts prev = function | Image (_, i)::t -> image_numbers_of_elts (i::prev) t | MCSection (_, elts)::t | MCSectionProperties (_, _, elts)::t | Clip (_, elts)::t -> let these = image_numbers_of_elts [] elts in image_numbers_of_elts (these @ prev) t | _::t -> image_numbers_of_elts prev t | [] -> prev and make_xobjects pdf elts = let numbers = image_numbers_of_elts [] elts in setify <| map (function n -> ("/Im" ^ string_of_int n), Pdf.Indirect n) numbers and make_resources pdf g page' = let resources = match g.resources with | Pdf.Dictionary rs -> rs | _ -> [] and fontdict = Pdf.Dictionary g.fonts and xobjdict = let objs = make_xobjects pdf g.elements in Pdf.Dictionary objs and resources_frompage = match page'.Pdfpage.resources with | Pdf.Dictionary d -> d | _ -> raise (Pdf.PDFError "bad resources in page in make_resources") in let resources = remove "/Shading" resources in let resources = remove "/Pattern" resources in let resources = remove "/ExtGState" resources in let resources = remove "/ColorSpace" resources in (* [fold_right] so that entries overwrite *) Pdf.Dictionary (fold_right (fun (k, v) d -> add k v d) ["/Font", fontdict; "/XObject", xobjdict] (resources_frompage @ resources)) and page_of_graphic pdf (xmin, ymin, xmax, ymax) graphic = let page = Pdfpage.custompage (Pdf.Array [Pdf.Real xmin; Pdf.Real ymin; Pdf.Real xmax; Pdf.Real ymax]) in let ops, page' = ops_of_graphic_acc pdf page [] graphic.elements in (* We're not including the ExtGState because it's in the page', so need to merge with resources *) let resources = make_resources pdf graphic page' in {page' with Pdfpage.content = [Pdfops.stream_of_ops ops]; Pdfpage.resources = resources} let ops_of_simple_graphic graphic = fst (ops_of_graphic_acc (Pdf.empty ()) (Pdfpage.blankpage Pdfpaper.a4) [] graphic.elements) (* FIXME Add in here a function to copy a page/graphic from one document to another *) let streams_of_simple_graphic g = (page_of_graphic (Pdf.empty ()) (0., 0., 600., 400.) g).Pdfpage.content (* Transforming a graphic *) let transform_segment tr s = let f = Pdftransform.transform_matrix tr in match s with | Straight (x, y) -> Straight (f x, f y) | Bezier (a, b, c, d) -> Bezier (f a, f b, f c, f d) let transform_subpath tr (h, c, segments) = (h, c, map (transform_segment tr) segments) let transform_path tr (w, subpaths) = (w, map (transform_subpath tr) subpaths) let transform_element tr = function | Path (pth, attr) -> Path (transform_path tr pth, attr) | x -> x (* FIXME: Add rest of elements. *) let transform_graphic tr g = {g with elements = map (transform_element tr) g.elements} camlpdf-2.8.1/old/pdfgraphics.mli000066400000000000000000000122251477056064700167250ustar00rootroot00000000000000(** Structured Graphics. This will (eventually) be a module allowing for the raising of a page's contents to a tree form, the manipulation of that tree and its writing back to the page, with no possible loss of fidelity. It is only a little experiment at the moment... *) open Pdfutil open Pdfio (** Point. *) type fpoint = float * float (** Winding rule. *) type winding_rule = EvenOdd | NonZero (** A segment (a straight line or bezier curve) *) type segment = | Straight of fpoint * fpoint | Bezier of fpoint * fpoint * fpoint * fpoint (** Each segment list may be marked as a hole or not. *) type hole = Hole | Not_hole (* A [subpath] is either closed or open. *) type closure = Closed | Open (** A [subpath] is the pair of a hole and a list of segments. *) type subpath = hole * closure * segment list (** A path is made from a number of subpaths. *) type path = winding_rule * subpath list val string_of_path : path -> string (** Colour values *) type tiling = Tiling type function_shading = {funshading_domain : float * float * float * float; funshading_matrix : Pdftransform.transform_matrix; funshading_function : Pdffun.t} type radial_shading = {radialshading_coords : float * float * float * float * float * float; radialshading_domain : float * float; radialshading_function : Pdffun.t list; radialshading_extend : bool * bool} type axial_shading = {axialshading_coords : float * float * float * float; axialshading_domain : float * float; axialshading_function : Pdffun.t list; axialshading_extend : bool * bool} type shading_kind = | FunctionShading of function_shading | AxialShading of axial_shading | RadialShading of radial_shading | FreeFormGouraudShading | LatticeFormGouraudShading | CoonsPatchMesh | TensorProductPatchMesh type shading = {shading_colourspace : Pdf.pdfobject; shading_background : Pdf.pdfobject option; shading_bbox : Pdf.pdfobject option; shading_antialias : bool; shading_matrix : Pdftransform.transform_matrix; shading_extgstate : Pdf.pdfobject; shading : shading_kind} type pattern = | ColouredTilingPattern of tiling | UncolouredTilingPattern of tiling | ShadingPattern of shading type colvals = | Floats of float list | Named of (string * float list) | Pattern of pattern type transparency_attributes = {fill_transparency : float; line_transparency : float} (** Path attributes. *) type path_attributes = {path_transform : Pdftransform.transform_matrix; path_fill : (Pdfspace.t * colvals) option; path_line : (Pdfspace.t * colvals) option; path_linewidth : float; path_joinstyle : int; path_capstyle : int; path_dash : float list * float; path_mitrelimit : float; path_transparency : transparency_attributes; path_intent : string} type text_attributes = {textmode : int} type textblock_attributes = {textblock_transform : Pdftransform.transform_matrix} type textblock = text_attributes * Pdfops.t type image_attributes = {image_transform : Pdftransform.transform_matrix; image_transparency : float; image_softmask : softmask option} (* The /ca value *) and softmask_subtype = Alpha | Luminosity and transparency_group = {tr_group_colourspace : Pdf.pdfobject option; isolated : bool; knockout : bool; tr_graphic : t} and softmask = {softmask_subtype : softmask_subtype; transparency_group : transparency_group; softmask_bbox : float * float * float * float; backdrop : float list option; softmask_transfer : Pdffun.t option} and fontname = string * Pdf.pdfobject (** For now, just support for reading paths out. Eventually a tree-structure for an op stream. *) and graphic_elt = | Path of (path * path_attributes) | Text of textblock list * textblock_attributes | MCPoint of string | MCPointProperties of string * Pdf.pdfobject | MCSection of string * graphic_elt list | MCSectionProperties of string * Pdf.pdfobject * graphic_elt list | Image of image_attributes * int | GraphicInlineImage of Pdf.pdfobject * bytes * Pdftransform.transform_matrix | Clip of path * graphic_elt list | Shading of path option * shading * Pdftransform.transform_matrix and t = {elements : graphic_elt list; (* Page content *) fonts : fontname list; (* Fonts *) resources : Pdf.pdfobject} (* Anything else in /Resources *) (** Bounding box xmin, xmax, ymin, yman of a graphic *) val bbox_of_graphic : t -> float * float * float * float (** Make a graphic from operations. *) val graphic_of_page : Pdf.t -> Pdfpage.t -> t (** Make a graphic from a simple string. *) val graphic_of_ops : Pdfops.t list -> t (** Flatten a graphic to a list of operations and replace the operations in a page by them, returning the new page. *) val page_of_graphic : Pdf.t -> (float * float * float * float) -> t -> Pdfpage.t (** Debug string of a [graphic] *) val string_of_graphic : t -> string (** Operations from a simple graphic (i.e no need for resources etc.) *) val ops_of_simple_graphic : t -> Pdfops.t list (** Pdfdoc.content entry from a simple graphic (i.e no need for resources etc.) *) val streams_of_simple_graphic : t -> Pdf.pdfobject list (** Transform a graphic by a matrix. *) val transform_graphic : Pdftransform.transform_matrix -> t -> t camlpdf-2.8.1/old/pdfshapes.ml000066400000000000000000000140001477056064700162300ustar00rootroot00000000000000(* \chaptertitle{Shapes}{Stroking lines and making shapes} *) (* This module provides for the stroking of lines, and production of shape primitives (circles, regular polygons etc). *) open Pdfutil (* \section{Common geometric functions} *) (* The factor by which we multiply the radius to find the length of the bezier control lines when approximating quarter arcs to make semicircles and circles. *) let kappa = ((sqrt 2. -. 1.) /. 3.) *. 4. (* Calculate rotation from [p] to [p'] about [c] with the shorter arc-length. When arc-lengths are equal, the result may be either. *) let rotation (cx, cy) (px, py) (px', py') = let px = px -. cx and py = py -. cy and px' = px' -. cx and py' = py' -. cy in let a = px *. py' -. py *. px' and b = px *. px' +. py *. py' in atan2 a b (* The absolute angle to a point [p] from a centre [c]. The angle is the rotation clockwise (i.e the first quadrant encountered has positive [x] and [y] values) from East. When the point is [(0, 0)], the result is [0].*) let angle_to (cx, cy) (px, py) = let r = atan2 (py -. cy) (px -. cx) in if r < 0. then r +. 2. *. pi else r (* Restrict an angle [a] to one of those at $s, 2s, 3s\ldots$. We find the two candidate angles, and see which [a] is numerically closer to. The candidate points are taken modulo $2\pi$ for this to work. *) let restrict_angle s a = let p = mod_float (floor (a /. s) *. s) (2. *. pi) in let p' = mod_float (p +. s) (2. *. pi) in if abs_float (p -. a) < abs_float (p' -. a) then p else p' (* \section{Some Useful Shapes} *) (* Make a quarter-circle from a single bezier curve from [s] to $(s + \pi / 2) \bmod 2\pi$ with centre [c] and radius [r]. We cheat by making the standard quarter from [(1, 0)] to [(0, 1)] and rotating using the [Transform] module. *) let quarter s (cx, cy) r = let standard_quarter_points = [(1., 0.); (1., kappa); (kappa, 1.); (0., 1.)] and transform = [Pdftransform.Translate(cx, cy); Pdftransform.Scale((0., 0.), r, r); Pdftransform.Rotate((0., 0.), s)] in match map (Pdftransform.transform transform) standard_quarter_points with | [p; q; r; s] -> Pdfgraphics.Bezier(p, q, r, s) | _ -> raise (Pdf.PDFError ("Shapes.quarter: inconsistency")) (* The anticlockwise variant. *) let quarter_anticlockwise s c r = match quarter s c r with | Pdfgraphics.Bezier(p, q, r, s) -> Pdfgraphics.Bezier(s, r, q, p) | _ -> raise (Pdf.PDFError "Shapes.quarter_anticlockwise: inconsistency") (* Some of the following functions generate what is supposed to be a connected list of segments. However, since they operate by calculating each segment seperately, floating point inaccuracies can arise, making the end of one segment misalign with the start of the next. This function corrects the defect by copying the end of one segment to the beginning of the next. We only need to deal with bezier segments for now. *) let rec joinsegs segments = match segments with | [] -> [] | [x] -> [x] | Pdfgraphics.Bezier(_, _, _, d) as s::Pdfgraphics.Bezier(_, b', c', d')::rest -> s::joinsegs (Pdfgraphics.Bezier(d, b', c', d')::rest) | _ -> raise (Pdf.PDFError "PDFShapes.joinsegs: Segment not supported") (* This version sets the start and end points to p1 and p2 respectively. Used for ensuring round joins join correctly to the rails they connect *) let joinsegs_ends p1 p2 segments = match joinsegs segments with | [] -> [] | [Pdfgraphics.Bezier(a, b, c, d)] -> [Pdfgraphics.Bezier(p1, b, c, p2)] | segs -> match extremes_and_middle segs with | Pdfgraphics.Bezier(_, b, c, d), m, Pdfgraphics.Bezier(a', b', c', _) -> Pdfgraphics.Bezier(p1, b, c, d)::m @ [Pdfgraphics.Bezier(a', b', c', p2)] | _ -> raise (Pdf.PDFError "PDFShapes.joinsegs_ends: Segment not supported") (* The shorter arc made from bezier curves from [p1] to [p2] with centre [c]. The arc is formed from zero or more quarter arcs rotated accordingly, and at most one partial arc produced by truncating a quarter arc, again rotated. If [p1=p2], no segments are produced. If the two curves defined by the arguments are of equal length, the one chosen is undefined. *) (*i let arc p1 p2 c = let ninety = pi /. 2. and angletogo = rotation c p1 p2 (*r signed angle to turn through *) and abs_angle = angle_to c p1 (*r absolute angle to the first point *) and r = distance_between p1 c in (*r radius of the resultant arc *) let quarter, ninety_abs = if angletogo > 0. then quarter, ninety else quarter_anticlockwise, ~-.ninety in let segments = ref [] and angletogo = ref (abs_float angletogo) (*r Have dealt with sign. *) and abs_angle = ref abs_angle in while !angletogo > 0. do if !angletogo >= ninety then begin angletogo := !angletogo -. ninety; segments := (quarter !abs_angle c r)::!segments; abs_angle := mod_float (!abs_angle +. ninety_abs) (2. *. pi) end else (* Calculate a partial arc to finish, if required. *) if !angletogo > 0. then begin let q = quarter !abs_angle c r in let portion_needed = !angletogo /. ninety in let portion, _ = Polygon.bezier_split portion_needed q in segments := portion::!segments; angletogo := 0. end; done; joinsegs_ends p1 p2 (rev !segments) i*) (* Approximate a circle using four bezier curves.*) let circle x y r = Pdfgraphics.NonZero, [(Pdfgraphics.Not_hole, Pdfgraphics.Closed, joinsegs [quarter 0. (x, y) r; quarter (pi /. 2.) (x, y) r; quarter pi (x, y) r; quarter (3. *. pi /. 2.) (x, y) r ])] let rectangle x y w h = (Pdfgraphics.EvenOdd, ([(Pdfgraphics.Not_hole, Pdfgraphics.Closed, [Pdfgraphics.Straight ((x, y), (x +. w, y)); Pdfgraphics.Straight ((x +. w, y), (x +. w, y +. h)); Pdfgraphics.Straight ((x +. w, y +. h), (x, y +. h)); Pdfgraphics.Straight ((x, y +. h), (x, y))])])) camlpdf-2.8.1/old/pdfshapes.mli000066400000000000000000000013071477056064700164070ustar00rootroot00000000000000(** Basic Shapes *) (** The factor by which the radius of a circle is multiplied to find the length of the bezier control lines when approximating quarter arcs to make circles. *) val kappa : float (** Calling [restrict_angle s a] restricts an angle [a] to one of those at [s, 2s, 3s...] returning the chosen one. *) val restrict_angle : float -> float -> float (** Calling [circle x y r] builds a path representing a circle at [(x, y)] with radius [r]. *) val circle : float -> float -> float -> Pdfgraphics.path (** Calling [rectangle x y w h] builds a path representing a rectangle with top left [(x, y)], width [w] and height [h]. *) val rectangle : float -> float -> float -> float -> Pdfgraphics.path camlpdf-2.8.1/old/pdftruetype.ml000066400000000000000000000676461477056064700166560ustar00rootroot00000000000000(* Convert a TrueType Font to a Type 3 font. *) open Pdfutil open Pdfio let dbg = ref false (* text-based debug *) let dbgg = ref false (* graphical debug *) (* 32-bit signed fixed-point number (16.16) returned as two ints *) let read_fixed b = let a = getval_31 b 16 in let b = getval_31 b 16 in a, b (* 16-bit unsigned integer *) let read_ushort b = getval_31 b 16 (* 32-bit unsigned integer *) let read_ulong b = getval_32 b 32 (* Signed byte *) let read_byte b = getval_31 b 8 (* Signed short *) let read_short b = sign_extend 16 (getval_31 b 16) (* fword *) let read_fword = read_short (* f2dot14 - 2 bit signed integer part, 14 bit unsigned fraction *) let read_f2dot14 b = let v = read_ushort b in float_of_int (sign_extend 2 (v lsr 14)) +. (float_of_int (v land 0x3FFF) /. 16384.) (* discard n bytes *) let discard_bytes b n = for x = 1 to n do ignore (getval_31 b 8) done (* longDateTime (stub) *) let read_longdatetime b = discard_bytes b 8; 0 (* The empty glyph. *) let notdef = {Pdfgraphics.elements = []; Pdfgraphics.fonts = []; Pdfgraphics.resources = Pdf.Dictionary []} let string_of_tag t = let a = i32toi (Int32.shift_right t 24) and b = i32toi (Int32.logand 0x000000FFl (Int32.shift_right t 16)) and c = i32toi (Int32.logand 0x000000FFl (Int32.shift_right t 8)) and d = i32toi (Int32.logand 0x000000FFl t) in Printf.sprintf "%C%C%C%C" (char_of_int a) (char_of_int b) (char_of_int c) (char_of_int d) let tag_cmap = 1668112752l and tag_glyf = 1735162214l and tag_maxp = 1835104368l and tag_loca = 1819239265l and tag_head = 1751474532l let read_format_6_encoding_table b = let firstCode = read_ushort b in let entryCount = read_ushort b in let arr = Array.make (max 256 (firstCode + entryCount)) 0 in (* FIXME: This format can address glyphs > 255, but we don't support that elsewhere yet --- but we read the whole format table nonethless *) try for x = firstCode to firstCode + entryCount - 1 do arr.(x) <- read_ushort b done; arr with e -> failwith ("bad format 6 table: " ^ Printexc.to_string e ^ "\n") let read_encoding_table fmt length version b = match fmt with | 0 -> Array.init 256 (function _ -> read_byte b) | 6 -> read_format_6_encoding_table b | n -> if !dbg then Printf.eprintf "read_encoding_table: format %i not known\n%!" n; [||] let read_loca_table indexToLocFormat numGlyphs b = let fix_empties arr = for x = 1 to Array.length arr - 1 do if arr.(x) = arr.(x - 1) then arr.(x - 1) <- -1l done; if arr <> [||] then arr.(Array.length arr - 1) <- -1l in match indexToLocFormat with | 0 -> let arr = Array.init (numGlyphs + 1) (function _ -> i32ofi (read_ushort b * 2)) in fix_empties arr; arr | 1 -> let arr = Array.init (numGlyphs + 1) (function _ -> read_ulong b) in fix_empties arr; arr | _ -> raise (Pdf.PDFError "Unknown indexToLocFormat in read_loca_table") (* NB. Global *) let lastval = ref (false, false, false, false, false) let repeats = ref 0 (* Read the flags for pts points *) let rec read_flags flags b pts = if pts <= 0 then rev flags else let getsingle () = if !repeats > 0 then begin repeats := !repeats - 1; !lastval end else let flag = read_byte b in let oncurve, xshort, yshort, rp, xsame, ysame = flag land 0b00_00_00_01 = 0b1, flag land 0b00_00_00_10 = 0b10, flag land 0b00_00_01_00 = 0b1_00, flag land 0b00_00_10_00 = 0b10_00, flag land 0b00_01_00_00 = 0b1_00_00, flag land 0b00_10_00_00 = 0b10_00_00 in if !dbg then Printf.eprintf "flag has on curve %b, xshort %b, yshort %b, repeat %b, xsame %b, ysame %b\n%!" oncurve xshort yshort rp xsame ysame; if rp then begin let rs = read_byte b in if !dbg then Printf.eprintf "There are %i repeats of this flag...\n%!" rs; repeats := rs; lastval := (oncurve, xshort, yshort, xsame, ysame); !lastval end else (oncurve, xshort, yshort, xsame, ysame) in read_flags (getsingle ()::flags) b (pts - 1) let read_flags = read_flags [] (* NB. Global. *) let prev = ref 0 (* NB. Set up prev before calling for each glyph *) let read_coordinates b flags = map (function (*short, same *) | true, false -> prev := !prev - read_byte b; !prev | true, true -> prev := !prev + read_byte b; !prev | false, false -> prev := !prev + read_short b; !prev | false, true -> !prev) flags (* Returns a list of lines and quadratic beziers for the input contour. Returns floats. *) type point = float * float type part = | Line of point * point | QuadBezier of point * point * point let rec break_coordinates_inner prev = function | (true, (x, y))::((true, (x', y')) as l)::r -> break_coordinates_inner (Line ((x, y), (x', y'))::prev) (l::r) | (true, (x, y))::(false, (x', y'))::((true, (x'', y'')) as l)::r -> break_coordinates_inner (QuadBezier ((x, y), (x', y'), (x'', y''))::prev) (l::r) | (true, (x, y))::(false, (x', y'))::((false, (x'', y'')) as l)::r -> let midpoint = ((x' +. x'') /. 2., (y' +. y'') /. 2.) in break_coordinates_inner ((QuadBezier ((x, y), (x', y'), midpoint))::prev) ((true, midpoint)::l::r) | [_] -> rev prev | _ -> (*if !dbg then*) flprint "break_coordinated_inner: unrecognized sequence\n"; rev prev (* FIXME: The truetype spec says that any combination of on and off points is ok, but our conversion relies on the pattern (true + zero or more false) being repeated. Strategy: We can special case when all are false (ignore it), and otherwise cycle the list until a true is first. Then we have just reduced the problem to not being able to do anything when all points are off the curve. *) let rec all_points_off = function [] -> true | (false, _)::t -> all_points_off t | (true, _)::_ -> false let rec cycle_true_first = function [] -> assert false | (true, _) as h::t -> h::t | (false, _) as h::t -> cycle_true_first (t @ [h]) let break_coordinates = function | [] -> [] | [_] -> [] | l -> let tofloat (t, (x, y)) = (t, (float x, float y)) in if all_points_off l then [] else let closed = match cycle_true_first l with | [] -> assert false | h::t -> [h] @ t @ [h] in break_coordinates_inner [] (map tofloat closed) let print_unbroken_coordinates (t, (x, y)) = Printf.eprintf "%b, %i, %i\n%!" t x y let break_coordinates cs = if !dbg then begin flprint "This contour:\n"; iter print_unbroken_coordinates cs end; break_coordinates cs let sofp (x, y) = Printf.sprintf "(%f, %f)" x y let string_of_coordinate = function | Line (p, p') -> Printf.sprintf "Line %s --> %s\n" (sofp p) (sofp p') | QuadBezier (p, p', p'') -> Printf.sprintf "QuadBezier %s --> %s --> %s\n" (sofp p) (sofp p') (sofp p'') let print_coordinates = iter (function x -> flprint (string_of_coordinate x)) (* Cubic bezier from quadratic bezier *) let mkcubicbezier (p0x, p0y) (p1x, p1y) (p2x, p2y) = let cp1x = p0x +. ((2. /. 3.) *. (p1x -. p0x)) and cp1y = p0y +. ((2. /. 3.) *. (p1y -. p0y)) and cp2x = p2x +. ((2. /. 3.) *. (p1x -. p2x)) and cp2y = p2y +. ((2. /. 3.) *. (p1y -. p2y)) in Pdfgraphics.Bezier ((p0x, p0y), (cp1x, cp1y), (cp2x, cp2y), (p2x, p2y)) let graphic_of_contours contours = {Pdfgraphics.elements = [Pdfgraphics.Path ((Pdfgraphics.NonZero, map (function bits -> Pdfgraphics.Not_hole, Pdfgraphics.Closed, bits) (map_lol (function | Line (p, p') -> Pdfgraphics.Straight (p, p') | QuadBezier (p, p', p'') -> mkcubicbezier p p' p'') contours)), {Pdfgraphics.path_transform = Pdftransform.i_matrix; Pdfgraphics.path_fill = Some (Pdfspace.DeviceGray, Pdfgraphics.Floats [1.]); Pdfgraphics.path_line = None; Pdfgraphics.path_linewidth = 0.; Pdfgraphics.path_joinstyle = 0; Pdfgraphics.path_capstyle = 0; Pdfgraphics.path_dash = ([0.], 0.); Pdfgraphics.path_mitrelimit = 0.; Pdfgraphics.path_transparency = {Pdfgraphics.fill_transparency = 1.; Pdfgraphics.line_transparency = 1.}; Pdfgraphics.path_intent = "/RelativeColorimetric"})]; Pdfgraphics.fonts = []; Pdfgraphics.resources = Pdf.Dictionary []} let merge_components graphics = {Pdfgraphics.elements = flatten (map (fun g -> g.Pdfgraphics.elements) graphics); Pdfgraphics.fonts = []; Pdfgraphics.resources = Pdf.Dictionary []} let arg_1_and_2_are_words = 0b1 and args_are_xy_values = 0b10 and round_xy_to_grid = 0b100 and we_have_a_scale = 0b1000 and more_components = 0b100000 and we_have_an_x_and_y_scale = 0b1000000 and we_have_a_two_by_two = 0b10000000 and we_have_instructions = 0b100000000 and use_my_metrics = 0b1000000000 (* FIXME: Missing things: WE_HAVE_A_2_BY_2 and WE_HAVE_AND_XY_SCALE missing. Also, args_are_xy_values false ==> points not values - need examples of all these three *) let rec read_composite_glyph rg b = let graphics = ref [] in if !dbg then flprint "reading composite glyph...\n"; let xmin = read_fword b in let ymin = read_fword b in let xmax = read_fword b in let ymax = read_fword b in if !dbg then Printf.printf "xmin, ymin, xmax, ymax = %i, %i, %i, %i\n" xmin ymin xmax ymax; let finished = ref false in while not !finished do let flags = read_ushort b in let glyphIndex = read_ushort b in if !dbg then Printf.printf "flags = %i, glyph_index = %i\n" flags glyphIndex; let argument1, argument2 = if (flags land arg_1_and_2_are_words) > 0 then let one = read_short b in let two = read_short b in one, two else let v = read_ushort b in v lsr 8, v land 255 in if !dbg then Printf.printf "arg1 = %i, arg2 = %i\n" argument1 argument2; begin if (flags land we_have_a_scale) > 0 then let scale = read_f2dot14 b in if !dbg then Printf.printf "have read scale %f\n" scale; let currpos = Pdfio.bitstream_pos b in let graphic = rg glyphIndex in Pdfio.bitstream_seek b currpos; let transformed = Pdfgraphics.transform_graphic (Pdftransform.matrix_of_transform [Pdftransform.Translate (float_of_int argument1, float_of_int argument2); Pdftransform.Scale ((0., 0.), scale, scale)]) graphic in graphics := transformed::!graphics else if (flags land we_have_an_x_and_y_scale) > 0 then let xscale = read_f2dot14 b in let yscale = read_f2dot14 b in if !dbg then Printf.printf "read scales %f, %f\n" xscale yscale; else if (flags land we_have_a_two_by_two) > 0 then let xscale = read_f2dot14 b in let scale01 = read_f2dot14 b in let scale10 = read_f2dot14 b in let yscale = read_f2dot14 b in if !dbg then Printf.printf "read scalesss %f, %f, %f, %f\n" xscale scale01 scale10 yscale else if !dbg then flprint "no scale\n"; let currpos = Pdfio.bitstream_pos b in let graphic = rg glyphIndex in Pdfio.bitstream_seek b currpos; let moved_graphic = Pdfgraphics.transform_graphic (Pdftransform.mktranslate (float_of_int argument1) (float_of_int argument2)) graphic in graphics := moved_graphic::!graphics end; if (flags land more_components) = 0 then set finished done; if !dbg then Printf.printf "We have read %i composite glyph components\n" (length !graphics); merge_components !graphics and read_glyph rg b = let numberOfContours = read_short b in match numberOfContours with | 0 -> notdef | -1 -> read_composite_glyph rg b | x when x < -1 -> raise (Pdf.PDFError "Unknown numberOfContours") | _ -> let xMin = read_fword b in let yMin = read_fword b in let xMax = read_fword b in let yMax = read_fword b in if !dbg then Printf.printf "numberOfContours = %i, xmin = %i, ymin = %i, xmax = %i, ymax = %i\n" numberOfContours xMin yMin xMax yMax; let endPtsOfContours = Array.init numberOfContours (function _ -> read_ushort b) in if !dbg then (Printf.printf "endPtsOfContours:"; Array.iter (Printf.printf "%i ") endPtsOfContours; flprint "\n"); let pointstoread = (endPtsOfContours.(0) + 1)::couple (fun x y -> y - x) (Array.to_list endPtsOfContours) in let instructionLength = read_ushort b in if !dbg then Printf.printf "instructionLength is %i\n" instructionLength; let _ = Array.init instructionLength (function _ -> read_byte b) in (* Read a list of lists of (on/off, x is short/long, y is short/long, xsame, ysame) triples *) if !dbg then Printf.printf "Reading flags...\n"; let flags = map (fun pts -> if !dbg then Printf.printf "to read: flags for %i pts on a contour:\n" pts; read_flags b pts) pointstoread in prev := 0; repeats := 0; if !dbg then Printf.printf "Reading x coordinates\n"; let xcoords = map (fun flags -> read_coordinates b (map (fun (_, xs, _, xsame, _) -> (xs, xsame)) flags)) flags in prev := 0; repeats := 0; if !dbg then Printf.printf "Reading y coordinates\n"; let ycoords = map (fun flags -> read_coordinates b (map (fun (_, _, ys, _, ysame) -> (ys, ysame)) flags)) flags in let contours = List.map2 combine xcoords ycoords in let pairs = if length flags <> length contours then raise (Pdf.PDFError "bad flags / contours in truetype font") else combine (map_lol (fun (on, _, _, _, _) -> on) flags) contours in graphic_of_contours (map break_coordinates (map (function (a, b) -> combine a b) pairs)) let read_glyph rg b = try read_glyph rg b with e -> if !dbg then Printf.printf "Failed to read glyph with %s\n" (Printexc.to_string e); graphic_of_contours [] let parse_truetype_font data = (*if !dbgg then ignore (Graphics.open_graph " 1024x1024");*) let mk_b byte_offset = bitbytes_of_input (let i = input_of_bytes data in i.seek_in byte_offset; i) in let b = mk_b 0 in let major, minor = read_fixed b in if !dbg then Printf.printf "Truetype font version %i.%i\n" major minor; let numTables = read_ushort b in let searchRange = read_ushort b in let entrySelector = read_ushort b in let rangeShift = read_ushort b in if !dbg then Printf.printf "numTables = %i, searchRange = %i, entrySelector = %i, rangeShift = %i\n" numTables searchRange entrySelector rangeShift; let tables = ref [] in for x = 1 to numTables do let tag = read_ulong b in let checkSum = read_ulong b in let offset = read_ulong b in let ttlength = read_ulong b in if !dbg then Printf.printf "tag = %li = %s, checkSum = %li, offset = %li, ttlength = %li\n" tag (string_of_tag tag) checkSum offset ttlength; tables =| (tag, checkSum, offset, ttlength); done; let cmap = match keep (function (t, _, _, _) -> t = tag_cmap) !tables with | (_, _, o, l)::_ -> Some (o, l) | [] -> None in let glyphcodes = ref [] in begin match cmap with | None -> glyphcodes := ilist 0 255 | Some (cmapoffset, cmaplength) -> let b = mk_b (i32toi cmapoffset) in let cmap_version = read_ushort b in let num_encoding_tables = read_ushort b in if !dbg then Printf.printf "cmap version %i. There are %i encoding tables\n" cmap_version num_encoding_tables; for x = 1 to num_encoding_tables do let platform_id = read_ushort b in let encoding_id = read_ushort b in let subtable_offset = read_ulong b in if !dbg then Printf.printf "subtable %i. platform_id = %i, encoding_id = %i, subtable_offset = %li\n" x platform_id encoding_id subtable_offset; let b = mk_b (i32toi cmapoffset + i32toi subtable_offset) in let fmt = read_ushort b in let lngth = read_ushort b in let version = read_ushort b in if !dbg then Printf.printf "subtable has format %i, length %i, version %i\n" fmt lngth version; let got_glyphcodes = read_encoding_table fmt length version b in if !glyphcodes = [] && got_glyphcodes <> [||] then (if !dbg then flprint "USING THIS TABLE\n"; glyphcodes := Array.to_list got_glyphcodes); if !dbg && got_glyphcodes <> [||] then array_iter2 (Printf.printf "charcode %i --> glyphcode %i\n") (Array.of_list (ilist 0 255)) got_glyphcodes done; end; let maxpoffset, maxplength = match keep (function (t, _, _, _) -> t = tag_maxp) !tables with | (_, _, o, l)::_ -> o, l | [] -> raise (Pdf.PDFError "No maxp table found in TrueType font") in let b = mk_b (i32toi maxpoffset) in let major, minor = read_fixed b in let numGlyphs = read_ushort b in if !dbg then Printf.printf "maxp table version %i.%i: This font has %i glyphs\n" major minor numGlyphs; let headoffset, headlength = match keep (function (t, _, _, _) -> t = tag_head) !tables with | (_, _, o, l)::_ -> o, l | [] -> raise (Pdf.PDFError "No maxp table found in TrueType font") in let b = mk_b (i32toi headoffset) in let _ (*major, minor*) = read_fixed b in let _ (*revmajor, revminor*) = read_fixed b in let _ (*checkSumAdjustment*) = read_ulong b in let _ (*magicNumber*) = read_ulong b in let _ (*flags*) = read_ushort b in let unitsPerEm = read_ushort b in let _ (*created*) = read_longdatetime b in let _ (*modified*) = read_longdatetime b in let _ (*xMin*) = read_fword b in let _ (*yMin*) = read_fword b in let _ (*xMax*) = read_fword b in let _ (*yMax*) = read_fword b in let _ (*macStyle*) = read_ushort b in let _ (*lowestRecPPEM*) = read_ushort b in let _ (*fontDirectionHint*) = read_short b in let indexToLocFormat = read_short b in let _ (*glyphDataFormat*) = read_short b in if !dbg then Printf.printf "head table: indexToLocFormat is %i\n" indexToLocFormat; let locaoffset, localength = match keep (function (t, _, _, _) -> t = tag_loca) !tables with | (_, _, o, l)::_ -> o, l | [] -> raise (Pdf.PDFError "No maxp table found in TrueType font") in let b = mk_b (i32toi locaoffset) in let offsets = read_loca_table indexToLocFormat numGlyphs b in if !dbg then begin Printf.printf "Have read loca table:\n"; array_iter2 (Printf.printf "Glyph %i is at offset %li\n") (Array.of_list (ilist 0 numGlyphs)) offsets; flush stdout end; let glyfoffset, glyflength = match keep (function (t, _, _, _) -> t = tag_glyf) !tables with | (_, _, o, l)::_ -> o, l | [] -> raise (Pdf.PDFError "No glyf table found in TrueType font") in let glyphcache = Hashtbl.create 300 in let glyphs = Array.to_list (Array.map (function offset -> if offset = -1l then notdef else try Hashtbl.find glyphcache offset with Not_found -> let r = let b = mk_b (i32toi glyfoffset + i32toi offset) in read_glyph (* Build the function reads a glyph from an offset. Gross. *) (fun glyphnum -> if !dbg then Printf.printf "READING GLYPH NUMBER %i\n" glyphnum; try let offset = offsets.(glyphnum) in if offset = -1l then notdef else try Hashtbl.find glyphcache offset with Not_found -> let b = mk_b (i32toi glyfoffset + i32toi offset) in let r = read_glyph (fun _ -> flprint "too much font recursion"; notdef (* FIXME *)) b in Hashtbl.add glyphcache offset r; r with _ -> flprint "Failed component read\n"; notdef) b in Hashtbl.add glyphcache offset r; r) offsets) in if !dbg then Printf.printf "Read %i glyphs\n" (length glyphs); (map (function incode -> (*Printf.printf "So, incode %i " incode;*) let glyphcode = List.nth !glyphcodes incode in (*Printf.printf "is glyphcode %i \n" glyphcode;*) try List.nth glyphs glyphcode with _ -> if !dbg then Printf.printf "ERROR: no glyph for incode %i which is glyphcode %i - substituting notdef\n" incode glyphcode; notdef) (ilist 0 255)), (let scale = 1.0 /. (float_of_int unitsPerEm) in Pdftransform.matrix_of_op (Pdftransform.Scale ((0., 0.), scale, scale))) (* Make a CharProc stream from a graphic. We need to filter out ops we don't want. *) let charprocbytes_of_graphic g matrix = Pdfops.stream_of_ops (Pdfops.Op_d1 (0., 0., 0., 0., 0., 0.):: lose (function | Pdfops.Op_q | Pdfops.Op_Q | Pdfops.Op_cm _ | Pdfops.Op_w _ | Pdfops.Op_J _ | Pdfops.Op_j _ | Pdfops.Op_M _ | Pdfops.Op_ri _ | Pdfops.Op_CS _ | Pdfops.Op_SCN _ | Pdfops.Op_cs _ | Pdfops.Op_scn _ -> true | _ -> false) (Pdfgraphics.ops_of_simple_graphic (Pdfgraphics.transform_graphic matrix g))) let to_type3 pdf font = match font with | Pdftext.SimpleFont ({Pdftext.fonttype = Pdftext.Truetype; Pdftext.encoding = original_encoding; Pdftext.fontdescriptor = Some ({Pdftext.fontfile = Some Pdftext.FontFile2 fontfileobj} as fontdescriptor)} as fontrec) -> let glyphs, fontmatrix = let str = Pdf.direct pdf (Pdf.Indirect fontfileobj) in Pdfcodec.decode_pdfstream pdf str; match str with | Pdf.Stream {contents = (_, Pdf.Got data)} -> begin try parse_truetype_font data with e -> Printf.printf "Error %s" (Printexc.to_string e); raise (Pdf.PDFError "TrueType failure") end | _ -> raise (Pdf.PDFError "Truetype data not a stream") in let charprocs = let scalematrix = Pdftransform.matrix_compose fontmatrix (Pdftransform.matrix_of_op (Pdftransform.Scale ((0., 0.), 1000., 1000.))) in map2 (fun n g -> "/" ^ string_of_int n, Pdf.Indirect (Pdf.addobj pdf (charprocbytes_of_graphic g scalematrix))) (ilist 0 (length glyphs - 1)) glyphs and fontmatrix = Pdftransform.matrix_of_op (Pdftransform.Scale ((0., 0.), 0.001, 0.001)) and fontbbox = (0., 0., 0., 0.) and encoding = Pdftext.CustomEncoding (Pdftext.ImplicitInFontFile, []) in Pdftext.SimpleFont {fontrec with Pdftext.fonttype = Pdftext.Type3 {Pdftext.fontbbox = fontbbox; Pdftext.fontmatrix = fontmatrix; Pdftext.charprocs = charprocs; Pdftext.type3_resources = Pdf.Dictionary []}; Pdftext.encoding = encoding; Pdftext.fontdescriptor = Some fontdescriptor} | _ -> raise (Pdf.PDFError "Pdftruetype.to_type3: This is not a TrueType font") (* let iround f = int_of_float (floor f) / 3 + 100 in flprint "This glyph:\n"; iter (fun (flags, coords) -> flprint "This contour:\n"; iter2 (fun on (x, y) -> Printf.printf "on = %b, point = (%i, %i)\n" on x y; Graphics.set_color (if on then Graphics.blue else Graphics.red); Graphics.draw_circle (iround (float x) + 200) ((iround (float y)) + 200) 10) flags coords; let broken = break_coordinates (combine flags coords) in print_coordinates broken; if !dbgg then begin Graphics.set_color Graphics.black; iter (function | Line ((x, y), (x', y')) -> Graphics.moveto (iround x + 200) (iround y + 200); Graphics.lineto (iround x' + 200) (iround y' + 200) | QuadBezier ((x, y), (x', y'), (x'', y'')) -> let Pdfgraphics.Bezier ((ax, ay), (bx, by), (cx, cy), (dx, dy)) = mkcubicbezier (x, y) (x', y') (x'', y'') in Graphics.moveto (iround ax + 200) (iround ay + 200); Graphics.curveto (iround bx + 200, iround by + 200) (iround cx + 200, iround cy + 200) (iround dx + 200, iround dy + 200)) broken end; ) pairs; (*graphic_of_contours broken*) if !dbgg then begin ignore (Graphics.wait_next_event [Graphics.Key_pressed]); Graphics.clear_graph (); end;*) camlpdf-2.8.1/old/pdftruetype.mli000066400000000000000000000003261477056064700170050ustar00rootroot00000000000000(** Convert a TrueType font to a Type 3 Font. *) (** The type 3 font will not necessarily be valid for inclusion in a PDF file, this is used for rendering. *) val to_type3 : Pdf.t -> Pdftext.font -> Pdftext.font camlpdf-2.8.1/old/pdftype0.ml000066400000000000000000000022371477056064700160170ustar00rootroot00000000000000(* Convert an Type 0 composite font containing CFF / Type 1 / Truetype descendant font into a Type 3 font. The resultant font is for internal use only and is not a valid PDF font. Only deals with Identity-H at the moment. A full treatment of composite fonts will require more work. *) open Pdfutil let widths_of_cidwidths l default = let arr = Array.make 256 (float_of_int default) in iter (fun (x, f) -> if x >= 0 && x <= 255 then arr.(x) <- f) l; arr let to_type3 pdf = function Pdftext.CIDKeyedFont (basefont, cidfont, Pdftext.Predefined "/Identity-H") -> let font = Pdftext.SimpleFont {Pdftext.fonttype = Pdftext.Type1; Pdftext.basefont = basefont; Pdftext.fontmetrics = Some (widths_of_cidwidths cidfont.Pdftext.cid_widths cidfont.Pdftext.cid_default_width); Pdftext.fontdescriptor = Some cidfont.Pdftext.cid_fontdescriptor; Pdftext.encoding = Pdftext.ImplicitInFontFile; Pdftext.firstchar = 0; Pdftext.lastchar = 0; Pdftext.widths = [||]} in Pdfcff.to_type3 pdf font | _ -> raise (Pdf.PDFError "Pdftype0.to_type3 : not supported") camlpdf-2.8.1/old/pdftype0.mli000066400000000000000000000004561477056064700161710ustar00rootroot00000000000000(** Type 0 font support *) (** Convert an Type 0 composite font containing CFF / Type 1 / Truetype descendant font into a Type 3 font. Only deals with /Identity-H at the moment. Used for rendering, not a valid type3 font for inclusion in a PDF. *) val to_type3 : Pdf.t -> Pdftext.font -> Pdftext.font camlpdf-2.8.1/old/pdftype1.ml000066400000000000000000000001571477056064700160170ustar00rootroot00000000000000(* Convert a PostScript Type 1 Font to a Type 3 font. *) open Pdfutil open Pdfio let to_type3 pdf font = font camlpdf-2.8.1/old/pdftype1.mli000066400000000000000000000002161477056064700161640ustar00rootroot00000000000000(** Convert an PostScript Type 1 Font to a Type 3 Font. *) (** Not yet implemented. *) val to_type3 : Pdf.t -> Pdftext.font -> Pdftext.font camlpdf-2.8.1/pdf.ml000066400000000000000000001203711477056064700142570ustar00rootroot00000000000000(* This module declares a data type which represents an Adobe PDF document, and defines various simple operations on it. *) open Pdfutil open Pdfio (* Predicate on characters delimiting entities. *) let is_delimiter = function | '(' | ')' | '<' | '>' | '[' | ']' | '{' | '}' | '%' | '/' -> true | _ -> false (* Streams of binary data, byte-addressable, can either be in memory (Got) or still in an input channel (ToGet). It may have been decrypted or encrypted, but the actual calculations deferred: this is indicated by the crypt record element. *) type saved_encryption = {from_get_encryption_values : Pdfcryptprimitives.encryption * string * string * int32 * string * string option * string option; encrypt_metadata : bool; perms : string} type deferred_encryption = {crypt_type : Pdfcryptprimitives.encryption; file_encryption_key : string option; obj : int; gen : int; key : int array; keylength : int; r : int} (*let print_deferred_encryption e = begin match e.crypt_type with | Pdfcryptprimitives.ARC4 (a, b) -> Printf.printf "crypt_type = ARC4 (%i, %i)\n" a b | Pdfcryptprimitives.AESV2 -> Printf.printf "crypt_type = AESV2\n" | Pdfcryptprimitives.AESV3 x -> Printf.printf "crypt_type = AESV3 %b\n" x end; begin match e.file_encryption_key with | None -> Printf.printf "file_encryption_key: None\n" | Some _ -> Printf.printf "file_encryption_key: Some\n" end; Printf.printf "key = "; Array.iter (fun x -> Printf.printf "%C" (char_of_int x)) e.key; Printf.printf "\n"; Printf.printf "obj = %i, gen = %i\n" e.obj e.gen; Printf.printf "keylength = %i\n" e.keylength; Printf.printf "r = %i\n" e.r*) type toget_crypt = | NoChange | ToDecrypt of deferred_encryption type toget = {input : input; position : int; length : int; crypt : toget_crypt} let toget ?(crypt = NoChange) input position length = {input = input; position = position; length = length; crypt = crypt} let length_of_toget t = t.length let position_of_toget t = t.position let input_of_toget t = t.input type stream = | Got of bytes | ToGet of toget (* Type for individual PDF objects. A Name includes the initial `/'. A Stream consists of a reference to a pair of the stream dictionary (another pdfobject) and a stream. Thus a pdfobject is technically mutable. However, at the user level, it is intended to be immutable: changes should be limited to encoding and decoding of the stream. Note that pdfobjects are not always amenable to polymorphic equality testing, since the Pdio.input in the ToGet part of a stream contains functional values. *) type pdfobject = | Null | Boolean of bool | Integer of int | Real of float | String of string | Name of string | Array of pdfobject list | Dictionary of (string * pdfobject) list | Stream of (pdfobject * stream) ref | Indirect of int (* For debug. Filled in by Pdfwrite *) let string_of_pdf : (pdfobject -> string) ref = ref (function _ -> "") (* An object is either lexed, or needs to be lexed from a position in the input. Parsed - Not from an object stream, fully parsed, not necessarily decrypted yet ParsedAlreadyDecrypted - Was from an object stream, decrypted already when object stream read ToParse - Not parsed yet. Needs to be read from an object, which may still be encrypted ToParseFromObjectStream - (stream object number, index in stream) Not parsed yet. Will come from an object stream. *) type objectdata = | Parsed of pdfobject | ParsedAlreadyDecrypted of pdfobject | ToParse | ToParseFromObjectStream of (int, int list) Hashtbl.t * int * int * (int -> int list -> (int * (objectdata ref * int)) list) type pdfobjmap_key = int type pdfobjmap = (int, objectdata ref * int) Hashtbl.t let pdfobjmap_empty () : pdfobjmap = Hashtbl.create 500 let pdfobjmap_find key map = Hashtbl.find map key let pdfobjmap_add key value map = Hashtbl.replace map key value; map let pdfobjmap_bindings_inorder map = let r = ref [] in Hashtbl.iter (fun k v -> r := (k, v)::!r) map; sort (fun (a, _) (b, _) -> compare a b) !r let pdfobjmap_iter_inorder f map = iter (function (k, v) -> f k v) (pdfobjmap_bindings_inorder map) let pdfobjmap_bindings map = let r = ref [] in Hashtbl.iter (fun k v -> r := (k, v)::!r) map; !r let pdfobjmap_iter = Hashtbl.iter let pdfobjmap_remove key map = Hashtbl.remove map key; map (* We hold the maximum object number in use, maxobjnum to allow easy production of new keys for the map. *) type pdfobjects = {mutable maxobjnum : int; mutable parse : (pdfobjmap_key -> pdfobject) option; mutable pdfobjects : pdfobjmap; mutable object_stream_ids : (int, int) Hashtbl.t} (* PDF Document. The major and minor version numbers, the root object number, the list of objects and the trailer dictionary. This represents the contents of a PDF file's user objects (object streams and other mechanisms involved only in reading and writing are abstracted away). *) type t = {mutable major : int; mutable minor : int; mutable root : int; mutable objects : pdfobjects; mutable trailerdict : pdfobject; mutable was_linearized : bool; mutable saved_encryption : saved_encryption option} (* The null PDF document. *) let empty () = {major = 2; minor = 0; root = 0; objects = {maxobjnum = 0; parse = None; pdfobjects = pdfobjmap_empty (); object_stream_ids = null_hash ()}; trailerdict = Dictionary []; was_linearized = false; saved_encryption = None} (* General exception for low-level errors. *) exception PDFError of string let input_pdferror i s = Printf.sprintf "%s whilst reading file %s at position %i" s i.Pdfio.source (i.Pdfio.pos_in ()) (* Predicate on those characters considered whitespace in PDF files. *) let is_whitespace = function | '\000' | '\009' | '\010' | '\012' | ' ' | '\013' -> true | _ -> false let is_not_whitespace = function | '\000' | '\009' | '\010' | '\012' | ' ' | '\013' -> false | _ -> true let process_deferred_cryption toget_crypt data = match toget_crypt with NoChange -> data | ToDecrypt saved -> (*Printf.printf "Forcing...\n"; print_deferred_encryption saved;*) Pdfcryptprimitives.decrypt_stream_data saved.crypt_type false saved.file_encryption_key saved.obj saved.gen saved.key saved.keylength saved.r data let remove_string_compare (k' : string) l = let rec remove_inner r (k' : string) = function | [] -> r | (k, _)::t when k = k' -> List.rev_append r t | h::t -> remove_inner (h::r) k' t in remove_inner [] k' l (* Remove a dictionary entry. Also works for streams. *) let rec remove_dict_entry dict key = match dict with | Dictionary d -> Dictionary (remove_string_compare key d) | Stream ({contents = (dict', stream)} as s) -> s := (remove_dict_entry dict' key, stream); Stream s | _ -> raise (PDFError "remove_dict_entry: not a dictionary") (* Replace dict entry, raising Not_found if it's not there. Also works for streams. *) let rec replace_dict_entry dict key value = match dict with | Null -> Dictionary (replace key value []) | Dictionary d -> Dictionary (replace key value d) | Stream ({contents = (dict', stream)} as s) -> s := (replace_dict_entry dict' key value, stream); Stream s | _ -> raise (PDFError "replace_dict_entry: not a dictionary.") (* Add a dict entry, replacing if there. Also works for streams. *) let rec add_dict_entry dict key value = match dict with | Null -> Dictionary (add key value []) | Dictionary d -> Dictionary (add key value d) | Stream ({contents = (dict', stream)} as s) -> s := (add_dict_entry dict' key value, stream); Stream s | _ -> raise (PDFError "add_dict_entry: not a dictionary.") (* Get a stream from disk if it hasn't already been got. *) let getstream = function | Stream ({contents = (d, ToGet {input = i; position = o; length = l; crypt = crypt})} as stream) -> if l = 0 then stream := (d, Got (mkbytes 0)) else begin try let data = process_deferred_cryption crypt (Pdfio.bytes_of_input i o l) in (* Correct the length *) let d' = match d with Dictionary _ -> replace_dict_entry d "/Length" (Integer (bytes_size data)) | _ -> d (* May be null in Pdfwrite.WStream *) in stream := (d', Got data) with e -> raise (PDFError ("Pdf.getstream: can't read stream" ^ Printexc.to_string e)) end | Stream {contents = (_, Got _)} -> () | _ -> raise (PDFError "Pdf.getstream: not a stream") let recurse_array (f : pdfobject -> pdfobject) elts = Array (map f elts) (* Similarly for dictionaries. *) let rec recurse_dict_inner f prev = function | [] -> prev | (n, o)::t -> recurse_dict_inner f ((n, f o)::prev) t let recurse_dict (f : pdfobject -> pdfobject) elts = Dictionary (recurse_dict_inner f [] elts) let change_obj doc i obj = fst (pdfobjmap_find i doc.objects.pdfobjects) := Parsed obj (* Parse an object [n] in document [pdf], updating the object in the document so it is ready-parsed should it be required again. *) let parse_lazy pdf n = match pdf.objects.parse with | None -> assert false | Some f -> let obj = f n in change_obj pdf n obj; obj (* Remove an object. *) let removeobj doc o = doc.objects <- {doc.objects with pdfobjects = pdfobjmap_remove o doc.objects.pdfobjects} (* Look up an object. On an error return Null *) let rec lookup_obj doc i = try match fst (pdfobjmap_find i doc.objects.pdfobjects) with | {contents = Parsed obj | ParsedAlreadyDecrypted obj} -> obj | {contents = ToParse} -> parse_lazy doc i | {contents = ToParseFromObjectStream (themap, streamobjnum, _, objstreamparser)} -> parse_delayed_object_stream themap i streamobjnum doc objstreamparser with Not_found -> Null (* When we encounter a ToParseFromObjectStream, we: a) Find all the ToParseFromObjectStream objects in the PDF with the same stream object number b) Read the object stream in the usual way c) Replace each object in the PDF with the parsed one, marked as already decrypted. d) Delete the object stream, since it is no longer required. e) Return the new object. *) and parse_delayed_object_stream themap objnum streamobjnum pdf objstreamparser = let indexes = Hashtbl.find themap objnum in let objectsfromstream = objstreamparser streamobjnum indexes in iter (function (objnum, newobject) -> pdf.objects.pdfobjects <- pdfobjmap_add objnum newobject pdf.objects.pdfobjects) objectsfromstream; removeobj pdf streamobjnum; (* In the event that the object number we're looking for wasn't actually in the object stream due to a malformed file, we would enter an infinite loop parse_delayed_object_stream -> lookup_obj -> parse_delayed_object_stream etc. Check object was actually returned to avoid that. *) if mem objnum (map fst objectsfromstream) then lookup_obj pdf objnum else Null (* Parse all object streams in a document *) let resolve_all_delayed_object_streams pdf = iter (function (n, _) -> ignore (lookup_obj pdf n)) (pdfobjmap_bindings pdf.objects.pdfobjects) (* Return a float from a PDF number. *) let rec getnum pdf = function | Real a -> a | Integer a -> float a | Indirect i -> getnum pdf (lookup_obj pdf i) | _ -> raise (PDFError "Pdf.getnum: not a number") (* Parse a PDF rectangle data structure. Returns min x, min y, max x, max y. *) let parse_rectangle pdf = function | Array [a; b; c; d] -> begin try let x, y, x', y' = getnum pdf a, getnum pdf b, getnum pdf c, getnum pdf d in fmin x x', fmin y y', fmax x x', fmax y y' with PDFError _ -> raise (PDFError "Pdf.parse_rectangle: bad rectangle") end | _ -> raise (PDFError "Pdf.parse_rectangle: not a rectangle") let catalog_of_pdf pdf = try lookup_obj pdf pdf.root with Not_found -> raise (PDFError "No catalog") (* Given any pdf document and object, follow indirections to yield a direct object. A hanging indirect is defined as Null. *) let rec direct pdf = function | Indirect i -> begin try match fst (pdfobjmap_find i pdf.objects.pdfobjects) with | {contents = Parsed pdfobject | ParsedAlreadyDecrypted pdfobject} -> direct pdf pdfobject | {contents = ToParse} -> parse_lazy pdf i | {contents = ToParseFromObjectStream (themap, streamobjnum, _, objstreamparser)} -> parse_delayed_object_stream themap i streamobjnum pdf objstreamparser with Not_found -> Null end | obj -> obj (* Iterate over a stream. *) let iter_stream f pdf = let rec iter_stream_inner f i = function | ({contents = ParsedAlreadyDecrypted (Stream _ as stream)} | {contents = Parsed (Stream _ as stream)}), _ -> f stream | {contents = ToParse} as r, g -> r := Parsed (parse_lazy pdf i); iter_stream_inner f i (r, g) | {contents = ToParseFromObjectStream _}, _ -> (* Can't be any streams in here.. *) () | _ -> () in pdfobjmap_iter (iter_stream_inner f) pdf.objects.pdfobjects (* Lookup a key in a dictionary, following indirect references, returning None on any failure. This works on both plain dictionaries and streams. *) let rec lookup_string_compare (k' : string) = function | [] -> None | (k, v)::t -> if k = k' then Some v else lookup_string_compare k' t let lookup_direct pdf key dict = match direct pdf dict with | Dictionary d | Stream {contents = (Dictionary d, _)} -> begin match lookup_string_compare key d with | None | Some Null -> None | Some o -> Some (direct pdf o) end | _ -> None let lookup_immediate key dict = match dict with | Dictionary d | Stream {contents = (Dictionary d, _)} -> lookup_string_compare key d | _ -> None let lookup_direct_or_array pdf name obj = match explode name with | '/'::'['::num -> let digits, _ = cleavewhile isdigit num in begin match obj with | Array a -> Some (direct pdf (List.nth a (int_of_string (implode digits)))) | _ -> None end | _ -> lookup_direct pdf name obj (* Follow a nested chain of dictionary entries. *) let rec lookup_chain pdf obj = function | [] -> Some obj | [n] -> lookup_direct_or_array pdf n obj | n::ns -> match lookup_direct_or_array pdf n obj with | Some obj' -> lookup_chain pdf obj' ns | None -> None let indirect_number pdf key dict = match direct pdf dict with | Dictionary d | Stream {contents = (Dictionary d, _)} -> begin match lookup_string_compare key d with | Some (Indirect i) -> (* If the indirect points to an indirect, this will still be unique, but isn't the "actual" object number *) Some i | _ -> None end | _ -> None (* Add an object, given an object number. *) let addobj_given_num doc (num, obj) = doc.objects.maxobjnum <- max doc.objects.maxobjnum num; doc.objects.pdfobjects <- pdfobjmap_add num (ref (Parsed obj), 0) doc.objects.pdfobjects (* Follow a chain from the root, finding a dictionary entry to replace (or add). Keep the same direct / indirect structure as is already present - any terminal chain of previously-absent dictionaries will be created in direct form. *) (* Find the final indirect object in the chain, returning its number and the remaining (fully-direct) chain *) let rec find_final_indirect remaining_chain pdf obj objnum = function | [] -> (objnum, rev remaining_chain) | k::ks -> match explode k with | '/'::'['::num -> let digits, _ = cleavewhile isdigit num in begin match obj with | Array a -> begin match List.nth a (int_of_string (implode digits)) with | Indirect i -> find_final_indirect [] pdf (lookup_obj pdf i) i ks | newobj -> find_final_indirect (k::remaining_chain) pdf newobj objnum ks end | _ -> assert false (* chain pre-checked by lookup_chain *) end | _ -> match indirect_number pdf k obj with | Some i -> find_final_indirect [] pdf (lookup_obj pdf i) i ks | None -> match lookup_immediate k obj with | Some obj -> find_final_indirect (k::remaining_chain) pdf obj objnum ks | None -> assert false (* chain pre-checked by lookup_chain *) (* The object number is now chosen. We follow what remains of the chain and insert the new key-value pair. *) let rec replace_chain_all_direct finalobj chain (k, v) = match finalobj with | Dictionary dd as d | Stream ({contents = (Dictionary dd as d, _)}) -> begin match chain with | [] -> add_dict_entry d k v | c::cs -> add_dict_entry d c (replace_chain_all_direct (unopt (lookup c dd)) cs (k, v)) end | Array a -> begin match chain with | [] -> (* Put the value in the array at the position indictated by the 'key' *) begin match explode k with | '/'::'['::num -> let digits, _ = cleavewhile isdigit num in let n = int_of_string (implode digits) in Array (List.mapi (fun n' e -> if n' = n then v else e) a) | _ -> raise (PDFError "replace_chain_all_direct: nothing to put in array") end | c::cs -> match explode c with | '/'::'['::num -> let digits, _ = cleavewhile isdigit num in let n = int_of_string (implode digits) in Array (List.mapi (fun n' e -> if n' = n then (replace_chain_all_direct e cs (k, v)) else e) a) | _ -> raise (PDFError "replace_chain_all_direct: bad array chain") end | _ -> raise (PDFError "replace_chain_all_direct: bad chain") let replace_chain_exists pdf chain (k, v) = match lookup_chain pdf pdf.trailerdict chain with | None -> raise (PDFError "chain must already exist") | Some _ -> match chain with | [] -> raise (PDFError "no chain") | chain -> let finalobjnum, remaining_chain = find_final_indirect [] pdf pdf.trailerdict 0 chain in let newobj = replace_chain_all_direct (if finalobjnum = 0 then pdf.trailerdict else lookup_obj pdf finalobjnum) remaining_chain (k, v) in if finalobjnum = 0 then pdf.trailerdict <- newobj else addobj_given_num pdf (finalobjnum, newobj) let replace_chain pdf chain obj = let rec find_max_existing to_fake chain = if chain = [] then (chain, to_fake) else match lookup_chain pdf pdf.trailerdict chain with | None -> find_max_existing (hd (rev chain)::to_fake) (rev (tl (rev chain))) | _ -> (chain, to_fake) in let rec wrap_obj obj = function | [] -> obj | h::t -> Dictionary [(h, wrap_obj obj t)] in let chain, to_fake = find_max_existing [] chain in let chain, key, obj = match to_fake with | [] -> (rev (tl (rev chain)), hd (rev chain), obj) | h::t -> (chain, h, wrap_obj obj t) in if chain = [] then pdf.trailerdict <- add_dict_entry pdf.trailerdict key obj else replace_chain_exists pdf chain (key, obj) (* FIXME When the final item in the chain is indirect, shouldn't it be kept indirect and the object just replaced? *) (* FIXME Add remove_chain *) (* Look up under a key and its alternate. Return the value associated with the key that worked, or [None] if neither did. *) let lookup_direct_orelse pdf k k' d = match lookup_direct pdf k d with | None -> lookup_direct pdf k' d | result -> result (* Look something up in a dictionary, failing with given exception if not found. We make direct both the dictionary and the result of the lookup. This also allows us to look things up in a stream dictionary transparently. *) let lookup_exception (exp : exn) pdf key dict = let dict' = match direct pdf dict with | Dictionary d | Stream {contents = Dictionary d, _} -> d | _ -> raise exp in match lookup key dict' with | None | Some Null -> raise exp | Some v -> direct pdf v (* A specialised one raising PDFError. *) let lookup_fail text = lookup_exception (PDFError text) (* Parse a matrix. *) let parse_matrix pdf name dict = match lookup_direct pdf name dict with | None -> Pdftransform.i_matrix | Some (Array [a; b; c; d; e; f]) -> let a = getnum pdf a in let b = getnum pdf b in let c = getnum pdf c in let d = getnum pdf d in let e = getnum pdf e in let f = getnum pdf f in {Pdftransform.a = a; Pdftransform.b = b; Pdftransform.c = c; Pdftransform.d = d; Pdftransform.e = e; Pdftransform.f = f} | _ -> raise (PDFError "Malformed matrix") (* Make a matrix *) let make_matrix tr = Array [Real tr.Pdftransform.a; Real tr.Pdftransform.b; Real tr.Pdftransform.c; Real tr.Pdftransform.d; Real tr.Pdftransform.e; Real tr.Pdftransform.f] (* Iterate over the objects in a document, in order of increasing object number. *) let objiter f doc = (* PdfObjMap.iter doesn't like you altering the map inside the iteration. *) resolve_all_delayed_object_streams doc; let f' k v = match v with | {contents = Parsed obj}, _ -> f k obj | {contents = ParsedAlreadyDecrypted obj}, _ -> f k obj | {contents = ToParse}, _ -> f k (parse_lazy doc k) | {contents = ToParseFromObjectStream (themap, s, _, func)}, _ -> f k (parse_delayed_object_stream themap k s doc func) in pdfobjmap_iter f' doc.objects.pdfobjects let objselect p doc = let ns = ref [] in objiter (fun n obj -> if p obj then ns =| n) doc; !ns let objselfmap f doc = resolve_all_delayed_object_streams doc; let rec f' k v = match v with | {contents = Parsed obj} as r, _ -> r := Parsed (f obj) | {contents = ParsedAlreadyDecrypted obj} as r, _ -> r := ParsedAlreadyDecrypted (f obj) | {contents = ToParse}, _ -> ignore (parse_lazy doc k); f' k v | {contents = ToParseFromObjectStream (themap, s, _, func)}, _ -> ignore (parse_delayed_object_stream themap k s doc func); f' k v in pdfobjmap_iter f' doc.objects.pdfobjects let objiter_inorder f doc = (* PdfObjMap.iter doesn't like you altering the map inside the iteration. *) resolve_all_delayed_object_streams doc; let f' k v = match v with | {contents = Parsed obj}, _ -> f k obj | {contents = ParsedAlreadyDecrypted obj}, _ -> f k obj | {contents = ToParse}, _ -> f k (parse_lazy doc k) | {contents = ToParseFromObjectStream (themap, s, _, func)}, _ -> f k (parse_delayed_object_stream themap k s doc func) in pdfobjmap_iter_inorder f' doc.objects.pdfobjects (* Same, but also pass generation number. *) let objiter_gen f doc = (* PdfObjMap.iter doesn't like you altering the map inside the iteration. *) resolve_all_delayed_object_streams doc; let f' k v = match v with | {contents = Parsed obj}, g -> f k g obj | {contents = ParsedAlreadyDecrypted obj}, g -> f k g obj | {contents = ToParse}, g -> f k g (parse_lazy doc k) | {contents = ToParseFromObjectStream (themap, s, _, func)}, g -> f k g (parse_delayed_object_stream themap k s doc func) in pdfobjmap_iter f' doc.objects.pdfobjects (* Return a list of object numbers. *) let objnumbers pdf = let keys = ref [] in objiter (fun k _ -> keys =| k) pdf; rev !keys (* Cardinality of object set. O(n). *) let objcard pdf = let card = ref 0 in objiter (fun _ _ -> incr card) pdf; !card (* Return a list of (k, v) pairs. *) let list_of_objs doc = let objs = ref [] in objiter (fun k v -> objs =| (k, Parsed v)) doc; !objs (* Add an object. We use the first number larger than the maxobjnum, and update that. *) let addobj doc obj = let num = doc.objects.maxobjnum + 1 in addobj_given_num doc (num, obj); num (* Make a objects entry from a list of (number, object) pairs. *) let objects_of_list parse l = let maxobj = ref 0 in let map = ref (pdfobjmap_empty ()) in iter (fun (k, v) -> maxobj := max !maxobj k; map := pdfobjmap_add k v !map) l; {parse = parse; pdfobjects = !map; maxobjnum = !maxobj; object_stream_ids = null_hash ()} (* Find the page reference numbers, given the top level node of the page tree *) let rec page_reference_numbers_inner pdf pages_node node_number = match lookup_direct pdf "/Type" pages_node with Some (Name "/Page") -> [node_number] | _ -> match lookup_direct pdf "/Kids" pages_node with Some (Array elts) -> flatten (option_map (function | Indirect i -> Some (page_reference_numbers_inner pdf (direct pdf (Indirect i)) i) | _ -> None) elts) | _ -> (* Missing /Type /Page in a malformed file would end up here *) [node_number] let page_reference_numbers pdf = let root = lookup_obj pdf pdf.root in let pages_node = match lookup_direct pdf "/Pages" root with | Some p -> p | None -> raise (PDFError "No /Pages found in /Root") in page_reference_numbers_inner pdf pages_node (-1) (* Renumber an object given a change table (A hash table mapping old to new numbers). *) let rec renumber_object_parsed (pdf : t) changes obj = match obj with | Indirect i -> let i' = match tryfind changes i with | Some x -> x | None -> i (*r A dangling indirect is valid. *) in Indirect i' | Array a -> recurse_array (renumber_object_parsed pdf changes) a | Dictionary d -> recurse_dict (renumber_object_parsed pdf changes) d | Stream {contents = (p, s)} -> Stream {contents = renumber_object_parsed pdf changes p, s} | pdfobject -> pdfobject let renumber_object pdf changes objnum = function | ToParse -> renumber_object_parsed pdf changes (parse_lazy pdf objnum) | ToParseFromObjectStream (themap, s, _, func) -> renumber_object_parsed pdf changes (parse_delayed_object_stream themap objnum s pdf func) | Parsed obj | ParsedAlreadyDecrypted obj -> renumber_object_parsed pdf changes obj (* Renumber a PDF's objects to 1...n. *) (* Calculate the substitutions required to renumber the document. *) let changes pdf = let card = objcard pdf in let order = ilist_fail_null 1 card and change_table = Hashtbl.create card in List.iter2 (Hashtbl.add change_table) (objnumbers pdf) order; change_table (* Perform all renumberings given by a change table. *) let renumber change_table pdf = let root' = match tryfind change_table pdf.root with Some x -> x | None -> pdf.root and trailerdict' = renumber_object pdf change_table 0 (Parsed pdf.trailerdict) and objects' = let nums, objs = split (list_of_objs pdf) in let objs' = map2 (renumber_object pdf change_table) nums objs in let nums' = map (function k -> match tryfind change_table k with Some x -> x | None -> k) nums in objects_of_list pdf.objects.parse (combine nums' (map (fun x -> ref (Parsed x), 0) objs')) in (* Update the object_stream_ids so object streams will be conserved over PDF merges *) let newids = null_hash () in Hashtbl.iter (fun o s -> match tryfind change_table o with Some o' -> Hashtbl.add newids o' s | _ -> ()) pdf.objects.object_stream_ids; objects'.object_stream_ids <- newids; {pdf with root = root'; objects = objects'; trailerdict = trailerdict'} (* Renumber the objects (including root and trailer dictionary) in a list of pdfs so they are mutually exclusive. We iterate over the key lists to build a list of change tables which are applied to the input PDFs. NOTE: This can't be used on PDFs where the generation numbers still matter (i.e before decryption). *) let renumber_pdfs pdfs = let keylists = map objnumbers pdfs and bse = ref 1 and tables = ref [] in iter (fun k -> let length = length k in let table = Hashtbl.create length in List.iter2 (Hashtbl.add table) k (ilist !bse (!bse + length - 1)); tables =| table; bse += length) keylists; map2 renumber (rev !tables) pdfs (* Give a list of object numbers referenced in a given [pdfobject] *) let rec allfalse = function | [] -> true | h::t -> not h && allfalse t let rec containing l a = match a, l with | _, [] -> false | (name, Name n), ((h, Name hh)::_) when name = h && n = hh -> true | _, (_::t) -> containing t a let tocontinue no_follow_entries no_follow_contains d = (isnull no_follow_entries && isnull no_follow_contains) || allfalse (map (containing d) no_follow_contains) (* Sets of references *) let refset_empty () = Hashtbl.create 500 let refset_add n rs = Hashtbl.replace rs n (); rs let refset_mem n rs = Hashtbl.mem rs n let refset_elts rs = let r = ref [] in Hashtbl.iter (fun k _ -> r := k::!r) rs; !r let rec referenced_pdfobj no_follow_entries no_follow_contains pdf found i = function | Indirect j -> if not (refset_mem j !found) then begin let obj = try lookup_obj pdf j with Not_found -> Null in match obj with | Dictionary d -> if tocontinue no_follow_entries no_follow_contains d then begin found := refset_add j !found; referenced_pdfobj no_follow_entries no_follow_contains pdf found j obj end | _ -> found := refset_add j !found; referenced_pdfobj no_follow_entries no_follow_contains pdf found j obj end | Dictionary d -> iter (function (_, v) -> referenced_pdfobj no_follow_entries no_follow_contains pdf found i v) (if no_follow_entries <> [] then (lose (fun (k, _) -> mem k no_follow_entries) d) else d) | Array a -> iter (referenced_pdfobj no_follow_entries no_follow_contains pdf found i) a | Stream {contents = (s, _)} -> referenced_pdfobj no_follow_entries no_follow_contains pdf found i s | _ -> () and referenced no_follow_entries no_follow_contains pdf found i = function | Parsed ((Indirect _ | Array _ | Dictionary _ | Stream _) as o) -> referenced_pdfobj no_follow_entries no_follow_contains pdf found i o | ParsedAlreadyDecrypted x -> referenced no_follow_entries no_follow_contains pdf found i (Parsed x) | ToParse -> referenced no_follow_entries no_follow_contains pdf found i (Parsed (parse_lazy pdf i)) | ToParseFromObjectStream (themap, s, _, func) -> let result = parse_delayed_object_stream themap i s pdf func in referenced no_follow_entries no_follow_contains pdf found i (ParsedAlreadyDecrypted result) | _ -> () (* Nullify all references to page objects which are no longer in the page tree. This prevents (for instance) annotations on a page referencing a deleted page, thus preventing the deleted page's objects from being retained during garbage collection. *) let nullify_deleted_page_references pdf = let rec nullify numbers = function | Indirect i when tryfind numbers i <> None -> Null | Array elts -> recurse_array (nullify numbers) elts | Dictionary elts -> recurse_dict (let p2 = nullify numbers in p2) elts | Stream {contents = (p, s)} -> Stream {contents = nullify numbers p, s} | x -> x and page_object_numbers = let nums = ref [] in objiter (let f2 = function objnum -> (let f1 = function | Dictionary d when (match lookup "/Type" d with Some (Name "/Page") -> true | _ -> false) -> nums := objnum :: !nums | _ -> () in f1) in f2) pdf; !nums in let refnums = page_reference_numbers pdf in if length refnums <> length page_object_numbers then begin let table = Hashtbl.create 50 in iter (function x -> Hashtbl.add table x ()) page_object_numbers; iter (Hashtbl.remove table) refnums; objselfmap (nullify table) pdf end (* Remove any unreferenced objects. *) let remove_unreferenced pdf = nullify_deleted_page_references pdf; let found = ref (refset_empty ()) in referenced [] [] pdf found pdf.root (Parsed (lookup_obj pdf pdf.root)); referenced [] [] pdf found 0 (Parsed pdf.trailerdict); found := refset_add pdf.root !found; let eltnumbers = refset_elts !found in (* If not found, just ignore. *) let elements = map (fun n -> try lookup_obj pdf n with Not_found -> Null) eltnumbers in pdf.objects <- {pdf.objects with maxobjnum = 0; pdfobjects = pdfobjmap_empty ()}; iter (addobj_given_num pdf) (combine eltnumbers elements) (* Objects referenced from a given one. *) let objects_referenced no_follow_entries no_follow_contains pdf pdfobject = let set = ref (refset_empty ()) in referenced no_follow_entries no_follow_contains pdf set 0 (Parsed pdfobject); refset_elts !set (* Find the contents of a stream as a bytes. *) let bigarray_of_stream s = getstream s; match s with | Stream {contents = _, Got bytes} -> bytes | _ -> raise (PDFError "couldn't extract raw stream") (* Given a dictionary and a prefix (e.g gs), return a name, starting with the prefix, which is not already in the dictionary (e.g /gs0). *) let unique_key prefix obj = let elts = match obj with | Dictionary es | Stream {contents = Dictionary es, _} -> es | _ -> raise (PDFError "unique_key: Not a dictionary or stream") in let names = fst (split elts) in let name_of_num n = Printf.sprintf "/%s%i" prefix n in let num = ref 0 in while mem (name_of_num !num) names do incr num done; name_of_num !num (* Given a PDF and potential filename, calculate an MD5 string and build a suitable /ID entry from it. *) let generate_id _ path gettime = let d = match Sys.getenv_opt "CAMLPDF_REPRODUCIBLE_IDS" with | Some "true" -> Digest.string "camlpdf" | _ -> Digest.string (path ^ string_of_float (gettime ())) in Array [String d; String d] (* Find the indirect reference given by the value associated with a key in a dictionary. *) let find_indirect key dict = match dict with | Dictionary d -> begin match lookup key d with | Some (Indirect i) -> Some i | _ -> None end | _ -> raise (PDFError "find_indirect: not a dictionary") (* Look something up in a name tree. *) let rec nametree_lookup_kids pdf k = function | Array (h::t) -> begin match nametree_lookup pdf k h with | None -> nametree_lookup_kids pdf k (Array t) | Some result -> Some result end | Array [] -> None | _ -> raise (PDFError "nametree_lookup_kids: malformed name tree") and array_lookup k = function | Array elts -> lookup k (pairs_of_list elts) | _ -> raise (PDFError "Bad lookup array") and nametree_lookup pdf k dict = match lookup_direct pdf "/Limits" dict with | Some (Array [l;r]) -> (* Check we're not searching in a malformed tree *) if k < l || k > r then None else begin match lookup_direct pdf "/Kids" dict with | Some kids -> (* Intermediate node *) nametree_lookup_kids pdf k kids | None -> match lookup_direct_orelse pdf "/Names" "/Nums" dict with | Some names -> (* leaf node *) array_lookup k names | None -> raise (PDFError "Malformed name tree entry") end | None -> begin match lookup_direct pdf "/Kids" dict with | Some kids -> (* Root node with kids *) nametree_lookup_kids pdf k kids | None -> match lookup_direct_orelse pdf "/Names" "/Nums" dict with | Some names -> (* Root node with names *) array_lookup k names | None -> raise (PDFError "Missing name tree entry") end | _ -> raise (PDFError "Malformed name tree") (* Return an ordered list of all the (k, v) pairs in a tree *) let rec contents_of_nametree pdf tree = match lookup_direct_orelse pdf "/Names" "/Nums" tree with | Some (Array names) -> let rec pairs_of_list prev = function | [] -> rev prev | [_] -> Pdfe.log "warning: contents_of_nametree: odd number of /Names\n"; rev prev | k::v::r -> pairs_of_list ((k, v)::prev) r in pairs_of_list [] names | _ -> match lookup_direct pdf "/Kids" tree with | Some (Array kids) -> flatten (map (contents_of_nametree pdf) kids) | _ -> raise (PDFError "contents_of_nametree: neither names nor kids") let deep_copy_pdfobjects frompdf from = resolve_all_delayed_object_streams frompdf; let deep_copy_objdata objdata = let deep_copy_pdfobject = function | Stream _ as s -> begin getstream s; match s with | Stream {contents = (dict, Got stream)} -> Stream (ref (dict, Got (copybytes stream))) | _ -> (* getstream only returns things of above form *) assert false end | x -> x in match objdata with | Parsed obj -> Parsed (deep_copy_pdfobject obj) | ParsedAlreadyDecrypted obj -> ParsedAlreadyDecrypted (deep_copy_pdfobject obj) | ToParse -> ToParse | ToParseFromObjectStream (themap, x, y, z) -> ToParseFromObjectStream (themap, x, y, z) in (* shouldn't occur due to resolve_all_delayed_object_streams above - do we really need that? *) let pdfobjmap = pdfobjmap_empty () in pdfobjmap_iter (fun objnum ({contents = objdata}, gen) -> ignore (pdfobjmap_add objnum (ref (deep_copy_objdata objdata), gen) pdfobjmap)) from; pdfobjmap let deep_copy from = {major = from.major; minor = from.minor; root = from.root; objects = {maxobjnum = from.objects.maxobjnum; parse = from.objects.parse; pdfobjects = deep_copy_pdfobjects from from.objects.pdfobjects; object_stream_ids = Hashtbl.copy from.objects.object_stream_ids}; trailerdict = from.trailerdict; was_linearized = from.was_linearized; saved_encryption = from.saved_encryption} let change_id pdf f = match pdf.trailerdict with | Dictionary d -> pdf.trailerdict <- Dictionary (add "/ID" (generate_id pdf f (fun () -> Random.float 1.)) d) | _ -> raise (PDFError "Bad trailer dictionary") let transform_rect pdf transform rect = let minx, miny, maxx, maxy = parse_rectangle pdf rect in let (x0, y0) = Pdftransform.transform_matrix transform (minx, miny) in let (x1, y1) = Pdftransform.transform_matrix transform (maxx, maxy) in let (x2, y2) = Pdftransform.transform_matrix transform (minx, maxy) in let (x3, y3) = Pdftransform.transform_matrix transform (maxx, miny) in let minx = fmin (fmin x0 x1) (fmin x2 x3) in let miny = fmin (fmin y0 y1) (fmin y2 y3) in let maxx = fmax (fmax x0 x1) (fmax x2 x3) in let maxy = fmax (fmax y0 y1) (fmax y2 y3) in Array [Real minx; Real miny; Real maxx; Real maxy] let transform_quadpoint_single pdf transform = function | [x1; y1; x2; y2; x3; y3; x4; y4] -> let x1, y1, x2, y2, x3, y3, x4, y4 = getnum pdf x1, getnum pdf y1, getnum pdf x2, getnum pdf y2, getnum pdf x3, getnum pdf y3, getnum pdf x4, getnum pdf y4 in let (x1, y1) = Pdftransform.transform_matrix transform (x1, y1) in let (x2, y2) = Pdftransform.transform_matrix transform (x2, y2) in let (x3, y3) = Pdftransform.transform_matrix transform (x3, y3) in let (x4, y4) = Pdftransform.transform_matrix transform (x4, y4) in map (fun x -> Real x) [x1; y1; x2; y2; x3; y3; x4; y4] | qp -> Pdfe.log "Malformed /QuadPoints format: must be a multiple of 8 entries\n"; qp let transform_quadpoints pdf transform = function | Array qps -> Array (flatten (map (transform_quadpoint_single pdf transform) (splitinto 8 qps))) | qp -> Pdfe.log (Printf.sprintf "Unknown or malformed /QuadPoints format %s\n" (!string_of_pdf qp)); qp camlpdf-2.8.1/pdf.mli000066400000000000000000000301551477056064700144300ustar00rootroot00000000000000(** Representing PDF Files in Memory *) (** {2 PDF Objects} *) type toget (** A stream is either in memory, or at a position and of a length in an [Pdfio.input]. *) type stream = | Got of Pdfio.bytes | ToGet of toget (** PDF objects. An object is a tree-like structure containing various things. A PDF file is basically a directed graph of objects. *) type pdfobject = | Null | Boolean of bool | Integer of int | Real of float | String of string | Name of string | Array of pdfobject list | Dictionary of (string * pdfobject) list | Stream of (pdfobject * stream) ref | Indirect of int (** {2 The Object map} *) (** You should not expect to manipulate these types and functions directly. *) (** This type represents a possibly-parsed, possibly-decrypted, possibly-read-from-an-object-stream object. *) type objectdata = (* Not from an object stream, fully parsed, not necessarily decrypted yet *) | Parsed of pdfobject (* Was from an object stream, decrypted already when object stream read *) | ParsedAlreadyDecrypted of pdfobject (* Not parsed yet. Needs to be read from an object, which may still be encrypted *) | ToParse (* (stream object number, index in stream) Not parsed yet. Will come from an object stream. *) | ToParseFromObjectStream of (int, int list) Hashtbl.t * int * int * (int -> int list -> (int * (objectdata ref * int)) list) type pdfobjmap_key = int type pdfobjmap = (pdfobjmap_key, objectdata ref * int) Hashtbl.t (** The object map maps object numbers [pdfobjmap_key] to a reference to the object data and the generation number *) (** Make an empty object map *) val pdfobjmap_empty : unit -> pdfobjmap (** Find an object in the object map *) val pdfobjmap_find : pdfobjmap_key -> pdfobjmap -> objectdata ref * int (** The objects. Again, you won't normally manipulate this directly. [maxobjnum] is the biggest object number seen yet. [parse] is a function to parse a non-object stream object given its object number, [pdfobjects] is the object map itself. [object_stream_ids] is a hash table of (object number, was-stored-in-obect-stream-number) pairs, which is used to reconstruct stream objects when preserving them upon write. *) type pdfobjects = {mutable maxobjnum : int; mutable parse : (pdfobjmap_key -> pdfobject) option; mutable pdfobjects : pdfobjmap; mutable object_stream_ids : (int, int) Hashtbl.t} (** {2 The PDF document} *) type saved_encryption = {from_get_encryption_values : Pdfcryptprimitives.encryption * string * string * int32 * string * string option * string option; encrypt_metadata : bool; perms : string} type deferred_encryption = {crypt_type : Pdfcryptprimitives.encryption; file_encryption_key : string option; obj : int; gen : int; key : int array; keylength : int; r : int} (** A Pdf document. Major and minor version numbers, object number of root, the objects objects and the trailer dictionary as a [Dictionary] [pdfobject]. *) type t = {mutable major : int; mutable minor : int; mutable root : int; mutable objects : pdfobjects; mutable trailerdict : pdfobject; mutable was_linearized : bool; mutable saved_encryption : saved_encryption option} (** The empty document (PDF 1.0, no objects, no root, empty trailer dictionary). Note this is not a well-formed PDF. *) val empty : unit -> t (** {2 Exceptions and errors} *) (** This exception is raised when some malformity in a PDF is found -- quite a wide range of circumstances, and may be raised from many functions. *) exception PDFError of string (** This function, given a [Pdfio.input] and an ancilliary string, builds an error string which includes the source of the Pdfio.input (filename, string, bytes etc) so we can trace what it was originally built from *) val input_pdferror : Pdfio.input -> string -> string (** {2 Useful utilities} *) (** Get a stream from disc if it hasn't already been got. The input is a [Stream pdfobject]. *) val getstream : pdfobject -> unit (** Return a float from a [Real], an [Int] or an [Indirect] *) val getnum : t -> pdfobject -> float (** Lookup an object in a document, parsing it if required. Raises [Not_found] if the object does not exist. *) val lookup_obj : t -> int -> pdfobject (** [lookup_fail errtext doc key dict] looks up a key in a PDF dictionary or the dictionary of a PDF stream. Fails with [PDFError errtext] if the key is not found. Follows indirect object links. *) val lookup_fail : string -> (t -> string -> pdfobject -> pdfobject) (** Same, but with customised exception. *) val lookup_exception : exn -> t -> string -> pdfobject -> pdfobject (** [lookup_direct doc key dict] looks up the key, resolving indirections at source and destination, returning an option type. *) val lookup_direct : t -> string -> pdfobject -> pdfobject option (** [lookup_immediate key dict] looks up the key returning the value, without following indirects at either source or destination. *) val lookup_immediate : string -> pdfobject -> pdfobject option (** [lookup_chain doc start keys] looks up the key in a nested dictionary. For example [lookup_chain pdf pdf.Pdf.trailerdict ["/Root"; "/StructTreeRoot"; "/RoleMap"]] *) val lookup_chain : t -> pdfobject -> string list -> pdfobject option (** [replace_chain doc chain obj] sets the object at the given chain from the trailer dictionary to the given object. If the final part of the chain does not exist, it is created as direct, nested, dictionaries. *) val replace_chain : t -> string list -> pdfobject -> unit (** Return the object number of an indirect dictionary object, if it is indirect. *) val indirect_number : t -> string -> pdfobject -> int option (** Same as [lookup_direct], but allow a second, alternative key. *) val lookup_direct_orelse : t -> string -> string -> pdfobject -> pdfobject option (** Remove a dictionary entry, if it exists. *) val remove_dict_entry : pdfobject -> string -> pdfobject (** [replace_dict_entry dict key value] replaces a dictionary entry, raising [Not_found] if it's not there. *) val replace_dict_entry : pdfobject -> string -> pdfobject -> pdfobject (** [add_dict_entry dict key value] adds a dictionary entry, replacing if already there. *) val add_dict_entry : pdfobject -> string -> pdfobject -> pdfobject (** Make a PDF object direct -- that is, follow any indirect links. *) val direct : t -> pdfobject -> pdfobject (** Return the size of the object map. *) val objcard : t -> int (** Remove the given object *) val removeobj : t -> int -> unit (** Add an object. Returns the number chosen. *) val addobj : t -> pdfobject -> int (** Same as [addobj], but pick a number ourselves. *) val addobj_given_num : t -> (int * pdfobject) -> unit (** {2 Compound structures} *) (** Parse a PDF rectangle structure into min x, min y, max x, max y. *) val parse_rectangle : t -> pdfobject -> float * float * float * float (** Calling [parse_matrix pdf name dict] parses a PDF matrix found under key [name] in dictionary [dict] into a [Transform.transform_matrix]. If there is no matrix, the identity matrix is returned. *) val parse_matrix : t -> string -> pdfobject -> Pdftransform.transform_matrix (** Build a matrix [pdfobject]. *) val make_matrix : Pdftransform.transform_matrix -> pdfobject (** Make a number of PDF documents contain no mutual object numbers. They can then be merged etc. without clashes. *) val renumber_pdfs : t list -> t list (** Given a dictionary and a prefix (e.g gs), return a name, starting with the prefix, which is not already in the dictionary (e.g /gs0). *) val unique_key : string -> pdfobject -> string (** {2 Iteration} *) (** Iterate over the objects in a document. The iterating functions recieves both object number and object from the object map. *) val objiter : (int -> pdfobject -> unit) -> t -> unit (** The same, but in object number order. *) val objiter_inorder : (int -> pdfobject -> unit) -> t -> unit (** Iterate over the objects in a document. The iterating functions recieves object number, generation number and object from the object map. *) val objiter_gen : (int -> int -> pdfobject -> unit) -> t -> unit (** Map over all pdf objects in a document. Does not include trailer dictionary. *) val objselfmap : (pdfobject -> pdfobject) -> t -> unit (** Iterate over just the stream objects in a document. *) val iter_stream : (pdfobject -> unit) -> t -> unit (** Select objects matching a predicate, and return their object numbers. *) val objselect : (pdfobject -> bool) -> t -> int list (** {2 Garbage collection} *) (** Garbage-collect a pdf document. *) val remove_unreferenced : t -> unit (** {2 Miscellaneous} *) (** These functions were previsouly undocumented. They are documented here for now, and in the future will be categorised more sensibly. *) (** True if a character is PDF whitespace. *) val is_whitespace : char -> bool (** True if a character is not PDF whitespace. *) val is_not_whitespace : char -> bool (** True if a character is a PDF delimiter. *) val is_delimiter : char -> bool (** List, in order, the page reference numbers of a PDF's page tree. *) val page_reference_numbers : t -> int list (** List the object numbers in a PDF. *) val objnumbers : t -> int list (** Use the given function on each element of a PDF dictionary. *) val recurse_dict : (pdfobject -> pdfobject) -> (string * pdfobject) list -> pdfobject (** Similarly for an [Array]. The function is applied to each element. *) val recurse_array : (pdfobject -> pdfobject) -> pdfobject list -> pdfobject (** Calculate the changes required to renumber a PDF's objects 1..n. *) val changes : t -> (int, int) Hashtbl.t (** Perform the given renumberings on a PDF. *) val renumber : (int, int) Hashtbl.t -> t -> t (** Renumber an object given a change table. *) val renumber_object_parsed : t -> (int, int) Hashtbl.t -> pdfobject -> pdfobject (** Fetch a stream, if necessary, and return its contents (with no processing). *) val bigarray_of_stream : pdfobject -> Pdfio.bytes (** Make a objects entry from a parser and a list of (number, object) pairs. *) val objects_of_list : (int -> pdfobject) option -> (int * (objectdata ref * int)) list -> pdfobjects (** Calling [objects_referenced no_follow_entries no_follow_contains pdf pdfobject] find the objects reachable from the given object. Dictionary keys in [no_follow_entries] are not explored. Dictionaries containing entries in [no_follow_contains] are not explored. *) val objects_referenced : string list -> (string * pdfobject) list -> t -> pdfobject -> int list (** Generate and ID for a PDF document given its prospective file name (and using the current date and time). If the file name is blank, the ID is still likely to be unique, being based on date and time only. If environment variable CAMLPDF_REPRODUCIBLE_IDS=true is set, the ID will instead be set to a standard value. *) val generate_id : t -> string -> (unit -> float) -> pdfobject (** Return the document catalog. *) val catalog_of_pdf : t -> pdfobject (** Find the indirect reference given by the value associated with a key in a dictionary. *) val find_indirect : string -> pdfobject -> int option (** Calling [nametree_lookup pdf k dict] looks up the name in the document's name tree *) val nametree_lookup : t -> pdfobject -> pdfobject -> pdfobject option (** Return an ordered list of the key-value pairs in a given name tree. *) val contents_of_nametree : t -> pdfobject -> (pdfobject * pdfobject) list (** Copy a PDF data structure so that nothing is shared with the original. *) val deep_copy : t -> t (** Change the /ID string in a PDF's trailer dicfionary *) val change_id : t -> string -> unit (**/**) (* This is only for the use of Pdfread for when the /Length is incorrect. *) type toget_crypt = | NoChange | ToDecrypt of deferred_encryption val length_of_toget : toget -> int val input_of_toget : toget -> Pdfio.input val position_of_toget : toget -> int val toget : ?crypt:toget_crypt -> Pdfio.input -> int -> int -> toget (* For inter-module recursion within CamlPDF, hence undocumented. *) val string_of_pdf : (pdfobject -> string) ref val transform_rect : t -> Pdftransform.transform_matrix -> pdfobject -> pdfobject val transform_quadpoints : t -> Pdftransform.transform_matrix -> pdfobject -> pdfobject camlpdf-2.8.1/pdfafm.ml000066400000000000000000000043321477056064700147410ustar00rootroot00000000000000(* Parse Adobe Font Metrics files *) open Pdfutil let read_char_metrics_line l = match String.split_on_char ' ' l with | "C"::charnum::";"::"WX"::width::";"::"N"::name::_ -> (name, (int_of_string charnum, int_of_string width)) | _ -> failwith "badline in read_char_metrics_line" let lookup_charnum table name = match Hashtbl.find table name with (c', _) -> c' let read_kern_line l = match String.split_on_char ' ' l with | "KPX"::n::n'::i::_ -> n, n', int_of_string (implode (option_map (function '\r' | '\n' -> None | c -> Some c) (explode i))) | _ -> failwith "badline in read_kern_line" let string_starts_with sub s = let sublength = String.length sub in if String.length s < sublength then false else let rec loop n = if n < 0 then true else s.[n] = sub.[n] && loop (n - 1) in loop (sublength - 1) let get_tables lines = let char_metrics_lines = isolate (string_starts_with "StartCharMetrics") (string_starts_with "EndCharMetrics") lines and kern_lines = isolate (string_starts_with "StartKernPairs") (string_starts_with "EndKernPairs") lines and header_lines = map (fun s -> let a, b = cleavewhile (neq ' ') (explode s) in (implode a, implode b)) (takewhile (notpred (string_starts_with "C ")) lines) in let remove_empty = lose (fun x -> String.length x < 5) in let charmetrics = map read_char_metrics_line (remove_empty char_metrics_lines) in let charmetrics_hash = hashtable_of_dictionary charmetrics in let kerns = map read_kern_line (remove_empty kern_lines) in header_lines, option_map (fun (_, (c, w)) -> if c > -1 then Some (c, w) else None) charmetrics, option_map (fun (n, n', kern) -> let p = lookup_charnum charmetrics_hash n and p' = lookup_charnum charmetrics_hash n' in if p > -1 && p' > -1 then Some (p, p', kern) else None) kerns, option_map (fun (name, (_, w)) -> Some (name, w)) charmetrics let read i = try let lines = Pdfio.read_lines i in get_tables lines with e -> failwith (Printexc.to_string e) camlpdf-2.8.1/pdfafm.mli000066400000000000000000000005461477056064700151150ustar00rootroot00000000000000(** Parse Adobe Font Metrics files *) (** Return the header lines (header item, contents), character metrics (character, width) and kerning pairs (char1, char2, kerm), and (charname, width) pairs from an AFM file. May raise [Failure]. *) val read : Pdfio.input -> (string * string) list * (int * int) list * (int * int * int) list * (string * int) list camlpdf-2.8.1/pdfafmdata.ml000066400000000000000000012710711477056064700156020ustar00rootroot00000000000000(* AFM data for standard 14 fonts *) (* This file constitutes a modification of Adobe's AFM data files. This file also constitutes a modification of Adobe's license file. This file and the 14 PostScript(R) AFM files it accompanies may be used, copied, and distributed for any purpose and without charge, with or without modification, provided that all copyright notices are retained; that the AFM files are not distributed without this file; that all modifications to this file or any of the AFM files are prominently noted in the modified file(s); and that this paragraph is not modified. Adobe Systems has no responsibility or obligation to support the use of the AFM files. *) let courier_afm () = "x\001\189[Iw\220\198\017\190\243W\224\152\188\151\241\003\026K\003\246\137\162(\155\137\022G\020%[7p\1669D\132\001h,\146\168_\159\234\189P@\139\202%\207\2074MVwW\215W\203W\213\195\235\169\030\166\023}7\189\018\211\208\236\199(\251)9\187\232O'\209M\209E\255\24084\199\251)\250\219\254\239QR\149\213?\224k\021\171\175\137\250\202\212\215T}\229\209\249\161\191\021\209\245\2278\137\211\024]u\251~x\232\135z\018\135\159\162\232\188m\163\183r\1831z+F1|\134\159\250\163\006QOM\223E\207A\250\231\232\221\253\028\189\170\031\163(\137\018\2543\227?\199\149:\193\201\223t\205_\179\184z\030ei\156\199\238\199\239_\205c}\020QZ\241<\139\242\152\243\234L\222\238u}\018p\157yh\196p\246bn\219\229\015\234S\211>.~\244A\168{\191\018\135f>\157]Mu\219\236\207\187c+\162\248\236j|\209|\021\135\223\155i\127\031M\195,\206.\238\235\161\222Ob\184\022St\249u\018\221A\028\222\246\167\186S\167?{\214\127\141v,\133\127\2438\226I\030\149q\030\157\221\128\212\2086\157\248\189\031\027u\249]\018\199\254\199\239\238\155\253\167N\140#\\\228\236\189\024F)\018\199\233O1H\189\238\167f/\254\031\016]\130\204\161\233\142\215\251{\001\022R\027\\Ouw\168\135\131\253\221\217E\253\240\1556Y^\176\179?\204\247\025+\206\206\199\1894\199\016\021\172:{.\236\255\237\146\156\159]O\135\223>Dy\"\191yo\190\001\127\148\230\180\254\152&\249\217E\148\178\232\151\232\195\031Q\017\199\240\205\235h|\168\225\242\191D\207\162\216\252\243\139\148J\151R\226\235\190\173OJ\140\165\133<2J\011p\011\206\180x\182\020\255k\238\193\012\183\173Z\144\148\028N-\163,I\229\149\244\130|\185\160\155O\183\018\150c\167\150T\0000(\n^\023\021i\165W\020\203\021\135\190m\235A\031\000.\176KX\017eU\017\021\246\004\190\148\127\016\195^\250\181\\P&\234\006yR\130)\141x\185\020\175O\176`\004h\212\130\"\213\011@*\207R\189\160\218\184\178\246\031e%\184\172\188t\202\011w\233,&*\213\131\232ZqgV\020\149\244Z\176\019\200Y\181\178dc\137?%)b\189&M\019\191\134 \\\143R\177\241\147^\145\020\017\203y\148\149\025\bp\189\128\128\253\208\206\163\182S\012\202D9\131\255p\237\023\025\001z\015\217\1626(K\163&\012|!\139\018\171\n\129\249\254\241\225^t\006\180\020\\)\001\204x\196\202\\\139\023+\204\154^#\192X\165\189\142C\030\139\181Kd\004\226\177\173\199{\1899\003\143\144\218\243\\\006\139\150&\b\127\019Co4\209\014\157U\153\183!A\183\239t\140\128\131\197\224\150\185\019\204\t\166\211\023\189)\151\145\148q\143JN\144\156\238\007\161\247\228\185>\190(\1880\129\240\014r\169\150-\213\249\222Ar\130\221]\243\217h\202\204\165\184\1959'\224\141\205W\227\019\137\151\181\251\018\228F\241\217\000W2y\1792\245\219\018\212\132w\207\216*\225\003-'\160u\1417\173\146-+/[Rok\251n\229\014\169\241\158\188\162*\159\026\191\194\251'ZR\016\244ZY\"\1644\196\029\132Q\158T\128\161\214\165 \248\137\191\230\186\181Q\146\200\196\000a\"\163]\t\019\252\142\178&\011\r!\192,\183\134(q[\1674\149\136Q\0211\237\202\149\177!s\233\182 @\214\218\220\156\155,\149:\011\022\004\198s%\152J'\002\176mb*\b\130\207\180\r\148\024X\213\137\017\232.\172\169v\137\204\139 \\\234,Q\016\220\158\163\253x\230\247#\128]*\177\\\031\027;1N@z\129\196 \19381\002\208\175\250\170F;\b2\171\029'\224\252\166\005\165[\231\160\185\219\143\160r\133\019\128\191\004'X\252S\239\150\233c\011\159\2539\129\226_ZP\0054\196\148\019#X\188\212\182\227\202(\232X\130\197+-\166\128Eg\018 ^k?\001\221\160\020W\190\028s\130\196\027\011\152\186\004\132\172\181]I\176\248]oX)\237\188\237J\130\197\191\253~)\217\144\128\241\022[\005mH\192\184\214\231Bz\129\168\203!D\220~\004\142wh\191\194_\184$`\220\232X\227\250\194%\018$p\188W\130\187L\153\176@~P\018@>h\193\212\b\162\029\t&\127\232\132\166\131\195\199dI \249S\139)\132\017\167\168\b \031uJR^\154x\237*\002\200-\144\236Ob\218\"\031\204%\143\138`s\011kP\141\005K\169\026[2Wc\171t\243\024DX\192IV\132\165\162\233l\2207\205\190\025\246\179f\156\240\251T\245 \190@V\004\191Y2\225\017\024\184\165\178;I\001\228ow\\\167\250\170\136\214|\205\223\031\012\171\232Z\233\017\168\b\162\181\205;*\201B^\204$;\147\130\004\209[}\213L\011\"\nR\017L\247\182 (A\230wLb\002\171&A\153f\ny\149\184-\147\152\214\165\197\158Y\137\246\164\164\194\192\168\\*5[B\190i\128D\168o\218\232\1745K\t\174G\164\014WY\206\159B\1924\206b\211\156\215\155 \216h\168s\203\175rn\228\bn\255\137\012\tQGgI\140D\t`\159P\217)ct4\193\171%G;9\002\151\246\198\157\148+@\206]9!`\025\138\162b\144c9\002\149f\138\005s\189\133\151$P=h\r\141\185s\188'\229\014Kd\192S\188(A\198\208\145\216Ty/G\169_dX\142\238\153R$I\1761\221\149\165!2\229ZI\002\205\172Md\25000\001\244\183F\146\128\243Y\251\143\234s\224>1\146$\240|\241\1699V\169\217I2\002\144\166\189,6\142\225\229\b@\143\145-\151\202\150HKF\000\250\166\001Ru0\198r\027\t\209g\157D\185\177\204\186\169g\222\t\203h\218\213H1\217(\200\177G\n\187\243<6\210\249\198\t\184CL\205\017\168\217\149\189\242:\227NM{0\217#\133\t\007W\148.e\230\156\021\255U\019\129C\255\197x\187\158\np5\022\128I\146YD\204\228:pI\246\161\199R\157\140\244K%Ll%\219V\024\222\232\\\003u}\007\240\228\240o\145\024\167\1624\248NN\142,o\150\253\143D\r\130\184(r\179\128\216\234Q,B\213\151\203\1322\226\187\182\031\026-,\253\011rJ\158\250>%\161\204x\020^\017\025\162; b\153\1643\1655\012\237l\230\001\026\251\189q\184Tv>9\227\170\228i\249\173i\195\216\1681\154\186\001\004\176\170_\016\154\238\018\1488\219\169\140\247\191L\015)d\159\234W\017\160\143s\003+N\189'\011\224\172\\\211\169,3\250QN-\023)\245\208Y\149\\\149\229\tZ\149\006V!\255\221ZFq\215\181\195v5.\127S\198}\215\006\228\bz0V\179$\007\182\144C\138\028\162\204\014)\018J\170\015\245\241hz\187D6C\018\235\2203\210\132\146k-\239\166c[K(\205\214\131\016\025=b\016v \194@\014P\135\181)3\021\144\178i\024\023\213\199\161~\208\151\201cuR\158 \180)\177\190\133\137\1740\166\007P\147T\166G\201\139R#\159\133\028\241\182\030\141/&\138\244f\170\027VLF-\204\183\157\209-K2\179,\131\176\245\203\138\237e\216C\140\019\231\028]\139\007\156\216\175\219\240bJ\205E\2196\015c3Zy]\172R]\201\213\130j\133\211t\223\207nn\168\185b\129\2305\te\226\182\217w\153T&k\205m \018]&\165\204\026P5\131\158$\215C4\233\b\005\183\167PJ\189\159'\131\014\016|)\158AJ\241\226\004\028M\190\239Za\006DL\014+\164F\192\192s\147\174)\161\246\229Cr;9\198\201c\217\249\024\219R6}\170\247\131\027q\196*\194\178R\226a\162lE\170\007\225.\012\2491\150\249@\142\182L\012Sj}\232\167z\239\202\r\147\181\006\000La\176Vd\218\164l\197\177\225\181BX\180\019`\206rE\006\135\249\021$\188\006[\157\024\020\215\012\028#U\012\151\027\233\148\022\191\0038a\029\217~c'\145K\193c\019\187=\157\150\206\221\177\030\230S[\207\198\213a\178\147\153\194l\177c\148 \247G\024V~2jI\130\005\130\025P\227\204\136\019\028\246\181\135!SS&\133rQ\025q\026\018'\151\027c\149\026\229/ljd\148\140\156_\250\140\139&:\140\017%\250\225p\007\211:7\011L`\166(1\147\221\168M\138\140\190\\\188\244\189\232j<\194\232\003\198\027$\156\170\190UN!l\t`\244\001\227\141V\\m[p\180m\190R\252\004\228in\189\230\220h\158z\205\233\020\1916\178\149\233\016cG\169\025\157\152\031d\221\029G\210\029Y~\2012\218\202\248k\174\250\025\182\026j{a\217\132H\155\200\233\140\137XFG\219\253Rk\21220:\220\134\250\006/v\144\166\2054\181\212K\202\210)\179#+\174\022\209\231\166l\146n\201\158\147Do\169\017/\183\247\174\253\222\216\144\001\155\220\2082\226\199k\161\003\030\253\001\168\237\n\0290\170\231'\148\231e\147*\253\022w\169k\164\150Za\184Lm[]\196%z|\133\"\222\022^\214\017\180 \128n\1412\182\178*\151I\143\007/p\227m\132v\015Ax\003\154\137\191\252\160S\1369\221\224N\202\215\131\144\2183jZ\188\167\004\146\152\250\144\1948\171\241\131\153p\192\240\153A\022\200\208c\204\202\144>5!;\0069\136\151\182\158\021\020\245<\2061\149t[\135\211\220N\205C\171\007j\178\152B\154\147\175\232<\016E\1364!\179\004\179)\t\234\"\r\0065\140`\166\166n\015\205\221\157\131(\213\227\030\158l+\243\184(\193\152\007\177\237\005\175\151\172I\191\237\134\140\216\144\232\1752\247\228\178\029\251\151\235taru\136%R\n\225k\229\182\254b\177\000\019\178\192\130\253\154\254\179p\241\235\016\184\246Q&$;\163hB\158`\199\018\235*\239<\001[~{\239+Tdl\131\019BI~\006\011\026b\251A,\174>\136%\247\015\208\164\219\161\255$\186\197S\129\156\127\202\167\130\130o\0311\136c3\250\129\226\211\212\234W\020~\254c\021\161\b\188Zf\234'[\186q\134\226\231\167\230\242\002R\149\136S=h\139\202\191\131`\133T'\156\246\196\178\n\255\000\183\186BN\241\020K\185BY\193\t\135:\143\151\168\173\161\243\250\149\183u\226\190n5c\142\213C\190|\245/\002\217FN\200\255\135:\217\211\t J\127\001\014\220\249\225\134\167\144\001^r\179~\1831)\167\n\019\148\203\197d\245\251dF`\130\226\001\r\229\226\163\167m\248\019[\161\2417\152\222\196\020\182>\2522d\253k\196\129qs\203\002\210t.\198L\140|'\b\223\172Lj\019a\0256\211\001*\179\249\136}\162\"\165R\143\152\161D\219\163:\254t=\188@\206\140gc\129\174\194\239\253\003\237%\004y\179\175\237\135\021t\022\132|_\177\192\004\182FS\011M\252Bz\012\212\248\133\029\152\231\225\145\203k\239\251\190\199\225\129\020\216\163O\017!+\006\167c\193\132\025\158\211\188\164\1392;Z\253NB9\247z9B\023\184\1949*Z\166f\021qX\157s7P\241L1\224\197^\007\\\199\003j|#\253\147c\139\129\188}\233\253\000e\144@o\134\153\165%\219q\216z\159V&O-Nq\176\026\162\2465V\175\183\242/$X\185\205Z\174\232T\194\181\139\001F\215\249\235\250\140\\\132:\017\250Nd=\006}Fq=\230=\202(\236z\183D~2C\210\2164pL\191\028c \247\015@6/\159\001\241\186\031C0\174\007\189\177\225\179\221W\198\018\198\1659\138H\165\029@\224~h\167\193N\207\170\164(\140l!\173i\020\004\235\r\132\144\218\ns\189\023\152>\007\209\204\239\133 }\255\248p\175\028\202\016\156X\158%\156\151\160-n\197\197\n\181\166\179\016\176\1884\024\228%\196\180\212\026EA@\030\218z\184\183\147\195>N\205\017\011\237/V\154@\252]\245\157\219\137\179\007\201\131\018\t\188\221\193\186IU\130\143\240,\br\002\234\248\213N*\1813qQ\006A\002\229x\223+;'\156\200,\159#a\130\225\029\004\212\217\216\181\017fA\148\160w\215|q[\173\156\209V3\210\156\16074\223\156\006\184\145\213\170\154\231%\208\r\234\139G\0146\012\170\005\021\207\243\018\220\020\178Pw\184\018\029\142\192vh\188rs\135C\017dKjomwX\024D\001\186\200\157\253\240\138\238y\223\132\017\179\133\226!\130\224\215\234\015\148L\1547\167\2182\157\159\173Xv\175\252\129\193\1658\144\b\141\184p}\194\140r\237m7\214\1559\237\228\016l8tR\181mi6\173\135\176\021\231\134\251\012\229\225f\160\026=\130\195ba\004q\176\222'\169\028N\160\171\028\158\166\006m+\157\211$\184\005+t\173\212\202\240%hRA9\157\249\233i+u:\236\234~\218\183\245\228\137Ce\177+\243\025;F\249r\183\131N\230g\231\138\218\000\165n\216\194\217\1578\193aS\2070\128\247\020\154\177C^\022\162r\226\212'\246sx\1324\174\163\163\000\134\224\163#\163\180\228\236\"D]\030*Y\198\200.\186~{\007\157\188\185O\200\000W]tr\221\189pq\145\209\171\141\215\161@]5N\024\189\225x\023\132u\195Cw\142Q\169\198\232\r\199\187\011\239\193\169Qu\152\151\175v\190\007\0305\181\243\214\001N\179\245<\180?\024\237\242\215V\182\200\\\128\bT\156\209\134\250V'\223a \229\146\167\154\250:oY\219\160s\026aSH\187S\174z\222\168\159\158\218~\186ff\158y0\218\250\238\236\182]7\029\215D\1406\191!\201\193\165\030\132j\023>K7$\236\230\148\140\184\\8\224\220\129\147\011\213\128\233\151\149\207\158\012\014\rU\253\019\001\174\237\190\171\195\206\t\023&EW\224\134\199\207y\021\246m\175\133\n\237\174\199'\254\153\162\164/\186\012H\232\166k\229\227\171\176\022:n\177\176V\1471\222\130\016\227_\229\012\228X>_\196\252\170\015g\158\155\1431\1646\011\162l\18903\216\198\160\250\180\180\156\249F$f9\239\239\187\222\025\142\225w\169\136\026\252;t\200\249\162\172\140\158\243\n\021Z\246\202/\238\175\215\203\028\234n\184b\210\219\160Aw-\160_G\197\184\212\r\2186N\011\177}O!\171ac\137D2\243\176a\152L_\194\183>r`\151\169\169\203|\169\187Re\136O\232\2021\202H\130\1807\174\168h\160v3o\201\143\239a?\181c\243\208>\186\163\230:Iiy\255\248e\165\023L2\029YO\217\019A\021\165\015\127\023\025\243mh\207\140M\221n\155;{1\163\179_n[A2;\190\157\199E2^\240\"v|\196[dd\137\191\015\142)\178!A\192\022\016<\030\002.\200\128\016\179c\188qq\000\025z*\177\253\171%\129\194\004-2b\243\247\234\130C\0167\0238O\193;a\175\154\205!4-\214\025?d(\164\252\227\147_\162|#\158I\245\250\253\022T\203Sx\199\002]c\2219\142\144\166\219\190\251\172\014\243\141\130yW#\245\019\191\202\\D\031\141\216j\215\012\161\225\248\023\136\214\207\193\r\209s\140\152'^.c\246\179\229\2220A\"\012}us\181l\194k,\205^\132\0002\155eL\159}\208}HO\017#\232\022F\192\1585\130Oan\155\152\158H\t\159P\144\023\207P\003\247\218(\209m\230\154\012\207]\006G\134%z\006|\148\174B\152\236!\\:\226\161\251\011\016\226\161\189+\196\241C_/\234E_\132\160'h\235\0248\1353[/\138x\171\243W\026/s_{\163'\130t\208\235\224.s\187;f\155c_o\213\190\238]\031\137\003\183\129\212Z\196c\159Z\166\227\191B\180.\145Y\248\236\029\219\207%.\163\172p\188\136z\0294i\015\154\199\247\rfs_\183\150@C\1521\023\255\154\213DB\142\238\164\147\140iHJ$cv\171J\026\189u\142p\226\003\186\b\179'\141\183{=5s\1847\158\137c\196\146\195\030|J\127b\027\223II\229\159\165\197\002\248E0\004T!E\2025\2043\029\249\198\239\227\169\252g\170r\2383\028z\152\185\226$sI\171?\151d\158\005\128\139\179\2428\131\185\164\012o.!#\252\238\128\239\186\r\175\142\183\139\199U{\\\248\146\006=q\\\247\129w\218\019\015\157\127\237\198M\031\136Wp\209\031Y\168#\r\014\252a\154HO\138\140\240\001\"\206\133a?!\233\153\143\247\t\243\158\142Gp\216\173\188\030\165\002\153\030\207\218j\188_zq\030oO~G\225\208T8,\142\196\129n\134\t\127\179\199\163!\bl\149P\232\204P\232\162\138\247'\027\204Qly\145G\243\228\197\228>Z\022>Uyq\216\162\143c\234\255\162\207\015\255\015C\020b\214" let courier_bold_afm () = "x\001\181[Ks\2206\018\190\235W\224\184[\181\147\"H\016$\227\147,\203\137\018?\178\150\031\137o\244\0125\226\1383TH\142m\249\215o\227\221l\018\150\247\176\149*E\0305\192F\127\253\248\186\193\185\158\234az\222\031\167\151\2054\180\219\145\137\159\248\217E\12784\199\137]\244\247\015C\187\191\157\216?\182\255d\188*\171\127\193\207*\209?\185\254\153\233\159\005;\223\245\159\026v\2530N\205adW\199m?\220\247C=5\187\159\024;\239:\246F\2373\1787\205\216\012\159\225\211\240\144\161\169\167\182?\178g \2533{\t\191\253v:\1784c\\\254\156\150?'\137~\130\151\127wl\255>5W\207\152\200\018Q\250\143\223\191<\141\245\190a\130\243\172by\202\1658S\231zU\031\0268\200ih\155a\243\180\239vg\207O]\135?e\230\211\250\208v\015\248\243\179\015\141>\187\254\243\213Tw\237\246\252\184\239\026\150\156]\141\207\219\175\205\238\143v\218\222\178i85g\023\183\245Po\167f\184n&v\249uj\142\187f\247\166?\212G\173\197\211\167\253W\182\001\213\216&\205\019V\136\138\149\tgg\239@l\232\218c\243G?\182\218\n\027\158$\225\227\183\183\237\246\238\216\140#\203\147\179\247\2050*\145$\201~J@\234U?\181\219\230\255\139\210%\200\236\218\227\254z{\219\128i\244\006\215S}\220\213\195\206\253\237\236\162\190\255\213\216*\151\233\217\159\246w\145Ug\231\227VYb`2\173\206\1585\238_\027\158\023g\215\211\238\215\015\172\020\234\151\247\031\024O$\252\006\222\168L\233\1881\227\249\217\005\203R\246\132}\248\147I\240\133'\236\021\027\239k8\247\019\246\148%\246\191'J*\155K5_\183]}\208bi\146\170g\178\172*Y^\164F\\\204\197\255>\245`\135O\157^\192\179\156\165E\193\132\204\213\153\204\130|\190\224x:|R\136\236\143zI.\217F\128\180\016L\230\220\172\144\243\021\187\190\235\234AK\151J\161T\178\156WLJi\196\139\185\248}3l\149k\235\221\181\254y\1493\201\173t9\151\174\015 ?\0022Z\030\030\173\023\bx\132\200\204\130j\229\192\198q\244\145\011n\142\012\145\231\142,\018\162Q=4\199\174\1851+R\208\029\2205\005+q\175\150\224+K\208S2\187&+\209\026\130o=*\197\198;\189\162\226\250Ay\002\134J\140]\005A\250\190;\141Z\022\142\160\131\191b\162(\141(Ay\011\233\1626\154\1929!\"\213\nH5\1330\226\004\227\219\135\251\219\198\224\011q\t~\004\182\129\255g\220\152T\200\005bmo\000\224\149q9\145\148\218\180Z\156\000\007\195\200\212\026\133\224\251\173\025z\227:\133\129\022t\240\006$\208\246G\019\030`\227\132\229`\018'\152\019@\167/fO\169\004E\133\004\t\140\211\237\208\152=ef\030\159\004\252r\130\223\r$P\227\181\153z~R\004I\130\220M\251\217\236Z$f\215\148{\148s\002\221\216~5\182B\162n[\002\219\216|\182\168\193_\212\193D\216\149@\214x\215,\237\1938R\151\000vl\173a\139\202\202&A\182\164\158\214\245\214s\192\133\141+\168\232\202\141tE5>\180h\133\243M\229=n\137$\216u\170,hD$\211\246\2004(Z\148\160\215\252}\170;\023!\156\151:DT2\212\194\004\189\189*\200\141\001\016|Rm\r\185\210o\157\209,\210\140\186p97\230F6/MV\150\004\197\218\230\001\155\159J\225\r(\t\136\231ZpS\001\128\018\130\223\229$I\000|j\242\157\170\002y\017R\151$\208]\152\148\165\130\018\142\015\182\244\n\018\220\158\161\253\192o\252~\004\176K\179\159r/\189\155\021+\bH\207\205n\149\214\014\137\017\128~\153i\167\030k\181+\b8\191\218z\198\204\001\252~\004\149+\135^b\252\194\137\0170~3\218\021\250\177*B\188 \193\226w\155\240\181Q\002\022\005\193\226\005>m\025\196\b\022/\r\178\169F6\rb\004\137W&,U\161\004'A\135%P\188\158\025O=\215\026\175$`\252\161\005!\177\194^y8EI\192\248\1839\133\218/#\027\0184\222\152'\011b\150\146\160qm\158\011f\006%s\200\129yi\005\t\030o\145\153\011\180\031A\227\157\217\207:\139\012r\004\142\247\198\206\\ea\201\131\027\148\004\143\015V\174\212r\001\183\146\000\242\167MN\218\249\144\024\193\227/,\022NQ\0174>\154\228\149\218\018\229\197\b\026\159\128W\2235S`\029\"\183\172\163\bd\168\"\192|\1305\168\186V\182\186f\190\186V\217\234S\016QI\237c\178\028=\134&\179q\219\182\219v\216\158\012\207\228\144\174\021\191\023U\026\214\016\240N\138\001\143\192\188\029\131\221\168G\169\191n\n\147\232+\201\150D\205\159\159\131?\026\158\022\016\168\b\160\134\225d\1504B\222\017\185\2257\021A\244\147\215\193\230bg\030\002\233\214x\156\021\004\004\132*` \200\019\130\234\206%(\195W\185\223\146'\180(\205\246\132\186\226\148TV\159\179\004f\2353x\nD\145\222\017rM\011\244A\255\210\177\155\206\174$\176\238]2\135\178$u\024\135\135\016,\141\171\232|^\165Hk\002_;\207\1722/\173\028\001\237?\204\147%x\178\128c\006Q\130\214\029\206\2339z4\001\171#\143\246r\004\172\131M\175:\191\130\144?2'XY\178Q\2183\0079\130T\031\1728w'\206\tR\2476\147\168S\167D\148\018\135\224(J\020<%\136\018h\006\151?\1479\132\156\210>csU1 \2183\228\165\156\1603\249\140\172\233M\168A\156\019pN\225D\202K+\213\214ZI\002\207g'\153\232R\026\228\b<_H\182\245\130)\129\199\208]i\137H\016#\232<\152\253\1321\228\236\209)\129\231\027\011]\001<-\200\173dC\148qd\226\250\188\192\214x*h\20250\165\144/\245\144#\1314Q\228\137\149\206W\158\128\219Bi\031!\018\244\b\185\146n\167\182\219Y\018\014\\V\021Sp\204,\183K\022\204W\015\001v\253\151#\011\131\000\bHE~\133\176\199\167\012\216w\221R\245\244P\154\020;\226\214\233(\001V\189*\140jL\166\001\186\182Qy9W\011\184]@\012u\163\006E\1421\171*\163\232#0))\221\002b\171\007\223\129jW\bD\136S.|\211\245Ck\1327:\\3\174\231\029\222\162\148\021\143MPE\245?\138\162\170\216\177|\135Sr\188=\r\208\206o\141\203A\024*\227\168\196\170\162F\203\175\205\024\198V\143\205\012I+t\241\202\016S\231\1483\187I\140w@;\153P\017\029\022\017\160\247\167\022\022\028\250@\020JE\198\021\219\018\194\158\158\146i\181F+\023\\\029\198\023:iUhU\022Y\133\220wm\025\133\221T\014C\139*\148\190)\215\190\233b\130\004<\152\1659\134\003.\163g\019`!7\155\224\148N\239\234\253\222\182u\170Z)\172\005\23448\165\213F\222O\196\214\150P\130m\230\031*|\154\161qs\016\169=Z@\189\205\236\\\140S\030\rC\162z?\212\247\2460\198\015\011\137\030D\019\020\204p\027g{\024\016g*9\169\132\230\228E\204\015?\213\163qEew\1571\005\248$\18332N\169\182\243E\191L\218U\170\131\014\171\228\250\170\224!\210\186p\138\\\152\210p\239\194a\025T\168\194\022g\231W\148\1487]\215\222\143\173\169}\169m\171\193\249\184\139yJ\207\001\164\233\182?\249Q\161\025K\195\170\002M\1488\165\225\174\207\247\169T\145jM\170t\214\182\153\148\210j\000\213\014x\020D90\154L\1410]\166[\240\233\237i\178\137\"\201\181\184\128\012\020\196\t8\134y\223t\205W\235\162\016\235\224)\002\232\176\204mF\162d:\148\015\176\139\000}s\213]f\238\212\004\146C\189\029\\z\132\180\174\148\002q\197\210\1408\165\211Cc\143\171\212\000\213\2450)s\234\211\000\235\167z\235kM\154\169\224\002\003\001\22423T1]\176k\184\151h\028\216\028*\141Z!T\134\247+Hh\r\1744)eE\169FJ ]8\233\140V\190\029\248`\237!\216\164\016\246YY\216\017{J\217\240\237\233\184\175\135\211\161\171O\214\207\213CJ\221\030:\216RJ\141\251=\204'\239,\181P^\004\134\017I\226\159A0\216\214\014\002\rpe\001\150\133\021\167\241p\240Y\017\024\133>\162\026\030\184\180\152R&rn&9\155\180\"\227\bU\171\230z\015\187\027\024\211\249! \135\232T\254%tGo\181\167w\021/B\027\186\152\139\164\244\202\226u\016V\227\0125-\208\211\007a\197I\184\188v\170\155\174%G\027\231\011\213\015\192\158N\221wu\167\179\251\218\200jj\153\027fi\169wJ\007\229;Ux\199\145tG\142`\166\130\1822\225\160\139~&]L\179\145\t\129\212\000\241\212\141\133\180\128\210\153vo\181\230\165Q\155#\181\233X\027\n\028\\\209A\166\030\189\209u\219*\1896\027\178\226j\022\130^\249\194:;\021oBJC\157\174\140H\215!\129\160\230=&}ZD\159mSdZF\0235!\156f\n\021\171\210\127\145\132cG:\177\211\238\218\207-\"\231RWIua\178\186w0M\216\216\186:\149='\169\222O\133\139r}\243:l\254\003\150|G\182\015\163\181\216\254\015a\127\220y\197\0300\234{'\148\237U\147\170<\023w\169K\168\136V\b\175|\029\175w>\221\135#\148I\228\2083l\209\145c\206\137\242\182\182\169\154x\150a\188\176\216\031\185>\178\231\186\240\tm\174\189Xo\158\251\012B\229/g\202\2511|L\247gP\198\237\205\195b\178Oe)T\166\014\170\134\022\202\206&b\248\173\191\132w\003\181R\255-\143\248\207%b\022A\251\164\\\223|\025\179\"\143\198l\237}\000{~\177\190\245+zZ\235\151x\222N\215t\001X\159\255bNV\007\006\248\003q\248va{n\195\004M\195\233\162\011\196\026\195\245N\204\209\234@\000\177B\153\140\184\217\156\163=\230gc@\n\141\161bH\141\152n\233\140\000T\233{\025\161]\177|\204\150]\255\1739\238m\211\162\135H@\031\n\177\238\142o\130\222\2546\163\168\214e\127Y\128\148Z\144Pk\184\136o\154\192\195@-\150\203j\178\004\195\021Yr\142\162*\148\136HT\r(\170\220h1\134\212\022#\165bP#%\226H}\156;\142\191\229\1369\206\219\219~\176\186\152\235\169\"\234\239\175q\234\b\151^\177c\190A\225\225\161\141\004\1995J\217\225\182*&\189CNc\210R\145\022Q\226\244\014\169\141\234AD\235\147Ob\216S\"IL\191\1560\158\244\244\193\0148\160\029JA}\145\133\150va\199\144\154\176\025c\012$H#\242\017\145\r4\238Q\217\195\169\155\218\251\206L\212J\251\254J\226\223_Y\216\005\241\014d\152h>\r\b\185K\197XX\195\012fj\235n\215\222\152\235\022uu\161\174?\225v\184H\215\149y\152\021\225\025\015\202\"\229&\168\031\238uc\166iI\002(2\127\233\178\030\165\151dAH\2151\1508;\192\172\030\172\235\223\2049\019\"d\145\005\219%\255\023y\020\175#\162\196\238V&\202\254q\174\011\174\224f\019\203B\239]\001Y>\226\011W+u&\134\146z\249\n\154\226\240\006\150\234\207\020\237\231\235\138|\026\250\187\2308\187-P\1638u[ \139\245%C\179o\1990R|\156]\253\018\002\016\189S\017;\193\213\023\191\152\r\164R[we\028\249\142\146\147\162\176\228\004M\024\022\245c\198\004\220\149`\145d\2359\000\181*:\166\245\155\031Y\188\015\194\242V\028\189\180\177(\030(\195?Zh\230\t\216\139\199z\255\224\135?0\140\248\134r\181\1871\140\201\182\232\140\202\226\250\144\232z|Q{\151\156\253;\181\183G\205|\242h\019Q\227\168\200\031\141\138\017E\005\166\236\145\131\174\143\127\212=\238\2349iE\194\135]\247\224w\b$\246X\219\252\172\233&\219>\216H\146e\140#9\130\169\222\208\243\215\243\209\144\248\210\207\t\021\\u\232\t54JQB5\239\201\209Q#\198<\160\203u\165\015\186]_\216=X\229\209\206\167_\204\197\172\215H\025\159\139]\"\015N\221t\163\136\135\233.L\020V^vYe\168\144\031\007\200\147\142-\021\250\230W\138\184N\215\179\174\163\176\217\015\189?\182\204~>\145\025+Uq>\254{\180\215\174\226\189\246\011\020\137n\154\029\243\205i\168w\205\161\030\238\\rR\254\163\190\249\016\219\188\153\215\225\031`WW+^\017\173\242(-\004\225H\251\241\"\024R\159Sf\241~\012\220\230\182\238n~\024U5'\255\031jeO\219\224\228\2096\248\024f\028\129FF&\028\239\022\193b\178\1422y\204\148\151({?\198g\026\220\246\005Dc\217x\143&\224\232\173\173h\168\031]T\025\243\171/a(\243\231\242;A5+\246\174\199\141p\155k\026%\194\241\137\239\132\225\235\133Mm2T\131\249h7\r\213\217\190b\015T2\133|+\n\017\205\181=\154\171=^\018/P\031\136Fd\1453\159P\171\251x\143\tQ\222n\1733o\2047B\004\168\014&\141\180\176\207Pl9\254\023Se\136\154\031\189\007\182hu\208\029ohu\"\131\154\030\205\003\145!#\209\242f\1454\197\015$M\186H}\007\198L5\2038\r\012z\005^\0239\1959\030\158\219\011U\137\2224X\200\135\225\138\219:6\191}\029\212\192\005=\162\200\183y\006\015\1801\146\191/\145_\250D\018\235I#\0203v\200\187\229\028\223\185N\030-\138\243FV\189Q\163\190(\193\215\027\129+:\159\b%h\253\bGt\149\029\218\251\"\210\147\196<\031\189\173\184\156\249\238U,\030{\255\222\020\183g\016\1453\244\243\t\b\142\128\200\000j\222r\160\252\016Y\000\202\132j\007\193\168Jd\174\203\233\186F\251E\180\160:P\240H\149\177\re\174\134\232\133\254\202[\012\226oh\016\018\218\154H!\165\186pwm\135^\151]\169Is\234\156[\234,\138h:o\215\200I\172F^\158\2367\193\194\183\031/\143;\244\181I\245O\244\157\222\255\002\158\141J\161" let courier_bold_oblique_afm () = "x\001\181[\201r\220F\018\189\243+p\156\137\152v\160\128Z\000\251DQ\148M[\139G\212b\235\006v\131M\140\208\r\026\139$\234\235'\179\022T!\209Ez\014\019\014S-1k\203\151\203\203\172\234\235\177\234\199\023\221q|U\143}\179\029\018\254\003;\187\232\014\135\2508&\023\221\253C\223\236\239\198\228\031\219\127&\172,\202\127\193\2072\213?\153\254\153\235\159*9\223u7ur\2530\140\245aH\174\142\219\174\191\239\250j\172w?$\201y\219&oq\158!y[\015u\255\005\254\213/\210\215\213\216t\199\2289H\255\152\188\130O\191N\199$\203\019&\127\204\138\031\185\212+\204\242\239\143\205_S}\245<\225y\202\203\249\159?\188\154\134j_'L\137\172LT\153q~\134\231z]\029j8\200\2127u\191y\214\181\18777-Np\246bj\219\240\151\t\2542\153\127[\029\154\246!\252\253\217\199Z\171\002\197\206\174\198\170m\182\231\199}['\027\150\157]\r/\154o\245\238\247f\220\222%c\015\019\\\220U}\181\029\235\254\186\030\147\203oc}\220\213\187\183\221\161:\234m={\214}K6B%\155L\164I!\203\164HYr\246\030\164\250\1829\214\191wC\163\181\178ai\234\255\249\221]\179\253|\172\135!\017\233\217\135\186\031P$M\243\031R\144z\221\141\205\182\254\255\162v\t2\187\230\184\191\222\222\213\160\027=\193\245X\029wU\191s\191;\187\168\238\1271\202\0182;\251\195~\230yyv>lQ\017}\"\179\242\236y\237\254\182aB\157]\143\187_>&\005\199\015\031>&,\149\240\t\172\0195\233\1723g\226\236\"\201\179\228\167\228\227\031\137LS\248\240:\025\238+8\247O\201\179$\181\255\253\132R\249R\170\254\182m\171\131\022\203\152\1925\019^\138D\168\204\136\243\165\248_S\007z\184i\237\000\150dJ%\162\016x&3@,\007\028\167\195\r\"\178?\234!E\145l\184H$g\137\020\204\140\144\203\017\187\174m\171\222H+\180#\153\200\153H\160\167\203\189\246J\002\199\r\240\235\207\245\232\201G\150\027\"!!\207\186\224Q\018dn`\140\207\177\025\232\029\147,/}\146-\243\147\203\004\132%\181\235\240\"X\135\134\179a\2194\219\166\223N\134qb\190G\166/D0\134\1927!\023\030\128\131\215\214\0154'\020\154tn\148\t\247\165L\214\148\205\171\000\002326^\004j#\152\026\1663\179\193\028\b\142!:%A\245\198l<7\0019\0154Dp\221&6\175\027A\200M\152\198@\144\165\004Y\203DS\027\227\197<%\218\23625-\230\132L\233v\137\138_\210\005\231\149\232\027\134/\253\004\001\167\001\030\161?\180\201mkG\018d\247\198\237q7\192\218$\004\n\191\b\129\243\206\2301\237\208\225\182\t\132\141\143\175\002\231\020\133\149#\176\253\199\004Di\150\1980\226E\t^\134\243\230\185\rN~i\002WK\150\158\229\bZ\007k\\\218\189\128$\206gf\004\172\227\242\204^\142@e\216\162r\245H\022H\018\168\238\205\210\144\180\225\216\025\145\165\004\194\155\n\138\022\225\006\b8\134\147\024N'B9J\000\205\148\168t\176\019\208\223l\167\140\192\227\168_a\156Dzo\194je\233\180\230\244\233L\252x\238&%\000}q\146\024%E G\000\250j\178\002\002\174X0_F\2401\204\215\228\004\022\136\017x\030,\222\204j2\\:#\000}Of\134\142T\208\203\157\136\137A\212q\001\017kK\023\220X\198i\228\237\17343M\015\001\206\163Dj\165\197\137\021\194\"\145\219%\130\216\2062y\"\232\142M\187\171\019\207\128!\187A\130\201\133\029\179\226\192\186+\176\235\190Zs/\173Or\012\163\220\158\159ra_\134\163ZA\n#\020j\204H\019ma\237\n\205\155\189\205\030\176@V\128\165\162\142\153\029Atu\139\173#\199\1581GI\204\1520H\186\001D]\015\182\178)\011m5>\0073J\139o\219\174o\140\176n?1\136\215*\245l\155Q\130<\212~+\200\165\020VN\233L}\024\229\201\219\169\135\250~\251\224\194\017j\007*n\129\142\163\229O5\029\134F\183\210\012\195\206M\014+=/a\148>\187\230\204l\131\0120\214\189\138\146\007\163\b\214\251\169\129\017\135\206s\006\144\196\243\128\157sn\207O\1535\014\210\219\011\214\0188J@\254\242\163\242\200\168\192\134\165\025\134\1425\015\163\1927\137\167R\216\015qQ\156\018\239\2196&H\224\131\006\155c;\1522\208W%\192\237\218\021\140\146\235]\181\223\219*\015\023E\184E\225\153.\163$\219\200\187>\153\246\007=D\249!\148n\155\150\b\250P\221\215\1825\002\228\027\245\195\193\192s\219-c\148UC\227\168\218\247\213\1899\1414+\233jg^\137\198)\232\241\214\227\236\216\012\203E\136e\216\2221\242\160\166\150_\137\180\244\001\149\146l\128\2136}2\133A\030j\r4T\023\238V\236z;\141V\207\204\136K\152\221\139\019t\012\015\191mk\14723\204\170\005\250\001(Z\216\176D\137u\144F\128\239b0\210\236+w\231&\152\028\170m\239\186\029\216a\197|\144\155~\177\145\167\228\186\175\221\129!0rY\152\214U\238N@\189\172\027\171\237\156ur\240\022^\022fW\185\225\141\217\138k\195\157E\237\240\2060\163\193\b\157\161\231\017\196\191z\151\163r\176B\2361\t\204S\202I\2314\007\238\192\012+\027\218\128)a{3\151\133\237\190g\148\026\223M\199}\213O\135\182\154\172\173#k)\176\191\224\161\203(Q\238\246\208\183\180m_\1424\0034\147K5/B`\216V\014\133,w\250A;RV\156\250\196a\014\142\185i\229b\t\225bcFI\201\185i\238l2S\193\250\1308\203\200>\186~w\011\173\187\1851\136\222\136&&2\031J3z\141\241\210\023\166\171VIFo3\222xa^\004\r\004n\197\137\199\188\177})\169w\206\130y\197j\231\007\224QS\187\218:vF\220\214iO\191r\182'\225~\238\020\171\226\244\236\149\159]>\173\250\247d\250\176\221\022[\225\193\175\176(\196bk\012\250J*\136\248X\180\162\249\134U\235\026\176\229\198f3\242Ynu\150\222\151%\254\020E\02699\19388w\204L\131\240\173U[\150\139\150\211j\133\016\231P\173\167\197\167`zm\209zz_2S\249\203eNt=\250\216\238\159CJ\183\215\018\171\182?\149\165\1281a\171\220\028\155w\017\245o\231\155z[\241\235F\181\244\212yu\128\128f\248\237\167\197\233\217\255'\007\174fS\bZ\131.\249S\225\215\244\184\1339l\216\141\167cZ\143\173\t\134y\025\181\180\202\243\193p7\017\156\222\173v\227\188%\232\149\211A\023\193v\252\245J\204\210*O\007]\136\b\216\224\218\206\022t\237IC\027[<\166Ud\136|:\012\158\007ne\179E\030u\171\222\159yn9\198\160\218\134P\161\019j\168\130\0149\029\240ii9\243\029H\204r\222\221u\189\221\139\238\211fq\255{\019\028\210Y\188\140\031\243\1737\026\003\173\140{\199\181\151\r.\179b\210\187\192\218\r\156\005\156.F\163\222\135\149U\152\019\"\251\158\2308\022\244dcqL\191`\024&\221\144\176=\015\1363x+\132D\221\021\185+M\250\232\020\\.F\233\136\151\014\152HD\214\211\186\141\187\026\142\201\030\166vl\238\219\007\171\025\253\202\005o\190x\228\172S\016\005\156f\202Gb\170O\030\238\2181\230\217\208\151\025\155\170\2215\183\230.\006z\002\027\188 \133\162He\1677\243\176\200\196KN\148GrN@\144\231\171\223\152r\026\0267t\233\160\226!\224\146\246\b\230\152\029#\141\139\019\004\143\171b\251\175\023\003\130\155\173\216\128\237\186\"\224q\192\142\001u*lz\141\214\003a(\176\151qA\179b\157\237\189-x\205G\140\225\138&\027\030\143\004\248H\011\138d\251RKI\1404\152n\004;\189\145\155\190\251\\\031\231\139\004\253pL\225\003\154R'\145\147\209\186\2227\131\2393\254\r\142\245\179\247A\231\221\143x\225\2132`?Y\230\r\019$A\2550F?\151\131\205c\027:\194%\130\214\152\183\201\211\155\233\189\238\131\212tz#]h\003\236I\027\248\020\212H\217\019\233\224S\016\224\179'X\129}U\228_\"\233\014\005\134\014YF\0202\218\022\201S\148\252\"L\190\154l`\242}\132l\180+\134b\159\231\134\247\169\171\020\226\015\235\238\011u\224K\243\211Q (Y\n[\017\133\215\219\171\244\0236\192R; |\217\177J!A\169YZ\027\136\166\155e\020\158\179S\172#\224M1\012_\017\233\239\139\240exdL\182\t\0119e\011\185\224\254|\149\129\215\228\253\145\012\220\005\210O\007\210*p\012\249\180c\012\129c\184\155\229\248\228\205\186)$\144\252\176\2009i\026\011\015{\218\136\223{\144\254N\t\253\188nG[I\184\215\158E\140+9\170\185\184\192\143\250\197\215\142\016+\006\205F\244\165,N\172\150\218\t\014\027Q\231\193\220\190\243\210\236\231\177\218\191\tH\219\252F\"\022\027\215\2532c\b\197#\208^\0066\156\t\235\217*\206\199w\190\187`i0\222\246G\213\137L\021\130d\015\193rp\169X\226K\130\248\142\174\195\000(\230\000\232\159\153\173\003\224\028\203\180\142T\030\231\229\191\209`\153\217\134G\248\014\144\014z\025\\\220\184\014w\2042\199\190\218\213\135\170\183\177Rj\235\193/J\196&\175\151\169\248o0\172+b\019\143q\149\1710_j\225G\138\167\151^\145\250\156J\168\232\182\193h\238\170\2140gw\213\207\226\182\137\189s\154-\241\217u$[v4\130\248g:1*|\012\174\190\220\147\200X\167\227\253\250V\199\006\157\"\141\007\228\203\160\182|\138\211\212\129\222\139\167\195\241\222\179\183\240aW\212\211\143\206\169\204\230s\251\212B=\226T3\180\174\214-\226\244\230\154z\137\152\155\030q7|\179\014?&\020\1702\174\211\029dg\251\026\031\031#dx[\131W\194\145P\219\005\166\031\152D\228\208\023A`p\1568~\232)\152;\168\193#s\131\1557[k\206R\127\021\004om\224\160\145:\246y\224[\142\002\198v\210S\245s\203\232\194wb\171r\199\219\127P\238D\0266\157\023VO7\006\223\174\130\1663\007\022\015\016/\233 \b)fP\254\b\r\244\2512\188\014\002g\236\012\231A\230\218\1486s\229\241(~>\183Xf\202\024k\228\190\t\212\227zN\241\141|_EpK\027#\241\2512h?\206q$V\151\158\160\152\225co*\255y\165\245\220j=x\132\185\226#s1\139\151Z\250\171A\016\151\221}\242jK\167\154\020&\007\157>\1951\1685\n\219\166\140\181\030\199\213\141\004\179M\250\2409\227\186\253\187Gg\155E\243\228\145StK\210\022\004\147\bj\211r\128\139\016\2414\r\187\241\025\015|q\195\205\021\176\144\167w\180_y}\144\t\020\139\228\025[V\150\185~x-\031iI~_\\\172X\139\136\192p\\\193P8\143\143G 0\212\005w\198\007+\154;3\030\r\232\r\229'B\137h\150\188\156\236\023\199\252\247%/\143\187\224\139\150\248\215\224[\193\255\005\206\204\\\205" let times_roman_afm () = "x\001\189}Kw\027G\178\230^\191\002\203\153s\134=@\225\221\189\146mY\237+\183(\201*R\184;\136,R\024A\132\026 \005\194\191~\178*\227\249e\020\220\171{|\142\012|\145U\149\241\142\140L\020\255x\\\239\031\127\221=<\254\171y\220on\014\131\201\223F/~\222}\251\214<<\014~\222}?\2377\247_\030\007\255\235\230\127\015F\203\197\244\255\180\255\206\187\127\151\237\191\203a\247\239\184\251w>xy\187\251\220\012\2548\029\030\155o\135\193o\0157\187\253\247\221~\253\216\220\254m0x\185\221\014>\180w;\012>4\135f\255#\161\250\168}\179~\220\236\030\006\191\164\209\127\031|\252\2424\248\215\2504\024\140\006\163\234\239\147\229\223G\243\238\t2\190~\216\252\251\169\249\237\151\193d<\156-\004\190\250\215\211a}\223$t9\\\014\166\147\229x\242\162\229\238\237\250[3\248\184\249\214\028.>\236\190\173\031^\252\250\180\221*8 p\253m\179=)\252\226\186\233\184\207\212\223\030\215\219\205\205\203\135\251m3\024\190\248\237\240\235\230\185\185}\183y\188\2492\184[o\015\205\139\159\191\172\247\235\155\199f\255G\2438x\245\252\216<\2206\183t\2314\135\159~\218=\015.F\179\197\224\162\026-\006\163\225p8X,\023\131\023u\026\183\223n\030\154w\187\195\166\019\194E\"*\252\241\203\230\230\235Cs8\012\166\195\023W\205\254\208\014\025\014\171\191\165;\188x\187{\220\2204\255\003\170\202\130\218\028\006\235\193\227~}\219|[\239\191\014vw\131\2237\015\187\199\211\247\230\226\159M\186\234\229\235\193\250\225\246\255\238\246\131M\186\248\240\244\249\176\185\221\172\247\155\230\240\183\023\175\210Cn7\015\247\127\220|i\146\136\187\025\252\241\152\134\175\247\183L{\241\243\250\251?\179\212g\179\234\197'\250\243\195ow\219\237z\223\r\157L\006\023\139\244\128\233|0\175\230y\244<\143^\208\212\1917\251\155\2143\218\225\179Q\178\172q\154R\165sY\228\225\243y\158\251\250[\186\224\144t\146\239_\229\011\146\176\228\130\165\023M\199l\182\188\142\221ebw\154C\151\242:?\237\134OFjo3\210\225\178\026e\183~$\195\204\162^\012U|3\210\225\188\170\186\161/\243\2006\154\206\135\173\173\211\004H}\179\217\188\027\246S\0306o\189~9\022-\207\230~\216\207\194O;\187\228\220\242\216\133\127\236/\249~\179t\191Y\027\159\248~\164\175\217(3\242J\237{\154\1781\015\155\179\146:+{;\248\213\012\155hJ\152\143\252C_[\031\152\027\161\204+?\240\159\249~\203N(\149\222\015\242\221oy\216\162\245\254\14521'm\140\023\203n\216\127\229a\157\177\165\1963\212\129\160\1397\236x\233\177\149\ny>\243B\249\221\ne\161\1958\165\209c\255\165\195\0223s7\208\196[\030\214\250\206|h\132\188\244\003/mXh\163\007Ko\001\218x\167\186\157NTz\011\208\198{\189_\154\211|\168\129nQy\171\250\160\1987\155j\136Y\140\253s\255\024H2N\225ei\2387\241\002\252\024\027\243\002\212Q\231a\0192\023U\240b\230\007^1\195\173\bg\198N\023\164\146%\185\241u\014\128\221\184\229\216\136\006t\242\137-\166\181\191\137\014\003\141\172\178\183U\2210\229c9\244\236\254w7l\t>\180\132\234\225s*\202\1916\143Rq,Z'N\146\173\150*\241e\229\195\233\231t\201\217\244\186\028\135\015\209\"\165S\127\251\148\137\138w\201\133\226,\027\242\250p\179\217\220l\2467O\185\182L\169\185J\140L\140\167/!3=\1815\239!\021\235\\\180^\140\170iG\189h\157\174\189b6(\0114a~4\154\230\002m\170Av9\24719W7\169\144L\203\144\004\166\1643\203\005\200\018j\138\207y`\030\215\165\211q\030\183\2447\188\201\220M\243\192\145\222\176\171l\\m\155G\210\163[K\167[\142\134#\127\207\198\221\179\154\152{V^\000w\003J\228)\152\165\187uwL\161f\147\138\135\238\195vp\183\165+\161\186\184\151\160\223\214\179\147\249\208<\004\138\139/b\138\147\214Jd\214SoW\027\141 \213tl\198\205\252\184\255\151\237\174-\002\187\181b[\130\201X\168)r\141\219\249|\235\2022\012\202\137\173\134\254\182\252\212q\236{4\238\155Nq\158LJ8\030\129\170\030t\220da\199A\229GU\2312+\202\202p\004e\223w\014\"iE\007#A1\255fw\201C\147G\235\208\137\215\254~\192k\170\241\216\206r\234SY.\133\166\163n\150\227\137\189!\168\134\252([}\149r\201t\190\164\145\160\152'\178\137\204x[\137\241-\193\143~\176jra>7#!0\0303\227\163\156\170\146U\200\200\n\212\243\172\169\192=\187\002\245\156$\023d\027\159\154\161\149w\185?\2179['^\152q\\\211-\134\018\011M\196icS\187\140\025\183\171\200\005_\195\171*\014%\180\162M\1371[|R\223|Q\209\224i\240\000\r\181\221\146\188{\194\194>\129\235\244\201H\131\237\227f{K\203\144T\201&\023\152\166h1\174\200\021f\1449\242\178\255vw\204\182\190\164\185U\195\214\144\230t\r\024\177,\182\167\173\133\140\219\181\195BMd\006\134\220\174RS\139'\007\154\182TI\227\151\186\216\030q\253;\162\130\225\174m0q\185\156{Im\233e\214R\163\025d\140\019\173d.\210\132R\136\024ir\030\205`)s\183\221\2377\015\020N\146D\1510\025\176\239C\163s\233\150\171\173\219T3s\001\216\249\205\211>-\228o\178\201\181\203\159\180\228\153\166\255\205\134j\138V\173jS\139s6\162fz5\196\158\232\211\195\253z\255\244m\187~\202,\\\144\198\230\170\177j\b\226\223\221\167\174$\181s[\031Oi\174\154\140\229\017 \255\155\181\021?\168\182\026\022n\240\r\130aG\225hXq\253\193\r\136\151\175h\168o@T\1494hs0\222\237o\239R_N\154~\147\174\151\218\006z\246\227\138\247#\164\005\162\171\206\162\015R\241\182\1324.tp\187\220\236\170\159\212p\024\019\155\188/\193\211\190|%\2067K`\187.%a\243\142D\023e\243\196\191\165z\233i\2033\159u3\183=\250\138\155\244\220\203XScs\209\213\187\179\177\174\242\170\t\172\130n\219<{8\192bH\135\227\202\197\200$/_\150\146\215\170\162w\173\131\1875G\187\218L\002\159N\201v\185\131\2052\220i?\182\157\246RW\029\021\246\176SFK{y)4\031X?\1691`\215\189\023P?\254\134n\151\219i\139\241\212\r\151%\173\1980\179\174e\143\192\209k\r\026f\169\206A\227\002\230\254T8]^\151L\187\164\018?\161Q/r\243\241O\144\158\141cVz7\200,\183\137o7?6\183N\246\221\166\011e\170\226\230F4r\231\2290\028\251\018\131;\183\128\023\139Y,I\189\185\149$HE\154gx{m\163\225\003\164\004\215\007\216\133\022>A\214\162\221\022\147\t\241\237\178\180K\151f]Z*\203O\235?\208X-A\222\242\176\236a\219\219\178\185\160\199\154\215&bwbmw\224f\203\130\001y\128\023\146Lg\024\219\179\185{k\201i\007g\178\208\1333\015\151v\187\159=\183\221q\238\210\196O\217\155\183\026\176\147\207c\221~\160U\214\146V\176\169\140\188\128\233\204g|\r\239\214K\200\156t\015\231\232Z\204\223\022\0202\251\2098\148\252M\233\183\163\170\176\002\209\147X\1291~N\245(\152\183\200m\215^_.\\\127]$\196\241\219h\182\139\223\203a\161W\153\141V}g|Q\250\221\197th\137n\187\223\023\144\168~6\177D\247sz'\164u\159\157\208x\209cg\1906\23534uuQ\2138\007\228\174K\002\170\210\209\182\208\026\229B+\n\n\210n4\146\159\145\228\139h?\207S\223\238\254l\030\238ip[X\181\027\135\243j\018\202\240\131)\176x\247\002\163\159lN\161\146\198UV\146\221\168*\252\027\194\153v\209z\237\024\174p\230\019\007\192\151\214\171$K\140\226d\190W\150\185\155\2167\149\027\171\167j\154\245d\251\222h6\255\237\205f\217c5\188\200\255\248e\1837\237W\187\023\133,^\026\022\205\014\0232)z5\006#z\197\016\204\187R:\214lM\021\163\023T\243\153\160\14853MV=[\198\001\184\182\1541\217\000\166-\214\"1L\237\004C\216\216\158D8i\146\143\166\020\248\166\210++\204\210\132\014\177H\144\166d$\149\188f\164\216\000v\198\000\204V\028Z\128\228#\027:\226I\200P5\150e\143\007M'\185|\161\147Az\154\168\234\178Ww $V\206\171\199/\131\179E\184\212t.\227.r\198\181\199t\138\154\180\168\028\169l\183{\163\"\240*\007\190G\227\024y\255o\220\1501U\021\251\191Y\162t\254\220.\128\204Fu\145\243\204\248.\231\205\166\238pF\1459\140\227\253e\150\241\241W\134\247u\"\212\n\255\131N\196\159&n\241\230 \142\149@m\153\156e&\219\179\153(rI\188fm\222\159x\197\204\205L\140\149\247uPlmd\22698\133T\223\198\221t\159\184\151Q'\241\139n\221\211\030-\234Iw\151X\189\026f{\234\234\218\132\138\254\005\243lDK\218f\251\152\221\163\243\165\161\158\147D!>Jui\182\226\011\151\208\003\160\190\150\234\218\155\213r\214_J\249\236\228\\I{J\212\254\152\163\176~\223\1950\014P\245t\226\220\005&4\224xJti.\154\231Z\187\031\183\167+\230\221\145\1370\244#\2236\001\204'\203\240\162\230\241\139\159\127{.*\238\242\252\233\218\148\188\150\233I\161\133\014\168D\181\231a\177`N6\234\n\230\020\199\187\138y\178\232]\171nLv\236\218Z\237\252{R\227\171'\250\153\151\254\156\241\213\195\173\249\029d\254a\228\155f\255\240\203\250q\173\223\222\1737\169\230\172\134\243\241\1397\239>\r^\014\210\189'C\254\156s\185\001\178\152,@U\168B\175\237\231\156\177\r`e\167\240e\2182\155\242gz\168\002\198\161\012*\022g\176\156\157\012\224\178\173\193I\180\006\201\231\007\012\144#\156\002\239\205\231\143m\254\024\241\023\018\138E,\151\138\215\230\0225\178Y\135l\214\001\1555\178Y\247\176Y\023lr\179\193 ]\208\215\239Wi\194c\254r\157V\176\172\163U\235DL\160\141y\139\232D\0214\191\0185b\2481\184\152O\232\2431=\161\162\207'\251\153\030\160\128\222\159\177<\196\024,\001`\181\132\130\2332\138\246\155\241\215\005\000\150Lhh\206\153fl\154\000\2088\161\145\218\137T\234\158\b`\000\132\198V@D4\005\130\193\236\t\005\219\207\232{\004\172\023\016\130\174\192p\232\015\153X\227m\235PNu\191\156\234>9\213\161\156\234sr\170c9\021~C\176w\158\012Z\015\202\136q\163\012X_\"\004\029\138\224\192\1712%t\173L2\254\149\129#\250\204\169\000\192\221\b-}.\187\129\2419\002\192\231\b\005\159c\020}.\227\175\011\000|\142\208\208\2312\205\248\028\001`K\132F\182D\164\210\150\136\000\182DhlKDD[\"\024|\142P\240\185\140\190G\192\250\028!\232s\012\135>\151\1375\222\182\014\229T\247\203\169\238\147S\029\202\169>'\167:\150S\225s\004{\159\203\160\245\185\140\024\159\203\128\2459B\208\231\b\014|.SB\159\203$\227s\0258\162\207\156\n\000|\142\208\210\231\140\022\140\227Y\020\188\207\146\192\005\029\t\253\208\016_\199(x\164%\133ni\006\024\223\180(\024\158%E\214g\233\165\tZ*\216\161%\197\198hG\160EZ\026\184\175%\129\015\027\210\251\016\181\222latiG\011\253\218\140\168\195G\213\253\130\174\255B\208\245YA\215\253\130\174\255R\208\245\025A\023\254oi>\b\024\138\141\004\0066\225\192\1606&X\024\003\131\165\005\209\193\144\195\016a\232&N\024\244\024:\251)F!lXR\025;\0041\145C1\136\027J\128\168a\b\0243\132\244:\194 ^(!\140\022B6\177B10`%D\230\171\212\210x\149\006\166\171\132\216p\149\142f\171\020\136\014J\128\216 \132\247\001f\227\130\130\024\021\012%\140\tB\175\131G\212}\226\172\207\138\179>#\206\186O\156\245_\136\179\238\021g\017\003\148\226#\128\224\214\255\0054\222/\152\245}\005\209\243\149\018\248\189@\161\215\011\213\248\188`\199\192EO\017\006\222\174\132\210\215\179\248\141\163\019\000^N(\1848\163\232\223\025\127]\000\224\217\132\134n\157i\198\167\t\000\011$42?\"\149\182G\0040G\2261N\199\bx\029\195\224v\002\163\223\017\225u\137\128\2311\028\186\030\017\141\2391\002F\197pdUL+\205\138)`W\012\199\134\197T\180,\198\193\005\025\006\031$\248}\129X/d\b\221P\240\208\015\137Z\023\183\174c\161\213g\132V\247\n\173\142\133V\159\021Z\221#\180\194\031\025\247\014I\168\245H\130\140K\018b}\146!tJ\198\003\175$R\232\150D3~I\200\177p\172S\137\128k2\\\250&\201\196\248&#\224\155\012\131o\n\140\190I\132\215%\002\190\201p\232\155D4\190\201\b\152\025\195\145\1531\17343\166\128\1531\028\155\025S\209\204\024\007\223d\024|\147\224\247\005b}\147!\244M\193C\223$j]\220\186\142\133V\159\017Z\221+\180:\022Z}Vhu\143\208\n\223d\220\251&\161\2147\t2\190I\136\245M\134\2087\025\015|\147H\161o\018\205\248&!\2017\167\222\177N%\194J\000\216\b\154(\029\239\1983\243w\240\203\012\130W\018\136>\217\193\175\241;\248c\006Co\236H\198\023\243w0\170\012F&\149)\165Ae\028\204)\131\1771e\026\154RF\193\2512\b\190\215\129\239\225\187\245\187\012\160\215\017\026\250\\G\171\225\150u$\154\186W4u\143h\234H4\245\025\209\212\161h\n\031\203\168\247\176\238\155\245\175\0140\222\213}\183\190\149\001\244\172\140\006~\213\017B\175\234(\198\167\186\239&\219u\223O\248\0292]\006\203<\151-\1928\019\001\224M\132\130;1\138\254\148\241\215\005\000\030Eh\232R\153f|\138\000\176\028B#\211!Ri;D\000\227!4\182\030\"\162\249\016\012\174E(\248V\254\250\030\001\235]\132\160{1\028\250W&\214x\219:\148S\221/\167\186ONu(\167\250\156\156\234XN\133\159\017\236\029-\131\214\2112b\\-\003\214\215\bAg#8\240\182L\t\221-\147\140\191e\224\136>s*\000p9B\011\159\251i\240rpA\204\253\196\219\165\006 /Q\192jMQ\189\175b\164+\005X\019\138\176\018\020\201\242\215\239d\184\002\212\173\220\248\179\136\152\001;9E\173\200\025\163\201)\224mHq\158\180\"\001o\218\146s,\15997\011\224R\177\160&\021\011\198\169X\000/b\197%E\011B\"V\12832\003\233s5\229\2074G\005\168~4\128\153\180\162:i\131\201Y{\003\018'\n\240\140\021a1\011\178\147\250\225\141\024\170\002AA\243\198\026\170b\190\160y\131\134\1708\020:o\196P\021\240u\205\155\193\147\024\237\027~\241\129\001\002gzc\142\170\027\204;\211\027xo\150\193\193\153\222\200\027\137\012\226\"\194\155\182\200\020\153\158P\211\167R\133v\145`,\217\193`\212\142\022\217\183\027P\154\186#\131\213;Z\236\000n\b\250\130#\130[8\026x\136\1655\177t\208o\028\r\\\200\211\002or\003\206k%\2421G\007ws4\244\001\026\241Wt\159\128\000\252A\247\t`\228\207u\159\000D\254\140\011\189\236\129\145WKC\142--\228\219\014\b\184\183d\148\129\165\021\146\176\196B\030\150\bR\177$\144M\254\250\178\000@\030\132\130$\b\141d@\164\146{\"\000\223\132\"\199\004#\175\004{.\t\244\252]\026\214.\145\171Kd\2322\228\2292`\227\0189\184,&\127Y\204\251\018\166|Y\206\246\1634\248.%!\024 \216`\187l\211\192\148?_\155{}2cVf\140t\004\0050\001\1540\012y\151a\200\187\012C\222e\127\200\187\236\011y\151a\200\187\140C\222e\028\242.\163\144w\025\134\188K\169\021'\142a\020yT+z\218\021\202\236\026\031\242\t/Y\225%\168\144\162rd\130\145\168Q\141EA?\150\004J\178\164HS\150^\170\203RAg\150\132\138\1794\212\158\165y\021Z\n\232\209\255\140fR\202\t5\218\251#\154`\192U(\249\235\240\233\159\194;\172\194;\160\190\227\031\1500U\016\163r\197@\225J\000u+!R\182RKU+\r\020\173\004T\179RP\201J\241*V\028\020l\127\r1A\137\160r{~\011Q\144\175\002\233^\007\207\252\020\\\187\n\174E\133F\191\023`Z\022\162\209%\001\160HBA\139\132F*$R\169?\"\128\242\bE\205\017\140j#\216\235\140@P\152\156\130\1598\134QU\209\025xO\187B\153]\227C>\225%+\188\004\021S\156\031g\130\235\223\024\229x\028t\228\137\160*O\1404\230G\148\138\243t\208\159'\162\026=\021\181\233\169^\169\158\006\186uD\163b\143\131\166\129\024)\220\r\185\234\209\202u\207<>\245\220g\213s\031\180\tO,M\131dk\140\130\0170\007\134\193\016\024\142L\128i\165\242\153\002jg\024\021\2068\170\154q\175dFA\189zv~\226yG\149\134'\231\129xUH\240\186x\210\167\226\170Uq\021\170\171\180q\128\250\230\031Z\143\159\201g>\130#\1289[CX\030b4I\000\176Mh\196;\145J\001\016\001\164@h,\n\"\162<\b\006e\019\n\026\151\198\205\204\003\160\251\168q\227i5\222\179\014eR\247\203\164\238\147I\029\202\164>'\147:\150Ia(\004{k\145N\212\194\001\198n\164\241\228\237\002-\168h<1!K\215\152\017\001 2B#\145\017\169\020\025\017@d\132\198\"#\"\138\140`0#B\193\1402j\204\136\0000#F#3\202\180\026\239Y\1352\169\251eR\247\201\164\014eR\159\147I\029\203\1640#\130\189\025\201!\221\133\003\140\025\201!]o\023hF\197!]!\248CM\242\224\224PSH\011\133\024\031j\n\201(\208\254CM\225\144B\184\193\161\166\144\134\198\231\247\210g\017\140\134\216\187\151\030\141\168\227g\213gd[\255\149l\235\243\178\173\207\200\182\254k\217\214\231d[\154\175%\130\017\251#\005\139\000\182\006\237O\020DvZ\024w|\158\128\200\031\187\194z\204\159\185\176\022\128\011k\001\\a-\168)\172\005\227\194Z\000)\172\005\145\194Z\016*\172\229;\023\214\012$/\028-\2483\215\161\002\184:TPS\135\n\198u\168\000P\135\n.u\168 |\014Y\000.\167\025\208s\211\031\165\248W\128$\170\128\157\180\162\133\245~\148\226_\0010\194\143Z\252\235\141\178D\245\187\247\237\143\169\248\223\182\183\152\234\247n1@\1992>\182\167\024\231L\227\163\139\n\144\219\027\192\158\178\023\1808\188\249\209\029G\212\129|\244^\0008\152\249QO\027\202\152/\167\239_\026]\176}\028ld!\250\145\255\170\160\001`\237\252\177=\162(\226\217\161\190v\161z\204\tD\197h\238\nx\155R\156yR\132lJ\001\210\146\000\188\"\019\181\236\r\003{\228\145\254\252\159\005l\b\022\248\208|\219\176\254\025{J\182!\1599\000\011\224\162\174\160\198X\005cc\021\000\130\170\224b\196\130H\248\020\132b&\127?\026\201\156\236g\212\222\169\212\147\028\030\225\152\226\015\143\000\n\241/8<\002\1642\018\250\195#\128bL\132\195#\000\251\232\232\015\143x\212\196I_\250\002\026E\204\162\244\005\002\196\206\176\244\005\"FQ_\250\002\n\2414\163k\212 FVB!\188\018\02691\145\202@K\004\136\182\132b\200%\024\227.\193>\248\018\b\0178\163\016\134\025t\1778\131&<\018\000Q\153P\b\205\140\150\231\236\153T\006i&\148\145\154(\016\174\t\197\152M0\006\238\012c\244\206\168\t\225\004@\140#\020\131y\134w(\243]h,\187~\179\216\245\005\014\140\242\132\198\161\158\136\024\239\t\134\160O(D\254\140b\248\207\232\030\249\222\135B\194l\192h\148\0182-\200\011\153`\146\003\001\144!\b\141\210\004\145\202\\A\004H\024\132\198Y\131\136\152:\b\198\252A\176O\"\025<\162\164O\005\016\154N\148X\252\169=\137\199\193\169\189\144\134\169\166\239\212^8 H;\193\169\189\144V\164\160\232\212^H\132t\020\156\218\139h65\005\011\233\144\022\166\169x!\029\1461e\245/\164\195!E\250\n\022\210!\rS\153\161\173c\203)\210\154\165ar\179\1800\150\217\001A\162\179dLw\150V$=K,R\159%B\002\180$L\131\134\134\201\208\145|J\180\191C2\169\197\194\152\030-\r\147\164\163E\169\210\014\b\018\166#\007i\211\210\253O\214c\208e!P\155\183:\212\248B\135\026\223\229P\015\162\2158\212\193\027\028j|yC]\188\183\161.^\217P\195\219\026j|QC-'\167\001\128y\251\147\211\128F\028\020'\167\129\000\188\192\201i\128\145+wr\026@\224\207\159A\142P\22448\131\028\145\"\158\2273\200\017\021\184\143\206 G4\148Cy\0069\162\128D\236\001\221\018\003i\020\007tKB$\137\232\128nI\003)\148\007tK\nJ\000\015\232\1508p/\231Y\001\000\190\253yV@#\142\139\243\172@\000^\225<+\192\200\165;\207\n \240\135'Cc\028\184\rO\134\198\196\136\247\190\147\1611\029$\017\159\012\141\169(\151\232dhL\003)\233!ID@2pH\018\225H\026\229!I\164\128\004\240\144$\226\200\181?$\137(pJ\023\191,\017\224\148a\224\148\225\136S\166\149\1562\0058e\0249e\0289e\220s\202(p\218\rz\137\223\129\203\012\002\143\025\1408\204\148\146\191\140\003w\025D\2222\138\156e\212\243\1491\207\213U\203\017\191\145\238J\2161\b\159&S\196\173\150\0216kd\005ye\172\136,v\021\146\163W\n\209\217+\005x\169+\200k9av%/`T\192\021\178\002_\026\190ag\253*\220N\191\n\246\208\175p\227\252\170g\183\252\170\216\"\191\194}\241+\220\012\191\026\152\147rWz\184O\017fU\017\183'&\168y\243\148`\220O\021@\214\129\130\136.\244\254\164\011\005\248\221S\012\208\130\128\022(Wr\224\175Z\018\224\230\219\020<\2012Y\129\136\165&`\201\174\130\205\r\145\209\166`\180)\025\229\181-\255\224\251\170]\209\206\2283o|\011\224^\152\"\168y\159\132`\252\234\019\001\228}'\130\192\011\157\174\186Wb\137\000\229\157X\1388/T\216\172\023\004\227E\173\000\208\147\210\171e\253*\b\183\159t\012/U\025\144\211\1562\196,\018\197&\210\202p\206n\200\203A\005\156\190\0055\250\022\1405+\128\231Eq\209\184 \210\215\016\132^\170\150\191_w\161\1444r\173\161P\017v=E\188\018\0046\161PA\014\133\138H(TH\172R!r?\0058\020\nr)\167T\175\181\207)@pz\246\218u4\005\243\167g\175\139\222\165\224pz\246Z\187\148\002\240$\025\208~\22856!\175\177\243x\029\182\027\175mLS\204wl\1745\166)\002-\196k\232\027^KD\019\128\172w<\151\239]D\163\174\215\245\192\142m\144\027\014g\006\136\184i\138\204r\237\194\153\014\244\233\230Z\163\153\"\005\139\028\204fl\220\0273|\227s\223\181\134\031Av\230^;\228p\0232\180\011\212\179C\245\196]\180\235\162uv\141\253\178kl\146]K\228\017\181\152\192#\170{\146F\239\181\004\030\005\220\139\131\005-~ p-\129G\001xS\176\224\242\146`A\228\253\192\130\208\171\129\249{j\012\209\223\154\190\150n\144\002&\012fle#\213\170\136T\171\"R\173\226H\181\138\"\213\170\136T\1712R\173\202H\181\194H\181*\"\213\202\188\186m\133\239k[\133/i[\005of[\225\235\216V=\239`[\021/^[\225\219\214V\248\138\181UW\128\r\229\139\132SAX\182\138\248\b+\1769\r'\152\127\181\227J\163\149\"\250C\004\129\248\151\b\002\248\151;\1748^\145#\172\176\002[\r\220\132\155\130)\014Y\022\t\153j\002\166\\\r\166#\145\213\166`\181)Y\149\026\140\170\178U\027\183\168\211\188\146\184\165\000\188z{\213\149M#\190\155\148M\1388\182\0206>&\152?}\176*\202&\189\026\182SVZ6\233\024.\154\025\192\178ie\163\151(\242\201\138\226\t*\231\021\188\196M\225\162R^i\229$\000\178#\004(\150W\230}l:\200\175\nV\210\231\021g\247\141^\1321B\005\173^\164\005\177\2027{\017.\162\022\180{\017\135\248\229\027\190\000\155H\230\127C\002h\020\211\138\223\144\000\001\162[\248\027\018 b\156\243\191!\001\020\"^Fm\216#\004\195\004\193\024\000\t\014\003\006\209\202\168A\004\b\018\132b\164 \184\b\023\132Cx$\020bdF\193\191\024\244\2092\163%\139M,\144\"x2\220/\144\166O a,%R(\171&\150U\211#\171\"\190f\216\004Y\002 \210\018\138\2256\1956\230\018\130\129\151\2240\250\018\173\012\193D\1288LhO0&*Fd\1301,\019\012\1779\163E\128\206p\016\1653\225\169\144j\017\175\t\014\1316\209\202\200M\004\b\223\132\246\196p\162b '\184\136\230\132CH\183\0279\018\253\138\157\156\128\130\177=\222\203\t\200A\132/vs\002J\017\231\203\253\156\128\004\209\190\216\209))&\230+\006a_\tQ\228Wj\025\252\149\006\241_\tq\nP:f\001\165@\"P\002\228\002!\216t\160 \006@\165`RPJ\024\006\149\\FB\165A\196S\002\006=\165\020qOI\144&\148 \189\n\164\128\159\027\220'\012!\132wiz\165Vd\014C9+\181\230\140\212\194\020\162\212>\1536\1892m\250eZ\164\019\161\152\140\162\024$\021%`^\017\138M-\nbvQJ\152`\148\\\230\024\165A\154QBO\166\209\001\152l\148\130\249F)\144r\132Pd\029\161\004\137GhO\145\n\138\244\163\1480\003)\185LBJ\131<\164\132\158T\164\0030\027)\165HHJ\2429i\221\254\253\"\138\203\235\246\152\rm\237P`2\196\012\152\0179@\153\017\0250#\140P\2040\131\154\1772A3R03.K\203\012\202\128\025AR1C\b1c\244\239\015\242\024\253\251\131<\134\255\154\026\143\224\191\166\198t\249\243O<@\254\252\019\141\248,\182GM\192\207\173YU\242\153\172I\129`\255\227\179\181\029\197\252\254\199g\180\021\197a_\228\179\154\134\"\217\"\228\251\015a\224\166\237\163\233g\182~\001LuAX\030r*\000\184\148\208\242z9\211\r\000\\_\156\233\022\002\253\129\185S\000\225=\024/\239\210%\163\238\181\196\183\159\183\244fb\138+\134\230\t\205@_\217\145>\251\253\211\004D\251\167\217z\248\243\209|~6cN\246\179g\"\146!%\199\251\002\128)\017\026\206K\157\223\001G\004\158\241\146S\001\192\132\2514O\137\251\190\000`\214\132\134\179\20643k\249\201\128\007\158\241\146S\001\192\172\251\236\205\022\021\2471\138\2437\164\152\t\0313K\244\024\162\207\225\029N1\138\220\025R\201\162 \247\017\006\236)!d\206\005y\196\142\001\246\028\\{\1380`I\t\001CR\205\221\135 \178\164\148\152'\161[\166\004\227\012w\225\132v\193\132v\248\236]x\130\231\171\249\251\135\130\248\019<_\245\239\0312\160a\187\b\216Q\168\254\n\191\157\227\251D\191\157\011i\160\151\222\223\206\133\003J\225\244\253v.\164\131\028\195\223\206\133D\212,\252\158-\132\207\ba\247W\140\238\2063\186;\195H\143m\132\191g\011\137`1\209\239\217\"\218)6\0174\169\158_A\017y\2195.\242\221\183\218\235!\000~\139\197p\158\176\002]\220\152\240g\157WQOE\149\212\131\1321\190\003\174)\031\1945\229C\223\154\242A\022\132|C\\\238=\132\203\189\135\190\229\222\131\021\131\189m\168\140\1353\202x8\175\140\007\233-\241#\228/\137\251\017x\219\226/\137\019ag\186:;SS\238\186[\014\249\179w\156\157\187\017a\162$\190\027\182\006v\1705w\t\222\188\212\026\017|\242\226\199\132+\224\029\172u\203;\224S{\214\186D\181\025\146\031\028\172Own-\138\215\226#\195\181(\209$\253\242\211p\185\181\211\213\149\187\004\031R\174\174\136\224b\146y\144\195\205\243\028~\234\185\015>\221\019\203IhQ\193\143/\022g;\179\020\243W\225\195\130\165\024Qr82O\145\248T9\224\132\151\224#\138\191+\198\004\241K~\130\244|+\007\156\240\018|B\233\168\153\240\221\\\250\029\175\250\030]\144[\204q\183\210\018=\133\199o\155\187\238Wg\139\b\166\167\1354\127\192\216\211\130\195\172~\128r\017\146\253\017WO\131S\173\158\b\135v=\209\029Q\246$\127\014\182\163E\130\233\149J\175H\206\203\227\1560z%\209/\134~\025\244\t\224<\247\250\137\127u`\012\233VV\224\022\188\233\254\248{@\217\138\193Z\208\155\183\165\248&II\247\165\146\1618[/f\189\143\230\198?\238\015(T2G\020;\193\146~\144\173W\011\250\237ZK\225\007\005\020\218\167\bin\018%\253\251\250\166\137\196\160\239M\177\160\151yA\255!|\238y\191~\194\223\239\229\130\189\246\189\004\136n\188\151\173\238\138o\194\187e\196\200\222\157%\227G\233\238\198\194\001\240\208pw\195\209\240\241\254\140\018\207\193\189\215\139\231\160{\021\011\007\192\028\194\189\nG\1959\248\151G\201\028\202\215\169\200L\012\201\206\199\1948+K\139\231\022\188\158\164\n\030\b\243\204\214\246\018\191{\155'\144\2517\014t\157\027G1\221\015\135s\183\198\129\210\167q(\028\136 \148z3\014\227\174\140\005?\138t\232;\175\165=\024H3\147\174\196w\242\247k9 \148\191\175\006\023K\247\157\164\230A\021\003\225?\218\214\025U\030?\164a\166\000\137Y\001\183\195,\168\217a\022\140w\152\005\144\157dA\224\207\136\255\224V\151~'Q\n@\214;\227\239\186r\249\161\173\011\001X\198\n\148\127v\225\135\235L(f\218\017\002\250\191\197\240\1954\030\004\129\191\197\240\163m1T,\235\157o(\255\240\205\004E\139\r\251\031\2106P \220\176\255\161\r\002E(\213)\192Re\128\253\144\196z4-\253#\182\244\143\216\210?\134-\253c\208\210?bK\255X\180\244\143EK\255\b-\253#\182\244\143`\020G\211\2139b+\231\024\246o\142A\211\230\136\157\154cO{\230X\244d\142\216\1369b\247\229\136\"\1276\150\252\140\150\252\140\150\252\028Z\242s`\201\207\145%?\163%?\023\150\252\\X\242\t\196|B\022N.\219z\016\135\226\177\189\0027\023\188z\184}\211\236\031\222\1737\251\003\127\249e\253\184n?\255\186{x\252W\243\184\223\220\028\254?\208=S\236" let times_bold_afm () = "x\001\189}Kw\219H\210\229\222\191\002\203\153sF=$\b\190\190^\185^\238\178\170mK%\145\230\183\163%H\230\232\001\023)\200\197\254\245\147@\198+o\006\232Y\205\233n7y#\001f\222\136\188\145/@\127\190l\247/\1915\207/\255\174_\246\187\155CQ\253c\252\230\231\230\233\169~~)~n\190\029\247\187\251\175/\197\255\184\249\159\197x\185\152\254\175\238\223y\255\239\178\251w9\234\255\157\244\255\206\139\183\183\205\151\186\248\243xx\169\159\014\197\239\2077\205\254[\179\223\190\212\183\255(\138\183\143\143\197ew\183CqY\031\234\253k@\245\167\246\245\246e\215<\023\191\132\210\255U\\}m\139\127o\143E1.\198\229\127M\195\127g\253/H\249\235\231\221_m\253\251/E5\025\205\166\002\175\254\221\030\182\247uQ\141g\147Y1-g\179\241\155\174u\031\182Ouq\181{\170\015g?5\143\183o~k\031\031\021+\"\182}\218=\030\021}\179\174\251\182\247\198\223_\182\143\187\155\183\207\247\143u1z\243\251\225\183\221\223\245\237\167\221\203\205\215\226n\251x\168\223\252\252u\187\223\222\188\212\251?\235\151\226\215\191_\234\231\219\250\246\178y\218>\247\021\248\233\167\230\239\226l<[\020g\229xQ\140G\163Q\177\156L\1397\215\161\220\254q\247\\\127j\014\187\158\129\179`T\248\234\235\238\230\225\185>\028\138\233\232\205\170\222\031\186\"\163Q\249\143p\1357\031\154\151\221M\253\255\193O\145\166\221\161\216\022/\251\237m\253\180\221?\020\205]\241\199\238\185y9~\171\207\254U\135\171\222\190+\182\207\183\255\187\217\023\187p\241\161\253r\216\221\238\182\251]}\248\199\155_\195\143\220\238\158\239\255\188\249Z\007\134\251\026\252\249\018\138o\247\183l{\243\243\246\219\191\"\233\179\249\236\205g\250\\\005'\190=\220t\140\238\139\217b\242\230\151\154\191\0052\231o\254|\185\253\215\186\168\170\238\195j]\140'\203\240)\132u\231\018\014\235\2018\004I1)\139\127\022\235\207E9\029\133\015\031\138\195\183m\160\239\159\197O\197\136\254\243\207\174\212$\150\154\244\031>\020\245\2237\143\219\167\190\216b\028\2203\t\215\143\139\217r\028KW\177\244t:\237K\255\2136\129\199/\143\177\252\164\168FUQ\205K-?\165\242\163X\135\231\246\233K\231\214\251\231\254\138*T\162Z\206\138\249\136*3K\139\2236\143\143\219}_\180\\\022g\203e\127\243\249\148J\207c\233>\190\186\226\223\234\253M\2151\186\242\227\178\n\181\175\138\197|\030jS\198\011\022\241\130\005\181u\251\020\1748\004\183\244W\204\202.f\139\249b\174\213_\166\228\244\205\141\193\215]1_\134\006\206\138r6\145+\170Qz\197\183\237\190~~\172\239\226\005\213,v\139\208\141\195\021U\188b\236\\\161\191Q\206\227%e_-\186\164Li\218\030\186Z\029\030\250\011\186\n\005\239T\1496\163\"\031O\231\196\211c{\232\203\134\159\028\021\211\192\2274T\168/Y\1651s\019\164f\027\139\006\254\199\139QQ\150\147b\220y\191+=M\171\254\245\248\237kM\158\173\138\241|\220\215\186\251__z\150\222;p\191k\"\245\021E\218x\020\238M5!\231\150\243E\140\222\199\237\225k_\248\172\247l\160~\164qV-RF\254S\239\155H_\213\223\185\154\007\194\023\139Xv\153\150m\158c\175\152M\187h\012\220r\193\233(-\248\242=\222s<\239\n\134zI\1931\020\252\186\175\227=\199\179>\b\171\153)\012\206\187k\218\024\225\161I\221m\167Zr\002%w\175\241\174e\136\212E(:\234\148#\022\173\210\162\135\221\223\177\228\130\154o\238\n]\242P\191\146\207\168]s\189+t\199Z\163\146\239k\216\154CW\223\017\175\229\140\202N\180\236\"\r\156\155\230\177\137uX\148\1629\221\205\251\194\208\t\015\245\211\014.\232\226r6\147+f\1634\222\031\187\140\210\007\241\184#n\026by:\142]i6N\139\214\127\181\219G\238\027\227\209\188\239\029\147 <}\2252-|\223\229\241z?tkp_H\225\135>\231\245\189t\030I\169:\199\208\221\201\135\203\t\245j\018\178\209\162\015\247E\169\225>#\031\206\203\178/\250\182/\217\197Ow\179\2172\234\227\140\2207\155\205\251R?qH\134b\225\134\236\229\217<\189\217\207\177K.\251_\157\0255\156-\210\130\191\196\251u\"\222\253\164\220o\153\254\236\175\230gCG\231bsr\210l<\238\139\253\166\197\166!\147H1r\208\156t\224]d{\222\215n\030\130\153k7/\211\130\255\138\1937\014\247\155O\181\181s\206w\029\235\161\216\239\177X\151\014'\166C\205\161C\189\143?\027rP\023f\230v\211\244W\207c\185\238v\243\153)\006\174\248C{\252,d%)F\174X\246:\252\161\248\1832\188,\ru\224\136\015\1705\139\192\171)\184Lk\2471\214n\026\201\1714m-\192\025\159\140\207F\202\202\002\156q\161\247\011%\146\027\150i\021/Y\n\002/\227\169\222\144\251H/5\031\138?m\005\167\227\137\164\238E\149\018x\197\157\174#p\166\247\131\142q\173\204,\019f\022\179\180\224j\136\194\005\0142\214\236\186\179\208\142\229\194\148\004\175|6\028.5\020\022\203\180\216&\022\155B\177\229(m\240\127\179\238v\r\174\180\024\140\030\190\132q\249C\253\"#\142Y\215Q\170.Yv\021\141\234\187\228\129!y\241K\184\196\166\215)\165W\245\230r\226\254\138\142R&e\252\153N\133\229g\184\011-bLm\0157\187\221\205n\127\211\198\225e\232\137\147\016n\211\145i4\228\166\182\027\247\030\194\128\157\199\173g\227P\187\206z6\143C\144\229\172\200Gh\210\250\208\161\251\001ZH\143\210\020HSqt\211\1839\228\233\197\162\207S}\193E\026\154_\n\202\145]\193\169\233\141KrhE\157\246&\185\227d$w\028\143F\233-om\201\169\241\234x4N\239Y'\247,g\230\158eJ\192\157J\198\164\207\005\221\157\254(va\244\208\127x,\238\030\233J\200O\247\028age\024\rV\139\137\249\145*\173\248W\163\213I\181\167id\237\180\\i\164z<\002\175\253\159\024y]R,C\181\236\128\186\203\193\201o\199Qn\232<\225\183\171\137\249\237E\250\219\143\240\219R\142\220\197\147\128'-\183\232\200\2296\143\193Y\207\154O\186,\175\229`\240\215$\174\154\027W\141\203\244\142\223DI\202@\220\180\180?\014\186\248W\236e\021\021\157\216\187Vi\168\200t)\004\222\196\222r\154&\190\131\173\231d66%\193;4\228\235{_\000\1950d2\162\146\224\155\1820\131\222n\228T\205\200\139c\024\160\1912\155\177\219MMI\208\199\239\177\228\164/9\031\153{\1500>\143C\222q\023\025\213\1622\229\192CG\169eGf\021r\159\022-S2\255\163N\175J[\142\005qY\137 \170\236t\227\243q\016\168I\213i\250\130.\225\169U9\"\213\141\158\154\205h\149$\136\212|QR\225\169s\127\149\219iE?\208O\181\249\007x\180^\142To_v\143\1835G\1968x\184\n\253\170wlw\201\012\178G\156\252\2236\223ul\221\247\1990g\153\142\168\2333\152\191\200\140{\218\187(\144\020F\247S\026\232\143q\016\220\205T\195J\207}\226\254n\202\177\168\232\002\162iLy\239\174[h\226Qs\\S\234\162\176\\\202db<\131\172q\164\249\204\217\172\234EB'4\227\025\204h\238\030\155\253\238Y\146K7o^v\249\159\139C\1788\21270\130/C\168\024\177\154A\152\223\180\2510\155\1919Rf\157u\243\141i\255\127\236\129e\170Z}\254:\236\250\165\183>\131M\2515\149r\164\025l<\135\184\231E\024\137\191P\171.\237U\139\153\185\b:\193}\187\011\023<5:T\b1M\186R\141\167t\017$\151\238\162\190rrQ\152\167\133\139&]?\146\139&\003\023\237\237\2441\\U\134\248\210\171 \197\220\2374\145uz\167\r\153B\193\199\161\130\224\188\176\136\198c\156\176\204\176\024\247\134r\206\165\193s\183\219\251{\154\218U\189\167C\156N\141\167\231K\175e\201\213\224\193\239\254\246.,\207\201\218\223YH\015!V\250\217'\165\235\146\247%d-D\231\158\217\130H\201\219\019\178\130\161\133\187U\130\016\143\221\170\195\156\"\173\228\253\t\169\248\199X\241nDF\179u\026h\148\019q\147T\253)\012\153\218G\174{\240j_\247\177\174q\150\188X\207\131\211m,:\137\163\211\217R\231Le\005s\161\219.\213\030\0140%\226\017e\167\250\233\244\197\206\200\187!m?\031gZ\1785l-\221\141\232\195\012\191\155yL\171\184\178X\242J6W\187\209u\228\190\218:\157(e-\155\210kHja[/\232\243\129=\212\141\191\166c]\022<\227A$\175\168%\189OV\214\186\141\024[\\\166\182\170ef~\203\253\226\012\180u\171\218a\230\236X\021\153\143d}\143\231&a\244\134?!\021\210\190d+D}\233\012\"`\147\180V\150q\176\181\188d|\187{\221\221j\208\004\149\236\183_&s\255\230\202\141\220yYN\220\178oA\229y5x9\174|&s\222\003\147H\138,\164\193\221\205\146\218\208\015\028M\229\205\\\011\127A\230\163\253^\147Q\250\174V\157\180\218\185i\238\171\180Z\255\015\014\187\022\173\183m\152L\253\194\169w\245\130\204\191\204\170\209\237\184\144\214\165\252*k\128\252@J\018W\007|,\241l\238\030\139O\226b\196,\141\127Yz\199\234\199%x\172\188,\232\135$N\187\0143X\212\231\162\201\198\160qV7F\238\243`P\1693\218\159\149\219Ws\186\134w\238i-\184on9\206\186\175T\223\014+\164\242\149\175#7y\183\r\202\142Q ~\146(\176\193_\141\\^>`k\227:q\186P,\012\177\128'\158\rj\031rI\230W\174\141\014\254N\244EY\251\198\234t{O\029\249v%\028\219\240\179V\199l\237\012V\200\172\027\024\153\157W\003a\150\014\209\216U\203\209x\160\171\163\171&a^\129\174\210\210f\188uJ\020d\213\017\153\0157\202\196\158\022V\030\155\255\212\207\247TxD+G\243\202W\131KSo\222\201@\245\147}\170\204I\212C\236\158U\214\191=\149\141+i\131\129<\160\128}t\250\n\248\214t+\206\018C\189jo\154\204K\138x_\237\129\142\163\236\0028\198\205\127\167q#\155\027\0247\188+u\245\181\217[5\024\229\250$\227D\211F\179\223\133\205\020\207\154d(\158\029\016\225?\181\172\217\168\194\210\179y\188\243m\022\235\179~\020Z\250\233 U<\2016Pm\137\1514\151Q\164\128\138M\236\169\132C\219\175:\208\158uh\236\162\023&\030\224f4\1700\025\022\007\135 ZZF\031CEu\028'E\193\235N\148}\024S\1547c\134\202\182\216\157b0\204\006\134\219\0314\024,\247c?/\253n*\194\147\156L3\204\137\1710-\030:v%n\229\189\129}\243P?\219\029\130q5\137;\004\163\185;\182\218\215\247\187\131\174#\158\024\\I\130\210\030hNS\012\165\236\223A\170\165\193(\213\188R\222\134\236'k\229\253B`w\174CW\205\178\184T\237\208\144,\253Q\255\2220/Ii`\194\216\152\0160\155r\024\002\146\146\204\173%\029\149\003\233\203H\187\148\197^TE\254\232\168\144\030/\234\211\204\180\156\012f\233__\226|~h$.\003;\155u\187\161]?\018\\\228\243s\025\152z\163\217~\236n\182I\133\242q\236I/\166\173q#\176[\189Z\140\167\190\0048\179 \187k\157\165=g^\227\141\173%{\168\151~\152h\0185\146\225\206\208bD>\016w\022#dw\016\164\168\219\"\196\178\162\212N\019\203y5\216=?f\163\012/\243J\148\231\018:?\177\136\226\244\137N\208\161O\200\000<\187y7\250\030lh\186\248*\t)Kx\220PHH\182\181\227\129)|\162\021C\147\230\217\152f\181\245\227\203V\187\210h\145\141v8]\188\232\248\210l\202c\016N\2448h2\154\234\214O\167\177\169C\163\169\132\026;,\157\251\227\187\167\150\243E\127&\163\223\247\159\249\189z\167\156\156\149sZ]\028\020\197l]\140\015\161\148\203\193\161\210\175N\004\207\170\156\0319\221\162\171\t\206\017\023\225fjF\167A\029\247A%i\2280\233uf>\153\012:\236O\171}\019\154q\216cc\2263\158\238%\025\190\219d+\243\1778\031\229\203fp#\154\193\153\131}H\210\031f\248\198\139\217\024\152\1788\173O\023\244\237\173\250\005\248\1659\128\155\015\173\210,l\198VC\139\177F\208\134\006)R\214\202\130,\219V~\162\252\1950\2177t\23409\149\019\214_\183\143q\208|6\143^5'\1461Wv\203\228&Q.\251D9\027\156\0017\0033\224\185s\t\143!\205\242\006\143!qqC\196\198_C\030\208\028\238+\176\004qj4S;j\\\230#\020\217\2494+\224\230\172V\150G\148{\234UrIG\127u\170Sma\230\220\207o\199\213@i\236%'\186\161\ba\198\233\137\028W\241\014{H\206t\172>\172\222Wa\011o\226\181\130\163\"\207\228NF\212A\148\180\217\174\142\r\180\185\133\252\227O19\156C'\223\221P0\135A\240Y\213\237\214\151\197b:\026X\132\213\142\197G\171\179\025\169\172\206\224\154\249\146W]\134\151\156?h\240\155Y\206b1\208\187\242\149\192n\248<\208Y.\179\n\209\216\210\030\250\205\165\004\007\164<\1385;\129\217\184N\235%\131\186\197\192z\151\221K\165\188\181\212c\242YqYT\145\177%\238\014p\024k\029l2_\248\206\250\015\1367\143\024\007W\191!Wy\147t\145n;\224\230\237\226\249h07?d~*\169\215\154#\149\217B\140\157\192\150\163e\031\245\221\234\145[#Te\201>\003\157\234\217\2040d^\143K\194|:!\171>\165f{:\017\171\255\216\220w\253\240\185y\2256tgF\237\243\029Y\236\187+\025\243|%C\132!\223.\162\021\007\188\128\180!TF3]\232\"g\001\239\206\249\244u\246\196?k\184I\001\139\210oF\253\2425k\000\196\156\196(8\161\159\209\012%\209\172.\180\ra\143\199\226\1609Di2h\238\014\186\132\161@9\207\149\\F\182&?\158-\250av9\152\029\127m\233\193/}\198\241\215\231[\243pd|Z\242\188\222?\255\178}\217\234\183O\219]\024w\150eU\1909\255\244\185x[\132{O\167\2529\166s\003D\158,@#Q\133\222\217\2071i\027\192\146\167\240\199\016\001\242\153~T\001\211\165\012*1g\176\152\160\012\144$\\\131\019\183\006\137'\t\012\016EN\129\011\243\249\1708[\202g\226\196\000\182\141\002_w\027\132\252\153\137\021\192\182QQm\163b\212F\005\2106*\206mT\132\212\210 \189\230\235\247U\215S\184\194\235\240e\194\150M\209?\178L_\168\250\006\209\154*\248\173{\168\130>\155GH\207\230\021\129\173\249\233\022)i]JZ\135\146\022)i\007(i3J\218\140\146\022(y\181-\250\030\252\201\159\143\166!\180\231o\000\173&c\177\136\233^\004@\031#\020:\026\163\216\219\"\254.\003\160\223\017\234v\190h3=\144\000\232\134\132z}\145Ly\135$\003\244JB\253\174IF\236\159\004C'%\020zjD/\0160}\150\000\232\184\140z\1897\218L\023&\000\130\150P/r\201\148\135/\025 \134\t\245\003\153\140\024\205\004cH\019\156\198u\004m\127\143\136\237\244\017\177=\159\016\236\254\004;\026\016-F\b\"\224\169A\180\180X\197\214\165\184\029\166\184\029\162\184u)nOQ\220\250\020\183>\197\173G\241k\198\134\017\145\b\028\145\004\148\019BsM\137\221\220h\n\001\160)\132\130\1660\138\154\018\241w\025\000\154B\168\171)\209f4\133\000\208\020B=M!S\174)d\000M!\212\215\0202\162\166\016\012\154B(hJD/\0160\154B\000h\n\163\158\166D\155\209\020\002 \224\t\245\002\158Ly\192\147\001\002\158P?\224\201\136\001O0\006<\193i\192G\208jJD\172\166D\196j\n!\168)\004;\154\018-FS\"\224iJ\180\180X\197\214\165\184\029\166\184\029\162\184u)nOQ\220\250\020\183>\197\173G\241k\198\134\209\148\b\028\145\004\212\020BsM1,\024a\177(\168\1395\129\196$&\212\025c|\231\163\1608\214\228\202\142)`\180\199\162 @\214\228\169\144\181\231Rd\173\160G\214\228\139\146-\129\202dm O\214\004\026eL\023.j\212\202\162 Y\137\201\211-S\192\136\151E\161{Y\147\215\199\172=\239h\214\n\189\205\154\252.gK`\191\1796\236|\214\150\246@c\177Jg`+w\006\182\154ga\020>ks\212\207\152\141\004\026\212\211Acn\221\166\180\195.k\127\224\178\246\164\203\218a\151\181?tY{\194e\237\t\151\181\131.{\245\1534\242i\208\163K \n\1695\229j*\136\209R\197@I\213\000:j\012\168\162bz\231a\160\160jp\245S\204F=\021\003\237T\131\167\156j\205uSm\160\154j\2405S\237\168\152j\001\189T\003\168\165\024.\028\204(\165b\160\147\198\224\169\164\152\141F*\006\221M\r^gSk\222\213\212\006\029M\r~7S;v2\181`\023SK\218\193\004\183\138(\160\213C\001\173\026*\136Z\168\022G\t\0052:(\152\167\130bl\157\170\183C.iO\186\164=\225\146v\200%\237\015\\\210\014\186\164\029tI;\224\146W\1431\163w\130\029\029\162P\235\212\144+]l\172\1459\002@\227\b\005\129c\020\213-\226\2392\000t\141PW\212\162\205(\026\001 g\132zZF\166\\\200\200\000*F\168/adD\253\"\024\196\139PP\174\136^ `4\139\000\016,F=\181\1386#U\004@\167 \212\235\017d\202\187\003\025\160/\016\234w\0042b/ \024\187\000\193i\252G\208\234QD\172\024E\196*\017!(C\004;\026\020-F\128\"\224\169O\180\180X\197\214\165\184\029\166\184\029\162\184u)nOQ\220\250\020\183>\197\173G\241k\198\134\017\151\b\028\145\004\148\021BsM\161\234\025Qa\004T\133a\144\021\129QW\200\240.G@Y\024v\165\133\140F[\024\001qa\216S\023\182\229\242\194\022\208\023\134}\129a+*\012\227 1\012\131\198\016|\145!Fe\024\001\153\017\216\211\0252\026\161a\004\186\001\195^?`[\222\017\216\002=\129a\191+\176\021\251\002\227\216\025\024O{\003\161Vq\b\178\146C\144\213\028\134Pt\024wT\135LFv\b\241t\135LmV\213\214\167\188=Ay;Hy\235S\222\158\164\188\029\160\188\029\160\188u)\127\205\1531\018D\2001#\004E\136\225\\\133\1686F\133\024\001\021b\024TH`T!2\188\203\017P!\134]\021\"\163Q!F@\133\024\246T\136m\185\n\177\005T\136a_\133\216\138*\1968\168\016\195\160B\004_d\136Q!F@\133\004\246T\136\140F\133\024\129.\193\176\215%\216\150w\t\182@\151`\216\239\018l\197.\1938v\t\198\211.A\168U!\130\172\n\017dU\136!T!\198\029\021\"\147Q!B<\021\"S\155U\181\245)oOP\222\014R\222\250\148\183')o\007(o\007(o]\202_sf\140\n\017\018Th\146\018\194*\132\1766\145-\253\175\026\r\138\223A\129\"\b\250C \170O\015\191\195\239\160<\017tu\1677\025\213\137\223As\"\232)N\180\228z\019qP\155\b\250Z\019m\1684\017\005\157\137 \168L\015^\192w\1630\241;\232\011\129\158\186\244&\163-\241;\132y\004\189 \143\150<\196#\014\001\030A?\188\163\r\131;\162\024\218\017M\003\187\255f\149\164\007\172\142\244\128U\145\b\160\134D\212Q\144\222`\244\163\255\238\169Goh\161j\173Gi;Hi;@i\235Q\218\158\160\180u)m]J[\135\210Wd\192\232D\255\253\b\r\199\145J\004\243qJ\140k#\017\004\128F\016\n\"\193(\170D\196\223e\000\232\004\161\174PD\155Q\n\002@*\b\245\180\130L\185X\144\001\212\130P_.\200\136zA0\b\006\161\160\024\241\235\005\002F3\b\000\209`\212S\141h3\178A\000\0049\161^\148\147)\015s2@\156\019\234\007:\0251\210\t\198P'8\141\245\bZ\253\136\136\021\144\136X\005!\004%\132`GC\162\197\136H\004<\021\137\150\022\171\216\186\020\183\195\020\183C\020\183.\197\237)\138[\159\226\214\167\184\245(~\205\2160\130\018\129#\146\128\146Bh\166)?\021o\195\bd\196\159y\176\"\000\169\128\002\1505E\205hF0\226J\001fB\017&A\145\216~\253N\029S\128\235\142\011\254,A\196\128\173\156\1626\168\024\163\202)\144\250Pq\174\180\"\\iEb\165\233\251/=\163S\254\204\140\n\192\140\n\1440*\168aT0fT\000aT\016aT\016bT\1903\163\012\132\014\\q\205\215\230\243\198~f%\023\192(5c\244wO\206J\002\1626\0262\b\000F\b\005Z\b\245\184!SN\016\025\128%B\145*\130\145/\130S\210\b\004\230\"j\232\139\192\026\129M\006\000\155\132\230\148FC\198k\255\248\169\2295\002\200kD\145\215\136\186\188F\147\195k4 \175\017\205x\141p\198k\132\129\215\b\"\175=jy\237\1295\002\155\012@^#\234\240\218\027\128\215\223:J\151\242\153\238\165\000\017\169\128\229PQ\2535\197\1369\005\1524E\152/E\"U\250\157X\018`+\025\2417~\231\157\001\168\182\n\216\218*\170\181U\140j\171\000\215V\017\174\173\"\177\182\250\157j+@\252\131Kg\203\146\190[[\141\181\1677\021Z\192\171}\237\212\222\203\230\239!\155\191\199l\254\190\139\225\241\148?s6\023\128j\171@\146\222\0055\233]0N\239\002H\026\023D\210\184 \148\198\229;\213V\128\2283\214\150c\214\000^mk\167\1826f\021\196&\212Y\019\234\172\t\141\253\1405l\220\n5N\133\026\252m\136Y\197\179:q\204*\128,\130\236\190\239\198\235bl\177\210\173[\233\214\169t\139\149n\007*\221f\149n3\"\219$\022\206\187\185-\005\237\185Lk\021pz\209\185\157\204*\150\246\162s\156\194*\014\189\235\\&\174\n\164\157\233\220H\2349J\2349J\234\185+\169\231\142\164\158{\146z\142\146z\158I\234y&\169\231FR\207QR\207]I=w$\245\028%\245|@R\2073I=GI=GI=7\209x\142\209x\238F\227\185\019\141\231\024\141\231\003\209x\158E\227y\022\141\231Y4\030ea\226\\&z\nd\139(\201\011?L$'0\004ub\243\226;)\144\135zb\134\168Ol~\007H\138`_H\140\208-\018\027\244\016k3.O`\136\202\196\006](\1819\193\155\020\200\22785\231},\177C\200'6\140\242\196\136\157\208\026\155\001\248\004\t\205\143\026\218\156nhs\162!\003\2218)r\170\173\216\185\019\027\244sk3]>\129\161\247'6O\b\146\002\185&$f\144\135\196\230+ER\004E#1\162~$\198TJ\172\233\232\011\006\nLb\203\180\230\143~\145\180\228\207\188>\170@\1784\202\240\202|^\155\207\027\251\153gd\002\152\169\022c\233\031\221\2241\198\031\201j!\015\150\255\232Z<\229j\031\211E\244?l\219\024\211\231L\203\004\128V\186\207\153&\182\021\002k\0046\025\000\205\207\030\201L\r\003D\228Og\n\027\242\168b\218Z\228%{T\145\r\182\185\134\162\004\006\162R\155G\151\005W>\188\246\225\205\000\0124&\182\156Lk\030\1604+\130\196B\031\243\248B\146\007\250\024\155\163\206\025\146\t\000z\025\245\136\141\182\021\002k\0046\025\000\004\018\154S\023\r\003\164\025#\210\021MGl-RDhFN\247Gc\249g\228\133\138\006\224\133\017\001\146\132&\168\201b\130q\234\018@\146\145 \146m\005\161\133\017\249\206y\136\128X\191\183\025\000\245&\020*O\168\215\0022\229\205 \003\180\133Pl\016\193\216*\130\211\166\017\b\237\147E`\000\160}\233\"0\160^\251\178E`0@\251`\017\024`l_\178\b\012 \182\207t\174\183\0030\182\213\218\176\197\214\230\182\219\022pZo\205\200\129\181eLXc\198\1355\002+\214\004\220\196\175o3\000\248 \020\152 \212\227\128Ly\235\201\000\237&\020[L0\182\149\224\180\149\004\166\237\251\2165\173\146\207\233\226\243Gi\144\002\201\198\183\160\217\242\244Gi\129\002\178\153-\b\215[\145Xe\253\206{\218\012\\\217\207\148*\012`\179\132\192+\217\139\252\216\229\006\249\252\217\148\217\024|\147n\181~\180\137\1291\145\188*\005\128\192T\242\000\245\168\204$\015\012@*H\030\192Ho\"y\000\002\2092J\004\000(\247F\137\169m\133\156\173\017\248\140\151l\176\004:$\0276\178\1930j\\cQ\240\1435\129\147\172\201\243\148\181\231\238\178V\240\1535\161\227\172\r\189gm\169\011\173\005\252\152>X\237\161\224\209\193\007\171\157\002+\151\249\181\139~v\239\176q\203\162\191\253\135\141\217*\136q\185b\224p5\128\187\213\2249[\173\185\171\213\006\142V\003\186Y-\232d\181\164.V\028\028l\159\006\2051p\238\192\211\160\153y\229\176\187v\176\207\206\181\027\167\028:\212{b\146m\145D\227K\002\192\145\132\130\023\t\245\\H\166\220\127d\000\231\017\138\158#\024\221Fp\2343\002\193a\242\028\028\000\224*\2399\184\212\182B\206\214\b|\198K6X\002\029\147=C\198\134d9\1998'\197\193G\169\017\\\149\026=\143\165%r\199\165v\240_jD7\166V\244fjM\157\154\218\192\183\137\241j\b\007O\131\209sxRd5\224\149\245\000\254y\224>\155\129\242\024\019\1691\015\r\226\214\004\005#\016\014\012C 0\236\133\000\219r\231\179\005\220\2060:\156qt5\227\169\147\025\005\247\234\211e\136\128K\221\167\203\192\184\202\024\\g\200\231\236\170MV\006\221\149?\145\197\150\184\218`\252D\000\184\137P\240\018\161\158\147\200\148\251\136\012\224\"B\209C\004\163\131\bN\253C \184GV\148\000\000\231x+J\169m\133\156\173\017\248\140\151l\176\004\186%[bb\131L0\171\020\000\175\164\019L@=\175d\019L0\128W`\130\t0z%\153`\002\b^\145S\199\000\128W\188S\199\169m\133\156\173\017\248\140\151l\176\004z%;\177K\134O\157C\232t\233'\241\133\002\228\006\005\172\007\020\205N\170~\018\222\021`\202\021a\182\021\137D\235w\226X\128\173\156\220\252\164gP\004\2243(\0028GL?%gP\004K\143\152~2gP\004\129\163\164\159\228\012\138|\231\211\019\012\164\231\168>\245\251\152l\171\211\133\149O\186c\169@\190\156\242)\217\155T\204lH\n\152\174\172|2[\143\130\192z\202\167~\147Q>c\r\027\183B\141S\161\006\127\027w\011\005\207\234$\251\130\002\164\0119\159\178sT\023\230\156\241\005\1583\190p\207\025_8\231\140/\240\156\241\197\1929\227\139\236\156\241Ev\206\248\002\206\025_\224I\154K\179\183\127\137\027\250\151\238.\254\165\179u\127\137\251\245\151\003\155\244\151\217\206\252%n\199_\226\030\252\165Q\179K\020\178K_\195.;g\200\245\215\216\174k\183]\215N\187\174\177]\215\003\237\186\206\218u\rg\219.\217\025\242}%;\016\151\157\186N\248\243\198~N\143\232^Z\245d,\0221\158$\000\154M\168\215v2\229\004\144\001X \212\167\130\140\200\007\193\224lB\193\227\184\028v\233.\135]\158X\014#\2195\222\243\218\229\228z\152\147\235!N\174]N\174Oqr\237s\146\005\n\193i\180\232\250^\226\2455\134\193&\003 \130\178\229<6DvM\024\017\000\148\017\234QF\166\15622\000e\132\250\148\145\017)#\024\194\136P\b\163\136\1540\"\000\194\136Q/\140\162\237\026\239y\237rr=\204\201\245\016'\215.'\215\1678\185\2469\201\194\136\2244\140\228\t\132i\226\2455\134\193&\003 \140\178'\016\196\224\158\028\187\193\237\245\143\185\189>\197m\030\190\214\bA\156\030\241\152:\145\183\246\003r3\000cp\251G<\200|e\030\251\184\194\199>\174\240\177\143\171\194{\236\227\202y\236\227\n\031\251\184\202\030\251\184\202\030\251\184\130\199>\174\240\177\143\171\174\023\142\023\252\153\007\166\002$\003SA\205\192T0\030\152\n\000\003S\193e`*\b\031\241\022\128')\012\232\004\229J\166T\n\240\131\197\002$\015b\nj&\150\130\241\227\151\002\200\195\149\130\b\163\130\016\163\242\157j+\151\2204\143f\014y\197S,\249n+_ck\234\244\204\205U:\197R\212i\141\157biAlb\1575\177\206\154\248\245\248\237km+\1773\206\216a\144\236db\193Hc.m\176\133\141\219\160&;\240s%S4\005\210\152R\\:\130 \020S\np\2203\192\147\029\233\b{\227\162}\186\202p\197\127\222\221\002V\130\005>\212O;\244\127k~\181E6Z\151\141\214a\163E6\218\0016\218\140\1416\243p\011A\252\221\212W\2239r\133o\027\185r\2223r%Gr\152\202\244H\014\160\160\127\206\145\0280\229J\152\030\201\001\0205\017\142\228\000\156\170cz$'E\141N\166C_@=\197\204\134\190`\000\237t\135\190`D\021M\135\190\128\130\158F\212\136*\001\016\155\132\130\188\018\234i,\153ri\"\003H\017\161\168G\004c\200\018\156\198-\129\160\192\017\133n\200`\162\197\017\204\218\\\187L\16043\234t`2\r1\225)5Y\\\142j\159\163\218\231\b\213;\162;\244\255\206\141\223L\204#\220\224\237\026\151\162f\152\012G\224\201\000\186F\168/ndD\133#\024D\159PP\254\244!\232\180\147\239140\017\016\n\217\128Q/%D\155\147\023\162\161\197\138\181.\177\2370\177\237\016\177\173Kl{\138\216\214'\182\245\003\173\245:\227wl\225\0173\005\230\020B\157\196\146\158\133\020W9g!]\027\166\154\161\179\144n\001'\2378g!][\150\130\188\179\144\174\017\210\145s\022\210\179\217\212\228L\164]\155\155\166\252\137\180k\198\1485<\145v\139d\233\203\153H\1876Le\198f\019\154\133\177CY\027&7ksS\156-\224\200\1875\163\148[[&\232\214\152\2456k\132>gM\152\006\141\r\181'1\165)\209>\236\229\255P}\130\209,I&6O\196l\129\211\140\186i\211\218O0^\159b\188>\197x\150N\141m\231G\226\238D\207\203\019\17216\254\2074'\bo~D\170\151x\173\025\179\132\181\r\228\n[$\203\024\214\136\t\217\2180-\027[\150\156\141m\239\135j\150\168\173\r\211ubs\147\182\001\189\212m\204\173\223\132\246\132\203\218\031\185\172=\237\178\246\132\203\218\031\187\172=\229\178\246TWh\135\197\231\187\207\206\209\207\230\217\016\192\218\178\129\192u\151\253g#\254L\215*@\"\174\128\229WQ\189\175b\196\164\002\204\141\"L\136\"\145\005\253N\145,\000)\234\148\191s83 \007\214g)\000\rK\015\172\003\23451;\176\014\006h,\028X\007\024\155\157\028X\007\016\b\136(\176\016A\164\"=%>sP \1979%\238\153\0271\255\242\1945Eh\154h\145\228\\\166\192\246`\166\130\230\165k\138\202yMA\244`\166@z2\147!^t\1609\213\170[i\152\204\2493\207\158\004H\142n\bj&R\130\241!\r\001\228\216\133 r\214\130\145\198\214\172\201xk|\150\026\143\165&\227\003_\005\167\134\156(y\025\156\"r\158\153\0179z+Ql&\240\018\027\173\253\140\145\221\186\129\220:\129\220b \251\211\239U6\231^e\019\237\021\204\174\215\189\026\210Q\220\181\170\161\"\172\134\138$\142P\2168BAv\132\"\194\183B\018\152\n\145\026*\192\030\016\228\163\028)^\235\026\180\000\206Q\231u\178\218,Xz\212y\157\173+\011\014G\157\215\186\130,@z\236}\221)\219l\202\1599\193\n\192\201U\128$\177\nj\146\170`\156P\005\144d*\136$RA(\137\202wN\160\012P\244N\245\187=\180\191.l\217\026[\195\178f\000\1755\181\211\026\171i\nb\019\235\172\137u\214D\2143\210\148\181Y9]\227r\233:[#]w\0184\231{\177\002)\144<\241!\168y\226C0~\226C\1284\166\020\151'A\004\161\152R\128\031\252`@V-\217-Fx\196u\2502\2495\190G~\237\190B~\237\188=~\141/\142_\015\1883~\157\189.~\157\189)~\r/\137_w\139v3\249\156\142>\215vy\142\176M\175Tc\249\194\222T\132\149J\145D\005\02062\160 \235\128\"\210\225\021\146\136Q\136\148J\001\022\001A>\202\169\189\141\030;\021\192y\167\245&9`*X\250&\235Mv\148Tpx\185\245F\015\141\n\144\190\188z\211)\213B>S\029\021 f\021\176\149VT+\173\024UZ\001\174\156\"L\170\"\145S\253N\181\021 \205\179\027P\170M?\004\027\143\249\139D\138 <\0043H\018)\002\155\206\173\152\025\129iI\238\242\002H\215\022D\131\135!\216\244\217\152\241\215\006\199_\155l\200\180\233\135Lr\179&kg\227\183\202\014\153\020\148\248\023\004\018\161\026\180c\b\196\169P\017\233\006\140\128pm\156\017\211\198\140\15268b\218\184#\166\1413b\218\224\136i30b\218d#\166M6b\218\192\136i#\235\234\210\195\211\133u\132Q\150\156\165u\1809\002\149.\174#\156I\021,\175#\014\162\149.\176\003l\228\011\030\234IQO\200\242\135zR\003H\154\255POjDq\131\135zR\020d.\162F\235\b\000\193#\020T\143PO\250\200\148\235\031\025@\004\tE%$\024\229\144\224T\019\t\004a\228-\145\164O%\251$)h\251'!(\"\004\163b2\236\t\012\217r\237d\131#\160d\002\021%\020\165\148\224LO#\142\162\026Q\163\172\004\128\188\018\138\026\027\225&\251\149\198'\1709\193\136\167\187dA\241%x@\129\201\154\2010\225\168\197\004\163 \167[e)[\1424GC\155\001 \210\132zJM\166\\\174\201\000\154M\168/\220dD\245&\024%\156\224T\199\237n\150H^\182\157\229XP\208\253\r-\199\236\200z\182\165\229X2q\2077\181\028\019H|\182\173\149[\140\208+\006Z\175\006O\238\213\154+\190\218@\244\213\224\235\190\218Q\250\213\002\234\175\006H\000b09@1H\003j\128L\160\006/\025\1685\207\007j\131\148\160\006\204\nj\193\196\160\15047(\014\233\193\236`&]\027w63\220\202\134\130\168\128j\193la,\158<\1709\207\025\198\230\164\r\181B\230P\003&\015\181d\249CL\152B\196`\178\136b\144H\212\128\185D,\141\247\163\205 \159\205i\214\188\188\162FL-j\025\200.Z K0j\194\028\163\022L3\217\246xF\170\147l\196\214z\024\164\0285xYG\173y\226Q\027\228\0305\248\233G\237\152\129\212\130IH-I\030\218v\127(\143\222\239N\nd\128\168<\0060M4\168\220\219`\177I\006\160\170\026D\255F0#\252\151@\249\187\252)?\002\190\132\255\240\250\230\023qi\197@+\175u\248\"nR\192yk\198\023\235\022\197\210\183f|A7(\014o\205\248\162\180+\146\188\020\245K\255w\tcc\162\220\193\187\158\171\204F\006Z\\\187\237\014\161\209\rno\250?\201\165@m\238^\1393\025\136\178h\129\196\153\140Zg\n&\226g@\2410\003\234aF\204_\129\142\200\157lX\241\247p\235\199\250p\216I\150\188\235d\174\228\207\141\253\204.\021\192\249\187\nw\206\031S\184\195\191\160p7\240g\019\238\178\191\149p\135\127 \225\014\255*\194\157\238\1980\144\250\148\150\028\239\172;\201\155\247x\237}\236q\136z\231F\201\214\191\245[?\179\138\011`\2129b\187\248\1671\227g\r\018\002 &\bMb\1300u?\001\198\253\132\216?\002\222#\015q{\146?\167\251&\015fsR\128|#\229!\221\154\020\204\238L2\152\238\174<\216}IF\224\1331\015\230\207A=\224\159\131zp\255\028\212\131\243\231\160\030\240\207A=\012\2529\168\135\236\207A=\224\159\131z\192?\007\245`\\\254\128.\127p\\\254\000\231\221\185\173\222yw\215\006~\025<\239\238\022\200\1895t\222\221\181\131\015\221\243\238\174\017=\011g\208=n\208\223\131g\208\221\002\167y\199\1288q\006\221-\130a\226\157Awm\016\163d\017`J\184\026fQS\214Q6\197L9T;\002L\137\196\133\175\003\184)\159\201%#\166Lt\235+\002\166\132\249c\199\022\208\018\148.`\152A\249\199\026S\011\151\127\172\239\250#\147t\183\020N%#\181\165\239\128Km\142d\164\0052\201H\205\169$\1646\144\132\212\b\146\144\026\147\023\133\165\166tg\189\183y\196\012\1782H\201i>N\1451\200\1960\r\195\028\012\017p\186\245\250\233l6Q[\012$}\197\154\005\227\136\213\177\216\016\204o\182\247.\217\167#|kI_\225\151X\2369\181\220\174\199\136,\152N\177\173\133~\200\179\132\188\247\248\184\245m\201a\185\220\254m{S\203\177(cx\149*\239\139\155\130\015\014\132\207\233\217\130\000p\194V\128\171\163P\178\218\178/\236\2455\222\176\198\027\214\206\179\149\251$\215+f\018\188\128\233\163\149{\147\202\005\129\243\017\251B\131s\207\003e\003$\164\n\012g2\246\133f\208=g+\003p3\021H\238*p\154S\247\253x\130\171\217 y\141\203U\227p\213 -\141\251\152\233\222\140\006\004I\031(\221k\222g\224\155\161E&\017#F\2542%5\157P\0313\193F\000\180\145P\136\018F1\246\188=\161\189\238\t%\165j\247\151j\247\151\220\160\204\246\131\208\144\135g\186\029\004(2\143\219A\t|\143Lb\220\018\234\006o\186\161\196\017\028Q\019\164\004@,\019\n\001\205\168\023\213d\131\208\214\029\168\164a\141\235\150f\216\001\205\144\003\026\151\230\129\192\199\189\167\020\134.\000;O\t\250\ri\206zD\132\255\194\011M\223\160\183mh\t\002\128\026B!b\025\197\190\145\188\194\131\251\134\188\194#-U\187\191T\187\191\228\246\141\236\021\030h\200\251F\250\n\015@\209/\240\n\143\020\190G&\177o\016\234\246\141\244- \2207\"j\226\157\000\232\027\132B\223`\212\235\027d\131\190!\175\rI\027\214\184ni\134\029\208\0129\160qi\030\232\027\240\218\016\128\161o\164\175\rI\209oHs\2147\"\252\023^h\251\134}\248\222\148\1790\210dm\024\195\137-\2353\249\147\254\210s`\229\195\185\162>Q\143\250D=\252\0305\176\242\225\154\157\222\229\173|x\182\204\203\238\202\135c\188\247}\148\245=k\243{\160\243\250\000\233\135\198f{\152\133\177OZ\027\246\204\196\230\246O[\002{)\172\2518\1644'B\160\249\145\155\155\211nnN\184q\168'\187\235>\158\017{\181\183\238\227\216\190\249n\204\251\1851\254\229\223J\251|\156\182\188\149%\004\250N\212\166 \191\146$\001\147\131\193\137\197\028\014Np> \156\128r\0248A\229@p\130\210\161\224\004\2277\140X\240J\030j\162\239<\241KA\231!\168hZ\201\206N\252\190\006\251\006~o\227\177\182\201hx5/\226\127\197\023\241\191\226\139\248_\221\023\241\191:/\226\127\197\023\241\191f/\226\127\205^\196\255\n/\226\127\197\023\241\191\202\003r\\{k\171\177\246\176\234\252\234.5\191:\235\203\175\222\162\242+\174$\191f\203\199\175\217\154\241k|,\136?c\r\027\183B\141S\161\006\127\187q\159\243x\181\015\0041\146>\231\241j\030\007\"\128\187\237<\002\223\129\230\239\166\017\223\177\017\223\221F|w\026\241\029\027\241}\160\017\223\179F|\199F|\199F|\199F\028\161\017G\019+G\140\149#\198\202\209\141\149\163\019+G/V\142\024+\199,V\142Y\172\028\205^\229\017\247*\143\238^\229\209\217\171<\226^\229q`\175\242\152\237U\030q\175\242\136{\149\199\140\230d*\206\\\235T<)\133\172\195T\028P\135\255|*\014\134\220\0190\021OQ\244\tN\197\019\216x'\157\194\002\234\249)\155\194\130\001<\230Na\193\136\190K\167\176\128\130\023\211\025+\187\018\207Q\1777\147sTX\022}\154\159\162\202\r\142g\1893T\142-\247ov\132*7\160\151\157#Th1\190\206\0148\229\006\207\227\222\241\166\220\006~\031:\220\148\219\209\251\217\209\166\220\0001\144\029l\na\240\235\243\237y\189\127\254\180\221\237\015\252\229\151\237\203\182\251\252[\243\252\242\239\250e\191\1879\252_PW\249A" let times_italic_afm () = "x\001\189}[w\219F\214\229\187\127\005\030g\214\026\247\144\224\189\251\201\029'\221\177\1478v$\209\252\222(\t\1509\186\192!E)\234_?\005\212\185\238:\160\191\167oe-\007\220\187\000\2129ujW\213A\001\250\227q\187\127\252\169}x\252\181y\220\239\174\014\213\244o\227W?\180\247\247\205\195c\245C\251\237e\191\187\249\250X\253\175\171\255]\141W\203\217\255\233\254]\244\255\174\186\127W\163\254\223I\255\239\162zs\221^6\213\031/\135\199\230\254P\253\252p\213\238\191\181\251\237cs\253\183\170zswW}\234\174v\168>5\135f\255\148P\189\213\190\217>\238\218\135\234m*\253\247\234\236\235\177\250u\251RU\227j\\\255}6\255\251l\214\223A\202\159?\236\254<6?\191\173\166\147\209\\\225\139_\143\135\237MSM\023\139zQ\205\150\139Y\253\170\179\238\183\237}S\157\237\238\155\195\235\159\031\183w\187\171W?\029\239\238\020\173\024\221\222\239\238^\020\127\181nz\251\127m\174w\199\251W\185\212\155\135\155\187\166z=\158\253m\246\234\231\195O\187\191\154\235\223w\143W_\171/\219\187C\243\234\135\175\219\253\246\234\177\217\255\2094\135C5\027\189\186h\246\135\174\200hT\255m\148J\253\214>\238\174\154\255\129\022\203\238\218\029\170m\245\184\223^7\247\219\253m\213~\169~\217=\180\143/\223\154\215\255n\210Yo\254Um\031\174\255o\187\175v\233\228\195\241\242\176\187\222m\247\187\230\240\183W?\166\155\\\239\030n\254\184\250\218$?\2475\248\2271\021\223\238\175\153{\245\195\246\219\191\179\235\231\179\201\171\207t<\157\142_\1899\\u\030\221W\243\229\228\213\219\134\127u\206|\245\199\227\245\191\215\213\164\238\014.\214\213b\158\014R|w-\194\241=\025\207^\253\144\138T\255\168\214\159\171z6J\007\191U\135o\219\228\189\127T\255\172F\244\223?\186R\147\\j\210\031\252V5\127]\221m\239\251b\147\212|\227q5\025\213\213|\190\200\165\167\185\244\180\206\215\252\243\216&7^\222\245\229\199\211i\"\198)\\\187\019\230\249\132Y>a6\202'<\028\239/\187f\189y\232O\169S-f\211Q5_P\241\185/~\221\222\221m\247\1856\227\234\245rUMS\131.\210q_z\145K/\169\238\223\154\253U\215C\186\226\139\174\242\147\244?s\241e.\190X,\251\226\219\251t\194!5J>a\158NXV\139z\162\149_y\223\244\214\230\208\235\237\157u\182\206\171\186\187\007\1572\029\249S\190m\247\205\195]\243%\1591\173\187{\140\187\006Jg\172\242\025\227\224\012s\147\190Z\163\170N\182\203)\181\247\210\246\208U\235p\155O\168\151\169\201g\201Q\218\nSj\228\249b\150\239qw<\244\133\151\243\174\001R\253g#*9\245As\149Dg\219\023}=M\021\169W\21385i\234\208\185\244\204\215\253\235\203\183\175Mn\217i*\153jP/\235\1906}\233\185\191v\242\254\174\205\206OB\214\133\21885\209x\148\003sJ\141[Sk\029\238\182\135\175\185&\243Y\223T\147T{\177p\233]\242\159f\223\230\176I._\244Q\195a0]\249\162\237C\1955\030\165\246[I\193\217\200\023||n\201\195]\193Y\173\005\199P\240\235\190i(D\250\187\167\nKYh\187/\2371\199\247\184\187\232\194\220}\002\005wO\238\154\171\177\024?\155\250\162\135\221_\217\246QWr\150\186\228|I%\161;\030\154'j\175\020\025\175\151\233\166\011\189*\244\197Fb2_w\186\154he\023\208\205w\228\212\212\155^\143\0239\024\185\236\210\007\205U{\215\230:$\135wQP\207\199\157\n\230\194\208\005\015\205\253NO\232\195&\197\164=c>\242\177~\215\141&}\172O{\011SMf\227i.:\246E\155?\143\219;\238\023\227:\247\140\t\185n^\251\1947\221h\222\236\135.\r\173\151\006\242C?\222\245-\216\005e\138\162\233\162\235\162t\002\181\225\138\148uK\221?\197y\023\235\203\145\198\250\156\026q>\030\247E\223\228^1\235\"h\150\1743\159/s\185\185/\247\207\\n\217\021[.\187A'\023\163\182\2355>\021\251\161/6\207r8\239e\135\238\203\250Y\215}\193\183z\189E2S\174\183\242\183\2531\023\235j7O\227\007\023[\140|\177\159\178'\187RIV\164\212\216\223\243_9Pj\210j\149\184E\237\011\254\219T.\025&\215\131\225\238g-6Y\154\202\2418\215\235\225o\213;\018\158\254\182}\215\227\1303\239\188\247\1853uw\237*\199\165\184+\245}\234\183\234\023\211\018)\194\165\024\140g\191\146\231\186r\203Ts)\183\2447\253-\151\171\187\2383\171\186Y\161\148\\y\175|\200m;\202m\187\210\182]Bk\252^\241Da>\210\214XBk|\204\173\209\r\181I\231\221\245j\127\189Od\202\004\130o\t\253\228\143\028\245\139\190\130\179\209Rf\030\203\169w\225\025\223\186\139*u\205r\230kx\158\1757\162\128\153\027[\160w\\Tf\0220\183U\132VY\231\130\227\190\224\170\235\151\\p\233\175\248\153\154\165\175\227\204\220y\229M\217\228\011.\193\148\213\200\023\251/\142\193\174M\244\174+\158?\244\151\253\173\186L\019\243\219\230Q\230\028uW\209Tv\210\015\024t\014O\ril\189L\167\152\241u\154m\155\140\181=W\147\240.f\158R\211m\186@\224\219\200l17\198\246p\181\219]\237\246W\199{\n\175I\154HLM/^\193\248t\236\230\189\1354a\231\137k\146\205Y\207\190^\228I\197j^\149s41~\188\200S\180\201X\167h+\024\171\182\026r\169p\n\000\030IV0\167\184\212\017\173+8\233f\231\185\224\202\171\197U\197\163dW0U\152\175\216\207m\220\252\182\226\017=\245\140Y\215q\233\146\253\012\203^3;\160\155\004w\215\236\006\015\185&4\230\023\234ji\002\149$!\141\189u\210\181\158\251\165\218\165iD\127pW}\185\163\211\161\007\222\144\014\167s\231\253\b\1657\130iF\142\150\020$\175\211\180|\1774u\159\249\026\237*\154_\229\209\189\147\217)\149\156\251\146\255\143\234\158\170\220\215\189^\204M\225\133w\t\205w\167\217%\243\177\169\192\210_6\015\234\211\236\188\186\155dII\016\200{\t\230U\026\161\166j\252\024Z\238An\222\025o\011\194d0\207\025i\130;Mc\168\150\132\169\224\183l|7\019\171\147\011\167i \213\1788\159\200W\237\139\166b\201\028-:\245]5OQ\210\152:\242q3\158\249ry\150\212\1757R7\158w\253\160\166\146\208J4\011\204&\213\169\007\206\166s*\t}\235X\201\178\167\2352\166'\140\151\1901\159T\172\146\139\234\185)\185\242\163\221\179\2143\197\220\2128\180\030\249k\254E\002L\190O\029B\139B\247z\161\162S\138{[\129\186\246\142\250\015\149M\003xZ\202\165\145sZ/\169$\181\210\148\021#\169\164\138\209\1723.\141\241\211Q\215\207\023t\n/\184hZyI\203\221\174\019\229\228I\146\176\005\135k=\011n\160\"\252z\145\2390\153\174\204\029x\2421\029\171\n?\238\238\174i\2173\170\198\233\242\179$#\147\154n3\1351%'\005\174\219g\154\167\175r\132N\234\186\215\193|\014D\179\174\196\187J\165\021h\167%\179\249\136JC\1573M\233\172\201D\151y\2279\140%/\141,\026\186\017T\007\218\241\028V:_\238\218\253\238AzX7\183\153\245mF\253a\014Q~h\180.\179nxH\190\232\245h\206U\129\145\228\234\184O\139\252+\014\186\186;k\214\253oEm\198s\232z<\213Q\237\176\235\147r\188\130\232R-\245\212\220e\001\019\006N\206\232h\216u\234\201\188_\164\232Y\160W7\199]:\227\190\213\025D7\170w]'\245\222\017y\140g\219<\234v'\245\213\179\193\158N\170S\015\209\147&\003'i\000\167\137}\127Vm\206\130Q\231\203\142\199\1831\141o\203N\249\169\175.f\216\148\174\2444\213k\169\r\185\128\134Li6M2\164\145--\158S\152\215S\174\n4\227\245\246\230\166\225\238\218O\179:)^\026\223\174\162\0198_V\215\2121\204R~\204\019q\159$\233:S\179o(S5\234\242\154UN$Q\255\224\249\246\172\150,\210\246f\191\253\150\141\153uQ\220%\182\198:o\028\243\212{Bw\186L\217\226\230Q4a\149\175\222\197q.>\173\202\137V\223|\151\219\003I\t\167\136\210\1659E4\230\0259F\165\1565\163E\252t43g\205\227\179\202\236\219\212\172:\198\203\197@0\155\016\155\229h^h\136\241\196}\201rww\183\251v\216\029\180zI\130S\159\230\212\212\152g\240\t\144Vz\252\218\030%\153\216\203\198*'\190\023\148Z\027\175\160\167qN@t\181^\146\174v\179\132\005yb\133\189f\191\229DP\151kMS\249\201x,i\132\241\n\154i{u|\164\226\221H\149\232\206l-\014\025\188<;\255r\215\228\177sEwXv\249J\174\016\204\184u(\233\252\211\169\246\180\155\200\214|\135\133/~\191\189\218\147V\166\150\155uB\150\234?\227\017n\005\217\161\203}\195\230R\030i\218\245\224\025\181\196\n\242C\215\237\227\246J\134\158N\030fi\1340\233\214\1764G\169G\144\162\189\222\165\158\197\173=\1663\166\238\012P\187\189\012T\148g\157t\171\187\213\152JC\131]\165\231*)\139\157U\165[\020\244\163\250\178\166\004|=\194$\234\241\225f\187?\222\223m\143\217\138\213$\183[\159\238\156\210I\208\b\237MJc\222\146\209y@\236*2\229{@#\\m\185\r8\136\186\025\0157q=\194\014q\143\186\184L\021b]\172yV\194\197\223P\202\167\031iWc\205\150\212\181$us\183n\247\215_RFO\210\133\211N\248\211r\205$Wk~\142!\201\019\179R\197\012J\205\1433$\225\161\133\251\172G\215\172)fz\186/\207i7\154\007~\200U\239\214*iq?\215q\178\230'\025\189\228\230\170\223\167\169\212\241\142\235>_\228\186\207M\2219\185\207s\215\173\201\138&\183\164\230\225Yf=\133E\211u7\002\031\014~\2374\153\153\019p\145\163\166\210Jg\146\166\251\188\210\169\139\180\183\022\239t\167K\235w+\142\025\173\182j\206~s\213\219F\163\171\238\251\134\212\004\243\223i\140KO\002\147Z\031h\240\157/i\168\238S\198\249!\198kx\238\241\179\235\135}\203NS\157\150\227\165+.\235a\0216^\020wq@\253\2275\212hkd$\235y7\223e\021\193\210\199\162\011\210\nf\182\028\021\183\144\ni\159\226\n\245\169\144\177\191\005\231|\156\181\146\251Ak9\217|\189{\218\145\200.\231\185*\171\172\181\225\197\2137ze\nI\1852'\143A\2415\141\188\164\153}\225K3\164\208\202j\185(\220\"\t8\184\190M\197\225\029d1\166w\208\021Y\208\186\178r\237\159R\025\221\239\022\135\157\202\218Ul\217^\190b\220h\253\140z\028\219\162\194o\173XN\226\2100\176\1523\160\149\197\179F\197{\215v\025\000\147\144*\238`Z\194\185u\030\135\181\185|\031\208\253\229\023\197\229%q\239{$'\240\177\246\2428 \141\235\244\212\162x&\192e\221cE\211`K\026\021S\160\190\134N\185\152\243)\252\216_\020.\153kR\148E\245\205LC*\191X\205\194h\1842\189w4\220{\185\1614\0164m\200\019\128\215\160\249\191\161\1779Q\159\250\140\205\212\139\135X\205\181mY\205W\195M\1875\179BS#TC\206\157c\141f\180Q\195\166\159\209\140\031\180B\252lh5\026\174\144\153\021\146\224v\003^=\029\13647m\027\0125\237\240:\127\201\249\170\233lZ\180\150\15063\176S\210 \249J\227{\218\003\209M\240P\248\023\185\242w\237\127\154\135\027^\151\247\143\134\187\tFl\233'\173\185>\012A\029\148\135]E;\213\185\242\246\193W\209\203A\215L\242m0\156Q\163m\b\197\218\240\198v.\0252\176wI\nR\173\206y\200I\217Z\218\019Mk\241t\217&\2091\154\255\011\130\135\031\144\020c)U\253\236k\187\207u\025\245\213^\021!/\147Gc\164yf\134VJ\219\154a\203\180m\220L\127\192(\186\236\159v\021\165\201)\215&\224\243\195\130\249L\019\238\197\184`\234m\007\006\172\184\132\140\200\153\r\022\144\179\137\221\220p8\246y\tJ-ORR?-\178&\186y\161\240\164\234\147q\228\224\156DK\219\233\200@a\157\218\153\194\243:\156G\221\031\239\030w\223\238r\226-MF\147\215\187\\\211j\017\251\197\232\000;fqBU\165\141\228\177d1\195\161uOJ\207<\238\182w\215\187/_$\004&\203\172\028\227Q<)\242\163\177\204\139\186\249\202h\030\143?>\154\164I49\151\153\158\029\129\2314_\178\027\129\138\185*\206Sj\154\167\216G\173\1978bf\220\228\198\254\025K<+h\204\218\165\023\129n\237b\158f\022C\160]J\229!p\234\182\127\020\195\136i\167\239\1439^\139\181\252P\178Bc\209<\193\031Z\206\254\199\202v\255\1441\138GQm\187\170[e\207\216g\236\197Pl\230\241\195C\177D\187\150\174\135\023\251\162\238v\2261\2207dbn\196\151\166\241\167\012uN\151\137y]\140\004b)\012N\206\220\129\153\147YG\157XQ\207\199\180\228m\238\030\169\155\244\2215o\028\138<\243(\147N\247|\127\176s<\183n\138\149D\179^tC\241tx\138\229\220cm\029\2006\220\231\135\2439%=\202;\171\249Iv\225{\245\011\167\"\187\221rC\018Y\228\207(vf\1712\127&zm\226\2485\245p\187_\016or\173\233\006\222?\179\168\203)\241\204\204Z\147V\238\147ff\015\2459\216$\132\233\017\210|h\142\238\022\142\139\172ivS\0266\219\157Y\231\140\141\166\197:\251\030esaVw\179x8\249\005&\t]\242\027\163s\181$\155\229\221\005\154\012\213\233\161\215jV\230\028t\174\229\198d+U\208\197d\0207\131\172\140\224\139\129\178v\201\216Op\146\143\134\214R\191\152\1610oX\157\151\203\180\153l\224\254\186\189\203\019\233\2014\183\234\180\\\139\240\200\217e\213\255\027\195\166\0043\168\136\217\2013\180\158~0\201\015\154T\206\139\220\135HN\209YN+\015\245\022\187\214\028\152\221H\179\026\199\203\004zQ\206X8{\175\2438\222\005\214I>\166\229\212\249\212\173*Y3|\175Wm\221\024\145\214`\245hp\193\240G\145\219=\209\015E\011\011\159\158\024\234x/\205u\026\165y\219\254\168K\183u\225\188\0244\163\213\208w!1\029\152S\137\209fg\245\144\209G#\1836}\003\t\168\025=\142L\139\170+\014\2314s\204/',\230CiZ\223\179\186\153`\177$\145\188\r\166.'\148\143\t\166^\178\236\209\232w\203\158\201\128\031\181\184L\167\231\131\153\194OE\141\198]\196-\023nWq\161\154\197Y\148p\182\207\014\139I\158\177\131fx\243\194\n)lG\175\025\r_\221\t\243y\156\133z#9\0233}\028\200\231|\208\154\2168\158\196\139\153\255\192\202J\247\169\205\135\150J6)9\176\128\023\021\183\134.\179\157v\231<\138\207m\209\127\167\185\189\236\134\205\"Mc\151\1825\189\136Q/\007\198\021\204A\244cK=\027\236]\015F\128zy\158\245\187\131\199\225\204\231\177X\219\208\210\198l{\196\234\223\1817]\135|h\031\217\134nG\170}\153\164\232\004n\242V\015\167ED!\252d\152E\"8\129F\189T\025\029\244\186\253\173\245\170\127\219g6\141\199\176\155\232\017\r\237\b^\012T\170\161\021\166\212\191\156\143I\144\218\220\b\173q\166\195\003\234`\016\153\157\1838\025KaZ\164)\0234q\029\202\128\217\004O~\206:1\155S\176Z?\030\233%3}\161\242\199\135k\243&f~5\243}\179\127x\187}\220\234\175\223\183\1874\011\173'\245\248\213\251\223?Wo\170\031\186i8\031\231\161\221\000\217W\022\160y\169B\255J\1993>\206\003\184\001\172\251\020\254P\189\158\242\249\180*4\128\233U\006\149\1763X\030\172\012\224F_\131\147w\r\146\247 \024 +\157\002\031\205\241Y\170\251\130\143\217'\n8\027\025>\239\158'\2421\217\168\128\181QQ\181Q1\178Q\001o\163\226l\163\"$\152\006\233\165_\127_tS&n\148u\018$>\222\164Br\204\149\023\192T\1471\243\130\170\186\224\216u\\>\166\171(`]\160\168^[1r\129\002\222\005\138\179\011\020a\023(\146] \191\159\140\017\207\230\248\197\030\163\007^J\015\228\"\1667\017\000]\138P\232W\140b\231\202\184\233a\004@7#4\236k\1533\029\142\000\232u\132F]\143\168\178\255\017\001\157\144\208\184'\018\137\221\145`\232\147\132B\199\204\232G\004L\023%\000\250)\163Qg\205\156\233\177\004@\183%4\234\187D\149\029\152\b\232\197\132\198]\153H\236\207\004c\167&\216\247\236\012\218\238\157\017\211\1993\176\193\b\198\222N\232P\192G\253>3\166\243\019\000\n@h$\003D\149Z@\004\b\002\161\177*\016\137\210@0\234\003\193^$2\248\132\182?#\240R\000\1613\003\245\200\029\218\168\007\001\160\030\132\130z0\138\234\145q\163\030\004\128z\016\026\170G\230\140z\016\000\234Ah\164\030D\149\234A\004\168\007\161\177z\016\137\234A0\168\007\161\160\030\025\253\136\128Q\015\002@=\024\141\212#sF=\b\000\245 4R\015\162J\245 \002\212\131\208X=\136D\245 \024\213\131`\175\030\025\180\234\145\017\163\030\025\216`\004\163z\016:\020\240\145zd\198\168\007\001\160\030\132F\234AT\169\030D\128z\016\026\171\007\145\168\030\004\163z\016\236\213#\131Oh\2513\002/\005\016:3P\015\227\004#!\022\005\029\177\020\136\137\163PQ\012id\197\162\160-\150\n\005\198\0200*cQ\144\026KEzc\249Rt,\011\202c\169X~l\t\212 \203\129\016Y\n\212\200P\031C\212\232\146EA\156\028\021)\148)`d\202\162\160U\150\138\004\203\242\165jY\022\164\203R\177~\217\018(b\150C%\179\156\1513\195XM3\176\0176\131n\194\030\134\018g\169\147]3\018;C\027\197\179(\200\158\165\"\237\179|)\128\150\005\021\180T,\133\182\004\234\161\229P\020-\231\149\2090O\161\203\158C\244%F\135\219%\144LA\140`*\006r\169\004\136\165!P*\1332B\169\024\200\164\018\161H\nm$R1\016H%\"yT\182\020G\229@\026\149\136\133Qy\148Ee@\020\149\000I\020\226c\128\0259T\012\196\208\016\145\020\nm\132P1\144A%\"\017T\182\148@\229@\000\149\136\229Oy\020?eP\250\148\241\194'\184\149=\001\141\232\t\182\tz\b\n\158\018'\186U$vB\026\169S\012\132N\137H\230\148-EN9\1448%b\129S\030\229M\025\0207e\188\180\t\254\0208\2319\192^\"l\200\243\129\160e[\141\154\017\000RF(\232\024\163(b\0257\nF\000\200\023\161\161ve\206\b\023\001\160Z\132F\146ET\169WD\128X\017\026+\021\145(S\004\131F\017\n\002\149\209\143\b\024i\"\000t\137\209H\1482g\020\137\000\144#B#-\"\170\020\"\"@\133\b\141%\136H\212\031\130Q|\b\246\202\147A+;\0251\154\147\129\rF0\170\r\161C\001\031\233Lf\140\200\016\000\nCh$/D\149\218B\004\b\011\161\177\170\016\137\146B0\234\t\193^L2\248\132\182?#\240R\000\1613\003\245\160\218\025\249`\004\244\131a\016\016\129QA\1360\018\194\bh\b\195\161\136\016iT\132\017\144\017\134#\029a\174\020\018f@I\024\142\165\132Y\212\018\198AL\024\0065!\248c\129\024=a\004\004E\224HQ\1364\146\194\bh\n\195\145\1680W\170\n3 +\012\199\186\194,\n\011\227\168,\140{i!\212j\011AF\\\b\217\020\017\142\242\194\240`\151\136\004\134(\1630\140\128\1960\028i\012s\165\2000\003*\195p,3\204\162\2060\142B\195\184W\026B\159\n7<\023\200K\137\196\190\r\228\134*c\228\134\017\144\027\134An\004F\185!\194\200\r# 7\012\135rC\164\145\027F@n\024\142\228\134\185Rn\152\001\185a8\150\027fQn\024\007\185a\024\228\134\224\143\005b\228\134\017\144\027\129#\185!\210\200\r# 7\012Gr\195\\)7\204\128\2200\028\203\r\179(7\140\163\2200\238\229\134P+7\004\025\185!dSD8\202\r\195\131]\"\146\027\162\140\2200\002r\195p$7\204\149r\195\012\200\r\195\177\2200\139r\1958\202\r\227^n\b}*\220\240\\ /%\018\2516\144\155\254\166Fl\242o\144\154\012\130\208\016\1362\211\195Fd\242o\144\152\012\134\002\211SF^\242o\016\151\012F\210\146\153RX2\014\178\146\193XT2\135\146\146Q\016\148\012\130\156\244\224G\248m\164$\255\006!!0\146\145\1582\"\146\127\131\132d0\018\144\204\148\242\145q\016\143\012\198\210\1459\020\142\140\162ld\212\139F\255\203JF\015\024\193\232\127o BQ,28\016\206\145P\244\132\145\137\252\027D\"\131\145Dd\166\020\136\140\131\161\237\207\b\188\020@\232\204R=\254Y\189Iw\147cv\148\000\212\223\021pN\019\212\248K0v\149\000\226\bA\196\007\130\144\249\242\155\186\160\000\231]`\2411\213V\001[9E\181r\138Q\229\020\240M\1688WZ\017\174\180\"\185\210\244\251m\231Q\210\192\183\226Q\005\188\130\190\245\030UT+\173\024UZ\001\174\156\"\\9Er\229\2447yT\128\011\209\179\183]'\149\227\141=\246\154\253\214\246J\198\178\232\025\219\t\000\007\016\n^ 4r\005Q\165?\136\000\167\016\138\158!\024\221C\176\247\017\129\224\168\140^\160\193k\0046\005\000\206#4\240`\255\022\166\245`\006\208\131\025E\015f4\244`\166\002\015f\002=\152\209\194\131\025.<\152a\240`\006\209\131=z\129\006\175\017\216\020\000z0\163\133\007\127\234\1567\030\207\248\007\235\131\"\2284\1318\201P\216h\134\130,\026\138\136:($\242\160\016\233\131\002\228\024E\182\221\187\204|L\213V\128j\173\128\173\180\162Zg\197\168\202\np\141\021\225\n+\146\235\171\191\169\186\002\228\191d\212}\231\144\000K6X}\250\154\159\005\162\2347A\245\205[\180\006D\155\154\194\166\166\176i\151\130D\1429\156\004p\147OAM|\t\198SN\001dB)\b\223[\144V'C?\241W\000,\226G-\129\237\176%\160\140[\130\224\192%\132\142\\\002\2094\215 \028\137\130\208_\1462\141\187\151\201\194O\252u\015\003P\227\026\192Ns\t~\215uL\234\164\239\164_*@\001\174@\176\026xg;\165b~\r\240N\187\164\"\210 \130\228\000\215\223~\162\255\174\235\142\019\174\249\214\203\239;\233\142\n\004\162\251\206vG\197\188\212\190\211\238\168\b\b\236;\238\142\250\219\203\234;\238\1425\255n\236\177\159\209\189\147\222h\128rF\247\206\246F\131ioT\208O\243\222ioT\004\166y\239\186\030\161\199X\1956\172P\027T\168\197{CgP\188\168\019w\005\005\252L\243\157t\004\001\142\198\229G\012\138c\024\003\199 \006\142\024\003\176zP\188\136\141c\017\027G\023\027\239\187\2136-\196\222\203B[\129`\249\248\222.\175\021\243\139\198\247\184\168V\028\150\138\239e)\173\0009V\128\198\212\183\241~|/\225i\128\210\177\239mx\026L\195SA\239\237\247\026\158\138\128W\223w\2259\229\218\182^\172\222\251\240T\180\208\166\247\018\158\n\132\169\137\247\026\158\138\248\132\196{\tO\001\142\246\024\235x\012\235x\012\234x\196:\030\007\234x,\234x\004]}\207\209(\191_\2361\214\241\165\172\141\029:L$;\024\130\218qQ|\187\002e\168;\026\162\222qq\007pE\176/8\018\186\133\227\160\135X\206\132\174\131\161\2238\014\186\144\231\130\222\228\n\148\029\203\211e\031sH\"\003\140\246\185$2\128h\159\233>o\006`\180\213rh\177\229B\187m\129\192zK\163\015,Wx\194\146\133?,\t^\177\020\248&\255|S\000\224\015B\193\019\132F> \170\180\158\b\176\155P\180\152`\180\149`o%\129\222\190\015\157i\164\135\031\196*\005\200 \005\220jF\208\226\t\222\007\177@\001Y\137\b\"\207n\005\161\199\182\242\155\023!\012\156\201\\\233\131\012\006\006\176\227\128\192\023\178\136\249\208\171?\031\1276e6\006\223\248\213\220\007\247\180\1510\145<\174\153\151<@\193\139\129\228\001U\250\211K\030\160\232Y\144<\128\189\143\189\228y\212x\219\207\226\016\141\252\174\1798\007\172\017\248\140\167l\176\0046H1\173c\194x\2124\141E\161},\005\141d\169\168\165,_6\151e\161\205,\133\rg9l=\203\249&\180\012\180\163\127\201yZ\250\t[t\240%\231\160\192E\232\249u\136~\014\175\176\t\203b{\015\188\251K\172 \166\201\021\131\006W\002\154[\137\168\177\149-\155Z9hh%\176\153\149\193FV\1987\177\226\208\192\246\165\205)z\004\027w\224\165\205\130\190\b\188\187\014\176\207\193\185\155\160\0286h\248n#q\217\137\166-\t\128\134$\020Z\145\208\168\t\137*\219\143\bh[#\240\025O\217`\tl\149r7o&~\239\026d%\199t\150\002\212\012\n\216\022PT\175\171\024\249]\001v\185\"\236mE\178\163\2457\249X\128m\245z)\199T[\005\168\182\n\216\218*\170\181U\140j\171\000\215V\017\174\173\"\185\182\250\155j+\000\236\212\250\189\178d\131\213\231'\135\006\136\170\223\004\213\183\015\006\021D\155\154\194\166\166\176\169\181\199X\1956\172P\027T\168\197{\195S;\197\139:\241\2439\005\208\173\184I\234\163\217\151\252\017\247%\127\012\247%\127\012\246%\127\196}\201\031\007\246%\127,\246%\127,\246%\127\132}\201\159\204\171\024\159\240-\140O\225\011\024\159\130w/>\225k\023\159\006\222\184\248T\188l\241\t\223\179\248\132\175X|\234\252\168\199X\199\243\176\142\231A\029\207\177\142\231\003ud\208yh\208\249)\131\206c\131\138V&\2167\181$\214|\147\173\017\216\020\0004\127\145Gc\"+\174\137\001\002\192e\132F.#\170t\025\017\2242Bc\151\017\137.#\024b\128P\136\129\140\158\023@h\208\249\176A\231C\006\157\135\006\157\1592\232<6\168\136\001\130}\012\200\190\127\223dk\0046\005\0001P\236\251\023\194o{\146\027\007\219\158B.tb\188\237)\164\209\161\195\219\158\194\"\133s\131mO!\135\145c\184\243\001\248\132\027\206\191\231\134\243\211n8?\225\134\243\239\187\225\252\148\027\202H\179$\196\155\223\129\016\005\201:\1347\0030\198a\188\003\129\232\179~\1294\226c?\139?\211e\145\000\193\166\1873\183\024\018\204o\175;3K A\224\021\1953Y\248\200o\191W\238\172\2350R\243\015\222\2103\2235\020\r\140\230N\160\000L\188\004\151\137\151 \188\171^\000\222T\207@\154\129\175j>\230\021\142\000\188\194\017\192\173p\0045+\028\193x\133#\128\172p\004\145\021\142 \180\194\145\223\188\194a\224\170\1893\235\2103^C,\166\244\219\150m\208\026^B\024\192\198\135\160&>\020\211%\132\158\206A#\128\004\141 \133\137__\190}m\030L\149w\198\156\157_\238\159\233\011\027\130\180\230Z-Z\216\134\205\211\006\205\211b\243\192\018D\241\162\217x\t\162\000\182\018/A\196\198\1891`\1436\194k\026g\241k\026g\213\161\185\223Q\251\207\025;\026\254\136\023>\006\t\1453\187\171P1\159\0069\195\253\131\138Cf\228Lw\n*\226\242!g\221\011\177\226\136\023{L\245U\192\236\000\"L\246\156\176\166\248='\128\130\254\005{N\128*\149\208\2399\001\0205\017\246\156\000\236\213\209\2399\241\168\209I?\197\0044R\204b\138\t\004hg8\197\004\018U\212O1\001\005=\205\168\017U\002\160\167\018\n\242Jh\212\137\137*{2\017\208\157\t\197\190K0\138\018\193^|\t\132\190\157Q\144a\006\157\022g\1768\181\t=\129\210\204h\160\207D\149\"\205D\169\212\196\128\\\019\138\154Mp\236#T\239\140\238\208\021\168\227\132\162Td\184\197\155\180\161\139\218\225\176h\135\194\162\r\195b@\234\137\140c\006E\159\2080:P\2543\186G\187\247\161\147p4`4\026\0182\023\140\011\1538b\201cx\199p\152 \170\028+\136\128\001\131\208x\212 \018\135\014\130\227\160\128A$\131\207\232\211\151\002\1281\133\208``\241\155\253D\143\131\205~!\135C\205\208f\191\176@0\236\004\155\253B\174\024\130\162\205~!\t\195Q\176\217/\226\236\208\020\172yC.\028\166\2265oH\227\1445\188\230\r\139\020\195W\176\230\r9\028\202\012g\0074\011\163RY\014\0077\203\133Zf\011\004\138fi\2125\203\021\002f\201B\214-\t\003\160\165P\232\012\135\131\161\163\252\144h_*\138/\214\156\240h1H:.\026*\227\151\167b:\0246\131\151\167\194s\139!4zy*\186j1\156\026n\023\187\180\024Z-Wh\169}{)\174B{\194\225\237\247\194\180=\029\166\237\1370\029\026\132m\145S\145\\\012\200\150;\017\173\197\224l\184}\236\185\253\t\151\023\195\181\227\194A\219\128\209\208m\232c|\214\241D}\226\193\220\022\b\134tK\227\192n\185\129\225\221\022)\006yK\158\nO\028\240\r\245\028\183\214\203\000\140S\128\129Wl2}n\190~p\142_?8\199\175\031\156W\209\215\015\206\131\175\031\156\227\215\015\206\139\175\031\156\023_?8\135\175\031\156\227\215\015\206\225{\002\231\248&\252\185\236\200\2303\252\142l@\193\186`G6P\165\157~G6\160h1\236\200\006\216\219\238wd{\020\188\144At\133\223\006\205\023\b\182AG\020xfh\027t\196\151>\n\182AG\020z+\218\006\029q\222o\1936\232\128\002\015\026\006\221h7\022\243\133\138\141\197%\001\014\1407\022\151l\233\188bcqI\160\227\202\141\197%\227\157Vl,.\bp\152\224\232.\217\184\203W\240\027w\001\005/\005\027w\129*\253\2277\238\002\138\158\129\141\187\000{\159\248\141\187\030\005od\016]\129\187e\249\018\225n\217\152\004\255\012\239\150\141K\148\222\nw\203\198$\250.\222-\027\179\222\147\225n\217\144\004\191:\014\221\171;N\249R\176\227\020apf\180\227\020\185\210\129\176\227\020at\026\2388E\220;\nv\156\002\012\206!\020\221Bw2na\004\220\1940\184\133\225\200-\204\149na\006\220\1940\186\133qt\011\227\222-\140\130[\b\006\183\016\138n\233\175h\156\146\127\131K2\b\014\201`\228\142\204\148\206\2008\184\"\131\232\136\140\162\0272\234\157\1441pA\015\130\003z\012\204\191\232L\159\143\248\152\204V\128LV\192\154\171\168\154\170\024\153\169\000\155\168\b\155\167H6M\127\147Y\002|\144\151\160/$\215\162\128\251P\136\160\197\251\211\023\146JQ\000\190g$\184|\255C\016Z_)\192\159\182b\160\219\1878\030\243\015N\b)\"\223\243\019\196\127\207O`\147\014RP\190\231'\136~\207O \253\158\159@\252=?\001\228{~\140\248\005\215\133\236\195\172W\004\184\210Ma\024\167!,\018\026f\191\154\167\152\230\025LI\254l\158\000\242\217P\219\224S\180M\248\232l\019\248\218\244O\187f|\204c\152\000n\b\019\212\140`\130\241\000&\000\140_\130\203\240%\b\143^\002\240\224\197\128\246\238\r\234\211\006\245i\019\234\211&\208\167\r\234\211\166\208\167M\161O\027\208\167\r\234\211\006\244i\003\250\180\169l\217\006\173\001}\218\132\250\180\t\244i\019\233\211\006\245iS\232\211\166\208\167\r>\163\217\152Y\214\006gY\155p\150\181\tfY\027\156em\138Y\214\166\152em\140\216mP\2366\161\216m\002\177\219\160\216m\006\196nS\136\221\006\197n\131b\183A\177\219\004b\183\233\196N\248#\026r\012\r9\006\134\028\209\144\227\128!\199\194\144c\209\210G\031\204\146Jgy\240\169t@A\202\130T:P\165\168\249T:\160(o\144J\007\216\011\157O\165{\212H\158\127\197\005\208H\252\138W\\\128\000\025\012_q\001\018\005\209\191\226\002(HcF\183\216\130(\146\132\130R\018\026E\030Qe\248\017\0011H(\006\028\193\024u\004G\161\135b\202\207>\\Or\015D|\201\226\212&\244\004\170,\163\131\158\b\244\150\137Rt\137\001\229%\020\229\151\224\216G(\196\025\221\021\000H2\161\145.\019U\1383\017\160\208\132\162L\019\140Z\157\225\022\173h\1956h\135\189\221\014\197]\027\198\221\128\146\019\025\007%j:\161a\248\161\186g4\144\248L\028\177\2281\180\2558l\255q\200\254ch\255\241\148\253\199\216\254c\028p0\030\184/\236\140\016\131Q\161\252\194NADcC\248\133\157\130\131\017\"\248\194N\193\2248Q|a\167\192a\180\016\194\012\024\138\193\152\161D4l([\142\028\202\193\224\161D<~(\143C\13620\138(\001\003\137\016\219\160\245q8Q\002F\020%\162\224V\182\140o\229 \196\149\192@V\006cY\153\129p\198a\198<\242t\029\026\031\133\022\229\163k4C\222\194Q\199\016\167\188\021\140=\134+\135\031%a\004R\002\007!e\006]\137C\145\016\187\b\131\001I\137hLR\182\028\150\148\131\145I\t\028\156\148\193\241I\15260\176\029j\182\246d\235\180'b\185\029\138\229\129\017K\249\193X\199qK\137\161\144\198\209K\136`\000\019\238\024\148?\0149\232x\210A\199\019\014:\0149\232\248\029\007\029\007\029t\028\140`?\182m+\253\022A:\230'7\002\184\141l\012g\015\220\020\000\156Mhx\137\\\244\166\000\224\018\132\134\1510\238\190\137Q\184\152\165\194+\138\143n\"\012\174\166Dx\173\220\1647\005\000W!4\188\0045\238M\137\192E\024\014\175B\129pS\"p\021\134\195\171\244As\131\191\225\n\025\012\207\207\221\242\166\000\224\n\132F\151\184\148.\253\215\024Q\192\221Z`y\1807#\224\201\028?\155c\141\007\251\161\251\226\027\247\209\231\237\027\183\232\030;\208\212\217\235!\160a\237\253\018\139\171\154\209'\004\158\0170\022e\224\005k\140\182\017Z\026\232\222h\027;\208\024H\000\024Hhh\160\127A\138\171\159\209'\004\158\0170\006\202\251?\190\198h`\249\254\015\019\197V\200q\201XS\203\001%\162b\163\203\205\149b\151RO!\250\028\162\214\017\138\190\132\230\021.1T\233\023\156\228\143\0177>)\006\197\146\b\253Q\204\198\216B!\158\002\2369\192\140\031\004{\t\140A\031(\017x@\022\017\232\002!\172\015\020D'(\019{A\248\194\r\194Bgg\242\197,~`\006\127\131\174\160\211\192\246\0126\005\000^ \020\\\193h\224\015\162J\1670Qz\134\024p\015\161\232#\130\209Q\184L\189\t\151\1697'\150\169\196\161\243\130w%\249\004xW2\132\193\157\209\187\1461\023\184v\224]\201\152.\221\028\189+\025r\232\242\240]\201\136\188\025\128\161\017\028\0236E\2446 5\200\173q\245-\250\247\022\157z\027z\2426p\223m\228\179[t\212m\225\157\219\194%\183\249/\022\2431\214\176\r+\212\006\021j\241\222m\2485\203[\251\183\138\025\145?U\204\128\252\165b\002^\2361\214\241\165\172M\028\236\183'\130\253\246D\176\223~/\216oO\007\251\237w\130\253\246D\176\223\158\n\246\219S\193~\011/\235\134\240\t'\180\2233\180=mh{\194\144\129\216\b_\214\rI\136\152\232e\221\136{\025\128O\184\161\140\174~\170E\243\148\007YK3 kO\001\204\197\012\156k\169@k\004\169E\021jc\233i\251\137\016\029c\250\180\r\211\167\237\137\244i\171\137\001\002\194dh;\156\012m\191\151\012ma\129Jh\144\"m\135R\164\237\233\020i\235\022}\132a\218\180\r\211\166\237\137\180i\171k\t\002\\\b\223\012\225p\007O\1347rE\204\253\138\188m\027\231m\219Sy\219\214,\022\b\201]\233\166\000\224\170\132\134\023\205\156\185&\230e\2190/\219\158\200\203\182\210?\b\160\145u \011hY\160z\236\174\249\242h\142d\235\1909A_\238\177`\242\214\2461b\220\173\202\171\237\163s\248\197\255\128\161\017'b\\F\180\224\2455)\011\210\141\002\230\202} \2221\148\131\r\185`\141f\249o\219\171&\244\131\190\020dAw\185\146\215V\223\247o\005\205\248\216o\011\216\235;A\002\004\251\003\246\238\141 \193\252~\128\189y\031H\016\025Q\005\161\183\129\228\183\127\208\191O\025x\222w\190\231\164\186\001\200\247\006`\151+D\179v\242\228\190\011K!9\026\005\176Wo\240v\r\222\206\255AhA\205bW1\243\167\159\005\228\135\196\002\200\195aA\228/;3rc\143\169\181\020\240q\1920?\r\1759\006\186\191\t\205\030\150?\004-\128{\147PP\181J1~\131P\000\248\212\171\224\242V\161 \252m[\001\248\197A\006d\230/-\247\1671\233`\"\250\224g\027{\233\147\006\224\1840P \146{\217\161\200\001\232w(\002\n\157%\216\161\bT\217m\252\014E@\177\003\193\014E\128}W\242;\020=j:\021\001\016\234\132B\1883\138}\204?l\225\230\202\2325\022\195.';!\001\bk\212\1325\n\187a\177\019\018\137\178C\250\157\144\128b\215\132\157\144\030\190)\000\232\169\209\164\209s\216ge\183\226\2125%\246\222`\183\"Pe?\246\187\021\001\141{4\236V\004\024\250\182\223\173\232\209\162\151g\248Ot\199\001\251(vzB\161\2313\138\221\159\241H\003\228\011\153\220i\252\0232\001\005\r\b\190\144\tT\169\001\254\011\153\128\162\006\192\0232\001\246\026\224\191\144\233Q\163\001\004@\143#\020z\028\163\168\001\254y$7fF\175\177\024j\128|\137\019\128\176FMX\163P\003\138/q\"Qj\128\255\018'\160\168\001\240%N\015\223\020\000h@\244\024\214s\168\001\2429\206\169kJ\212\128\224s\156@\149\026\224?\199\th\172\001\2409N\128A\003\252\2318=Zh@\134\255Dw\028\176\143\162\006\016\n\026\192(j\000\227\161\006\024\208*\129\133Q\015,\135\170`\185P\027l\129@!,\141:a\185B-,Yh\134%A9,\133\250as\226\166\141,\140=\215r\216\127\029W\232J\144\128\15101\220u|J\1614>\143\025\194'\234\222\156\168{\172@q\0303\166\0035\n\242\152!W(S\148\199\140\200\155\001\024\181j0i\031\149(t\203'N\167A \021\0266\1488\r\011\004z\022$NCn@\219\162\196iH\162\206\005\137\211\136+5\207\144\127\198n=\196\250T\168\160\229P\011\029W(\162c\003]\204i\1377\021?\150\165\223\\\001\007\178\004:0\248\242,1F\244\028\238\1915K |A\150P\2097\135\146\1769\204\127H6\131g\248\155]\231A\231\021K]\164F\155\153\223k\201\235\228\223\155\234\245\194\242\252\151E<\168n \252\t\190\209\250\132\031\200|\134\002\207X\224\133\011\208K\226/R\128\001\183\128\243 \022\197\237G\005nN\248\241\225\250}\179\127\248}\187\219\031\248\199\219\237\227\182;\254\169}x\252\181y\220\239\174\014\255\031\004\212\156\151" let times_bold_italic_afm () = "x\001\189}[w\2198\018\230{~\005\031w\207\217\204\234Ni\230)\221\233\204t2\221q\167M)\2187\217\150\019\173e+\163\139m\205\175_\128\168\027>\020\213o{\250L\134\250\n$\129\186|U\000A\250\207\227j\127\252\176{:\254\182>\2387\183\135j\244\183\254\155\159w\143\143\235\167c\245\243\238\199y\191\249\246\253X\253\143\219\255Y\245g\211\241\255\138\255\214\237\191\179\248\239\172\215\254;l\255\173\171ww\187\155u\245\231\249p\\?\030\170_\159nw\251\031\187\253\234\184\190\251[U\189\219n\171/\241j\135\234\203\250\176\222?\007To\181_\175\142\155\221S\245>\180\254{u\253\253T\253\182:WU\191\234\015\255\222\027\253\1897i\239 \237\155\167\205\127N\235_\223W\163ao2\017x\254\219\233\176\250\182\174F\227i=\170\198\147\233l\246&\142\238\247\213\227\186\186\222<\174\015o\127\218m\239~=\174\182\155\2197\031N\219\173J\170(\169X\180z\220l\207*|\179X\183\138\136m\222\1646\239\158\190m\215\213\219\254\248\205\175\135\015\155\215\245\221\213\230x\251\189\186_m\015\2357?\127_\237W\183\199\245\254\207\245\177\250\229\245\184~\186[\223}\217=\174\158\218\254\252\244\211\238\181z;\232\245\194?\253i5\155M\170\217\160_\189iB\179\253v\243\180\190\218\0296\173>\222\246{=\133\175\191on\031\158\214\135C5\238\189\153\175\247\135\216\164\215\027\252\173\023Z\253\190;nn\215\255\031\172\150\212\1819T\171\234\184_\221\173\031W\251\135jw_\253{\243\180;\158\127\172\223\254k\029\206z\247\207j\245t\247\191w\251j\019N>\156n\014\155\187\205j\191Y\031\254\246\230\151p\147\187\205\211\183?o\191\175\131\138\219\030\252y\012\205W\251;\150\189\249y\245\227_I\235\147\201\236\205W:\030M\006o\222\029n\163B\247\213d:|\243~\205\191\130.\2357\127\030\239\254\181\168F\131x0_T\253A?\028\005'\143\022a'\031\006\163\253\\\r\007\213?\170\197\215j0\238\133\131\223\171\195\143UP\223?\170\159\170\030\253\247\143\216j\152Z\r\167\179\182\213\250\245v\187zl\155M\234`\158a5\172{\161#\163\212z\148Z\143\199\227\182\245\127N\187\160\199\155m\219\190?\156T\195\217\180\026\135\255\159L\199\233\1321\157\208K\157x:=\222D\187~{jOy\027n\223\011'\012\171\186G\253\153\228'\220\237\182\219\213>5\030\244Z\127\169F\193\170u\236xl_\167\246\211v \191W?\214\251\219\024*\241\132\225,\182\175\234\217\176\154\204\006\169\24945\175\235i\219|\245\024N8\004\203\180'\140C\251Yh\027\2547\165\2463R\015]\190\029pr\191xB\024\237p2\171\134\189\129\140x\212\203\207\248\177\218\175\159\182\235\251t\194`\026nQ\1353F#=\163\239\156\161\247x\027\154\182\231\012\234\190\1583\200\213\180:\196n\029\030\146\225\198\213`4\011,\161v\024\145\153\199uj\255c{:$\029%\003\212\225J\147\212r\148\187\205m\224\158U\234\200$\234?(\166\031\218\244\135\201#F\227\188\243\223\207?\190\175\147qC\195\201\164\237\245\128\1809\154\228\215\014\186\223\236\146\234\223\206Zg\235\007\133\247\135\212g2\237\128lu\216\174\014\223\169'Q%A\247#\163\247i\174\145\255\174\247\187\228\150\209\141G\225ju\140\167\212v\150\183\221=\173\201\254\193\185\162\007P\187q/ow|\217\145'\214\177\229h\162-\251\208\242\251~\157\174\025\024\180\029\217h\220\211\214`\189\251\221i/\141\1319zCm:\132\166\155g\190n?]wZG\002I\141Gy\227\195\2305Yb\216^y\220\011C\171\169)\004\230a\253Lf\011\157\011]\024\140\245\170\016\146kq\205a\234Am\244PC\188o\158\184\187\1316\024G\245X\027Os\223\185\221mwO\218\225a5\bv\030\141\169\023\016\137\135\245\227FOx;\136Z\158\230\167Lz\185\211ocfi\251\029T\023yj\022\236\150\220x\210\207\155\174\255sZm9@\250\189\186\r\145\225\140\174;\200\027\127\139\217}\189\239\1864X0$\246C\155\251b\243zF*T\142\157\140\152\209\006)\180\147\174'\195\214\229\235\182er\249\t\217p2\169\219\150\239(8\162s\142g\234C\147I\222\238'R\217(\180\155\132\127\217\208\147:o\247s\026\209\160\189\241\164\141\031\1861\179\232 u\241=\017\213\164J\157\147\011\206\242\011\254b\162g\018<\155\219\213\189\188\221\007r\153\200M\147IO\219\245\243\251\25439K?i\166\167tW\015r\154\255\151\025q\029\233\157/\b\217\239W\202J1\004F\241z\220\014\002\235\163\012\248m\184\218\216\232\176\006\155|\162;\247\227\157c\154\224vl\147~\191m\247oj\215\006\223\204\012\153\243\027\245\2407j7k#j\214\215\224\175\193(\191\139\178c\236\215\129\031\165\229,o\2499\169\177Nv\158i\150\153\246\242N^Y\251\245\213~S\176\203\031r\193A\015\1748\200\213\243E\134\019]\209\\\145\131\166%\159\223\171?)\163\196\030\142\007j\232\233(\239\225u\162\176^\235`\170\197\2338\239`SI\129\019\028g\164\230\155B\168\204+J\168m\195\190\186\246\020\236\178\176\rg#s\235i~\197\1756\248f\230\206\179|$\203\196\015m\b\140\213cg`\146\255#\201 \247\155\025\020\0217\161^\127X\031\165\016y;l\253\"T\"\129\205&u\162\158\025\151\140\02067\225\028\147uS\156\r\234\153\168\1276t\239b\138\151`\191p\155\192\157\161\002\145\219\140r\254\\\029n7\155\219\205\254\246$\133\231\1767Ji\144\135\003\233\234\020+\226C(\229\185\162\r\2090n\165ok\234\218\164*+7\025~\127@\149\219P+\136\025\228\174\149\132n[?\132\1409\154\164:f\006\181\198\r\233g\148\200<\250\019\165\138\025Yu\212\150U!\197\145VRe\029\244\205\151\236\247\160\214\1843w\031\134dR\2035\251\189~~Q.^\2105\167\230\154\131\\\007\247\212\2070\240\016\153\227T\193\180\131\249w\181\t\165E{\176\173\238\183t:d\174o\212\249A<;&-{\171Q\030\176\223\133\194Ce7\154MM\239\199\185\147m8\180C\133;\025J\026\236\247&y\187\255KW\156\182\157\175\201\015\1851\216\238\129\1807\140\217x4\029\154\219O\243\203n\205\237c\252H\187Y\158B\030\213\198\179\150Gd\232\253^>t\170H&i\228C\211\016\138D*&\169\138\n\211\000m\t\005\226\015\186y\156\001\177\225\1801\022\024\201\195\169em/;\202\211\221\222$\167\136i\195q\222\240@\247O\213Jt'm\nf:\n!E\141\134\2040\158\145\141\250u\174\167S\234\2318\233\201*t\154\251\247sj8Iz\234\217\001A\129\241b[Nb\212r\203\001\132W*\140\219\012\030/:1\131\031@x\157S\2110\140V\163Y\212\014\006\185\162\254K\151\r6\173#\195\004\231\027\145C\r\152+GS\225J%\1646q\212a\158\022s\219\132\206\224\169\216\128h\134&\194\161\158k\215U\250\161\222\175\167\220\147\177syC\196\253\182d\152\2144Y\229[L\028*>n\182w\196)a\162WG\246\153$\014\137\167p\169\156\175\024\220\237^\146\223\247\137[\1341Dh\214\221\159\128?\203\020}\020Sz\208\214(\022\2045u\n+\2308\183\r\203CD?m=:\b}\210\249T\159k\230>\249\193}\\\157\226\026;\241]p\134a\172\211\228\020\200(g\154\254\180\019\226\201@\171\165\254\004\230?\247\219\221~C\151\158\182Yt\210N\015\234HB\237\t@F\135\181vf8\161\001\1435\139\246'\144OnO\251\176\004pK\142\023l\020&\219\177\234\025\179\217\184\176\230\160k\147\219a\211.\217Iz\011\164;\bW\150\187\212\016\002\188x\163>8ls\2268\198\142\156\004\156\245\237\180\t'<\238\142&\149\198)\194(\186z\159O\130\188\019Oj{''\r\219\147\1341\139\200I\195\142\147\212\137\131\201\195Y\145T\244,\200;\247\027N\019\211\228\135q\026V\247\200\232\\\157K\235-\183\158P\235q\\\138\"\194\170\193\142a\025Nj\161P\225\245c\254\011m\006\236(5\152\241n\245\237\027M\011gm\017\017\232x62\186\157y\237e9-\0225\195\148B\228\020\174\200\243\021\148\024N\235\253\154\022\177\194zK(\184\194\218g\224J>\r\243IX\190\253\182_\253\160\193\140\163\023\135\219\140':A\233s\t>\164[\221\132\229\228u\178C\175\213d\020\196u\130\212zT\149\229Vk\190\155\213\129\150\000\198\180|4\155\201\242Q\127:\246\157\210\156U\167\211F\189\1619m\226\159\166\190\2269\243\180\238pf\227b\1657s\005\031J4\242\131\237v\243\227\176IIq\212\154)\2040\006\178p\213\231Z^\206\bf:~\223\157d\161\177n\167\175\145\133\194f\200#\000\019\220\174\246\1864\213^Y@\140\202\156\197\t\155\174\127\r\248\017\135,\162\152\201j\177\1462\224G\029\178\236\161\173\219\181\143\184\228\025\162\176\158\144j\248a\007\247\253s\234{\154S\204\226\212\169&\157\243S\142!\023\246\251\187\199PI\157\182\220\249qt\252\144\188F\186\1346\024\193\162\201\202\176d\156+k\141=\024\193\148\233.\166\223\195\193\206\156\134S\211\028\1678F-ul=\236\233lrP,\134\155\214qj\018\n\18687\025O\200\007xQ\156\251\189K\253\166\154\187\214\154{\128\139\226!\185\133'\132\129\165i:\145\030\016\198\007:u\204\186I/o\161\188\2525\011BZ\154\011}\152\210]\222\226dXI\141\022\222\135c\137\142\183\208\163\149R\136\204\243\227S\022\226\016i\2063\150\"\002\211\236e\018kQ\184\133\244G#\138\250c\248\146\027\203\162O6XY\252\193\177r\181~\183y\222\016\189\006\231\142)\165}\1463\028\251\023W\205\200\149gT\235H[^J\006\174\215E\229i\151*\245\234\162\2028\157\135\230\178\002\00770kq\211\014M\158\205\029x2\230\025W&\173\237\163+\195\249\237\2525r\172\157\192\150\246\202;FF\139k\147`4\025\138\176\190\025D|\222\2376\206,lG\1416f\189\026\002O\138\157\014\179\197\168\226\014\170&\219\0310\180\184\180\147\031\236d\028\029\227\151<\028e)\127\218\209\155\247!\163\175x\2011-\130+%s\227\236Y\1635\216\144g\186\241\177\202\024\212?\170\233$\222\016\192UR\187T\171\019\159b\b\166\2040\003\024\246\\\127\184\213\248}\219\029\192b-\241\005\187n\200\021\000*\231\247b\192\237\154yk\178i\169%\166s5p\203\253qA\1620/\247G\011B\219!\012\025Y>\199\014\141\169*\177\139\233\168\207\159\181?\230YQg\143\180$\148\030\197\007\004\227\014c\229e[\183\195i\212\171\189h\189j\020\231\253`0mn\139\176K\004!\235\149\168\254P\249\023\228?K\206\179\221\253w\253\244\141\n\152\248Pb\020*\199z\228\015\245\139\233\185<\016\153v\240\231?\209RQ\151\003x\012V\004;p\155\174\189u\2503\230\129\204\137z~\238\176\241\165yc\232\027`oG\029\t\194\179\150\006\163\181\214\152\140\229\209\021?\030\001\247\145\231$\211\142\019\174\191\239\246\150\026\198\245\176p|) \205@\205\2113\028\169\216\215fH\182o\023/\255\153yY|\234\021(\176\200\214=\170\007s\029\166B,\208No\234g\b\211o\155\129\160\223\2265:\171\017\127AF\027\218}\015\135S\187,\145V>\250q6\016\151\003\251\178\246V\232QI\202\168\177\17941\148&\222\213\217\216\020x\234\138\024\030TN=\158\182\199\205\143mZv\011\004\028\166\028\227v\021\179C/f\250l\002\169\139Y\181\012\228\167\147\211\014\214\b\1713\199\205j{\183\185O\015l\250mh\183\226z\236\007\1989O\203R\030\197\167n\192\172\146|\172;\234Cb\212\164\208\0302A\251dg\232\004\171Pw\193\029\194\221]5$\020\023\\\145O\138AH\181\150O\209\019\221\199\220\217\209\254\214\012\250\194\244\128\159\228\152\214\2428\167\171\241\201D\149\241\135\193\176#\245\175l\r\194\218\159v\212\178\191\154\158\164)\208\208I\250fsW\1529w\237\240\018\203\242c\133\253\238a\253d\031.\196\005\234\246\225B\175vK\174\253\250\219\230\160+\142\023j.IW\026\135f\187\006\006\162\206\249r\214\150\253\024\005k\243\n\251)$CYco\159\195\1341O\199\178\188V\248\166\173\139\216-Q\159\146\162\242\169M/-bu\248\240\206f?z\1807)\253@\018\148\185\182$\167\130\205\184\177\173m$\147aGF\169\215\180+Iw2\r&\237\198.]\224F#\253r\228i\127W\161.%\159\205\195\177\232\027\192\014\161\162f-*\221\017\157e\031\186\138\226i\r\232\152\1437\134\2120r\224\200\231\0023\149\161\153\140}\026^dA\211z\163\186xV\144\178,\228\155Y\149\221\r\134\235\230F\251\020YY`\245/\004\150\r\148\024U\222\172A\026\227RHw$\n\023\022\026%>\172\1579\249\136\025%di\218\213\223\214\022u\251\132\185\024\003;\133u\253\138\183xu\209\219\207:b\179\136\2145\228\147^\187{\234\201\206\028\130|s\187\210M\005!\169\140Cz\154\142{\029+\182\026W\178\163\187k^\178/XjB+\152v?Y1\249\177k\128f\242\211\177\004\1903\205I\147\023V\012\191\148\196I\171zv\131q\201&\197Y\236F\179\238:\248\157\141\226\174\026O\026\219\012\198\021\231\1647*<\234\204\152\191\156\232m4}\247\242\151\167;\243\210fz\139\243\211z\255\244~u\\\233\175\171\213&\148\163A\155\2117\159\174\190V\239\170p\237\201\152\143S\1387@R\149\005\168BU\232\159\177\160\231\227\148\200\r`\149\167\240\231\248\244\141\143\233\166\n\152\1922\168\184\157\193R\2182@\150\134\rN\1865H\218\149`\128Dx\n\252\017\142y\140\215\246\152tb\000;F\129\027s\173\006\199\216\184cl\156168\198\166c\140M1F^\1450H\155\001\244\247<\248\025\247wQ\181/O\167\031\203\016\022rL\157W@\187)\152y\145\245m=\"\240\020\194\145\027\208\234\182\001\172\n\020\213k+F*P W\129\226\172\002EX\005\138$\021\200\239g\211\223\023s|\182\199\172\001\001\140\006\bKML4\017\000!E(\196\021\163\024\\\t7\017F\000\132\025\161n\172%\153\t8\002\192#\t\245\220\146D\165o\146\000\028\148P\223KI\136\174J0\196$\161\016\152\t5\209\153\128\235\002\1288e\212\011\214$k\240&\141\171\164\166[IM\151\146\026WI\205%%5\190\146\138\160&8\143\236\004\154\240N\128\141\241\132\152@'\000\162\157\2082\228\147\192\139\251$1\193O\0000\000\161\030\r\144\168\228\002\018\000!\016\234\179\002\t\145\026\bF~ 8'\137\004>\227\b_\0168\023\000\016\007\161%{\164\1286\236A\000\176\007\161\192\030\140\"{$\220\176\007\001\192\030\132\186\236\145d\134=\b\128\192 \212\011\012\018\149\129A\002\b\012B\253\192 !\006\006\193\192\030\132\002{$\212\176G\002\174\011\000\216\131Q\143=\146\172\193\1554\174\146\154n%5]Jj\\%5\151\148\212\248J*\216\131\224\156=\018h\216#\001\150=\018b\216\131\000`\015BK\246H\002\143=\146\196\176\007\001\192\030\132z\236A\162\146=H\000\236A\168\207\030$D\246 \024\217\131\224\156=\018\248\140#|A\224\\\000\192\030\132\150\236a\148`(\196\162\192#V\004d\146\137\144Q\140\208\208\138E\129[\172\200%\024\211\192\176\140E!\138\172\200\011%+/\227\201J!\168\172\200\143,\219\002\195\203\202\128\136\172\b\216\200\136\012%\025\244\218G\129\1562\145\199P\166A\227\222\189\233\214r\243\023Zn.j\185\233\214r\243\151Zn.h\185`2+\203\233\204H\012\167\025\212\018\155\129\r\187Y\020(\206\138J\1583R\143\236\140\2160\158E\129\246\172\200\227>+/\t\208J\129\005\173\200\167B\219\002\249\208\202\144\020\173,gF#yvu\242\226\162g\031\005\182\180\162\1462\0051\132\169\024\208\165\n\128,\141\000\169RD\134(\021\003\154T\129K\146\"6\020\169\024\132\174\n\188\192Ui\025\182*\131\160U\129\031\178*\199\128U\t\144\162\n\128\018E`\bQ\176k\015\00324\002\143\nE\2208\247l\186t\217\\\212esA\151M\151.\155\191\208e\211\169\203\130\250T\146\019\159\224\134\246\004\179\164'\160\161<\197\128\240TP\210\157 \030\217\137\208P\157b@t*\240hN\165%\201\169\012(N\005>\193\169\028\233M%Hn*\201\169M\240gg\252/\014v\2460\1604\021\148\132\150\198j\216\140\000\1602B\129\199\024E\018K\184a0\002\128\190\bu\185+\201\012q\017\000\145F\168\023f$*c\140\004\016`\132\250\209EB\012-\130\129\163\b\005\130J\168a\167\004\\\023\000\240\018\163\030)%Y\1317i\\%5\221Jj\186\148\212\184Jj.)\169\241\149T\144\015\1939\243$\208\208N\002,\231$\196\016\014\001\1926\132\150T\147\004\030\207$\137!\025\002\128a\b\245\232\133D%\183\144\000\136\133P\159UH\136\148B0\242\t\1939\153$\240\025G\248\130\192\185\000\128@\b-\217\131zg\232\131\017\224\015\134\129@\004F\006!\129\161\016F\128C\024vI\132\132\134E\024\129\ba\216\011\017\150\1491\194\018\b\018\134\253(a)\134\t\227@&\012\003\155\016l\232\132\144\235\018\001B\017\216c\020\0186\197\157\026_c\205\005\1415\157\026k|\1415\0235\214th\172`\022\198sj!\212p\011!\150\\\b2\236\194\b\208\011\195%\191\144\196#\024\018\025\134a\004(\134a\143cXV\146\012K\128e\024\246i\134\165\2003\140#\2090\1583\r\161\207\197X_\n\228\\\"\1926\012\151tC\1571t\195\b\208\r\195@7\002#\221\144\192\208\r#@7\012\187tCBC7\140@\2400\236\005\015\203\202\224a\t\004\015\195~\240\176\020\131\135q\160\027\134\129n\b6tC\200u\137\000\221\b\236\209\r\t\155\226N\141\175\177\230\130\198\154N\1415\190\198\154\139\026k:4V\208\r\2279\221\016j\232\134\016K7\004\025\186a\004\232\134\225\146nH\226\209\r\137\012\2210\002t\195\176G7,+\233\134%@7\012\251t\195R\164\027\198\145n\024\207\233\134\208\231b\172/\005\018\232f\b\b\143\030`3B\146\18075d\147~\003\213$\016\136\134@\164\153\0226$\147~\003\197$\208%\152Vd\232%\253\134PI\160\023(IR\134I\194!H\018\232\135H\146a\128$\020\b%\129@'-h\200\164\253}\141\191\129H\b\244h\164\0215p\253\198\211K\211\169\151\166C/\141\167\151\230\130^\026W/\005m$4'\141\246\151\161\140\246\183%\140\0220t\145~\003Y$\176\164\138\022\247\136\162\021\024\154H\191\129$\018\232QD\146\148\004\145p\160\135\004\250\228\144dH\r\tEbHhN\011\237\175g\024\215\011\252>\227o\168>\018X\214\030\201\133\r\027\016\000t@(\240\001\163H\b\t7\140@\000P\002\161.'$\153!\005\002\192\251\t\245\220\159D\165\255\147\000\002\128P?\002H\136!@0p\003\161@\014\233\167a\135\004\\\023\000\240\003\163\030A$Y\1317i\\%5\221Jj\186\148\212\184Jj.)\169\241\149T\016\005\1939S$\208PE\002,W$\196\144\005\001\192\022\132\150t\145\004\030_$\137!\012\002\1281\b\245(\131D%g\144\000H\131P\1595H\136\180A0\242\006\1939q$\240\025G\248\130\192\185\000\128<\b-\216\227\167\234]\252\219\000|Lg)@\241\174\128U\154\162z]\197HU\n\176\"\020a\029(\146\134\175\191)\004\005h\162\031\2411\245V\001\2199E\181s\138Q\231\020\200M\1688wZ\017\238\180\"\169\211\244\251\189\209\232{\212\232{\212\232{W\163\239\029\141\190G\141\190/4\250\190\208\232{\208\232{\212\232\251\024\170c\238\249\"~\164\142\142\151\006_\230t\244\222F%c\137\244\204\216\t\000\005\016\nZ \212S\005\137J}\144\000\148B(j\134`T\015\193\185\142\b\004E%t\142\0036*K\192\018[\160\242\bu4\216\190\143i5\152\000\212`BQ\131\tu5\152D\142\006\147\0005\152\208B\131\t.4\152`\208`\002Q\131-:\199\001[\r\182\192\018[\020\026Lh\161\193\015Qy\156f>\136\226\012BJ3HN\025\002[\206\016PHC\016e\007\129\148\030\004b~\016\128\020\163\200J\242\229\007\254P\156\001\168\215\n\216N+\170}V\140\186\172\000\247X\017\238\176\"\169\191\250\155\186+@\250\147G\241\139\217\004dcY\023j\167O\252e\136\171\246\181\167v\243N\173E\011c\172Kc\172Kcl\196\219>\240\151\170\012`\187\165\168\246J1\186\189\002|wE\248\230\130\236\164\134\249\192_\0050\128\189\183\162E\249\243\129_\1564@\158\188\020\231>)B\133\174\002d[\001\232ON\025\227\238M|\237\243H\252\192_\167\178@V\230&\248\163a\181\143Hh\031\145\203>\1864\246\209a\176\143H^\031\011\222\250XP\214G`\171\143HT\031c8\142\184\231\171\220I>J8*\224x\205G\027\142\138\229^\243Q\195Q\017\240\154\143\028\142\250\155z+\000\135#\255\182\1785\246\158c\209\000^\239\215N\239m *\136CZ\023CZ\023C\218\217c\236\225\206\237\208\206\233\208\014\239\r\129\160x\209'\014\004\005P\171\018\b\012\156\140\240\132\157>\185\157>9\157>a\167O\029\157>\021\157>\021\138\229slE\139\185\206'\153Y+\224\206p>\233|Z\017R\172\002\164X\0014\208>\137{*@\238i\128\146\n>Y\2474\152\186\167\1309?|R\247T\004\248\225StO=\198\030\238\220\014\237\156\014\237\240\222\224\158\138\023}b\247T \167\168O\209\027\007\172Q\246F\005\178>\nj\250(\024\247Q\000\232\163\224\210GADo\130\016\175\242\239\179=\198>\158\203\222\216\212a<9\131\193\1693\153\231\223Y\131\210\21331x}&\243\003 k\130\177\144\t!,2\025D\136\149\025\147g0xe&\131\016\202e\142\243f\rJ?\206\197e\140erp\249L\134^\158\t1\b\173p\215\001_P\194\238\175\006\186\187<\208\221\133\129t\132q\214\228\210X1\1843\025\196\185\149\157\252H\193\232\207d\030\017d\r.G!\210C&\243\153\"k\130\164\145\t\145?2aN%Vt\238\128/\168\161\228\154\127\199e\219\254\148\143y\130\162\128\173b\005\014s\215aM\199\011s\188\180\199\204P\002\024\214a\204.^\210R\240\191\219'\130\220\224\140W9\151W\145\247D\185\127\249{\162\136z#\146\215*\243k.\016X\022\000\244\175x\1712\023x\227\149W\012\243\166g\247\202\206\240\237\128\140\0182\024T\145\203<\133Xp\238\223k\225\195\203\014\024\134\147\201.\015\202S\026\004\130w\218\249\194\029\0295&22\n$\000T\199\168\167\180$\155\2275\023\b,\011\000\186JhW'=\133$\201\025\155\158\221+\151\195\143\127\020\150\019\175|\194\208\0004\215S\192\1691\236\215\012\r\150W\019\250\217g\131\1923\000\254\162\141\249\157\151\006\244I\218w\005\000\253&\020:O\1687\002\018\149\195 \001\140\133P\028\016\1938*\130\243\161\017\b\227\147Ed\000`|\249\"2\160\222\248\138Ed\016\192\248`\017\025`\028_\182\136\012 \142\207\132\207\187\014\024\199je8b+s\199m\0278\163\183b\212\129\149\021\154\176\194B\031V\bZ\177\"\208M\250\249\174\000@\031\132\130&\b\245t@\162r\244$\128q\019\138#&\024\199Jp>J\002\243\241}\142C\027\201q\190\128\240Y\006\164\128\179\162\240\217\014C\177|E\225\179v^\017X9\248\204]\214\223\249\250\199\231\152\017\2448_4\250\012y@`]\219\255\028\217_\142\191\1546K\131\195\194\254ggM\255\179P\222(\007@\1299\229\001\234\169\178\160<\016\128R\129\242\000F\245f\148\007 (Z\1708\000@\229^\021\151\203\230\168\179\005\002_\241\148%\182@\131\020e\029\011\140F\141i,\n\246\177\"0\146\021y\150\178\242\210\\V\n6\179\"4\156\149\161\245\172,7\161\149\128\029\243\151\156=\020,\218\249\146\179\211`\238j~\225\162_\221+,\221\182ho\255\221_\150\nbL\174\024\024\\\005`n\021x\198Viij\149\129\161U\128fV\t\026Y%\185\137\021\007\003\219\1516K\012\140\219\241\210f!\158;\218]8\216W\231\220\165\211\014\r\234\189\219\200\178\164DcK\002\192\144\132\130\021\t\245LH\162\210~$\000\227\017\138\150#\024\205Fpn3\002\193`\242\030\027\000`*\239=\182\\6G\157-\016\248\138\167,\177\005\026\166x\r\140\005\217\170\1381N\142\131\141r!\152*\023z\022\203[\148\134\203\229`\191\\\136f\204\165h\205\\\154\0275\151\129m3\225u\023\014\150\006\161g\240\172\201\188\195*\139\014\252k\199u\150\029\237\209'ra\233\026\164[\227\020\140\128;0\012\142\192\176\231\002,+\141\207\0180;\195hp\198\209\212\140\231Ff\020\204\171\239\140!\002&u\223\025\003\225\188\208\224\162@\190\022g-\1396h\174\242U+\150\164\213\006c'\002\192L\132\130\149\b\245\140D\162\210F$\000\019\017\138\022\"\024\rDpn\031\002\193<\178f\004\000\024\199[3\202es\212\217\002\129\175x\202\018[\160Y\138E$\022\200\004s\148\003`\149|\130\t\168g\149b\130\t\002\176\nL0\001F\171d\019L\000\193*\178\029\025\000\176\138\183\0299\151\205Qg\011\004\190\226)Kl\129V)v\243\146\224*\026d:\230c:K\0012\131\002\214\002\138\234u\021#\189+\192*W\132\181\173HR\180\254&\029\011\160[C\174pk\200\021n\r\185r\183\134\\9[C\174pk\200U\1775\228\170\216\026r\005[C\174pk\200\021\238\212\186\170\214F\241\235\220DW\242\228\208\000\229\134\243+\251\140\208`\250`P\193|\239\249\149>\002T\0046\149_\197\135}cV6?\225S \235\144\160\166C\130\241\189\005\128-\239\130K\159\004\225\183\001\004\224\023\001\024\192MR\127\152}\201\127\224\190\228?\220}\201\1278\251\146\255\192}\201\127t\236K\254\163\216\151\252G\177/\249\015\216\151\252%>R\031\201q\238\186_\242\135\231\138\022\158\250E\030\147+\224n`\249\162\015\196\021\201w\221|\145G\223\002\\\203z\217\023!.\003X\206\018\1841\23178\174\198\029W\227\140\171\193q5\029\227j\138q5\016\153_X\247\242{.OK\190\180\239B\240\241\210\030\179\223\b`<\132\176\212\196X\146\000\0246\161\222\216IT*\128\004\160\005B}U\144\016\245A0\024\155P\176\184,\127\rs\000l\239-\127\229\178\006\175\217\184:i\186u\210t\233\164qu\210\\\210I\227\235\164p\020\130so\145\245\188\220\234\011\004\150\005\000\030T,\223\177 i\215\184\017\001\1602B=\149\145\168T\025\t@e\132\250*#!\170\140`p#B\193\141\018j\220\136\000p#F=7J\178\006\175\217\184:i\186u\210t\233\164qu\210\\\210I\227\235\164p#\130s7\1467\022r\171/\016X\022\000\184Q\241\198\130\b\242\r[rcg\195\150+s\149\232o\216r\197\168\208\238\r[n\147B\185\206\134-W\134\206\151\239D\024z0:b\231N\004\175E\227\223\171\185\160\219\230\175t\219\\\214msA\183\205_\235\182\185\164\219\210}\173\016\1568\223\144\225y\222\194\135\151\0290:\183\191!\131\196\215qzBu\223\181LO\020\160\130_\001\167@\189\182\211\019\197\242\002\245Z\167'\138Hq,\b\189l)\191\243\202\244:F\161\244\252s>\210\235<\222\020u\006\205\145\165\000\212\161\130K\029*\b\005\142\002\252\182\011\003\241e\151\001\031S\031\021\224\151]\004\200^v\017\212\188\236\"\024\191\236\"\128\188\236\"\136\188\236\"\b\189\236\"\191\249e\023\006nw\219\246\021\138\145\252n\167T\"\183m\2158\026\158Q\025\192\027\141\157Q)\1663*m\200N#\1288\141 \197\016\191\159\127|_\219Nld\251\203\181\188\003\163\128<\226fd'\175\254\\\203\140L\001\231]\164k;#S,\127\023\233\026gd\138\195;J\2152#S \127%\233Zfd2\198\189\025\192\030\199\200o\173\024 \163`\134\015\235\199\r\218\255d\228'\188p\254N\177\160\197\182\163k}\147X\000\216a,\184\236D\016\164\176\016\1915\204\191_\204\241\217\030c\127\203\rQ\215\178\005\1359%\223\130\003(\240\159\179\005\007D%\019\230[p\000EN\132-8\000\231\236\152o\193\201Q\195\147y\233\011\168\199\152E\233\011\002\224N\183\244\005!\178h^\250\002\n|\154PCI\004\000\023\017\n\244J\168\199J$*\137\150\004\192\182\132\"\229\018\140\164DpN\190\004\002\003'\020\194\144\193\140\139\019X\156\186v5\129\212\204h\167&\028\146fA\201\212$\001\186&\0209\155`_G\200\222\t\221`\192\"\143\019\138T\145`\195\232\004\000\173\019\234q;\137J\130'\001\176<\161>\213\147\016\249\158` }B\129\249\019\138\244\159\208=\142{\239*\t\179\001\163^JH2'/$\193\t[\158\220;\186i\130D]\140\140\t\131P?k\144\016S\007\193\190S@\018I\224\011\002\231\002pG\232%\150|\239\163\240\177\179\247\209\149a\170\233\218\251\2326p\210\142\179\247\209\149\021)\200\219\251\232\n!\0299{\031=\153MM\206D\218\149\185i\202\159H\187bLY\221\019i\183I\145\190\156\137\180+\195Tfd\150\215-\140dne\152\220\172\204%v\219\192ItV\140\233\206\202\138\164g\133\005\173[!$@+\1944hd\200=\153(O\137\246\029\171\014\248\130F\139$\153\201\254B\163^\194\204\196N\218\180rL\158VV\164P+\188\164\241\"\157\026\217\198'\171\"\181ZY\193\165Fh\211\172\1331\217Z\153\155rm\003'\241Z1\166_+\235H\194\182I\145\138\173\016\019\178\149aZ6\178\"9\027\217\222\215\220\254\130\202\139t\157\201\220\164m@/u\027\241\201?\235t\161?~2\183\r.\231\194\"\177[YGz\183M\138$o\133\151\220\019\019\190\017\189\248\240\185\003\190\160\157\178\016h\218-\024c>\2305L\001\248\025\186\000\217J\166\160f\249R0^\179\020@V!\005\145\165GAh\189Q~\243\226.\001\186\255<\007\160\223\176\255\216\201\237\1600Ro'\183#\242\198\220\177\147\219\145\194\232\221\157\220\142\012\245\224\236\228v$\160\145l\155s\129\1296\202m\206\133\192\211\132\187\205\185\144\129\022\156m\206\133\0045Pls.p\024\189\238\n\206\001\0247\236\n\206Qo\196\229\174\224\\\000c\197]\1939\140\163\204w\005\231 \140\175\216_\235\2260Z\127\127\173+\244\198\222\185\191\214\149\131&:\246\215\186R\212\139\187\191\214\149\129\150\204VS@@3\184\213\020`O\027\206VS\144\128\006\138\173\166\128\227\168a\171)\1600R:\249]\137\192H\025\134\1452\236\141\148e\229HY\002#e\024G\2028\142\148\241|\164\140\194H\219F\239\2407\1402\1290\198\004z#L\146r|\t\135\209%\016\199\150P\028YB\243q%,\031\213\220\236\031\156\227\254\1939\238\031\156W\222\254\193\185\179\127p\142\251\007\231\197\254\193y\177\127p\014\251\007\231\184\127p\030?\169K\027\178\230\2425]\005\178\242U`\253\022\202\028?\1282w\191z2w>u2\199\239\155\204;>j2/\190d2\199\207\151\204\241\155%\2438]\239\247\251\252\131\215*\020\225\161*\146\173Y(lV*\020\228\245\tEd\201A!\217\000\167\016\237\128S\128\023\028\004\201\231\002s\22019\175\178\214\235b`\242m;\131\184\0033\179\225Z1\243i;m\201\223w\019@\190\227&H9V\158\216\214l\145\141,/\205e\n\171\000,\\\205\227dU/\182+\198\185\243G\181\243\204\181+\204\005SO#(\237\200\211L\131\020V\195\r\152sg^7\143\1479\025\222\t5pr\214\012\231v\174\166X\190:8\199Y\153\226\176T8\215\249\151\"\217\162\224\"\178\023\245w!\236\165\000E\141\002\217G\002\0055\174%\024;\145\000\226D\130p\231\020I\157\211\223\252u@\006\226\218$\247\\\022$\005\200\\DP\227!\130\177\131\b\000\254!\184\184\135 \236\029\002\176s0\176\018\182]\b\017)\144\231\131ENC\138\022\249`!$\164\000\228\131\133R\144\"Y>X\b\001\t@>;\214\223-\255\136\198\227\154J\143\143y\225H\000^\158S\192.\031\tZl\216^\228\171o\002\230\027\182\023\197\134\237\133Y\\c\132\137G\154\2322\218\002\215\206\022\197\130\217\"\018\207\148Oe\222Q 3\143\160\198<\130\177y\004\200}Jq1\155 \228S\n\176\149\024`\190\017\179\024\186\017\211\157\236qN7\011\151n\022\014\221,\144n\022\029t\179(\232fQ\208\205\162\160\155\179=\198>\158\139\222,\r?-\145\159\150\200OK\151\159\150\014?-\145\159\150\005?-\011~Z\002?-\145\159\150\145\159\006\220s\230'\005\156o\130--?)\150\127\253k\137\252\1648|\231k)\252\164@\254E\175\165y\176\177\196\167\025K|\132\177t\159[,\157\135\021K|B\177,\030K,\139g\017Kx\000\177\196\167\014K\230'\243\219>_X\218\242hY\148G\203\162H(:\028\193\232u\004{\174\135l\152P\136$\0063^L\160\141JB\144:\bF\154d\216\225J\018\149\132\201\002\1355I\004\212I(\242'\193\005\137&\028\1534\161\134N\t\000N%\020\1375\193\187\226.;_O>\207\146\204![\146 \227\018\220A\187$-\184\151p$`\130\145\133\019\140T\156P\135\143\147\224T\000n\232\156\186\131\228\212\021$'7H:\216\154\132~\004\157\252\b\002\242\182OQx\244\197S\148R\000,\238?E)\165%\151\023OQJ\0012z\249\020\165\148\228\188^\228\233M\209\226\001\231C\166-\005\243\167\158\015\154\189\020\129\175\186>\024%>\160\018\031\\%>d\025C\176\\\177\015\029\138}0iA\144\\\213\015\168\234\007\216\217;\244`\208\173\183\179\215\1519\026\239\216\217\235\139K;x;{]\025Z\199\221\217\235\tw\190n\208|\157\187m\221\006\165Q\189\221\182\174\2047\181\187\219\214\021\130\003x\187mI\246\020\255B(e\183\1674\\\003$C[\192\\\201\192\242\183F\t\216\197cz\170\182\139;B\007|\172\202\218\197\007\nz\156\171zg\031(0&\221\227+'\192\\>\001\175x\202\185\000\224n\132\150\1834F6\2475\168\185\185A_\221+\156}\020\250bEe\135\0041\221\017\204tF\176W\231\220\179\135A7TPv\"\185\174\233A\002\204\237\019\240\138\167\156\011\000\238Jhy\203,\"\204\1573\220t \195_;\174s\238\194\161W\185\176\236\028\197\162\233\022!\166C\132\188\022g\157K\004n\207py\227\020\231\230\190\t0\183M\192+\158r.\000\184g\241G\015X \161\206\183\148?+<\200\128W<\229\\\000p\203\226\239\012\147\128\234\002\191\196\179\194\\\210B\219\245\253\209\028\241d\1994\191\147\145X\240\182\2533\161\142\196\249\211\209\006\218{\167\236\243\205\014V\194\243rG\146\149\186\133\252\224\221\253\144\175\140Y\t\221\200\147\240\159o\247d\182\019\142\252\199\234\214\189\157\190n`A\239\253\n#W\151\218s\237;\225\223\\\0262\144\173\155\231 6\205\222\246\205\193\162i\249.\148'\130\211\146\022\222\201\144\232w\190y\129@\254\203\003\025\232\188\003B\018S*ex\254\214\007\129\240.\007\161\176e\130\208\236\237\r\194xW\158\005\231\178',\253^\192\239%\254f\015\204@\179\138\148\240gV/\221\236\185\210\240x\214\153\140\000y\152<\19569A\139\221B\207\249$H\192|\011\209\179\249\243\175\130\200<\137\145\157=\198\030\238\220\014\237\156\014\237\240\222;w\251\210\179)\240\004\201\183/=k)\199\000{&\169\245\165\210\249\227\139n\172\020 \223B\250\002\219*\005-\b\249E7U\n\000\229\232\139\217R)H\246M\193\023\221P\201@\238\020/\149\149\173\177\247\250\135\129\005\240z\191vz\239\204\140_\204\031\005f\160\024\210\186\024\146:\197\011:\197\139\235\020/\142S\188\160S\188t8\197K\225\020/\232\020/\232\020/\232\020\175F\173\175\168\214WT\235\171\171\214WG\173\175\158Z_Q\173\175\133Z_\011\181\158\193\017\2068\132sF\2559\136Mq)\189\192\205\t\191<\221}Z\239\159\174V\155\253\129\127\188_\029W\241\248\195\238\233\248\219\250\184\223\220\030\254\031l\0014)" let helvetica_afm () = "x\001\181}\219v\027I\174\229\187\191\130\1433k\141zx\191t?\185\171\202\238jU\149l\151$\150\231\141\146R6\143)\166\155TH\162\191~23\016\001`\003\145:/g\213j7s\003\153\137\000\016;\238\169?\0317\135\199w\245\254\241\247\234\241\176\189=\014\166\127\027\189\249\169~x\168\246\143\131\159\234\239\167\195\246\203\215\199\193\255\186\253\223\131\209j9\251?\237\191\139\238\223U\251\239j\216\253\187\024\188\189\171o\170\193\159\167\227c\245p\028\252\186\191\173\015\223\235\195\230\177\186\251\219`\240v\183\027|j\159s\028|\170\142\213\225\169A\249%\135j\243\184\173\247\131\159\027\237\191\015.\191\134\193\239\155\211`0\026\140\198\127\159,\255>\158to\200\250W\251\237\127B\245\235\207\131\233d8\155f\248\250\247p\220|\169\006\147\197p\190\026L\151\195\213\244M[\174?6\015\213\224_\213\238\169z\220\222n\222\188\011\187\029B\155\135\237\238\004\224\186\234\202\253{u\183\r\015o~}\220\236\182\183o\247_v\213`\248\230\215\227\187\237Ku\247a\251x\251up\191\217\029\1717?}\221\0286\183\143\213\225\207\234q\240\203\203c\181\191\171\238>\213\015\155}g\196?\255Y\191\012\206F\243\249\224l<\158\rF\195\225p\176\154\140\006o\174\026\189\195n\187\175>\212\199m\231\133\179F\200\240\229\215\237\237\183}u<\014f\1957\215\213\225\216\170\012\135\227\1915Ox\243G\221\152Z\253\143F);d\176=\0146\131\199\195\230\174z\216\028\190\r\234\251\193o\219}\253x\250^\1575J\187\193\219\247\131\205\254\238\255\214\135\193\182y\1921\220\028\183w\219\205a[\029\255\246\230\151\230Ew\219\253\151?o\191V\141\151;+\254|l\2127\135\187${\243\211\230\251\191\162\211\023\163\229\155\191\232\247l\021\230\175\2005\2271\0237\230]{\199l\210\021x4c\007M\135\228\160\206\171\141E\155C\181\223U\247\241\134\249\178\139\224`\188Z\r\022\147h\212t\228\220\193\239h<\030o\153\207\248\022\138\235\132\138\1899\182V\029\191\165rO\155j6\153\174\216(\138\240l9\141\175\216\133c\210m\252\223\020x6\140\014\157Nu.\2206L\179\233T\155$8\027M\023M\157jHj8\143\2183m\250\215\211\247\175\213>9s\220Dl\220X8i\157\215j\207\245\179\027\223o\235\187\244\240\161~\242\0022w\1839~\237T\207F\139.\174\227U\235\143E\212^\234\172\249Q\029\234X\190\168;k\254\151r`\186\210\186\245>\214\136\209p\212\2160\153\177\230l\1685\031\159\227C\199\243\214iMH\178\226\b\020\191\030\170*\007\175}\127\227\129\172<\214\202\247u\136\249\221pd[\023&\1729\001\205\237S\1975\161-\2134\215\155\217T\235\030\183/QuI\170K~,T\201c\245D1\155,\200\130\252T\168\141\021gez\174\240\194\002\170\250\150<;es\179\238\018\211lW\239u&\204F1\019f+\200\132\234a\171\212sV\166;\230C\157\237\187\182)\233\012Y\014F\141Z\1951\211UL\247\249H\171V\255\t\155]\170\025\029\2174)>YE\158\156\143\181\242\151\182\017\175\014\165GC\244\154\246\251\2165v\029q\180)4]5Y1\142\025<\167\2485Y\024\137u\019\253\220\150\173c\177\1349R\182\207g\154\197\222\146f\243\200y\147\007\169\210\207\231Z\237\159\145\163;\1811\019\214\156\194\182 \138\251\137\185\176\165\229\017\191v\169\021\127\142\001hk\205|!^\187\210\175\253%\170\181\005\1587\001Jj\011\n\210|4\234\212\222\177\218l9a5\n\208\130\162\255>y\251\172\171\210\211l\221b\172\173\251W,m\155M\243\169x-\180u\191\198fn\2125sKVK\213i8\236\212\254\029]\028c1\029\011E\136\197y|mW\218\185(\006T\164\223Xm6\225X,RsF|\250{T\1554j\139&U\179\026D\226\015\241RY\214\149\246\221\133l\022\023\147U\246\221r\168\011\241A\132\172e.z\222\018b\2411?\175)\149z\030\196\226S|^\219\214\207\151\156)\203\137~\237\1591\182\209\190y\219\202\167\231Mu\174\\r\194\207V\236\189\229L\191\246*\186\133\1587\021/\134\154q\029\249w\216\249O<\143\162\177\154\198\250\190\142\175m\221\178\018)\176\132N\197_Qm\213=M\168A\189\248,k-g\202\n\234\197\255\139\182M\186z\193O[\141t\030\2234=\241o\213#w4&m\169\231M\1632\140\254h\239\129\222\224MsK\127\187\186\154\184o\225\206\201xI\175iX+\191\134\1625\157\167\206\201\237v{\187=\220\134\007zQ\2115h\248n\186\228\134f\005mRh;\187\199\166\167\158z\171g\163\166yl\165g\212\243[\165\206\132\236\153q\241gM\015\162\169\210\141\t\1391\221\000\205S\236\2134\132\221\246\249f\147\182\"\146-\208\153\184\137\140\189\140\138#\206\143\213J\147\196m|\226\176S\1566u9=q4\132\158D\236\2444}\227Ns\197\029\181\182\019\162[\220X'\134\244\242\185x&D\243\158\243inC\132]\159nL\183\164\193\212|H\132\027c\180\154\210\148H\147\164i$\219\242\155}>3\173\255\130\212\173\160\030iG\181\143\219\221]\164\141\166\2030ZF\175L\198\177o<\154\195h3\014\246\239\234\231=\185\168c\244Y\199\232\185\236sH\224<\198nF>qL\222\228\237Vl\203\180kU\219\145\198X\220\000\237\197m84\003\248\219Sj [>m\254o\158M\167\\\031\173F\220r\029\183\221<[\231\211U\156T\152p\207k\180\128Y\1334\237\146\243\175\169\194m\1317iG\165\212\224\141\022@P_\194\182\185\225\161\230^B\211&\182\2449m_9\165\004I\029\233\244\170\246\174\206\186|W\227\218\246\174q34\226\187&\133\1878\131\221\219\160\159}\191\229\138?m*B\215\138u\138@b\247;\1698\022\138\016\190f\218,\245p\154\134q:\236\004\147\017\197b\001\177\187\219|\249\146Ftm\172g4l\205qXy\250i\254\203\189%u\174\245\172G[\131\170Cu\1518{\212\176\215\184i\210'#\n^\234C\207&\177N4\179B\155/\135\205\247X\148\174\1506>\159\138\238\239(\245\167'3\162\155f\218\183zL\250\221\211\155\232\180\205MT\159\014l\015\170\139\217\205\230H\169\216\022\168\233\144\183\019\\iff\180\156\249\185\152\239\026\207\227]mO\146\239\154\251w\137\190\228<\206\030\174D\155\189\\\020R\152o\243r8u\201\1879\231.\011v\187\237\247\227\246H\028\215\182\229\203\165\180n\00574Qz\252Z\135<7\024\251\198\171\021Oa\140R\023<\245\212\211\000?s\233\170\163\151\134-\154\209\246,U\202\021V\148\195\134fu\218^C#\029\143Z2\154\1466\180\241\155\219\240H\218M\212Z\245I7\150K\234\016\154\216\235\190\223U\177\157l\251$\221-cq\011\196\133[\143\179fv\169\241\207\164\029\159\166\006'u\162\147\246\195\230\246@\2208\138\211\n\147n\250(=|\169\213o\014U*l\147\136\141\181\147q[\216\017i\175\180\246]\253\184\185\205MM\219\166\207\155\254\232\184\181\158\2266\030\002/\222m\155J\149\226\220T\246\238\134\213D\220\000\236vH\237RC0\179\134\250\198\237\252\223,)C\172n\155\133\145f::>|\022\219\240\246\134!\169\227lh\216\127\217\028\194\195n\019\030S\167\162\245\255t\200!\027\015\193\255\245\151fB2vu\155\250\029_\209\205\137Em\240\255\237&\185\223\137\237xh\170\193\003\144a'Il8N]\144\172\255\150&o\218\017\239\140\187\220\227q2c\017\245\234\195\221}3-\151g\252\154\142\207\180\241\198\164\157\140\160fr<\129>\196ob\232\217\r\189\229D\2008\173I\228\185\011\214N\019\024\211\161x\248\020,\191\136\150Ob\215a5\159\t\221\020\166\249,\025\255\208t\156\194.[?#\235\185W0N\147\244i\161aS\r\196\240q9\229.\2528M\138'\194\191k\027\220\2271\182l\171Y7\2114\201}\171\241\020\135/\232\151\241\148;\002\2274{\157H\167f\237v,\222\146Bcr;k\217\169\167)\2364\133Q\147\217q\228\185\026\2420a<\003:k\218\181f%\175a\232X\153\230\1398\004m:\021\169\173=\1319\136_U\237\027M\186\145\232\188y\203H\169\231\150\153\201L\140oS\242\162\246\134\185C\140\217\019w\160v0u\143\006'\179\241\168\248\138\138kS\143Ay\254F\1516\205\227\152\210R\215\252n\251\180%b\165\004\238\150]\198\133\135\011\162\207O\030\175\\\221\183\192\242y\"\024o\200\174\228\135+WjS\242,\026<^\204\167\153\023\164\209\150\176^\012\185\140\223\211\128\180[d\018T\223\142M[2\146\131S\027,mVO\196rI\152\236E\025 \131\178\178\n\175\188\161\144\206\027\193\220\147y\156K\153\t^0/`'\245\1854%\180xz\183\136\216N\135\141xx\138I\241\1392?\207\190\163\241y.\191i\198i\197a\b\243\249\185\150S\175\018\131\213\174\192t\131\217fz\248l:\212\143\167\206\235m^\173O\019\128\029\131\207x\020e\236\023=\139l\253r\225\231\219-W\\1\251Vd\146\156\0062\251\169\205G\199\252\129\197]\208v\0069\209\158]\148(\156C\219MC\181\179\157\197\202\200\029\192\158\202\152g\190\209\156\017M%\200yp,\195O\130hyY\167h\016\247\000\165A\212\003\180y\166:i\197D\227\186\206\161\226\025\16823\136\030W\031+\164&h\203E\237Z\218n\182\004\030>]D_\238\234\031\213\254KZ\252\237\166{\198\166m\203K\024lw^\199@\015\2305*\012\210\148*\172\\\1752\021\028\248LL\166\021\019\025n\233\203\159\212V\200\014{j'\176Z\229\1901\151y\030\215\198\199\197H\221\170H\r)R\011K\127y]C'N^\224\192\196I\150_~\173\015\146\014\196\186\020\250\255B\020R\172va1sh9g\138\161\205KT\162*\241:\149\209\158\210hD${\236q\205\197\132\180i\016\132\217\162E0\164\151\018&\211\152L\021\160\177<\170kw$\028C7\247\016\1677\154aE;_\212e\229\196w\163`&\246b\177\023\162\006\178~\007$\235\138q \235\206\221~\211C\216=n\191\239N\201\142\180]e\238;E0o\185\0021\155nTehI\020m\158.h\206~sx\220nvw\219{Zhi\006g\237\164[\183\200\235\215\137\147\238!\202\158\208\176\208\218\136>AZ\205E\1312\213A\237?ko\232\182^\021\234\254/p\003su\169%P\246Kv)x\191\194\225w\238\145\225\r\1375DO\244\245\134{/\130\155W\160\n\186AT&\145\tif\1946\2439\019^u\252\175\162\141\025Q\027c\\(6Z5\227b\187\219J\251#/\016\028\234o\213^.\019\140f\195\184L0\244{V\135\234\203\246\2003\137}]\171\220\n\172\127<\168S<\157wJ\024\158NMvh\218\190ji\175%v\155\0039-\1538\138\025\153[$Q?\210:W)\003j\217\n\240\162\028f@n\143\248\209\220\022!\127%]1\237R\210\157M\227D\001m\018\226\141Eq\247X;K\182\240s\241\151\1994C\227w\196s\183NMGQ?Pn\2161\221R\236\151\204\023b\029\n\2222\025\197\240<*\142\136\224\019\214\235g\004N\006\000\142 \212\018E\172\187\130(\b\000\151\017\nD\145P$\138\136\1917\000\016\005\161.QD\217\133\001\\\187\\\162 \145\r%\t \148\132\250\161$!\134\146` \nB\129(\"\250\017\001I\020\132 Q$\216%\138(\020DA\000\016\005\161\030Q\144\200\018\005\t\128(\b\245\137\130\132H\020\004#Q\016\172\137\"\130\130(\"\176F\rI\020\132 Q\016\236\016E\148\004\012Fp\179+\148\179+\148\178+\184\217\021\250\178+\248\217e\136\130`M\020\017|\194z\253\140\192\201\000@\020\132Z\162\016N\016l!Qp\158\020\001o(\017\146\135\016\190\247Q\160\017)r\185D(\\\248h\217t\151Z\164\220f\128\148B\026H\145\159\011R\003\019B\202\128s\164\b\136G\136>\186\168\164 \t#\015)\153KFBC0\146D\129\150\164\200\227&)\183\004%\165\192RR\228S\149\212@\190\1462$-)\211\204%$\130\190\004\186vu%\145I\024\217L\202\028J\019\226\224\1349\148\147<\188\146\228\1617\201C9\201\195\171I\030z\146\220P\159\148i\254\019\146'\151\179\158]\244\228\163\192\137Rd\1371#\130\022\025\003\167\179\000(Q\b\144\016\179\232\189\135\001\025\178\192\165\194,\190\240\176\146\177.\t\178\212f\007\203 7X\224g\006\2031/X\002\212\199\002 \190,\248\232`\146\244\024D\202\019\018\151\240\178\\\208\029c@v,\240\168\142\165\150\232X\0064\199\002\159\228X\142\020\199\018$8\150hz\203\184 \183\140\173\029=Il\012\"\173\177\196!\181\012\005'\132\161\148\174\1617]CO\186\134R\186\134W\2105\020\211\213\144\024K4\133e\252\201\225\150g\007;y\024P\023\011,q\197\178\n\214\"\000\220J(\240UB\145\172\"\254\222\000@S\132\186\028\021e\023\006p\237r\169\137D6\208$\128(\019\234\135\152\132\024_\130\129\139\b\005\"\138\232G\004$\005\017\130\252\147`\151|\162P0\015\001@;\132z\156C\"K8$\000\182!\212\167\026\018\"\207\016\140$C\176f\152\b\nz\137\192\0265$\177\016\130\172B\176C)Q\0180\024\193\205\174P\206\174P\202\174\224fW\232\203\174\224g\151\161\014\1305oD\240\t\235\2453\002'\003\000W\016j\137\130\172\019L\145\016pZ\130\129+2\140dA\130\247\022\001\186H\176\203\023$\188\176\136o\158K\025If\163\154$\016\214\004\251qMR\012l\194\1297\018\012\196A\240G\131H\234H\016rG\198]\242 \169`\143\132\000}$\216\227\143$\179\004\146$\192 \t\246)$I\145C\018\142$\146p\205\"\132\n\026!dmt$\145$\b\153$\225\014\149\144(\152\240\004?\241BO\226\133b\226\005?\241Bo\226\133B\226\025JI\184\230\020B\159\012\007<\027\228d\017\224\149\004[b!c\004\177$\004\028\152` \150\012#\177\144\224\189E\128X\018\236\018\011\t/,\226\155\231\018K\146\217\248&\t\1967\193~|\147\020\227\155p \150\004\003\177\016\252\209 \146X\018\132\196\146q\151XH*\136%!@,\t\246\136%\201,\177$\t\016K\130}bIR$\150\132#\177$\\\019\011\161\130X\bY\027\029I,\tBbI\184C,$\n&<\193O\188\208\147x\161\152x\193O\188\208\155x\161\144x\134X\018\174\137\133\208'\195\001\207\0069Y\004\136%\193\150X\186\151\nZ\137\215\224\188\b\002\165\016\136\132\210\193\239\241\026\200$\130.\149t\162\011\188\246\012rI$Jl$#\014q\140\160\031\197(\195\024F\020\168#\130@\028\029\248\017\174%iD\000)\131P\1510:\153\160\139x\rd\017A\143*\162\196\018E\196\129&\"\232\147D\148!ED\020\t\"\162\154\030\186+A\014\221\245\026\228\146\024\"\128\180\016Q\135\020:A\000\215\007/\133B1\133B!\133\130\151B\161'\133\130\155B\134\004\"\170)\160\187z\130\186\250\012\215'\188\134\170\031A[\241c\186\138\154O\000\184\137P\168\251\t\197\202\031\241\247\006\128\234O\168[\255\163\236\194\000\174].\005\144\200\006\144\004\016AB\253\016\146\016cH0\240\000\161@\004\241\242#\002\146\n\bA.H\176K\006Q(\216\128\000\160\003B=> \145%\004\018\000#\016\234S\002\t\145\019\bFR X\179B\004\005-D`\141\026\146\024\bAf \216\161\134(\t\024\140\224fW(gW(eWp\179+\244eW\240\179\203P\004\193\154#\"\248\132\245\250\025\129\147\001\128'\b5D\241\2076\199F\249wvu\002\164\143\024\149\174O\024y\134\001\237\020\198\147?\024I\174`$z!_\199\191\249p6N\215\244w\026\018\240SR\152\164\235\164\144\128X.\208\138 \170\198j\n\170\0174\170D\144\168L0\168\2558)\016h\226\223\rj\249\027-\172]\131j\199\160\026\223]\187\029\144w\249\139\019\002\209\157\218w\233L\029\003)\135\217\175\135\166\238\204\210\239\196\019\025 \191\n@vh\t\254w[\019\168\181\254w\174\t\012Pn1 }\193(\251\1301\242\005\003\169\204\140\16480\018s\139\175\201\t\025\216\200\223h\237\006\173\221\184\214n\028k7h\237\198X\1871\214n\192\218\rZ\171\251\031\255\198\142\199\191\219\030qV\014X\156\224Z\031\028\235\003Z\015\029_\198M\169\130)UP\165:o\199\132\179\252[\147\207\185\030\t2j\184\230<\143\255\024p\1354\231<\234c\132\234\006\003\154r\206\007\220\206\156g\134a \213\004\006l;y.\025F`\2040\012\234&\243\156\025\134\017h(\207[\134\225\223ha\237\026T;\006\213\248n`\024\198\141M\137a\024\208-\244\185\024\159\157\227\208\236\220\029\149\157;\003\178s\028\139\157\023\134a\231f\004vn\006_\2310\238:o\007T9\234'\204\198\147\205;Iz\023\005\024\030\163d^~+\133W^\tY\175d~\005P*X\023\148\016\170\133\146A\r\1452\017r\005CV*\025T!-s\146W)\216<\214b[\199\148\028R^\2010\203\149\016+\161\020\214\005\184\199\t\245k\005\173\251\011Z\247\020\164P\141\149J_Y\177r+\025\212s)\019U^\193P\251\149\204#\002\165`9A\137\129\030\148\204g\n\165\130\164\161\132\200\031J\168\169D\138N~M9\2450\131\229\154\223\186\201\197Q\190H\243\138\002QS\138\025\191\150\023\235\179\166K\141\2541g\214\146 \250B:\137\016tR\130]'\229\233\t@\132\147\242\252D.\149\158\160@\216qR\148\148\156$\164\232\164(:a\169\209I\132:N\018\133V\174\146\184q\152\018\250n\019\232u\001\151.\020\176r\164\196\141;\165\208s\170\144\023]\139:\198\193\154\160<\191\025g\251\004\149\196\177\145\144\206&\004\221\156`\215\193Qxm\016\225\212\bHw\018\130\142$\216qa\148\148\156'\164\232\182(:a\169\209U\132\026']\136\017\241\005\142\136/pD|\225\142\136/\156\017\241\005\142\136/\204\136\248\194\140\136/`D|\129#\226\1396\154\211\252[w\211. \130\025\190\206m\214E\027\181\\\242\191\006g\243\244\251s\142\230E\014\027\003\\\188\140\209`7\191$\rv\019\016\159!\156K\000x\152Pp3\161\158\175Id\029N\002\240:\161\232z\130\209\255\004\235 l\"\b\145\200-\163.0\198\196k\023\181LD'\183\138\019\005\1368\229fr\161\001\136\152i$\181\000b\167\023`\018*\156/\162(Q\b\165\020A<\165\200\011\170\148\219\200J)\132W\1380\198R\134\129\1502\029m)\129\144\2353\138\142\1590\248\197\019\138\142\130H\003}DobQ\145\016\250\224\222\194A!5\252c{\142\020\146DH0S\242cD\1580\006Y\194\002\200\017\022x\025\194R\155\031,\131\236`\001\230\006K03X\162\243\130q\200\ny\132\203x\0043\162p\128\203\136E6\2003M\019\196D&\200sN\011\131A\022x\167\156\140\0122 \227\024\255\232u\017|\002 \242\132B\216\t\245bN\"\027p\018@\180\t\197P\019\140q&X\007\153@\136p>\030\163\011\140\177\245\014\199h\153\136j>J2Q\128\136g>[\178\208\000D\210\156,\209\002\136a\0041\128j\024.\226\168q\b\167\022BT\181\208\011\174\214\1761\214r\b\181\022b\196\181\020\003\175\165:\254Z\006i\160\132\151\005\239aR\128\208\203\r\165\"RD\225\"S\020.\018F\225\"o4\014\233\163\1336\139\148\028\146I\2010\167((\"\155\018\002y\148`\200\160\004{\185\147d6k\146\004\242%\193\152)\t\199\028I\184\206\142\132B^\240\025\024(;\230\130{\002\006\132\"\254|Ld\162\017\017s>8\178\000\004\226l\143\141\128\004bK(F5\014\163DP\t\128\152\018\n!%\212\139(\137l@I\000\241$\020\195I0F\147`\029L\002!\150y\200\172\011\140\145\244\006\204Z&\226\152\135\203\019\005\136(\230\241\243B\003\016C3z\214\002\136`\0041\128\177\188\"\128\004@\000\t\133\000\018\234\005\144D6\128$\128\000\018\138\001$\024\003H\176\014 \129\016\192\188\237S\023\024\003\232m\250\2122\017\192\188Er\162\000\017\192\188gr\161\001\b\160\2171\169\005\016\192\bB\000?\180\177K\219S?\228\184\t\132b&\016\181y\144a1\011\195`\218>\200H\222'\200P\222(\200\016\237\020d\128\226\194\200F\148a\163\215]>\228\181|\006\156\213\151\015r-\1591\189\206\242\129\215\242\025\129\165\161\015i-\159\175\245\162\201\135\188\171e\153\000^\023\248\144\215\206\024\160\244\018\128]H\252 \151\198\004\198\235a\012\234u\196\015\188\242\197\b\236\212\249\208\174q\241o\180\176v\r\170\029\131j|w\237.\\~\224\021*F\244\018\229\135\188\022\149\129\188\171\133\252\250Q\236{\253\136\251^?\186\251^?:\251^?\226\190\215\143\133}\175\031\205\190\215\143f\223\235G\216\247\250\169]I\030\231\223\154)?\2335cF\r\019~\202\171\195\012\184\2516>\241:0#\228Y\0064\239}j)o\146\127\235MV\159\128\2322|\149\019\254S\246=\003N\r\252$}\207\152\174\129\159\208\247\140C\205\252\196\190gD\213\204O\130\135?\t\n\254\212\146m\198?\235l\255$)6aQED\146\000\b'\161^LId\003K\002\136.\161~\136I\136q&\024\130M(D\165\177\007cJ\149\246)\185\nNz9\251\148\\Y!\213\188}J\174\016\211\206\217\167\228\201d\n:k\194\190\204MG\001\202\164\1480\166\166\148\185\t*\021\1564\149bLV)+\164\172T1\137+\133&}\165\016\146X/\140{\153\183\246\157\246\217\2156\201\237\175\138\147\248O8-\244'\158\022\250S\173Ei\016U\213\193\n\r\026U}\024\ba\163.\n\129\183\b\017\220v)Ga\151f\020viFa\151\254(\236\210\027\133]\154Q\216\165\029\133]\218Q\216%\142\194.\205(\236\178%\155i\254\173k\193\165\166\021FM\190_f\002a\192\205\236K\166\nF\244\222\181\203L\n\025\216H\1317\198\183i\1728\207\128\239\218\141\231\218\141qm\030.\242\243\172g7\232\2174`\2047\221\214;\193\136\151y\000\153\001\245\210\202\148\170\130s\169\151z\012)`\175Xr\020)P*l6\1782e\173lY\191\158\190\127\173\246\188\251\226\178\029Y\178\1846\166\215\190\161\181ghm\252\015\195K!0\198\166\241\165\208\1930\228\001fV9\168\011c\252\193\248\253\224\030\005\190\028\028\171\135-F9H\133`\030\030|\207\004\2073\193x&\148<\019\140g\130\rc\192\148}\150\023'ua\012\023\027e\210;\242\241\192\172\165\207\007\"\140\012\232\156\016D\153\227\022}F\016a\195\138pJ\016qp\137>'\b\176`J\221\199\007\212\227L\211\199\007\001\176\167\219\199\007!\242\168\238\227\003\n\140\026\209\141)\226\198\015\029\018,\161=\145\219\020#\183\241#gH\151\224B\2246n\224\144\131S/AUQ\213u\128\007X\187*\223#\134\156\019\\vIUt\137\203\213$\002\194&\212wVUp\150\225\239\b\215F\177\246\011[\247\148\170.\150\170\246\003]bw\146\250%3X\196/\238\193\143m\161\021\136B\167)\136\130`T\131\255\214\208\227\228Ptr\240\157\028z\157\028|'\135B\250\004\183\174=\027\228d\017\191\168^[\"|\171Z\020\137\155\167I\161i]\164\208\247\173\212\240<,\229\198\207Rh[\029)\181n\149Rt\174\148\153vHO\018L=\024\219\164\210$\129\171\224\180O\206$\129++\180U\222$\129+\196v\203\153$\240d\155\130{6}\201b\2183){5W6\175\228\202\166/Wl;'\133\189\169\178\233I\021\211\242\169Q\172\230%;\192u\031Y*A\213\231Y\219.*\225k\174\173^q\173\223RJ\005l/\165\172\207\245U\175\235m\011*\132u\225\166\186\207Q\245\171\190\168_\241E\221\151f\197VV\234\244\249\195\182\184R\216\147m\182\245\021\194C\t\239s\213\161/\167J\173\178@\189\182Y\136C\225\182\208gSx5|\225\149\240\133\190\240\133\255F\248B_\248Bo:\135\030&y.\224\167\018\222\231&\219\210_\137O\156\\\225\215M\174\240\195&W\003\239\155&W\206\231L\174\240K&W\230#&W\230\251%W\240\233\146+\252j\201\021l\193\184\194\221\023W\249T\003\000P0}\170\001P\175\136\230T\003\b\160\176p\170\001`,\246F\158j\000\016\028\224\157\015\184r\207\007\\\233\243\001\030\nNq\206\007x\"\207=\254\249\000O\n\142\242\206\007x2t\153=\031\224I\192y\197\205\243W\229\205\243Wr\243\188\197\192\133f\243\188\021x\238\2436\207[\025\184\206n\158\183\018t\027n\158\1838\184\172\176\215\252\170\180\215\252*\2395\007\000\028\165\247\154\003\234\185\200\2365\007\0018\007\246\154\003\140nQ{\205\001\004\135x\187\182\175\220]\219W\184k\219\199\1931\238\174m_\232\185\169\180k\219\151\131\211\252]\219\190\020]\232\237\218\246e\224\208\158\r\204W}\027\152\175x\0033\"\224R\216\192\140\176\231F\187\129\025%\224:\220\192\1408\186Ko`F\020\\\228\238\000\190\242w\000\167\021\200\183\022\001\183$\024\220\146`\207-If\221\146$\224\150\004\163[\018\142nI\184vKB\193-\004\131[\bE\183tO|\139\215\224\146\b\130C\"\232\185#J\1723\"\014\174\136 :\"\162\232\134\136j'D\012\\\208\129\224\128\014\131\226_\139/\172]\227\023\214\174\241\011k\215\003\239\011k\215\206\023\214\174\241\011k\215\230\011k\215\230\011k\215\240\133\181k\252\194\218u\251\237\220l\249{\029\143k\248bn\134/\228o\029\216kw\174\229\218\153`\185\198Y\149\235\194T\202\181\153?\185\198I\147k\156)\185\030\240\151\240\174\243\148\b\003TP\006\164\209\140\154\237\201\215y\142\131\129d\028#)\n\140\196(\2405Y\155\001\026\165M\249\154\166'f\004\200\144U\152Ti\238A\000^RUNR\201y\005\0061\211*\147i\149\201\1804S\144\129Z\254F\147k\215\194\218\177\176Fc`\132\207\18412\r\229\025\192\236\2311{r\180\0243\231h\004\017\169\128\185\020\220\212\tN\234\004L\029\024\2362nR*\152\148\n*\165\214-\235\204\242o\189=e\157Y\135\001g\015\244Z\178\014cz\015\244\154Y\135\017\216\127\189N\172\195\215z\243\243Zl\244Z\227\238\174\181\187\165k\237\236\227Z\227\230\173ua\199\214\218l\211Z\227\222\1725n\200Z\139]\250k\220\165\191\198]\250kw\151\254\218\217\165\191\198]\250k\179K\127mv\233\175a\151\254\026w\233\175\019c,\211u\14974\173\241\211\147k\252\244\228\218\253\244\228\218\249\244\228\218\251\244\228\026?=\1856\159\158\\\155OO\1743a\228\"\212BX\163\201\181ka\237XX\1631\254\183(\215\230[\148k\252\022\229\026\191E\185\206\132\145\253\028\1320\160\209\1935:8F\0074:\020\140\014\198\232`<\171\191\247\180ng\176rV\159\176\182\157L\189\250\220-D\141\242E\154\231b$-91\162f\005\025\022S\129\012\166\249?F\2422\018Cy\026\143!\154\187c \173\018e\164\161\149\229,\253NMN\006T\147\147Q\209\228d,59\025\128&'\227\185\201\201Hjr2\144\154\156\004lx2\2533/\2140\162\187&\159aY\134\245\236\151c>\243\002\012#\208\148|\022K-\172D\158e y6#\212$\206\249:vP\178\130\210\174L\177\242\242\136@\220rU^\185\212\234\007\163\166\180\149)meK\139K\026\159\007[\145\250[]?\026\000\142\224}\238\150=\242\189\181)j\237\023\172\246\nV\155\"\224\250\005\011r%a(-U0b\002\151{8\025\017=\156\028\206 kQ0\021>\248\213;x\213;\152\234\141s\250,\176\245>\216z\031\160\222\231\137gD\208l=\245\140\176[$3\249\140\018,\028L?#nJ\163&\160\017E>\203\007u\018y\232\131:\128z\244f\014\234\128\000\136\206=\168\003B\164<}P\007P \191\136J\222 \004+\017\193\192\133\132\186\245\139dN%#\t\2144\130\1451\b6\180A80%\161z8\2479-\029\168:\166\214\019\224\001\214\174\202\247\136\161\209\004\151]R\021]\226\178*\137|oU\190\183\170\130\183\012\211FX\208-\001\192\185\132\"\241F\1846\207\171}_\213=N\169\139N\169\253\146\151h\153\164\190_\012?\019\140$\173W\149\000v\232:\n\130a\138\2243`\232\161\186P\164\186\224S]\137\204IZ \194P B\228v\185\004\228\128X>\179\b\228H\220\194{\203@\142\016]`\023\130\028\145)*.\0059\002d\254,\017\228\207\024\240?\011\188&\128\165\182\021`\0254\004,\240\219\002\150cs\192\018h\017X\000\141B\022H^d\016+7K\160u`\129[\241Y\236\212}\022b\245g\t\214q\150\024\250c\017\180\023,\128&C\172\254\169\170\142\171\130\246I\174\177U\209k\166\005\017\146^\183U}ns\155\018\150\022\157Z\021\157Z\149\157j\154\149,\017-\011c\208\184\176\000\219\151,\169\189g\215E\151\214\253\142\171\251\028W\023]SjqX\193\012\bX\132\r\015K\176\2371\203\203V\226\180@Y\022<\210\nE\158\014\253l\028\250\2168\020\217\184\212&\177B\153\174C\153\174\161q\218\180\127\245l\156~?\139\223\252\201\213\r~mu\227|h\149(M<-\002\207\b\156\240\022|8\161\246\r\145\026\197\027\"\240\140\192\to\1937\016j\223 \002)^#\208g\023=\185O\192\183J\145}uF\196\1393\246\236`'\231^|%\011\236\011c\226\137\183E\224\025\129\019\222\130/!\212\190\129\242S\188\130\144g\131\156\204]\248\150\004\219\215\240\223\248\029k\228\217 's\023\190\198\254\141\223$I\127Gt,\175\159\225\250\004\250\248x\252;\162\t\207\127\128p\172\128g\004Nx\011\190\192\252\001B\018\2204\255\165\015\158\220\192\146\239\205`\151\223\211\252\214MK\003\168\245R\134\245Z\195\r\174\025\223\136?\135s\131\127\014\231\198\253s87\206\159\195\185\193?\135sS\248s87\230\207\225\220\152?\135s\003\127\014\231F\184\252F\204(\223\224\140\242\1413\163|\203\127\026\139\174\191\t\2177\207k\183z\188<\147\2247\212\242\159\160\207;\205$\248\r\181\nO\208'\168\2433\b\254f5\253\231t\141\231\241\251\230\150\215\192\226#\241+\223C#\004\tzD\012\027\019\240\1483Y\214\138j\240\"\240\147\192!~\149\019\191\202\011F\005\195V\133\n#\176q#\224\0055N\168\129\134\153\214.\t\188@Wp$J\161\194\186|\166G?\236\0055N\168\129\214\153\019>Y`\246Bfc\236^HG$\141\245\154W\137\190\184\186'W\215\020\192mt\147\212\012Df\128c\td+=\193\135<;\015~q\244N\142\030\218\237\181\220Y\150\135%hv\022\024\187\179D\026\158\193g\239\225/\158\230\201\2114\198\179\196Z\175v@&\251\244\014H\141\n\139\177\139B\192\011j\156P\003-4}\150$\208{\229\146!\176W\014`a\160\233\224$\228\197\232\156\140\014\026i\187\131\001X?\190\231\233\011F\212\250\241}\158\172\200\000y3_7Y\188\171\142\199v\248\189$H\170WX \216\127p\239\238?\184w\246\031\220{\251\015\238q\255\193\189\217\127po\246\031\220\139\237\006\247\184\221\224\222\221np\239l7\184\199\237\006\247\133\237\006\247f\187\193=n7\184\199\237\006\247\248w\019\239\161\1950Wp\196\168\127\241\165;r\148\127\167\017y\006\2104\016\003\2348\017\1931\241\014\006\128\199\017\n\207L\168\247`<\027\229\193\240\018\247d\148+s^(\255.\138\249\147(\222_C\2496\224\138\251-g0\003d\128\000l'\253\155\204`\129q\0063\168{\238\2238\131\025\129\030\250\1836\131\2497ZX\187\006\213\142A5\190\187vG\r\2238\131\025\209#\155o9\131\019\000\231*]\024,\247NU\2502\167\128\1333\149\190\216\198\193;Q\233\202\208\019\238\137JOX\023\224\030'\212\175\021\180\238/h\221S\144B\168\221\211\146\174\016\018\192;,I\178\135n\1780\255\214\181\251\001\166\0063*f\0043\166?p\250`\230\2552\014\0318}\016\179}\025Q\0318}\232N\251\205\210\239dc\006\1325\017\219\139B\237\177P{\183P{\167P{,\212\190P\168\189)\212\222\020j\015\133\146\243J{Q\192=\022p\239\021\144\023\027\135\n\128\162zK\141Zd\011\r\011\141\026\245\139\143\203\140\026FG\232EF\005\n\151\228\225\167.2:\199\012?\147\128\191w1T\000x\200\251\218\133\022Y\015\193\183.4\234{\b\190t\0010zH\127\232B\129\194C\252\153\011Ud\244\144\025\002g\001\156:\030:0z\171x\230\216Sp<\231\1578\246d\005/z\231\141]\161\241\168s\220\216\017I\239\194ac\199i\198\211\254Q\227$\142\196+\026U\167}\180\136_\b\130t\238G\163\249\240\143\134\243\t \r\2111 \r\166\179@\n\189A\224\214\000n\129i\249\198\160\180\028\131x\012\245J\129w\168u\215\020q\243\136\168yu\229\026T\185\006U\229\bT\165\b\168?\135\161%nl*?6\149\031\155{\004L\160\190\184\185\164\166Z@\246\021\129\173\001\\\159m\203\222\217\150\188\179u}\176\245}\176\245}\240_\b\024\141o=\165\221\025\192-\220\174\239\017\233\175\132(\244\001\001S\158\189\251\166\189\155z\251\158\247\239\221\186X\027\192}]]\142Z]\138Z\237F\r\255\172\138\022\250!\173]\215\213n\129\190\027\128\200]\019\193\127P\237`\000\215\017\007\215\239\135\030\191\027\191\028\221\007\031\221\007\031\011\228v\236y\161\005z\148\131\001\\\235B9\254\161\020\255\224\198?\244\197?\248\241\015~\149\014^\147\243\148\247\023\018\240\140\000\239\151%\224\132\026\169\193\006\148\011\170\005?\208\134\031\174\015\127\184\017\254\2250\191\247w\177j\247\239b\213y\1764R\247># \250)\184e\166v\183\204\212\165-3\223\243\138\208\140\174\243\194E\002NB\025\030\251\221{b\188\191\176?BJ}\017m\182\160\005\018\253\024\146M\133lW\221?\138_g\179\005\203\226Mwy\231\134\004SO\193H\164i\246a\007\239\150L.V\146\178\196\145\168jl\228G\023,\190\232X|\145 \029G\246\138\017\209\223TA\014\221>\239\252[OI\028r\015\150\001gz\226\1606qgLOJ\028\184\183\202\b\2046\028\242\014\237|\1576\200& n\222\153\240e\151\232\179t\189\029P\165:\164\206\r_\011\203\025\204\1343\020\237\230k2\155\001\178:\003\242\167t~Fw\226'X\181\243o\136\204\147\175\031\006\227\244s/~\198g\241u\204\023q-\158\205hti\190\254\206\222L4\145\221\201{\141\179\206\227`\154\127\202\231g4\176\217\001\n\027\188\016\004\027\130\000!\208-\018\195\024\153\128\145\137\237O\190|\226b\156\196\207h%_g\131\018\020\021DE!\000j\011\161Pe\b\245\234\r\137l\229!\001\212 B\177\026\017\140u\137`]\161\b\132Z\149&\194d\160\213\228\216L\129\\\201\232Z\135\153@'\214$1\001'\\G\157@\1361\161\016\232\180\017\017\174\189\186\021E;\188\246\138\176\235\185_W\208\br-\141\215{\188\214\245\149@]i\019\232\212\\\018\233\234K\211\149\0166\172\200\017\181\1819\226\\y\233\218\171\215i\225I\0239x~\011\197\208\135B\232\131\023z\191\214\235%'@\221\180\208$\144fr\181\011Nx\1739\001'i\019\206\127\191@\003@\012\250\175\023\000\234\017\131\253\227\005Z\000\196\000\127\186\000`$\006\253\151\0114\b\196 \255p\193\0040E\012\017db\160k\157\029\004:\217A\018\147\029\132\235\236 \0162\128P\200\128\180\191\024\174\189\138\029E;\188\246\138\176\235\185_\019C\004\153\024\226\245\030\17551\016\168\137!\129\0141\144H\019\003m\184\133\176!1\224_\r\208\218\\\251\233\218#\134\180\222\170\139\028<\191\133b\232C!\244\193\011\189O\012z\165\021P7-41\164eV\237\130\019^kb\1925\214\140\011GIz\1440\146\132\148!UH\153K\024R\193\161\r)F\242\1442C!Rh\136D\n\129N\164\bIE\200 \235\148D\019\140\016\t\154\145(d\156\020yy'\2296\251\164\020rP\1380\219\164\012sN\200\n\168K+\002\219\249h\185\224\187W\159\bt%D\130\180\004\186\247Q 0)\002\026S\"\143\204\164\002P\154\016}w\147\198\208\155\1449$'\164\130\207$\234\018\158\218>\225\185.\148#\018^I\197\208\155\138\161\156\138\005Rt6N\184\178\158d\005\154T\187&\\F\160[\250\163\235\195\229\223ha\237\026T;\006\213\248n\236\195e\220\216\148\251p\025\208=\227\031\185\r\000\000\172\213m\000\162NAL\027\128\002\235c\221\006\000\138%\1316@\195\181\001\220\226\212e\195\235\146\225\181k^! \208\006\000\012\161\209m@B\163\199-\000\005\"\020\226\147P\167\152$\178\197L\002\027\031\146\128\003\b\1972\018\140\241\137pm\000\1838u\217\240\186dx\237\154W\136\015\t}\2191>\132B|\216O>\b\005\019\018\136\149\1488\197\022b[t)\180q\019Rp\142\144\160\015\132\bc\200\162\218\005\139E\174\251\011V\247\021\172.\154^\136\173P(\151\rc,$\028\231_\246w\231\213a\255a\179=\028\211\197\207\155\199M\251\251]\189\127\252\189z\031\1837\219\245a\1879\254\237\213\155\230A7\219\135\187?\175\191l\026\027w\181\248\243\177)\190>\2200\247\234\151\245\183\127%\147\207G\139W\159\232z:.^\253t\188n\237y\232\136\215\027\254tV\012\231\175\254|\188\249\215\229`\212\016\205\213\170\185\154\012\155\171\198\183\219\030a\223\030\143\166\175~\025\140\139\193?\006\151\159\006\197|\209\\\25218~[7\214\251\199\224\231\193\144\254\251G[j\156J\141\187\139?\006\155\151\235\221\250\190+\182l\203\020\147I[\143Tv\146\202N\230\147\174\236_\213\1901\229\231]*\189\024L&\243\198/gZ~\154\202O\167\179\174\252Cu\255\185\237\211\187\135\238\027M\169a\211\224\197`\182\164\2423_\254f\191\219\173\015]\217q\227J\163\209t0-\198\131\249|\154\138\207S\241\197b\217\021\255\1829\\\183C\164-\223x\221\217h9X\204FMm\168\165\139T|^\020]\241\245}\243\133c\211+\221\023\166\147\238\011\243\225H\171\191\244\006\236\154\155<\175\253F;\252&\211A1\\\2027&Co\204o\235\195\230a\183\185M_h\204\209\244\225\162\233\158\198\164\173-\219o\140\130o\2323\154\026u_)\026\011\201W\168_\199\212\236\245\177\173\213\241kjw\211\003\139\230\255f\176I\165\168\135\167\139\212k\223v\213\177+;i\251w\218\244\239t8K%'\190\193\215\141\230\172S[[\235\204\154z4U\031M\168\244\212W\253K\253\237\203\230\129kQ4\1575n\238;\158\164\206\154\204\252\189\027\219o\2477|\243\161\191\243\028~\233\138\1585\207j\187i\213aYt\130S4\173+R\209\165/z\220\220o]\241\228\148\230\027\179\161w\246];\151t\021i\004a\209\152j\214\020M\227h6\242E7\127U\235\029\015\140f\012\181#c\210\212\189+[\248\178w\237d\1909\244\221\153:o6\026\145pl\142\221d\215\185Z7\234\026;\205\139\228\1913\234\190e+k\237x\166\161?\"\tk\139\146\171\207\166^\194~J]\215\222q>\212\017?\155\249b?w\197\230\173\235\206f\170V\179\185/\246Kj|\018\194\217b\162\143\005\229|m\238\183\152\234\253\168\183f\221\141\255\024\1881\197\n\149\213\249\208[\231W-6m\204.\197\168{\230$\002\255\180\181\155\143\198R\187y\225k\247\175t\191Q\251\216\169y\236\216\139\202o^{\164\024\012\166\223\147\137[Wk&\184\133)\b}\241\182+\184h\007\242\188\208\190\152\207|k\223\217\214\142\181\024\207e\228\233\255VY\154\207\212\196s\232\137?\180\216lj\234\182\244\182;w\182\027k\207.\134\190\203\222\219.\211\190X@_|\144\2515\138\214\222K\238\007}\241\209\220on\2387\246\143\2533\r\164e\242\188b\169\247\155x\235]\164\161\209v\218\180\157\018\249~\208\023ezl\210)\235\004\139\153\127\240j@\179lS\191\137\185\031\245\198r\146\134\251e*\2146cY\232\000Z,\252\221>i\237fS\237\219\005\140\139\171Tl\n\197\1500.\254cty\161\139\170%\172\024>7\011\241\175\155GYe\204\186\025\178\153x\219uI\145Tq\tK\193\207\205WNO\170\203q\248\020]\153\020\147\244\152b>\212\199L\188J\174\143\215\219\237\245\246p]\165\005e\163\162\227f\253\214N\006<\203,aB\170\218\165\238\177Y\167\243J\245l\212X\160e\207h\213\183\132\133D\183*\211\2147\139\178f t\1392\210\215%\204MiES\180\206\214,}\138y'\221]\193\133\239\128\207\233\142\163Tp\174\238\177\132U\196ur\223\t\221q\"wl\2466\254\1507\174\164q\204\209\016\214\0174\219\143\233\158\011s\207\194w\205mr\167v\018\0247w\235\154\221\200\204\182Y3t\023\187\193\237\142\190\t\243\210\221\128f\187\179b\212\152\161\241E}\b\012\188\228)\179\206\025'3S\237\169\239\141\173\nR\234\131)\149\131^\251\175d\136\246\201\019(\t\221\245U\23985\171\218\209p\225\239\184\131'K9\234,\222%\220\171\238/\154\005\151\180x\004]\245\224[\172\229F\190\220\222u\233\220t\212\168\240%\191\241 hwrP\020W\012r\211\174h\163\178Z\148z\134\151\255\007m\207xnzp\132K\189\129\172\199\154z\182k2)9\243\014\245\200\014u\150Td6\231\130s_\203*=z\150n\217,\244\167\227\130J\194\154\252)\221r\220\025sl\202\193D\245\172\190j1$\185M\157\180h\251\179\241\243\246\011\188\137m\229-\191\127\174\179\227\166\153\250\128Y \180\143\219\221\205\134%k4\027w{\229q\187\251k\1912\131i#\237\243o\246\207\180\150n\253\162\153e\218\237\1904}\006\219\021\217]w\222\222\244q\171u\179\130\006\218\012\182,\237\182\180\137\233$\145\233\246\227\179\174\179dd\242\194wD\243\226m\027R\226er\138\030\181\179\210XwE\163\0258uM\187\151\179$\015S\153WF3\216\190\220\238\246\135-\223\186\243\135a\218\154\209\1327\154\129\238\0287Z\153\174\189\139I\218\198\020\252\005\240\241\235\234\208\236\221\175k\154S\219U\207\180\217\192\204\1984zxy\\\140\205\196u\220vA\182n\1852\236\002(\237}\197D\188Vf'\229\136\139\206w\147n\190\155\140u?1\154\195 \184\171\182\205\023\238\247\186Fh\022.M\237&\179\180\162M_\130Y\165\253RW9\253R\215\164b:4_\026\247|I\2537\250\022\204-\183[\029\245\211\137\1770/\177\165\224\174\175 \244]\0190\227\197M3\027\180S|Ct\149\236JC\199\221\172\239\238x/\215jYc\191\180g\230NXF\2299\238\021~\133\215\213>\218\209\142\159\205aC\001\167Eg\244\162\249\218\152\";\163\005\012\184&\026\180\190;\172\191\209:\173\211\154Q'c\243!\141\b^J\143\167\1645M\204w#\n\222D\135\027\231\029v\0035\021\135\016\143:\225\231\245Qb!gm$\166\157EGla^a\163#\234\183&\233[\173'\234\183f\241\183L\016m\210\005\209:\255\021\227\205{\252\215xU\238\192\188\024o\214\\\233aM\148v\251\237\184M\243^\023ZX6k\006\1421\141xU.\229\155>z\252\178\175$\"x\150V\197]\240Z\004h\t\179?o\237EH\155\bK\243\173i\183\184\019!\197\213t\211\167\020\2069k4z\214,\182\218ia>\229\135L|\241\245u\245\184\161.]t\197\199mP@\138C .\173\184ow\155\023\145\187\238;\205T\160\223\1939_&\143\198\153\155\214\r;\135\018q\22854\023\191__\031X\168g\233\238\227v\161@=\184\132\016\207\231\195F\218K\165ms!\202s\179\127\\_\203\\\211.Eg\237\"q\220n4R8\166\024B\160\245f\219\140+\238\235YW~\220\238_\165<\168\219\129\231\165F\160\167m\b\169\145\1549-s\138!\244\214\245\230\166q@\n\132\166\019\141b2\165\248y1\1960h\245p\183>T\247\187u\149\026\176\236ZP\b\178\0253\205*\215d\026dfTe2V\236]\134\024\029\235[\129HY\179\152\235]\173\208\194\233\190\218=n\191\237R0\173Y:\141\210\1887\156\198F1\227\191\127\000\169\154\170\131\243I\"\214\131\213\162\137\192 8\236\191n\030\2361\193h:L\199\004\195xiu\216\220m\143\026L\212\181\213\"\155jd~\210\225g\178(z[\235\133Z\242$2\161\166\173\247\177j&?\t\152\183\235\1476\192\222.(\135\177\166\190Q\229\232\245H\153\146\208\244\139~o\217\027\0150\167r\232\0012!\153m\145LF=\203\241\255\152\173b_\217\233$U\1532\1324\169(e\142\181\233\139\195xBz\243H\001\128\190\165\184,\236\236\164\203\139\012\155\175\147-L\251V\179\197h\156=\133m\254hT\178;\n\156\180Kq\176\162(\128\221\006\141y\025\176\232\223\006\217\136W\193K\235Qo\147\1272\189\244\195i\198\171\145\020\239\011H\152\025\236D@\130O\t\161\"\237Q!\150\021\1696\141\028\205\210\222\176\141\229\240Qw6\243f\011\246h\230\021?\2075t~\"\144bW\128\170\232\179\158\254<\154\155\247\175\215\165\161=1\160l\190\227\134\194\140\244?Xg\148F-N\237\155ic\187\217=r\188\182\141\144\182\195#\030\254\143\178\190L\231\242\011\151\232\145\173\167\158\247n5\181l\020\1889c5\137\144YS\157ilCG\241R\230^\015\213\187\163\255`\183/f7\199\b\211!\231=\244\201b\022\027#\175\137bc\162\209v\152\146\007\207\198\203\204>\146\222\162\001\005\190{\176\242]\140'\003Y\1576\250xht\242(\163\164\181\207r\153\025T\150\226n\199\193\187\242\"\015)Lh\196\238`\138\159\012\251\183\204oQ(\155\163\168\180\1333\025}\216\232w\176\145h#\218\232\152\018\161\2147\n\200\031\218\028\233\229t\150\221]\215V~\195\212\191\184\146\153;s\139\209\137E\141=\201\025\143\187\165d\209\187\249x\007\219a\027\188\199\222m\028\231\203zw\203s_\234\215|\160\240|\217F\203\205d\185\228|\232a\\\147=H\200\t\t\148e\164I\144\144e$\174\149Xn\178\209\194\170\179\024\245\238\018\223\224\142\242\196\026{c\245X\251\180o\149rg\214n&]\011\155jlO\227\202\153\1276;1\172t\207\218\191\195\213\210\024\187=1\016E\n3\155\158\208}\030\1897\205\244L\249\244\211y\179\004\153\165\179\174Q\017{\133\186\254\t\135\208u\212\026\226\005Q\128Lv\022z\239SA\154\t\175Xo\182\215k\201W8\235\178\195\155\129\213S\149\215\024gj\150\127\189\139\225\190P\172M\255\2026:\198\249e\163S\140c+jYk\197\158\161\242\017\1713\167@\181M\248\205\133\164\231K\145\162\200\194\206\132(eU\007m\144\178vA:L3\215|R\244\223[\163\195rk<#`?\214jX\007\134\138\200\130\017\244[\022\141\160\222\186[_g\001\240^\2416\141\236v\128\221\154>\152\170$\151\178o#`3+\179P\140\221\199\182\153\000\211n\218\234\153|z\195\019}\227\234\193\204\207}\187{Y\127eq\240!\159\150k\154\"\214\127\183\191k\135\226\195\254Q\026\209.\243\204\219\029\217\000p\1396;\006\138\248\011\149\207?0\242\128\001\016\146\135\1662:\2175+\193\179I\027\220n\026?\143\231\174\187,\182lf\129E\207\132\183\161\r\229\137A,^jv\182}\219\026\2370t\162)\159L\2052\253\145\012\135\007\031\135l\132\188]:\023\237\187\003\163\158]\133]\154tg\226\139i\239\134\229ME/}\233\187\141o\030n\204K\145\233-\201\183\155\195\195\235\245\227Z?\189_o\155\197gs ?z\245\246\253\167\193O\131\230\222\147!_\167\025\221\000\201N\022\160\229\168B\255l\151]|\157\230m\003X\227)|n\190\127\142\015\181\219%\131\138\207\025,\205Q\006ps\174\193\201\182\006I9\005\006H2\167\192\007s}18[\2025\217\196\000\182\141\002\151\166\189t\012j\000\219FE\181\141\138Q\027\021\240mT\156\219\168\b\233\165A:\217\215\207\171\198\211\248\250\178\tz\240\245U\171\175\242\129*o\016\173\167\130U#~rM_Q\192\182WQ\189\143b\212^\005|{\021\231\246*\194\237U$\181W>?\153>}6xm\175\177\238u^\203T\196\012\029\002\192\149\t\133A\196(\142\164\132\155\225D\000\140)B\195\129\149\184s\188\231yX\175p\156\017\149\0156\"`\196\017\026\015;\"q\236\017\012\003\144P\024\133\t\253\128\128\025\143\004\192\160d4\026\153\137+\209j8F\t\141\006*Q\249h%\002\134,\161\241\184%\018\007/\1938\130\t\246\1958\129f,'\192\012\232\004\216QM\b\014m\130\131\241\157\152\n\199\000\142tB\163\225NT\223h\194\129Oh<\250\137D\t \024u\128`/\006\t|B\215z\198\018u\006\132M\014T\"\r\\\163\018\004\192h$\020T\130QT\137\132\027\149 \000T\130\208P%\018w\142\247<\015\235\021\170\004Q\185J\016\001*Ah\172\018D\162J\016\012*A(\168DB? `T\130\000P\tF#\149H\\\137VC\149 4R\t\162r\149 \002T\130\208X%\136D\149 \024U\130`\175\018\t4*\145\000\163\018\t\176*A\b\170\004\193\129J$\166\1941\128*Ah\164\018D\245\141&T\tBc\149 \018U\130`T\t\130\189J$\240\t]\235\025K\212\025\01669P\tc\004#\021\022\133qi)\016\rG\161r\024\210\200\135EAC,\021\n\137)p\030>\231\188\191\234\161\174X>\023\023\203\130\194X*\150\025[\002\181\198r 8\150\002\2131\212\135\0165\250cQ\016!GEJd\n\148\161\237Q\147,\021\t\147\229su\178,H\148\165b\157\178%P\172,\135\138e9/[\1341\218eP#`\006\181*fa\1482\203\005zf\232*\028\178\168l\150\138\228\205\242'\181\000\133\206R\177\218\217\018(y\150C\221\179\156\023?\195<\133\030\254\028\150\173c\180\223R\129*\nb4Q1\144\021%@\015\r\129j(\148\209B\197@\t\149\buP\232\243\224\254\231}\149\r\021P\217\\\255\148\003\245S\"\214>\229Q\249\148\001\221S\002TO\136\015\001f\020O1\208;CDj't\025\216\023\149N\137H\231\148\205UN9\2088%b\133S\030\245M\025T7e\188\182\tn\148M0\163k\130YUS\0165M\153@\209\004\170\130\193\134j\166D\164e\202\158\024\191\168cJ\196*\166\161k=c\137:\003\194&\007*A\18132\193\b\140G\134A(\004F\165 \194H\005#\160\021\012\135bA\228yv\223\243\184z\161^0\151\011\0063\160\024\012\199\146\193,j\006\227 \026\012\131j\016\252!C\140n0\002\194!p\164\028D\150\153\rQ;\024\142\196\131\185\\=\152\001\249`8\214\015fQ@\024G\005a\220K\b\161FC\b1\"B\136U\017\134PF\024\015t\132\168*\027&\168$\012GR\194\\\239\152C1a8V\019fQN\024G=a\220\011\n\161O\153\215=ge\234\028\137[\031\168\nU\198\168\n#0l\025\006U\017\024U\133\b\163*\140\128\1700\028\170\n\145\231\217}\207\227\234\133\170\194\\\174*\204\128\1700\028\171\n\179\168*\140\131\1700\012\170B\240\135\0121\170\194\b\168\138\192\145\170\016Yf6DUa8R\021\230rUa\006T\133\225XU\152EUa\028U\133q\175*\132\026U!\196\168\n!VU\024BUae^\247\156\149\169s$n}\160*\221C\141\166\164\2070d\019\bzB \170I\007\027-I\159AI\018\024\234HG\157\195\253\206\163\n\133\n\146\152\\?\018\014\234\145\192X;\018\135\202\145P\208\141\004\130jt\224\007\248l\020#}\006\189 0R\139\142*\193N\168\020\t\140t\"1\185J$\0284\"\129\177B$\014\245!\161\168\014\t\245\218\208}2\202\208}6\186\208}\182\170\144\000\212\132\132\006\138\208\017\02188\170A\002#-HL\2078A\029H`\172\002\137C\rH(*@B\253\248\239>=\129\255<\003_\227\231\168\157\193\168O\190j\134=\0010\204\b\133\129\207(\142\252\132\155\161O\000\140}B\195\193\159\184s\188\231yX\175p\252\019\149\011\000\017\160\000\132\198\018@$j\000\193 \002\132\130\n\164\143\031\0160:@\000\b\001\163\145\018$\174D\171\161\022\016\026\137\001Q\185\026\016\001r@h\172\007D\162 \016\140\138@\176\151\132\004\026MH\128\017\133\004XU \004e\129\224@\023\018S\225\024@e 4\146\006\162\250F\019\138\003\161\177:\016\137\242@0\234\003\193^ \018\248\132\174\245\140%\234\012\b\155\156\171\196\207\131\159\236\181\255\214\207|\226m\128\192h?\155x\170\193\188\169~\150m\143A\192\006?\147\152\153\2074\212\004hF\196H\174\2171\004\176\149S\2128\138`T9\005|\023*\206\149V\132+\173H\1704}~\221Zt\"\215^\213^\139E\021\b\020\238\181\181\168b^\215^\171E\021\225\202)\146*\167\159\189x\189n\135\164\\_\154\235f \206\229\154Z\161\128VO\176\244\1517\184\171^\243_\203\016 \169\1591\014\001`!B\193L\132F\182\"*7\024\017`5B\209t\004\163\253\b\246F$\016,\153\208\021\002\151\b\024\195\018\000\214%47q\"\192\206\t\204\140\221\189\212h\141\157\0004vB\209\216\t\r\141\157\168\192\216\137@c'43v\1303c'\024\140\157@4v\135\174\016\184D\192\026;\001h\236\132\006\198\238\b4v\007\130\177\127m\237\188\144kz\128\002d]\005\172a\021\213*(F\230T\128-\169\b\027Q\145d?\253L\166\019`\221\190\166\203\215T[\005\168\182\n\216\218*\170\181U\140j\171\000\215V\017\174\173\"\169\182\250\153j+\000\245@\251'\183\018\192\214g\228\247\214\252\133\\\251\006\253.\230W h\208\239\214\252\138\249\006\253\174\230W\004\026\244;\155_?\251\006\253\206\r\146\207\220\030\001*{\141\205\169\194\218WA\237+\172=,S\020\207ZUe\173\170\\\171\222\182\203\247\177\\\251U\195[\191hW4[$\188\149\165\186\002\225R\234\173.\208\021\161\181\185\002~\173\240v\208\206\239S\190\230\181\130\000\180\0247\128]<\bj\022\015\138\201\235q\006\228\021\133\000\178r\016DV\014\140\236\155\218\2025[Q\000gEA\141\021\005c+\n\000V\020\\\172(\b[Q\000\182\"\003\149\177h\133=]\133=]\005=]aOW==]e=\141K\229\183\176J~\219.\127'r\237\167\184\183v\209\203\152\221r\025Ov04\213qQ\171]\129\220\000\142\006[8.6\139+\130\022r$\012\011\199\193\b\177\156q]\007\195\184q\028\012!\207\005\163\201\021\200\007\150\167\2431\230x\024n\142\195\145\231H\028\132\1504\227\209\19304\029\023\141RW \031\176\142\134\177\235\184x\024\187\"8\162\029\t\131\219q0\206-W\197.R\157\024\018\213\143\134DuzHT'\134D\245\227!Q\157\026\018\153~8\210K\137\165\234X0P`\028\151i\205;\019\007z\135!\160wq\244\231]\187\176\229\160\198\187vQ\187\224\2356k\0246\166jl2\026\167\239\029\"\247\195\001\198N\014\006ky.\178\153\005\173\229,n\236gakE\135\163-\029\025X\212\242}v\205\202\156*P\199FCK\247\0129\166\147\236\025K\019\0006f4\178n\226\172]\019b,\154\000kKB\208\138\004\007\246KL\159\229\012\027S56\025\237Dhf\161\243v\2034\149k\031T>\151-\147\002A\128\249\220n\153\020\243a\229s\2212)\002\241\226s\2222\233g\154\155\004\184\0169=\151^4\128\237@\129W\230\251\151\230\250\147\185\214\232\1929\006\006\206\131\152\1929\239\221\228!\188wc \221\195\024\151\000\1760\161`fB#[\019\149\027\156\b\176:\161hz\130\209\254\004\251N \016zB\180\2227\024\251$\210z\207\173\240\158\151\b|B\192t\150\151~@\243nK\004\244]\002\177\003\141\241M/Z\020\186\210R\208\159\150\138:\213\242y\207Z\022\186\215R\216\199\150\195\142\182\156\239m\203@\151\251w\161\002;a\231\247\190\011\021\020X\133\207\185\012\209O!j\188\"xE(\162r\2550,8\137a\208S\2286\198O\020\003/Q\002|D\137\200C\148\205\253C9\240\014%\2087\148A\207P\198\251\133\226\224\021\246m\145\204\"\232\017=o\139d\244*\184\255e\128}\n0\227\007\217K\0219\145\251\128 \224\001\130c\255'\171\155\206'\000z\158P\232vB\163>'*\239p\"\160\183\t\197\174&\024\251\153`\223\201\004B\015K2\190o0\246m\148\140\239\185\021\222\243\018\129O\b\152\206\244\185\236\128\230\221\152\b\232\195\004b\007\186]\165\233G\143Cwz\018z\213\147Q\231\250\018y\031{\030\186\218\147\216\227\158\197\142\247\172\239\127\207\129\0278\242\162\199z\232\020@F\190\225\138\172z\158w\217\131\127\234\193\141\223x\028\220\199\147\185\0239\030\156\201q\232S\212)\198\155\024\001?b\024<\136\225\200w\152\203\189\134\025\240\023\134\209S\024G\031a\220{\007\163\224\023\154t\015mG_\b\147\238\129\\e\247\189\204\144O\025bz\027r\213\017\206{\152\024\232[B\177W\2116\202t*\001\208\167\132B\151\018\026\245(Qy\135\018\001\253I(v'\193\216\155\004\251\206$\016\250R\246\203\190\193\216\147\209~\217s+\188\231%\002\159\0160\157\232\183\207\128\230]\152\b\232\193\004b\007\166\246\154\014$\000:\144P\232@B\163\014$*\239@\"\160\003\t\197\014$\024;\144`\223\129\004B\007J\194\153o0v`\148p\230\185\021\222\243\018\129O\b\152\014\244\249Z\128\230\029\152\b\232\192\004B\007\190o\251\142\207{\223K\191\025\132\250\204 >\023H`\155\012$\160d\003\t\162i?\002i\222\143@\156\248#\000\245\139\"\154;\240^\206\218\021\240\217U\239\253Y\187\162Y\252\230\189\156\181+\000\017\240\247z\214\174\136\139u\191\151\179v\001\248\172\189`\192\146\027\172>\159\255\024 \170\254&\168\190=\222Q\016\219\180\201\218\180\201\218\1807N\178\247\145\249\247\254pF\209,H\255^\142a\020\b\211E\223\235\129\139\">I\244\189\028\173\b \025\011d\215\015&\141\237\003\166\177}\b\211\216>\004il\0310\141\237CO\026\219\135,\141\237C\150\198\246\001\210\216>\1443H\149\169\017\244\249c{n\170\215>K\225\163?!U4\203R\248(g\161\n\132Y\n\031\245\212S\0172\188\002>\213\226c\171\136zM\222j\000\171\131\002\151\246\026\219U\134\237*\131v\149\216\174\178\167]e\214\174\018\178/>r\215\200g\149\233\143&\229\233c\171\197\130_\249\201\237\163U`\198R\017\211\147\004@\179\t\141\218NTn\000\"\192\n\132\198\166 \018\237A0t6\161\208\227\018\159\004\000\250>\138Oz\174\204\128\208&e\191M\202>\155\148\161M\202S6)c\155d\142B\176\247\022\012\184~\148\128\235\196\001WX\002=(\139\1752\145\172k\220\136\0000\025\161\145\201\136\202MF\004\152\140\208\216dD\162\201\b\0067\"\020\220(\161\023\025\000n\196h\228F\137+3 \180I\217o\147\178\207&eh\147\242\148M\202\216&\153\027\017\236\221H\210[}\175\0277\146\244V_\002\221(Ko\021\194g\229\020\017\140\230\235\203\202\t\011\004\166\012\178rB\174\199\172QVNH\162\219\005Y9\017w\209\003\163#\246\158\022G%\202\030\248\132m\203\031\217\182p\137\128\209K(\014U\130Q8\t\246\234I \012e~\tj\151\027\b\1964\129\027\244e\148UBA[\025\r\004\150\168\190\177\018I-1\160\183\132\162\232\018\140\202\155\224L~\019\188\199f\239\195\254\222\247\247\236\190\175g\247a\207\246\1363\145q\183\163L\019\026v0\nvB\015\025\01663\214\239\196\005\"\158\136\nE\161\n5\174\234W\179\170O\205\170P\205z$\158\200X\234\170X\234\170H\234\158\209w\234\012\b\135B4\011\024{\218\185\192\194h-\203\225\188`\185\208\158\182@`UK\163m-\151\025\209\146\153)-\t\006\181\020\206 ~\219:\137`\156M\250\182\173a\129`f\t\182\173!\2153\203D\219\214\144\196\025'\216\182F\156\021a\011\227`\181\028\206D\150\011U\203\022\b\180\203\210\168`\150\203\164\202\146\217\183\255\145_\237O\251\213\254\132_\245\205\143\182\200)\215\203\230J\203\157p\175l\2224\220\161\007>a\162\158\153\212\128\209|j\232*\022\202\234\196lQ\253hF\168N\207\b\213\137\025\161o\206\181ENM\026\213\169I\163\234\1594\158c\143\174{\224\019\195:\159\157K\147\217PbRC\137\249\012e\152\202P\006Y\012%&0\148Y\238B\153\165-\148\144\177Pb\178B\t\239\212\151\248:}\137I\244e\152D_\134I\244e\127\018}\217\151D_\134I\244e\156D_\198I\244e\148D_\134I\244\165KG\247\141FS\132\233\232e\127:z\217\159\142^\254 \029\189<\153\142^\246\167\163\151'\210\209\203\019\233\232eo:z\217\159\142^\230\185\218\129\173\208\140A\174v\217\151\171]\246\229j\151's\181\203\019\185\218e_\174v\217\155\171]\246\230j\151=\185\218e_\174v\137\169\205\153U\208\\\152\218\\\134\169\205e\152\218\\\246\1676\151}\169\205e\152\218\\\198\169\205e\156\218\\F\169\205e\152\218\\\186$a\223h4EO\146py*I\184<\149$\\\2540I\184\252A\146py*I\184<\153$\\\158L\018.O$\t\151\167\146\132\203(_6\180 \1547\203\151-\227|\2172\206\151-O\228\203\150\189\249\178e\156/[\246\228\203\150=\249\178e\152/[\198\249\178\165O8\133\246\163Y\232I\198,\140\128Y\024\006\1790\028\153\133\185\220,\204\128Y\024F\1790\142fa\220\155\133Q0\011\193`\022B\209,\221\029\141Q\210g0I\002\193 \t\140\204\145\152\220\024\t\007S$\016\r\145P4CB\189\017\018\006&\232@0@\135A\243W\230g\134V\2483C+\252\153\161\213 \250\153\161U\2403C+\252\153\161U\2463C\171\236g\134V\2403C+\252\153\161\149\249\145\200\021\254>\228*\254i\200U\027?\209k\223\177+\031)Q4\235\187\149\196D\020\b\127\215p\165\209\015Eh\223\165\128\239\174U\027\220\152\201\181_\168\175$\140\161@\176\211^\217\128\133b~\207\188\210\208\132\"\176;^q\016B?Sm\005\240[\179\021\166x\174\006\182i\02749\199\016\012\016\245\193&\232\003\027\"P\016;f\147u\192\006\006\210J\182\253\226Y{\217c\173d\127\175@\176{\\\217\157\188b~\159\184\194=\187\226\176#\\\201\238\\\001\031\020\\e9\159\171`\163\188jw\199\210S\021\250R\021\186N\021\184N\133\174\003\219\\\1973\151\1702\151\170\156K]\182\170\163\215\190\142\151\162:\n\004\149\190\180\170\163\152\175\244\165\170\142\"P\185KV\029\253\236\253\253\210$\014]b\182\208e\152\"t\025\228\005]b2\208eO\006\208e\150\246s\137\185>\151\152\224s9\208t\247KQ\016\005\252\143\241]z\005Q4\139\n_\138\130(\000\193\221KU\016E\220\207\237]\138\130\b@>;\210\2076Jy\217\229\136O\249\154s\196\005\224\028q\005\242\223\203\185t9\226\138\153\028q\001\253\207\229\\\154\028qA$G\156\017\022\016i\210\2228\204\030]z\031z\240>\240\224=z\240>\028v\151* \138\144\147(\128\142\012\129\188K\171\031\210\023\141~L\184\149\172\031\n8\199\017\2128\142`\2368\002\192\193\129\224\226P\130\136C\tB\014\197\159k\227\2495\142\200:\027{W\221\187\030#\249\192\217\241\138\240\187\030\138\184\132y\133M\198\188\130\1562\175\136\228\198+$\201\241\nQv\188\002\252\174\135 \231\242j\203\149H\143\002\182\142\138fo\197\\\137\244(\224;Cq\174\184\"\228U\nP%\005X\203\020u%\210\163\128?\166\187\242\210\163h6\151^\137\244(\000s\230\149J\143\".^z%\210#\000\185\251T?\223\219\223\130\188\026\232z\243J\180G\001\210\030\003\228+\226+\171=\006S\237Q\208/\147\175T{\020\129e\242U+5Z\221=\188\184t\229\197\198\192\249kJW\"7\006\193\215=\132\192\247\151\174Dq\012\002o+]e?\173yeEGz\161\178\005\170\172IU\220\164*jR\1495\169\234kR\1497\169\194W\178\174X|\004\144X\178\012S\031LF\024\181%\b'#\023\168\140\015(#\156\233\r\132\148\017\007\229\241Ae\128\141\006\249w9\000\141\212({\151\003\b\208\165\240]\014 Q\161\252\187\028\128\130V%\212\b\022\001\160Z\132\130t\017\026\233\023Q\185\136\017\001JF(\202\025\193\168i\004{a#\016\212\141\143\001\220\224rg\003\224\197Fz\b\000\197#\020d\143\209@\251\136\202\005\144\137\\\005\137\001)$\020\245\144`\020\197\004\239\179\006f\242Hp((\196\005\170B\012J\011\193=\250Bl&2\132\163x\018\140\n\234Oq\000\014\1804\017UV\180\138-Q\157\176D\213k\137*\182Du\210\018U\143%r\205%\028\132\215\030\185\136Feg.\001\131\n\028\159\186\004t\160\195\217\185K\192dj\156\159\188\004\020hrv\246\1463F\153\021\003qV\"\210ges\137V\014TZ\137X\168\149G\173V\006\228Z\tPl!\140h+\006\186\173\004H\183\018\145z+\155\011\184r\160\225J\160\140+\131J\174\140\023s\197A\207\2051\155\027\227x\252\150\015\017#\164\138\129\182+\001\242n\136@\225\149\205E\222p\185\206+\tR\175\004\170\1892(\248\194\236\163\230g\178\175L\168wJ\007\146\167$\170\1582=\194\167\0052\237S\n'\002ep.\200\142Ws&\152\017\132\171\162/T\189\166\170N\155\170:e\170\170\215T\213\143LU\245\155*\159)\148\242\147\197z\160\239\1577\215\242[\014\012\184\179\002\129\159\006\252\027\206\2356\189F\1745\222\176\198x\195:\1367\144.\153\026\016\000\213 4\172K\226L\133\018\240\140@\141O\197\250\017\154W2U\198T\146\000\168$\161a%\019g*\153\128g\004j|*V\146\208\188\146\198\005MM-\n\213\181TXgS\192T\220\160\207!Z\135u\194vX*o\140 \166)\138AC\148\b\155!\180i\132`\207\001V\007\245\192\234+\145W>\rhSs\002\160\218\132\134uN\156\169p\002\158\017\168\241\169XOB\243J\146t\152Z2\002\213d8\172'\145\166\162\132\247\252%\151\207\217_r\249\156\253%\151\207\240\151\\>\183V\148\235\218^c}s+]\015\180\177\215\131\175\006\255\026\189\132~\221\026U\175\253\253\175\193\168\n\251\227\180\235\182\146\242\204\218\247\204\181\173$c\169\200\023\004Lu\t\b\159\159\184]\006@\237\t=u\011h\135\172\b|\181\176E\217\138\128\tz\029\012\001\211,\002\194:%n\151\001\208,BO\221\002\154%o\026\249ja\179\1787\141\132\160\1918\250%\135l\211\024\138kF\236.\128\176\129\140\159\190\0176\146\240:\175d\214P\198\243\166v\011\255\227\183\245\181\158\182\166-\"\254 |\145\145!\227ou3\184\145G5\215\215\221_.S@\197\243\198\232\230M\215$\185\230\182\b`\026AX\186\175y\020\001\240\188\244\241\t\191\247\140@\157\001P\007B\179\138p\208\148\030\184\129\223\171\178\179\133\157(6\131\023s]\219k\255\224M\244L\027\173\229\007\187\016`\225\192'\252\2303\002/\b\212\025\000\213\202\245\129\b\251J,\215\205\189ZY8\240\t\191\249\140\192\011\002u\006@\221\242A\206\004&qK\005\179\028\238\"g\158\194\027=\135\232K\136\2141\138\213\015\247\007\204BX\135[\128\187\254\002\241\167\224\022\207\001\246\018`u\132A\173\163m\129p\018\231\129J\011\142\181\022\226)\186\203s\004\190D`\029\130Xue\242\186\219\164m\174\183\203\217.\028\248\132\223|F\224\005\129:\003\160~\217N\134\t\151\220\203\149\243\185\189\133G\159\178/?g\200K\134\2129\002U\20470\204\184L[\174\163O\180-<\250\148}\2499C^2\164\206\017\168c\190o!\230VC\164\244yc\175\253\204z\171\127\127L\001\023\003c4\155yo\253\159\023\019P\194`\012hp\139\017\141i\017\178\151U\193\173\0042\021\b\150\248\1836l\169\152_\226\223b\144RqX\226\223JHR\001\159ovk\002\144\004\248\005\198\216\193\014\187kz`$\151\169y\2509\217\223|\214\214*(\1415\144\024_\177\212~\253L\205T\128,/\128n \179\173m\207\182\150J\233S\232\179o\022\129\190m\012\230\r$&k%\227YS\137\240\237%\016\026M(\180\028C\129wa(\240\238D(\240\206\191Y\028\162\222(\193{\1971\149\027(~\1718f3c\005\239\020\135\020\024.z\1638\226\238b\147\160)\029\023\025\244\139\2179\127\193\157\243\151`\231\252\181;\t\153\242\181\023\200\175p\238!h&\152_\245\148C\000\136\216\011.Z&\bG+\004\224\019\012\002\224\237\234\016\134\154\247\190]\029\022\200\219\019\189]\029rq+\195\183\171C\018\218\030\189]M\220\206\204z;3\187\237p^\219\0053\218\014\215\249;\\\214\239\194e\253\174oY\191\131\151\138#\184\238\129\225\017=/\0213\157,\244\140@\157\001p\219\236o\142\017qo\162a\247\024\r\187\015\163a\247A4\236\030\163a\247=\209\176\251,\026v\159E\195\238!\026vo\254\164\218=\2545\181\251\224\015\169=\164c:\190\246+\148\007<\148c4[\144<\152#8\006\194_r~\176\007n\140\192\154\228A\143\215\232\243\147\004\005l\012<\139~Gq\239\007\147\161\226\000hj\152\159\226\168\188\209\152\157\226\208\184\249Yn\138\131\209\016\144\153bAc\018<\154{\b\143\230\030\250\142\230\030\228\215\131F\030\000\011\005\191\030\004Tn!\255\235A\128\198\022\130_\015\002\024-\228~=\200\131\198B\178\221\247MF\011e\219}!\252\239A\140\"\024\173\213\247{\016a\129\192r\193\239A\132\\\143\021\163\223\131\b\201\204\162\249\239AD\148\181\174\151\238\200h\153\165c\233f:M`\198\210\004\128\141\t\141\172KTnW\"\192\162\132\198\182$\018\173H0\218\143`o99\239\1538\160\198&\163\157\250\142w\246\230\212co\230\184\253@\255p\193\222\220~\143w\222G7\021e\241\128\185\189\004\249\198\174D\141_\193\167\245i\207\222G\197\002\212<\220G\197\198y\217:\188\003\214\229\228\169\249\222\134\1852\204T\198\134\185\198X\174\014\190\139\2138q\250\189\151\b\144\007\204\227%\0024v%j\252\n>\181\239,\219\175G\159zpS\001\135\155z8\188\238\185\015\214\202\147y\2294\230\004\136\169\144\198\156\198\190L\157}\011\031\223{hN\171\236'\004\204c\019`\158*\171L\255\021|f\182\202dB\164\194\003\230\145\t0\143D1\217\135b\178\239\019\147ofM\252\r\151\195\223\130\1490\133czNy,\027S\254\156\199\223\134\184\133\225v\155\219Gsu6\153)\151\190t\227\191@ \157\224\228\140\030\171Y\208[\2032\209\209\154\229}\252\2020\214\006y\173\015\222\004\004R5\002\134\162\133\017c+\152\243\250\202\159\005\233A\001\227\127w\2051t\024\024r\182\018\001\159wl\"\212\213\015\205\249\183\185\246\029r\2243W\011pu\020J\241\215\025\127\1901\028;\132\000w\226\209\007\r\153\b\224\227$\012\243\171\152r\147\189\189\198*G\241\211C\016?=`\252\244\208\019?=d\241\211\003\198O\015\024?=H\252T\204\242\151!\143\166uG?\248\015\226\011\006`\155\027(\180\212\227@\030\241hK\b\250\196!\173C#@z\233\002w\007#?\012\209\161\1656\129\0000>\161\2244\140\162\231\216\147P\177S\002o\176\020:\018eVj\219\215>\001\211\163\161\181(\199\003\156+\161\251\012\b[\026\250\026Q\185\195\017\001^Gh\236zD\162\255\017\012NH(x\162;[\0063\255\133\197\142h\030\244NB\193E\025E?e\188\223\252\234\155\2449r[^${o\172\241\179\247b\\\2552Ng\220\218r\002\160\131\t\005Wf\020]\217\253\150\244\204\1297X\n]9\161\198\149\t\000W&4\180\165\255\153g\127\227}\006\132-\r]9\251\149g \192\149\195_y\006\018]\217\255\2023\160\224\202\254W\158\189\153\255\194bG4\015\1862\161\224\202\140\162+3\222o~\245W\250\028\1852\199I\1887\214\248\217\1872\006I\0047\015\176\014ma\236l\203\161s;.sq\203\130\163\027\234&\254F\230\244p\1622\r`\028\000\253'*A\137l0\248\131\137\016>a\171xx\196\007\019!\141C\165\255`\",\146\r\155\224`\"\228p\b\025.\027H\134\251+\254\20216v6\180,\135\003\204q\2170s\236\143:\217\140+\139\134\003\207\005\210\162\017T\199(\012\1970\138F\172\141V\0281\144s\196\020)i\188\133\194\147\026}\229\199o\227\210\167\139\129\188\020C\128\2288x\212\031BZn%\155\132\244\249\018>_\233~\146\000\238p\143\154m\171#x\191\1536\147\139\140J8\249\225\211@U\231I^\001T\128dA\129`h>\217W\253\020\243\131\240I_\237S\004N{\158\248U>\253\236G\212\019\252\182\205S\171.c\185\246\199AO^G\020\205\014\137\158D1\020\2402\1618\252\197\211'\017\004\005\252\031m}\194\031\138y\134\191\168\251l$\242\025u\2419\020\195\231@\001\159Q\246\158{\180\2389\019\184gT\181g\148\178g\252\131\191/&\243\231\0053\127^0\243\231%\204\252y\t2\127^\162\204\159\023\204\252y\2012\127^\178\204\159\218\252i\223\026\255\180o\141\127\218\183\014\255\180o\029\252i\223\026\255\180o\157\253i\223:\251\211\1905\252i\223\026\255\180o\r\158]\027\251\214h\223\026\237[\135\246\173\003\251\214\145}k\180o\157\217\183\014\236\219\186\237\148\175\217m\005pn+\168q[\193\216m\005\000\183\021\\\220V\016v[\001\216m\025\128\177G\019\140\241\012\002\192=\b\005\031!4r\020\162ro!\002\\\134P\244\027\130\209y\b\246\030D \184\145\219\230\251F\155\238%\000\188\138Pp-F\003\255\"*w2&rO#\006\220\141P\2449\130\209\2414j0u\000\184`\0205\240T\238\140\0165\240h\236\150\0245\24008(D\r\028\138\174*\1813\222\170\0248\172\018\224\179JDn\171l\238\185\202\129\243*\129\254\171\012\186\1762\222\139\021\007G\134\236\237\220*\198}\020\003\143V\002\156\218\016\129_+\155\187\182\225r\239V\018\028\\\t\244qe\208\205\1331\158\174\0248\187\018\145\191+\155\187\188r\224\245J\196\142\175<\250\1902\224\254J\192\b\192\164|\238\238\239\154\253\248\029R\030\191C\158\227\247(\185\241{\158\209\248=Hc\252\014\185\139\2231a\241;f)~gM\133\207\190\138NQ\017\204+\139z\138xVm\167\166\000B\003\188\1502J\127\201\012?\251V\016\232[\193`\222\nb\178V0\158\181\130\b\223\n\002\161\021\132B+\244\150\155\b\243\1731\132o\145%\242V\0256k\153\229\178\214\025\210\183\208\016\208J\195hK\223<\220\188\221\028\030\222\175\183\135#\127x\189~\\\183\215\191\238\031\030\255\189y\234\179\192Y\219\231\204&\164\014\228\022\183\137\238\151\169\224RZ\228je\249\226n\192\253d\247\196\t?q4\132\196\130r\160Tr>\019\134l\251\002[\178\210%g\173'\228\153\224\208\007i\190\211\182[\\\140;\248\143\193\182\205\"\250\031\187\193\195\142\238\132~\234svL;vK]\148\188\004\178\140\020-\243Y\159\184L\148\2183\235\142m*\151z\246\165*\007n\251\239\228\225y7n\028a\217\1335\239Wy\230\\\181\213\174\2192\207\220\149\222\189\178<\251(uY\182.\224:\143\192Y{[g)\007\174J\185\226r\210\183\139YKJR\0182\192o\212\230R\162\223\133\148\020\197\028\130\253\223\021\157\015\245S\243\240\140\234s\144\206o\218f\222Rnf\237\1522\163\249$\133\212x\165JB\190\158\0071md,\250F\222e\138\169$4\166f@\217V\031\208\237\139\218a-\149\\\218\183\127O\207\236)r\222F\162\020\\Y\022\127&\022\239\2533VO\028\015\237\019_\232\137\157\127Z\r\164\220\200\150;\165r\179.\212\166V\201\241\216\022\253\209\023\157\164\252|\164\202M\178\201\167L\137\194:\1711\209n;J\202t8\026\231\241\213|H\188\155\252\212z\168\159*\153\180c\166<\192\237*\235\159/\132;$\186\2372>~~N2(E\237\249\246i\187\187\175\0069k\026\181=\253l\217\177a\202\150Gs\024\129\166I\128\251\250y?\224\145qK\202]y\174\250\028b\152G\222\171Y\026\169w\n\204\1854\132q7^m\167{\136i\186\177\253\188\141@\161\210\017'\195\212C>t\179M9wN\019K\221\016\176KM\135\249\029\208m\156hP\211g\167\243\149\244/\1639$b\015\187\250\176\165G\207\198\212\180\250\017\250\130n\128\240>V\162\204\162\027\127\180\221d\223\019\240\r\208g\2205\135vP\127\151B\174\245|\167M\235\2419\235N\193>Z\141\164\251:n\251\025\184\020\165\139~\170a\188\148\127\166\145\222h\210\133\248\172\027\127\171\158z\177\138n\200\211c]X\165[T/\1533n;\031\210\181\164\234P\221\019\223\173\218\160h\167F\186i\148\017\1850'\214\179Ij\028\237\140\209\230\243a\243\141r\183q\023\145\173\225\231*'\030\229,{2#\222ig\136+j\177m\245[N\159\182U\159\141(\128s\174m\242\169\222q\183\155#\205\151t\169R\219v\187j\228Y\155\209r\022\199$\223\245z\158\238\154\180\138\201]\243\248.\021$-o\246\211\139S\213\131/\023\133P\214\247\rS,\183a\192\193\149\179\2446\015K\198h\231s\183\223\142\219#\197c\215\197\172\134Z\191\021\220\208z\234\233K\221\240\228\2252\r\149\219\174Qf8F9-\207\217{\030\2553\177.\187\190\167\155\182\152t\221\0209w\133-\230\176\161Y\159\174\193\207Zq\154\t\156Rq\232\2457w\205\019\249\1675UW\188\159\007\228\226\224\159\148\137?\236*\2345\219\209m\127O7\139\203\247\128wTo2\158\245\147\135\211nl\147{\160\156X\231\226\143\155\187C\158\244h\231!\231\227\142\202\218\220a\153\031\191\180\229o\015U\174\240\188\211\166K\221\187A\229\136\138\175l\241\251\250is\199\189\207x\218M3M\219\236\164\235\025\146\251\198C \202\251m\219\190\216\221\157.\195\142z&\234\014`\187C\238\171\186Ta\214r\225\180-\177\152\229\210\224\178\187v\025\165\157\185N7\164n\189\155\n\029Ri\1563m\246\1597\135\230q\183i\158\152\236;'\204\230\226\184\241\016\156P\127n\231-S\n\220*\158\2221]\241;\192\007w\027v\193\130<<_\170\135\187\006\241\136\228\216\182\133\005\179\2278'&|\195\027\154\226\233\007\196j\132=\030gM\022\169`}\184\127h\231\239xjp\212\133Ck\146\233T\166q\198\019H.\254\144\145\233t\004\211%\227\188\132\1933\028\170p\026\242/WC\245\236)\168~\153T_Q\019\238\178^)\156}5\159e\237\031\219\140\170\217\177\250\221Tb\167~oN\186+\207\232\231\133\137\r\205\218\166\177\229j()\2468O\160\231.\224\190\235\135\143\199\212\219\173:\"\026\171\028\182k\210vl\003\134\153\168\213\139q\158\232\206\252SK\225q\183\1680\238\023;f\211D<\227<\219\157'9j\026k\166\129\193j.\163\146\241\012\152\173\237\232\218\149\191\150\176i,AK)\179%w\191\175a\138\226w\211\006\251\169\183i[|5\028\153\226\220Y\011\173\229\177\239RH\016Ko\132B\242x~\177d\006\193\210\141k\128y\220\178(\191\162\146\022\197\n\r]i\158\223\001\198\201\243<\174\186\148\180\223o\191o\137b\151\180\128\208-\209\140\011O\023\227\168G\143Wa\2257\142\241i\206\024o`c\202\211\1791\003\211\243\\\027>^\205\186\1857\228\129\152\210_\141\198\156\233\243x\181_\146R\156?'\254\211cW\239/\171\151\154A)V\133I\223T\002\162\136K[\023\235;\n1\189Q\020\222Y\182\155l\209\243N\238\r\202L\231\172\154\195Z=\190\011\232\241\216\142\19610~3\021\224\185z\212\158g\254\219N\157\022(\250iP=\253\207\141\157rMt\216dE\219\002\218\142\244\245th\159O9\237\029/\242\247\157PZlZ\246\153\207\"\214_\229\025\172\253r\017\135\220\1574_5?W\228\019\142\0045=\152{\1274\204?\177\182\011\026\217\235Yy\182P\230q\213\200\250\t\155\246E\197\006)\025\161V\007\169'O\146\163:\221|y\210G\r\015\176\018\191\168XS\203@E\149$%\204*\181\147\0319#\244\145fR\182b\168I\131gg\229Y\170~\233\183D\015*\251:G\r\185+\218J]\251\014\183\031b\192\195\167\139d\205]\253\163\218\127&f\238\146\157n\014\026\2518^\239P}D^\244@\011\242\154\150s\211h\164\194\006b\158\2198\176\154\154p+\1982\220r.\132r\151a2\248\174\187h;FlY\156)\171\150\197\235\233\005W\221iW-\136\163\244D9\006\243\127A\178\159\023B0r\178\230W_\234\131f\004\181\230\137\014\184\212\149T\171cXOv\174\202HJ\206\229\021-\021a\178\172\229JOit\226R\011\189\136\232z\005\173\183\234\022\028\243\229\144a.\211\193\002\\\198#\189n\031\195\177\233\231%\014Y\255q7\1634\145]\n\206\146j\196\170\012YLHT\241R.\194e\213\216\176/\219fG\171\241<\204\161\030\155\221\211\246\219.M\185\205\186\189L\243vIc6\156\199fQ.*7\"!U\025OM\243\242#*=]\208\236\254\230\240\180\221\236\238\183\015iI\166\141\215\215\147nv\173\011\200\184a\156l2\161\147\162a\161\215\017\253y\t\024\021b\194C\214\232Yo4*\018\192o\152<1c\151\250\003\163\191\166\152\130\249+\155|\168\228\012o\200\212\161\234;-2\024/\217\168\238u\150g\016\011e\027\213\160T(\228\233\n\223\221\011\223\253\204\240\191\171 \235GU\190\239\249R\182\180p\234p\239\161\146\218\212{\148\187\2367\150\129\185c*\205O\168P,\143,y9Q\020\2255E,\203+\231\170\150\175\231\163\178\209\185\251\213\169{\185\251\229`WyL\142\24533+\170i\240l\128'G\206\197\021\239N\138,\205\253\146\157\019\154\229\157\011\216\229\229\138\226T\195\153\218r\204\168d\227\204\024z>\162An\181{\162\129D\191<\189\2285D4\204\019g\154z\025\2235\140\156W=\215&\171j\155\234\184]\166\236\231@KY\149\rH]\215BL>\166E\2481\239\021\240c\127\182\188\152\1657{\191\163\185\196\142n\186\140\226&\154.c\170\214m{\158\230:\244N@|\201\189\204.\228]1K?z^\210\178x\159\166\1824yh\233\146\2363Iy\246\178[\249\028\198\019\030\127j\018\\\209I\005\189\223\140\173\180Z\017\007\20284\r\210\167E\174\185(\205\002D\185\159\012f;\152r\252\250\0141\207r8*\246?\191)Z\254Y\182]\233|eZ&\229\188J*i\156\222\227\133\211\227\202\250\212\180\146\2423jY\195\241\153\150\197\206=7\222\229\210\208T\206\181E\166CoU\166D\159TO\169\205\220\183\253t\149g\202W\253\152\167_\184\193@\202\145\161z\245rPHR\165\178\157\159\207\1535\170i\149G\156\211Y\206_\239\183w\020\209m\147z\189\164\003\b\243qavV\230\016\242\230\236bj\236\166g\201\254z\215\152\027\246H\011\144a\207(\158\165\170\165l\238*\134\229\246\242\017\213Y\230\244Tm0\244tR\160[\189R\232r<\181\144=\165=BX\007.\171\147\205<\155>+\243\255\027Y<\224\220\017W\014r(+5t\183\142\214\204\201\163%qI K\163$\021\n%&a\n\215\201\230\132Rj\189%\030\149\249\234\214b\022\178\210\224n\20233<\172m[\211\184\219\249\213\170>^\022T\194\201\138\180TXnW{\213K\167\177\254\176\152q>\149\150\146\244\230FT\127W\127\238\154\226\190\206\188\147vK\233s\"\174\005\216\233\r\197%\165\233(\155\n+~\192\027\168\207k\181\145.\175\173\237\235\201\172\223k4\155\197\201\225g\172\185\238\n\150\2084\185\163\161\241\2292e\254=\001M\nQ*^(\014q\196c\232\133Y\030\253\249\169`\222\255\176\183\019\147\221\166\190.\135\158,|\198\199i\174\206P\210\240bQ\236&\127k\232\b\153\028\151\252m\127\175\206Y\166\131\151\023\213a\255\235\230i#W\2397\2196\011mgIg\175.\222\255k\240f\208>{2\204\191S\191\174\128d(\rPZ*\208;\253;\245\222\n\208\214\019\248R\255\198\151\234\161\147B9\232\020\150z)\005\152\142W\225d[\133\164\237\006\nHD'\192\007\245\251\170u\192\152/\200(\026\209\181\020\252z\240z\198\191\169\154\002\232j\n*\213\020\140\170)\128\173\166\224\185\154\130\016g*\164\231~\185\190ig>\242\239\181\194?\r\250\179\207tA\202+D\244\020\176Q&k\208\173M\232\214&pk\131nm\nnm\156[\243\186\178BR}\249\250{\183\168K\191\159\213\239\147\254M\186\011 Zf,\021Q\173\135\000\1686\161\208\1422\138\141)\225\239\028\000\205\138\208\176m%\217\165\003B\189\194\166F\"\239\024\018\128w\b\141]DB\244\019\193\208\006\t\133\134\152\208\015\b\232&I\b\182\203\012\135\1413\tU\011%\000\154)\161Q[%\145o\176$\128VKh\220tI\136\237\151`l\196\004\219\150\156@\213\156\019\176\198\018\186a\019\130\173\155\224\160\137'I\131\206h\194\232j\202\209\213\148\162\171\t\163\1719\023]M\028]\142\n\b\182|\144\192\239\216\174\159\01789\0008\130PO\020\169\237*\162 \000LF(\016EF\145(\018\254\206\001@\020\132\134D\145d\151\014\b\245\n\137\130D\222\149$\000W\018\026\187\146\132\232J\130\129(\b\005\162H\232\007\0044Q\016\130D\145\225\144(\146P\017\005\001@\020\132FDA\"O\020$\000\162 4&\n\018\"Q\016\140DA\176%\138\004*\162H\192\026Kh\162 \004\137\130\224\128(\146\164Ag4at5\229\232jJ\209\213\132\209\213\156\139\174&\142.G\020\004[\162H\224wl\215\207\b\156\028\000DA\168'\ne\004\197\022\026\005\227i\017\240\134\017!y(\225\187\024\005\026\209\162\144KT\129\203\024-\171\030R\139\150\251\b\208R\b\003-\138cA\151\192\128\2082\224\028-\002\226Q\162\015!\170)H\195\200CF\022\146\145*\161\024I\163@KZ\020q\147\150{\130\210R`)-\138\169J\151@\190\2102$--\179\204\165$\138\190\020\186\014\203j\"\2110\178\153\150\005\148\166\196M\232\230\166\028\228\205O\130\1889\027\228M9\200\155\159\006ys&\200\029\245i\153\229?%\249\030r\214s\136\158b\0208Q\139<12\162hQ00\186\b\128\018\149\000\t\145E\239\"\012\200P\004!\021\178\2482\194J\202\134$(R\031\029\"\131\216\016A\028\025\"\199\184\016\tP\159\b\128\248X\240!\1924\233\t\136\148\167$!\225\177\\\209\157`@v\"\136\168N\164\158\232D\0064'\130\152\228D\142\020'\018$8\145Xzc\\\145\027c\235\160\156&6\001\145\214D\018\144\026CM\224\194\166\020\174\205\217pm\206\132kS\n\215\230'\225\218\020\195\213\145\152H,\1331\254=\224\150\231\000;E\024P\151\b\002\174\016H\"\222\210\007\179\2125i\203\000y`\196\128\244\203o\243\199\254\020`s\220\183\230kn\nu=\255[}\228U\1296\019x\203'(\021\002]\252\219A\173\127\163\134u\168P\029(T\227\187\2350\001y\203_\161P\136Mj\223\230\131u\002\228\024\022\187\030\218\1823\203\1913O0@vU\128Nh\t\254{\215\018\168\183\254;\183\004\001(\182\004\208\182\016Tl!\024\217B\128\\gA\178\031\004I\177%\215d\004\0066\2507j\187Am7\161\182\155@\219\rj\187q\218n\156\182\027\208v\131\218\218\252\227\239\152x\252\189\203\136\185p\131\213iB\237\155@\251\006\181\135\196WpW\171\198\213\1701\181\186\232\198\1323\254m\201\231\194\142\004\005u\\s\193\227?\001\194!\205\133\140\250\004\161\182!\128\165\156\139\129\2443\023\2040\002\228\150 \128\239'/4\195(L\024F@\219e^\b\195\b\002\029\229E\1990\242\0275\172C\133\234@\161\026\223\r\012#\184\211)3\140\000\182\135\190P\227\179\011\028\154]\132\163\178\139`@v\129c\177\139\1940\236\194\141\192.\220\224\235\002\198]\023\221\128\138\189~\194h<\249\184\211\164wY\128\2251F\022\197\183)\240\147WB\212\027Y\220\000L\017l\011F\b\205\194\200\160\133h\153r\185\129!*\141\012\154\144\149\005\193k\n\2488\182b\223\198\140\028B\222\2000\202\141\016\027\161\022\214\005\248\140\017\234\159U\180>_\209\250LE\n\205\216\0209WWl\220F\006\237\\\203T\14770\180~#\139\136\192\020\240\156`\196@\015F\0223\133)\130\164a\132\200\031Fh\169D\139NqK9\157a\006\2075\127\244\147\139#\190\200\243\138\n1S\138\140\223\232\1395\143R\254\232\231\220\166|\145\231\128\004Q\211=\012\218?\175\128\130\140\2063zb\131\252\193\213\021\192y\242\0159=8\178\b\2146<=h\1337\014Q\149\151\211vS\139\160\025\252i;+)\025DI\209*|f\205\214\026\237\227\206\172eA\178\1336\018!h\164\012\135F\226\233\t@\148\145x~\130ke'(\016\014\140\148$%#))\026)\137NXk4\018\161\129\145T\165\141\1694\238\012f\132\177\217\020zS\192\181\t\021l\012\169qgN-\140\140\170\228E\211b\025g`KP\145\221\156\177c\130\202\226\212Ihc\019\130f\206ph\224$\188q\1362j\002\1809\tAC\018\028\1520IJ\198SR4[\018\157\176\214h*B\157\145.\213\136\248\018G\196\1518\"\190\012G\196\151\193\136\248\018G\196\151nD|\233F\196\1510\"\190\196\017\241e\231\205)\255\182i\218%x\144\225\027\238\179.;\175q\205\255\213\253u>\250\253\137\189y\201n\019@\170\199\024\rv\249%y\176\155\129\244\012e\\\002\192\194\132\130\153\t\141lM\"op\018\128\213\tE\211\019\140\246'\216:\129@\240\004\247\140\182\194\232\147\168_\1802\229\029\238\021'\006P~\226nra\001\240\152\235$\173\000|g\023`2\170\140\175\188\168Qp\165\022\129?\181(r\170\150{\207j)\184W\139\208\199Z\134\142\2142\235m-\001\151\2193\138\129\157\208\249\197\019\138A\001\021\006\246\136\222\196\163* \236\193\189E\128Bh\196\199\246\002)\004\137\146`\164\240cT\156\b\006Q\"\002\136\017\017D\017\"R\031\031\"\131\232\016\001\198\134H02Db\227Bp\136\n}\132\203Y\004#\162p\128\203\137U4\2323M\019\196T$\232sN\011\135A\020D\167\156\156\012\"\128q\244\127\178\186r>\001\224yB\193\237\132F>'\145w8\t\192\219\132\162\171\tF?\019l\157L x\152\143\199\216\n\163o\163\1951V\166\188\202GI&\006P\254\228\179%\011\011\128'\221\201\018+\000\031&\016\029h\134\225\202\143\022\007wZ!x\213\n#\231\218\018\222\199V\014\174\182B\244\184\149\162\227\173\212\250\223\202 \012\140\240\170`=\012\n\016F\177a\138\168\0161\184\138\020\131\171\1281\184\138\027\139C\248X\161\143\"#\135`22\140)r\138\138\166\140@\028e\024\"(\195Q\236d\153\143\154,\129x\2010FJ\1981F2n\163#\163\016\023r\006\006\234\142\177\016\158\128\001\161\242\191\028\019\153XD\249\\\014\142,\000\001?\251c# \001\223\018\138^M\195(\229T\002\192\167\132\130K\t\141S\136\217<(\176\154\133\0170o\031\020\132\247\t\n\196\027\005\005\162\157\130\002\144_\004\217\168:l\236\186\203{^\203\023 X}y\175\215\242\005\179\235,\239e-_\016X\026z\159\215\242\229\218.\154\188\231]-\203\012\200\186\192{^;\019\128\194K\001~!\241\189^\026S\152\172\135\th\215\017\223\203\202\151 \176S\231}\183\198%\191Q\195:T\168\014\020\170\241\221u\184p\249^V\168\004\177K\148\239y-\138\001\222\213Bv\253\160\246\189~\192}\175\031\194}\175\031\130}\175\031p\223\235\135\194\190\215\015n\223\235\007\183\239\245\003\236{\253\216\173$\143\249\183e\202\143v\205XP\199\132\031yuX\128p\223\198GY\007\022\132,+\128\229\189\143\029\229M\248\183\221d\245\017\136\142\225k\014\248\143l{\001\130\022\248Q\219^0\219\002?\162\237\005\135\150\249Ql/\136i\153\031\021\015\127T\020\252\177#[\198?\217h\255\168)6c\169\136\242$\001\224NB#\159\146\200;\150\004\224]Bc\023\147\016\253L08\155P\2408O@N,\000\190\143& \173LE\001\001\016\n\132F\241@\"\031\020$\128\200 4\014\015\018b\140\016\140\129B\176\141\022\156Q\253\1363\170\031y\002\213\150\192\br\019\168Y\144\172\171\194\136\000\b#B\1630\"\145\015#\018@\024\017\026\135\017\t1\140\b\1340\"\020\194\136\023/'\022\1280\138\150.\173L\133\017\001\016F\132FaD\"\031F$\1280\"4\014#\018b\024\017\140aD\176\r#^\138\181^_c\149?a\t\012#\183\014\203\002\187Oi\028\193\024R\165}Ja\129 \188\130}J\161\172\016j\209>\165P\136a\023\236S\138d:\004\1315\225X\022\134\163\002uPj\024CS\203\194\000\213\005\1300\213b\012V-+\132\172.\226\002W\011]\248j!\004\177]\024\143\"o\029\027\237S\\\218\005w\188*N\226?\225\180\208\159xZ\232O\179\022eA,j\014VX\208\021\181\135\129\016v\197U%\240\022%\130\219\174\244(\236\202\141\194\174\220(\236*\030\133]E\163\176+7\n\187\242\163\176+?\n\187\194Q\216\149\027\133]ud3\229\223\182\021\\YZ\017\212\197\251\021\019\136\000ad_\tU\bb\247\174]1)0\176\209\no\156m\243Xq\206@l\218Md\218\1413-\015\023\229y\222\178\027\180l\0300\242Mw\245N1\226\021\015 \0250/\173\\\173*8\151ze\199\144\n\142\170\165G\145\n\165\202\178\146\149\171k\229\235\250\229\244\237K\181\151\221\023W\221\200R\196\181S\189\142\021\173#Ekg\127\024^*\129S6\143/U\025t\003\0150\185\200\193\\8\229\015\206\238\135\240(\240\213\224X=n\209\203\141.\208\184\1357\177e\154\2002\141\179LS\178L\227,\211x76\024\178\207\250\226d.\156\226j\163L~\007\031\015\228R\246| \194\200\128\193\tA\148\005f\177g\004\017v\172\b\167\004\017\007\147\216s\130\000+\166\1809>\160\017g\186\028\031\004\192\158a\142\015B\228Q\155\227\003\n\140\154\208\141\171\226&v\029\018,\161g<\183)zn\019{\206\145.\193\005\199mB\199!\007\231,\1934Q\147:\192\003\188^Ul\017G\206\025.\155\164*\154$\228j\018\001a\019\026\027\171*\024\203\241w\130kW\176\142+[\159\169U]\172U\029;\186\196\238$\141k\230x\158\224\208\223\142\241\019|\240H\\\221C\236\219B/\144\132AW\144\004\141+\218\196om\206\024\185)\026\185\137\141\220\1565r\019\027\185)\132O\019\182\181g\135\156<\018W5\234K\148mM\143\162q\2474-t\189\139\022\198\182\213%\"\011k\185\179\179\022\250^GK\189Y\181\020\141\171e\174\031\178\147\004\211\b\198>\1694I\016\022\b\250\167`\146 \148\021\250\170h\146 \020b\191\021L\018D\178M\193<\155s\193\226\2503-\251i\172l~\018+\155s\177\226\2519-<\027*\1553\161\226z>3\138\181\188\228\007\184\225#K5\168\206Y\214\247\139F\2483\211V?1m\220S\234\002\216_j\2179\211WgM\239{P%\172\0117\213\231\012U\255\212\022\245OlQ\159\011\179b/\171\203\156\179\135\239q\181\240L\180\249\222W\t\015%\252\156\169\014\231b\170\212++4\234\155\149\184)\220\214\156\211\169\249\169\251\154\159\184\1759\231\190\230\255\195}\2059\2475g\195\1859\195$\207\005\252T\194\207\153\201\247\244\215\234\019'\215\248u\147k\252\176\201\245 \250\166\201u\2409\147k\252\146\201\181\251\136\201\181\251~\2015|\186\228\026\191Zr\r[0\174q\247\1975\159j\000\000*fO5\000\026U\209\157j\000\001T\022N5\000\140\2136\167\026\000\004\003D\231\003\174\195\243\001\215\246|@\132\130Q\130\243\001\145(2O|> \146\130\161\162\243\001\145\012M\230\207\007D\0180^q\243\252uy\243\252\181\222<\23910\161\219<\239\005\145\249\162\205\243^\006\166\243\155\231\189\004\205\134\155\231=\014&+\2365\191.\2375\191\230\189\230\000\128\161\236^s@#\019\185\189\230 \000\227\192^s\128\209,f\1759\128`\144h\215\246u\184k\251\026wm\1998\024&\220\181\029\011#3\149vm\199r0Z\188k;\150\162\t\163]\219\177\012\012zf\003\243\245\185\r\204\215\178\129\025\0170)l`F82\163\223\192\140\0180\029n`F\028\205e70#\n&\nw\000_\199;\128\243\n\228\027\143\128Y2\012f\201pd\150,\243f\201\0180K\134\209,\025G\179d\220\154%\163`\022\130\193,\132\162Y\250'\190\193k0I\002\193 \t\140\204\145$\222\024\t\007S$\016\r\145P4CB\173\017\018\006&\232A0@\143A\245o\212\023\214n\240\011k7\248\133\181\155A\244\133\181\155\224\011k7\248\133\181\027\247\133\181\027\247\133\181\027\248\194\218\r~a\237\166\251v.k\254\206\250\227\006\190\152\203\240\165\254m\029{\019\206\181\220\004\019,78\171rS\152J\185q\243'78ir\1313%7\003\249\018\222\rO\137\b@\021\021@+-\168\219\158|\195s\028\002d\229\004\201^\016$yA\174I[\006h\1486\149k\154\158\152\017\160]VaP\229\185\007\005DAU\005A\165\231\021\004\196H\171\\\164U.\210\242L\001\003\181\254\141*\215\161\134u\160a\141\202\192\b_p\167d\030\202\011\128\209/c\246lh5ffo4\202S\r\198R\019\134N\019\132N\131\161\003\131]\193]H5.\164\026\019R\235\142uf\252\219nOY3\235\b\016\236\129^k\214\017\204\238\129^\011\235\b\002\251\175\215\153u\228\218n~^\171\141^k\220\221\181\014\183t\173\131}\\k\220\188\181.\236\216Z\187mZk\220\155\181\198\rYk\181K\127\141\187\244\215\184K\127\029\238\210_\007\187\244\215\184K\127\237v\233\175\221.\2535\236\210_\227.\253uf\140e\190\174xC\211\026?=\185\198OO\174\195OO\174\131OO\174\163OO\174\241\211\147k\247\233\201\181\251\244\228\154\t\131\171P+a\141*\215\161\134u\160a\141\202\196\223\162\\\187oQ\174\241[\148k\252\022\229\154\t\131\237\220(a\131J7\161\210M\160t\131J7\005\165\027\167t\227,k\191\247\180\238f\1768\170O\216\218N\174]}\234\023\162F|\145\231\185\004\201KN\130\152YA\129\213T\160\128y\254O\016^F\018\136\167\241\004\162\185;\001\242*\017#-\173,g\249w\238r\0240]\014\163\170\203a,w9\012@\151\1958w9\140\228.\135\129\220\229d`#\147\233\159d\177F\016\155\154|\130e\025)\231\191\028\243I\022`\004\129\174\228\147Zj\145BdY\001\178e\025\161.q.\215)A\225\002\166t\229\170\197\203#\n\t\235UE\2452\171\031\130\186\218V\174\182\149\175-.i|\026lU\232om\251h\0018\130\247\169_\246\224{kW\213:\174X\029U\172vU\192\245\011\017p#\017(/U\b\226\028\199\025\014#*\195aw6\186\0215\174\1937q\243n\162\230\221\184\230\141s\250\"\240\237\190\241\237\190\129v\207\019\207\136\160\218v\234\025\225\176Jn\242\025%X9\152~F\220\213\198L@#\138|\198\007u2y\216\131:\128F\244\230\014\234\128\000\136.<\168\003B\164<{P\007P \191\132j\222 \004\027\017\193\192\133\132\134\237\139dA##\t\1824\130\1451\bv\180A80%\161v8\247)/\029\1526f\214\019\224\001^\175*\182\136\163\209\012\151MR\021M\018\178*\137bkU\177\181\170\130\181\028\211&X\209-\001\192\185\132\"\241&\184v\207\171c[\213g\140R\023\141R\1995/\2092Ic\1878~&\024I\218\174*\001\028\208u\0184\142)\154\152\001\1553T\215\020\169\174\137\169\174D\230$-\016aS B\228v\189\004\020\128X?\183\b\020H\194\202G\203@\129\016M\224\023\130\002\145\171*.\005\005\002d~\150(\242\023\012\248_\004Q\023 R\223\011\136\012:\002\017\196}\129\200\177;\016\t\244\b\"\128N\129\005\154\023\005\196\198-\018\232\029D\0166|\017\007m_\132\216\252E\130m\\$\142\254D\004\253\133\b\160\203P\171\127\166\169\227\170\160\127R\168lU\180\154\235A\148\228\172\217\170sf\011\187\018\145\022\141Z\021\141Z\149\141\234\186\021\150\168\158E0\232\\D\128\253\011K\234\232\217u\209\164\245y\195\213\231\012W\023MS\234q\164\128\027\016\136\b;\030\145`\223\227\150\151\189$\232\129X\214D\164\213\020y\1869\207\198\20596n\138l\\\234\147\164@\153\174\1552]C\231\180\233\254\234\2178\255~V\191\229\147\171\027\252\218\234&\248\208*Q\154zZ\002\158\0178\225-\248pB\253\027\0185\1707$\224\025\129\019\222\130o \212\191A9R\189F\161\207!z\n\159\128o\213\"\255jF\212\139\025{\014\176Sp/\190R\004\254\133)\240\212\219\018\240\140\192\to\193\151\016\234\223@\241\169^A\200\179CN\238.|K\134\253k\228o\252\142-\242\236\144\147\187\011_\227\255\198o\150\228\191#:\214\215\207p}\130\242\248x\252;\162\025\231?@86\1923\002'\188\005_\224\254\000!\tn\219\127\249\131'\183\176\228{;\216\241{\218\223\182ki\001\179^*\176]k\184\1975\227[\245\231pn\241\207\225\220\134\127\014\2316\248s8\183\248\231pn\011\127\014\231\214\2539\156[\247\231pn\225\207\225\220*\147\223\170\025\229[\156Q\190\rf\148\239\228Oc\209\245W%\251\026Y\237\206\142\151g\026\252\138\165\226'\216\243N3\r~\197R\133'\216\019\212\252\012\130\191\250\146\241s\250\206\243\248ms'k`\233\145\248\149\239\161\019\130\004-\162\134\141\025\248\206\145\172[E5xQ\248I\225\224\191*\240_\0219\163\130a\171A\149\018\216\185\017\240\130%NX\002\021s\189]\022D\142\174\224H\148A\149v|\166\199>\236\005K\156\176\004j\231N\248\176\192\237\133de\252^\200@\164\149\141\186W\141\190\132eOaYW\129\176\211\205R7\016\153\001\1425\208\189\244\004\031\242\028<\248%(w\n\202\161\222Q\207\2052\030\150\160\218,pz\179D+\206\224s\244\240\151\168\228)*\233\148\023\137\215\222\236\128\204\250\217\029\144\022U\026c\138B\192\011\1508a\t\212\208\229,Y`\247\202eE`\175\028\192JA\151\224d\228\197\1499\1852\168\164Oy\178\196n]\203\234\192\2145\128\149\150.?\202\200\139+srePK\1591\145\228a \127,\239\129\167<\004\176\127\206\252\193\206p\b\234R\153\007\158\207\016\000\214\143\031d\250B\016\179~\252\192\147\021\012\1445\249\186\141\226]uI\255\170#Xa\018\193\002\218\204\253\171D\176 \144\161\127\237\"X~\163\134u\168P\029(T\227\187\235p\212\240U\"X\016;\178\249\202\017\156\0018W\025\194\160yt\1702\150\005\021,\156\169\140\197\222\015\209\137\202P\134\150\bOTF\194\186\000\1591B\253\179\138\214\231+Z\159\169H\193\213\225i\201P\b\001\016\029\150$\217c?Y\200\191m\235~\132\169AF\213\140 c\246\003\167\143n\254\143q\248\192\233\163\154\237c\196|\224\244\177?\2377\203\191\179\142\012(m\018\182W\149\218c\165\246a\165\246A\165\246X\169}\161R{W\169\189\171\212\030*\165\231\149\246\170\130{\172\224>\170\160,6\014\r\000U\141\150\026\173\200W\026\022\026-\026W\031\151\025-\140\134\176\139\140\006T&\225\225\167\1732\026\199\r?\179@\190w14\000X(\250\218\133\021y\011\193\183.,\026[\b\190t\0010Z\200~\232\194\128\202B\242\153\011Se\180\144\027\002\179\000N\029\015\003\024\173U\180[\219\137\170\172\155\157\168\n\208\151\240\181\167\024\133\n\156]\029\170q\162j\1388\214@OTeM\245D\149\195^\130\151\157\"\012\244>\179\196TG\135]\235\240\176k\205S=Y1\158\234\177\192\011>\253\228\000P\176\180\"\224\234\179\015\223\180\015Co\127\230\253\251\176-\214\014\b_W\151\189V\151\188V\135^\195?\171b\133\177K\235\208tuX\161o\014 r\183D\240o,vp@h\136Ch\247\195\025\187;\187\028\195\007\031\195\007\031\011\228v<\243B\015\156)\2208 \212\174)\251\191)\249\191\t\253\223\156\243\127\019\251\191\137\155t\019u9\223y\127!\001\207\b\200~Y\002NX\"w\216\128JE\173\224\007\234\240#\180\225\143\208\195?\002\230\143\254.V\029\254]\172\154\007K#s\2393\002*O\193-3u\184e\166.m\153\249\198+B3\186\230\133\139\012\156Tax\236\183\232\137\233\254\194\254\b-\141E\180\217\130\022H\236cH6U\178]\245\240\164~\189\158-D\150n\186\231\157\027\026\204\153\130\147h\213\252\195\014\209-L.^\146\163$\144\152f\236\228\199\016,\190\232X|\145\"\157@\246\019%\146\189\169\129\028\250}\222\252\219NI\0288\131\021 \152\1588\152M\220\140\217I\137\131d\171\130\192l\195\129wh\243u\222 \155\129\180yg\"\151}\160\207\242\245v@\141\234\144\147\027\185V\154\011\200\138\011\148\244\150kR[\000\210\154\001\253S\027\159\209\157\250\tZ\237\226\027\018\243\240\245\227`\156\127\238\213\207\244,\185N\241\162\174\213\179\005M&\229\235ob\205L\019lN\217k\204e\158\006S\254\169\159\207h#j7P\217&rA\227]\208\128\011l\143$0z\166A\207\164\254\135/\191K5N\234g\210R\174Y\161\012\165\002\170\161\016\000\173\133Ph2\132F\237\134D\190\241\144\000Z\016\161\216\140\b\198\182D\176mP\004B\171\202\019a\218\209frlf@idtm\221L`\224k\1468\135\019n\189N \248\152Ppt\222\136\b\215Q\219J\162\029^GU\216\157\185\2236\208\004J+M\215{\188\182\237\149@\219h3\024\180\\\018\217\230K\211\149\2246l\200\t\245\1739\225\210x\233:j\215y\225\201V\185\137\236\214\020]\223\020\\\223D\174\143[\189]r\0024\012\011K\002y&\215\154\224\132\215\150\019p\1466\227\242\247\011,\000\196`\255z\001\160\0171\248?^`\005@\012\240\167\011\000Fb\176\127\185\192\130@\012\250\015\023L\0003\196\144@!\006\186\182\209A`\016\029$q\209A\184\141\014\002!\002\b\133\b\200\251\139\225:j\216I\180\195\235\168\n\1873\247[bH\160\016C\186\222\227\181%\006\002-1d0 \006\018Yb\160\r\183\2246$\006\252\171\001\182\180\180~\186\142\136!\175\183\218*7\145\221\154\162\235\155\130\235\155\200\24511\216\149V@\195\176\176\196\144\151Y\173\tNxm\137\001\215X\025W\134\210\244\160a$\t-C\170\208\178\1440t\129\1286\180\024\201C\203\028\133h\161#\018-\004:\209\"$\021%\131\1683\018K0J\164hF\163\016qZ\020\197\157\150\251\232\211R\136A-\194h\2112\1409%+\160!\173(l\023\163\229\138\239~\250D\160+%R\164\165\208}\140\002\129i\017\208\152\017Ed\166\011\000\165)\209\1830h\028\189)Y@rJ\170\248L\163!\225\153\237\019\145\233\154\178G\154\159\132bs6\020\155r(\022H1\2168\017\202\206\004+\208\164\2175\017\153\242\020\163@\156\225\150\t\146\226\177\006w\156\161_\t\206\133\205H%\023\176y\176E\213\189\209Y\149cxV\229\200GS\248\222\2408\210\017\255\160#\226\250\t\158\239\184t\016\213\145L=\141\227\219\030mJWWxm\231\1502\024L\029%\209\r\\\175y\198.]\127j\167\239\2055\245n\022\148\158\201\224yB0\205\246M\156(\2254{\248\189\235P\137\018\190s/*\000u\157\002\152\253\154\140\170M\154\140\229\157\153\012\240^KFx3)#t.\143\175\2436\203\012\144c\151Y{-\171P{\222a+@\164}\021ho6\2082\136U\170\\\149*W\165Z\255F\r\235P\161:P\168\198w\227\238V\198\157N\188\143\149\001\180*|\249\239y m\231YR+\006r>\197\128I\162\024u;\147\158%]b\128s$F81b\132\178!\190\206)P\006((\230Y{I\143\158\229k\017\012\216\237\245\207\240m\bF]\222\247l\191\004\193\160\205\000\159%(\004\129\\\239\185\255\n\003\255F\r\235P\161:P\168\198w\215\225.\181g\245=\005F\242g\020\024\176\137\2293\007\005\153\245E\029{y\193c//x\236\229%<\246\242\018\028{y\137\142\189\188\224\177\151\023w\236\229\197\029{9\245\\\198\191s[c s\025\003\193\222\243\147\2252\198\236.\243\147\2262F`c\252\137\185\140\175\237\150\241\019wR\195\012ha\133\234\195q\129SxF\224\020\028\0128E\167\001Nx\004\224\228\246\253\159\220f\255\147\218\225\127\194m\253\167p/\255)\216\192\127\194]\251\167\194V\253\147\219\159\127\194M\249'\220\137\127\146\014>\219\149'\156\199\022\000\253\237\1323\160Q\213\220\1323\b\160\1460\225\0120\154\218L8\003\b5\182)\155\173\181+V\133\181\198\224\202h\177\214U\169\214Q\172\145$\180G\021\219\163\138\237Q; \172N]V\188.)^\135\234\021\002\147\132\177\238\024\162\132\134^s\193\202\234\169x\021\012j+\002\136Z\017D\150\016\1697\134\200\192\030\"\192Z\139\004\157&\018\027\199\130\131Q\220Ilg\150\168pU2\011\134\181\018\1563Ku\198,Q|\139\176d\179\170h\179\170h\179:\194J5\173\207V\168>S\161\186\164s!\244E^\172\0196\000\017\148\220\141\205\224\199@\242\187\031\146\1951\144s8\001|\006\250\195\228p\130\169\028\142A\155\150\254P9\028#\144\150\254\232s8\254\141\026\214\161Bu\160P\141\239\198\028\142q\167\019\231p\012\216\204\248\007\247\001\000\128\182\182\015@4\168\136\235\003P\224ml\251\000@\177f\208\007X\184v@X\157\186\172x]R\188\014\213+8\004\250\000\128\1935\182\015\200h\178\184\007\160B\132\130\1272\026T\147D\190\154Y\224\253C\0180\000\161XG\130\209?\t\174\029\016V\167.+^\151\020\175C\245\n\254!a\172;\250\135P\240\143\216)\006\161bJ\002\190\210\146\160\218J\236\171\174\133\222oJ\n\198Q\018\180\129\018\161\015ET\135`\177\202\245\249\138\213\231*V\023U/\248V\021(\215\r}\172$\226\231\223\246\247\023\213a\255~\179=\028\243\197\175\155\167M\247\251m\189\127\250G\245t\216\222\029\255\031S\224c\026" let helvetica_bold_oblique_afm () = "x\001\181}]w\0277\018\229\187\127\005\031w\207Y\205\146M\178I\206<%\1773\147\216\137lGMZ\243FK\180\1965%:\164ZT\251\215/\186Q\168\143\139jz_\246\228\196\135\188\023\221\r\020\n\023@\161\154\250\235i}x\250u\255\248\244\199\230\233\176\1899\014&\255\024\189\250e\255\240\176y|\026\252\178\255\214\028\182w\247O\131\255q\243?\007\163\197|\250\191\218\127g\221\191\139\246\223\197\176\251w6\248\233v\255y3\248\1719>m\030\142\131\223\030o\246\135o\251\195\250is\251\143\193\224\167\221n\240\177\189\207q\240qs\220\028\158\003*\0159l\214O\219\253\227\224u(\253\207\193\213}=\248c\221\012\006\163\193\168\248\231d\250\207Q\209=\129\203W\143\219\191\235\205o\175\007\147\241p:fx\249G}\\\223m\006\163\201d^\012\202\249t^\190j\219\245\231\250a3\248\207f\247\188y\218\222\172/~\222\239n/?\239\218[\188\250\181\222\237,=h\233\001\243\235\135\237\174\177%^\1736\157A\218\130\175~{Z\239\1827?=\222\2376\131\139Q\241\234\183\227\175\219\151\205\237\251\237\211\205\253\224\203zw\220\188\250\229~}X\223\2529\216\188\220\236\214\015]\177\197$\148\025\0073\134z\196\178\147Xv2\155te\255\174\247\193\148\159w]\233\209b<\152Lf\131i\177\144\011\166\241\130\233\180\236.x\172\031>\183\157z\247\216]R\182\149('\147A\185\160\242\165-\127\187\223\237\214\135Xv\022\\e4\029\148E1\152\205\166\177\248,\022\159\207\023]\241o\155\195M;h\186\234\132{]\140\022\131\197p\020\170Cm\157\199\242\179\162\232\202\175\031\194\021\199\208/\221\021\225&\237\005\179`7\174\255\194\154\176kp\244\189\238\025\161R\147\2014T[.\153\012\173=\191\173\015\155\199\221\230K\188bV\182\2218\015\022\028\134\007M\226\021#\231\ny\200E1\141\215\140\203\133\\C};\166\150\175\143m\189\142_c\181&e B\213\230#\169\022u\243t\030\187\238\219\174>\198V\023m\031\004\003M\135e,9\177m\190\tJ\180\238\138\134\145|1*\231\131\"4\185}FWzj+\127\223|\187\223\196\222\157\141\007E\232\176\241l\017\028'v\216\164\180\247\014\230\223\238\163\245\203\214\217\204\157g\224\190\187\245\241>Zd<\235zj\018\2342k}\160-=\183\158\243}s\216\199\246E7(G3v\131\201\194\150\221?\198a1\n5\030\146\255\198\146\211\161-\249t\1387-\202\206h\170\224\b\n\222\0316\241\166\2294>?t \023.l\225/\251\250 \227a\186P%\199Pr\251\188I\214\234\238\026\156<\141\157\233\196\150=n_\162\001\168\002\186\1820,\143\155g\234\179Qp\182\208\178\153\186-\012\201\r;f\185\160\027\151r\227\025\140\247-\153v6\167\178S);\183\158s\179\223\237c%\022\173K\142\131I\167a\146\236\138.l\209\227\230a+\197\167etK}E9\180\238\190k\167\020r\247\139y\232\148i(\026\135R9\178E7\127\215\235\168h\161\134a\020\149\225\161\147P\247\174la\203\222\181\147\252&v^\1717\225\206\195\133\220\153z\175\028\141H=6\199n\206\139\218\017-\029\134h\017]\184\164\014\\\180\234\214\142i\018\025\242\224E\232\224\228\237\229\212\n\217O\209+[\247\153\rE\139\202\210\022\2519iP(\022\158\198\197f\182\216/\241\185\1958\202f\243\133<\023\004\244\181\186\225L\230\137\146\250\171\236\238\252\231\224\141*6\149b\179\161\181\207\175\170X\144Q.F\0294#!\2487U/\186\212\188\029\216T\189Ya\171\247\159x\195Q\184\225|(\237\157\141\173\178\252&\0024.U\245`@\253\158\198\232E(P\142UA\232\141\183\209\211f\237c\167s)V\218\230\190\147\230\182\016\023K\147\0269\251\031i\176\r\007\139\145\186\027t\197\159Rl>Tu[X\227]\154\190\157\023c6\222|h;\237\189\234\141\177^\192\002\226sX\154\127\221<\241\162\163\232lY\134\249\178\136Fi\175\129\197\225\231p\137\204\176\163\"\206/\227\161\012\174\197\216}\138Z\168\140\230\244\156\214\t\210s&V1\215\199\155\237\246f{\184\169\227\026s4\030\133\133\2348H\252\136\167\156\005LOu\187\252=\134\181{\156K.\138\214y\131\021\166\161\235/h)\184\128\149E\183Rc\011\180b;\t\2509.En\0230W\1975\206\180\157-'\161\186\161J\180\016Y\204m/|\142#m\212\021,'S\233\007XW\220D\135_\196;\0066\2211ly\236-oyn\n%g\202CGCXX\208t:\164{\142\213=\011\219?_D\133&\237\202\177mv\208\156mXDt\031v\131/;\186\018\230\169\1878\159\133\222,\130\184\150a\022\145\135\192\024\140\238\018\1672\181\238\031\r\167\182;\182\162N\227\178\245\142)\149\131n\251?\177\135\195\2426<{\002e\161\195\190\202=\203\217P={n\239\185\211\207.T9\234\174\180{x\144i`1T\1575\130\206z\180m\150r#[n\175;\181\156\168\174\026\021\182\228\183\232\164\243n\139\215\185\148\020\1975D\188\233\144\138\150\186(\245M\218\019\028\164=\147\185\174'\174\254b\18519\254D\149,\173K\209`\n\222{\209\142\242\162[(\198\1463[\205\186+\185\152\199\182\135Ip:.\168$,\212\159Ip\186i0`R\016f\174\019\021l\215\232\243`U.X\192\"\253%\022\236\250g\162\158\\\192Pj\186r\201\213\202\169\190eZ\231u\0035\236&\006\188\190\234\148\129\203\141\173\201[M\020\213YL\162\030N\219I\172H\151\164\237\213|H\194+\203\199\162\152F\137\"QkE.\191\191\167\184\173N\243\019JGr\159\182\187[\218\229\004\203\140BoO\195Bc\220n\011\219kJ\152Bb\020\224v\127\162%v\183\232\t\187\202\169j|\t\219\024\222zw\138\023\170\214J^Y\208h+a+\211nXC\196\231N\238\031\246\028c\017\211QZ\014\143h\146\252\210\006\156\210\2349\198\150\218=\224\\\246u\163\018<\187\217\1688\195,\012\1654\195\140J\216\213|\217\237\015[\186u[\153\"\220\178,e\225;*A|\142\027\169L7\021\180\227\166\221\185\021\233\002\240\243\155\250\016\182\2457\209\233B\161v\139\021\\\160\221\193\197\242)\2120V\019\216q\219\005\225x\n\011{\226q!\235\136QZA'?M\001\0255\241\r\187\137o:WU\155\193@\184\171\183\225\138\135\189\172\024FmG\004\199\r%'\243\t]\005\243K{UW?uU\187\175\232\156D\174\026\247\\%^\028\188\164\189*\184\175\\\005\211\204\151\173Lfe\240wi\202\020\n\238t\193\169*\b\253\023Bji\177\0194\162\b\197\202\240\127W\203\1748\244\222\237\250\238\142\246y\163n\208\005\203\148E\169zb\225]\144bc\1472]\"\235\222QZp\219`H;\1386\135\205-=k\216\025\190h\rD\161\159\209\028\198]\136\023\173\239\014\235o\247\162\185\237b\170\237\241!\r\140\180\198\030OItB\136x\019\173\031\168Q\016\170I\209F>\210\019 \004$\190\248y}\140\2388\233\150?ep\2152(\014\0259\173\188\209\029\249\170.&7iW\162cuU\233_\165\227lE\023g\155\206\213\018c>\235\241bu]\187\146*\187u\"\187VZ\162\135Y,>.\004s\183\223\142\2198\011v\161\135E\b\251\165(\212(\173\213\185|\232\166\167\251}\205a\195Y\220W\132U\148\196mF\011X\011\164\173\191(j;\221\006\007\157\134\216\006+*.\177C\175R\188\167\141f\150\1615\237\216\154M\211C&\182\248\250\166~\138\197\011*>m\227-\\\028Buq\021\254e\183ya\191n\175\153\180!\t\190\006W\000j\026\025S\216P\182\b\163\180\166N\197\031\2147\135\020\239h\151\011\237\237\131\195\1493\234\195\005\196\128>\0316\169\193\211\216\130Ih\164\212\006\226@\183\251\167\245\rO;E\016\173\178]4\206\219q\031\0036\197\016\194\177\183\2190\184Ro\143B\189\219+\218\163\021\185\002t\238\144&\169\246^\211 \235\237P\153\209\194\167\024B\151\221ln\131\027\198\189D\023\167l\207?\138\"E\219\139!\198K\235\199\187\245\161~\216\173\235'\169\211\1446\022\211t\021t\195\254.\196,\191\242@\236\158\209-\244bi\232\133\1555w\194d\017\253\162\r\018\241\205\179\017\241\128\218\024\214\222#\022\199\"\173J\248\130\159b\128\167]q\141\218\213a\026\163E\145j2\139\005\247\135\219/!v\199a\193v\1293\t[\156I\152\220\146\019\021cX\029\191\147}\233x\002\193\146\"\029_p|C\021\158v[\197y\235A\020\127.\210\t\006W\253\242M\154\131\186A\220.\162\165\"\169\175\202i\170\253CXL\213;\169\2548V\127\174\170\159\194\249i[\177\142e\187(e8\005+d\031PL`\151t\219N\193\199\163\222,\021\178*-&\184\177\145\182vA\144\137\138\251\020)\200\205\187\017)\\\180K\222\160\164\161\230\211\146\156 E\186S\136c\031kM\187\151E\152>\185\214S\208\1820\207\133s\191 \216\199T\239\184\232oua\212]r1\178\021\255\205\140\194\184C\t\189\180\024MMq\158\171E\216h\227\219\206\213\201\127\177\244ZD\1326\243e\027R\129\210\188Q\201\006 mZf\243I\239#62\162R\133Fyi\142\238X\205\225(O\214\\Z\175\223n\159\183\183b\254\176A\233tv2\247\239.\198Q\183\166Ue*\204qb\208|\138\024\231\023\1761\229\238\201\152\142\2339\210\150M)\018s\235{B#O\208[\177>\211\031\187\227(\165\250\237\190\181\213?\189q\205\251\203\214K\133Oz\155\194\178o\026Q\022~i\219\197\250\138\030\159^+\to-[\0206\232\148=Au\243\025\171\178[\171\219\183\014\221ZHo\195\209\139\222\152\006p\164\030k\207q\2550\173\211\241DY@\240\159\007;\1735\177\195F%%\005\132\149\216\005Z\127<\163k\210\017?Kgh\239XT6\171\191Zip\237\231\229\196\181\253\141\026\190\139\222\225\203=\197\158\160b\131i\254G\195\252\153\185\231\"\182V\199\228Q\014w\210\183\157\232OC\249\222\001)kB]\157\030u\187\202\140\223\134L\219\250\232\12896\226\023\229k\234\016\168\183J\178(L\0261Z\244\247\148]\180\245\186\154\012x\238,\nQ\157\235\172\163^\127\157\147\006\014L\130\237'\237\182\tn>Y\208!\226\254\251\230\241.\022^t\177\160R\150\022h\196\143\202\201\210\145G&\203\233D+\235\166!\141Y}\186\149\141qP5\021m\235\245e\184\228\140\011\241\148\161FV\156.\130\215\224\200\226\144\163\234\172vV\159\182\017\129\158\186\220\232\174\154\2090\209Qrl\239\127a\185\159\142A\208s\146\167]\221\239\015\186\003Fe\238\241i\213\1687*\234l\012\219\201\157\171V$}\157\203\231YR6\029j\133\187d\1740\161\253\137X0\173\189\194\022\163o\164V\186\222jZ\192z\179\203\176\150ig\001-\227\189^\155\195p\172\187\176D\012}\132]m\209\134\132&\146R\147YR\237Y\149!{\023$R\156O\175{\203\202\194.\150-\028M\1625\212C\189{\218~\219\197h[P\151Q\023[\156\014\167\190Y\164\139\206\012\"\017U\181\159J\135\143X\145\164\025!8\243\180]\239n\183_\226y\204\164\213\164\176\238\158O{\007Fc\230b\179(\162=j6\235\128\136\181\147\rV\136\005\015$ \170\222\164\127\249\250\006\023O\172\216}\243\129\169\127\146\152v\023\006\213\231\229\153]|\012\127x\193\141\026~\139\222U)\159\215(\235t\135\002\211I\255v@\r(\229\n)`\145O\247\162w?2\252o\170\026\147\190Y^eg\133m2\165huNV\182\007\158C\184u:C8\236\191n\030\211I\194\180\213\141\208\1906\233*E\000q\129u\216\220m\143\018g\156Ni\1335\201f\027\158\163TlF\165^\244\182\214\138u\153R\t3\177\166}\248\177\0143\160$\199\180\193}:\214\027\250\178\250F\148\163\215#yZB\211O\250\151L{\229\001\234\236\014=\128'%\021t\227\t\169gQ\254_\241\150\222\178\211I\1722e\022I2R< \235\182\237\254\156\244\230\137\014c\251\022\228\188\188\211\019o'\210\221\130p\158\175\217x\129\138\235\1471\173\"\245y*\026\253I\201d<1ls\224\230`G\214\000\181a\153\r\211b\224\204~H\149\031\165-\133\206\237\200f\015\213QQ\180\135\2533\141\017$Z\245\148\253\241\t\229\138\253;K>K\132\138\180K\030,\203b\173Z\217\222\183\219&\234C\241l\250\205\151\238\222\244\203\206\174\214&\228\235\2113;!54X\214\167\217\208\224\181\184\026u\227^\149\230\166\218\152P7+M\167\249\148\151\026\138\161\134\255\135\197F\165\214&g\247\208\180\201\221\236\158h#\209\014\189\224\188\237\153\138g\198'^i\1983\252\185I\011\201\214U\167\189YU\133\182\022\2436wz\209\191\170\178\241\005\221\214\145\191\164y\136'\240]\168\175M\020p\246\254ly1\011\197\028\251\195e\251,\\\150\146V\230gV\016zl\151\209\137u\030 >\228V\162\011|\247EVz>\158\012x\153\026d\242\016\228\146\014q\0224\155\229\006\229E\185\214\1929\133\208u\178\025\175\227h\212\238`\166\159\150\253\251\231\183(\151s\210X\157\r\136\141~\007[\138\022G\207\228\168\181\188\151\208\249C\155a\029\166\201Q\155\210\130\247\151E\150\221w+\161\130!\198S\184\242\139\148\027\217;\221+i\160xn\217\187\011y\007[\227v~\237\235\221\2248\247\235]\\;\143\198E\236\216\233<\235\2164o\182\241s5i.(\155\025'M\246g\144\0175\227\247.'%\220\017\151\147a\134\202\022MIq\242\227\157$<\243a\239\142\241\r\238.\207,\1827:\2405\236\213d\142\213\203*N\231wa[\149\245id\217\014\024\150gF\150l`%\135\179ws\156\r\1493c\145\2130\183*)\226b\152?*\141\224\2190MoR\162\1278v*\218c\232V\132\n\2233\196\251\2078\133\172\169\214\024?\240Bf\188\205\144\155\159\139\218L\210\242\245v{C\030\221\230\142]L\218\220\145v\028\012{\162\179\024z:\1794\198\014(h-\165S\198\178m\143\026\002\188\237)\198\190\029\165,\219\177\127\192|\196\234\204\168::c8\215\147\158\139\244Ia\182\198\147z\197\005^\bj`\027\184\172\154\192\138!M`\195\162\255\222\234\2048\0055\240\228 \249\178:Q\215\211:\212\132\023\143\016\003K\025i\168\225\178y_ga\241^\r\215\139\205t\172\172\019\226Q{\190\246\005\187u:f\022\153\225m\237\188\232\018\006\218\195\173\241\176g\n\194`ELf\236?\247xT\211t\020\231Q6\172x\029\134\213\159R\208Ug6b\245w\251\187v,>\238\147\240L\187\237\176~I$\027\001f\241\166\197\164\240/\168\205\005Z 0\030B\002\017j#s^\171\209\2371\127\216\163Mg\254\020v\151\237\231\212\\0\239\153\2476\180\191L\r\152\r\179Q\204^\1706\186\209C\251W\148\143\153\019M\201\137\138\\\1288\255\225\209\006&G\147y\183\134\030\207\243\149\001/s\245\018\165\219^\132\007\244\237]\222\212\244\250\152\188*\249\230\241V\189c\025_\186|\1879<\190^?\173\229\219\251\2456\172B\195Q\253\232\213\219\247\159\006?\r\194\189'\195\2449N\236\n\136\134\210\000\173K\005\250w{J\150>\199\233[\001\218z\002_\170\235/\241\161z\235\164Pv:\133\197iJ\001f\230U8\217V!1\221@\001Q\232\004\248\160>_\r.\022\252\153l\162\000\221F\134+\213^:\029U\128n\163\160\210F\193\168\141\002\2166\n\158\218(\b\t\166B:\225\151\239\203\193\197<}^\133\016H\250|\029\028n\196_\168\242\n\145z\nX\015.\198\252\153.\017@\183WP\185\143`\212^\001l{\005O\237\021$\181W\144\216^\254\254\172\250\244\164\240F\127\198\1867y-c\0175t\b\000W&\020\006QBq$E\\\r'\002`L\017\234\014\172\200]\226=/\221z\185\227\140\168|\176\017\001#\142P\127\216\017\137c\143`\024\128\132\194(\140\232\007\004\212x$\000\006eB\189\145\025\185\n\173\134c\148Po\160\018\149\143V\"`\200\018\234\143[\"q\240\018\140#\152`;\140#\168\198r\004\212\128\142\128\030\213\132\224\208&\216\025\223\145\169q\012\224H'\212\027\238D\245\141&\028\248\132\250\163\159H\148\000\130Q\007\b\182b\016\193gt\173\019\150h2\192m\178\163\018q\224*\149 \000F#\161\160\018\tE\149\136\184R\t\002@%\buU\"r\151x\207K\183^\174J\016\149\171\004\017\160\018\132\250*A$\170\004\193\160\018\132\130JD\244\003\002J%\b\000\149H\168\167\018\145\171\208j\168\018\132z*AT\174\018D\128J\016\234\171\004\145\168\018\004\163J\016lU\"\130J%\"\160T\"\002Z%\bA\149 \216Q\137\200\2128\006P%\b\245T\130\168\190\209\132*A\168\175\018D\162J\016\140*A\176U\137\b>\163k\157\176D\147\001n\147\029\149PFPR\161Q\024\151\154\002\2090\020*\135\"\149|h\0204DS\174\144\168\002\151\238s.\251\171\238\234\138\230sq\209,(\140\166|\153\209%Pk4\007\130\163)P\029E}pQ\165?\026\005\0172\148\167D\170@\229\218\0305IS\1580i>W'\205\130Di\202\215)]\002\197Js\168X\154\179\178\165\024\165]\nU\002\166P\173b\026F)\211\156\163g\138\174\221!\139\202\166)O\2224\127V\011P\2324\229\171\157.\129\146\1679\212=\205Y\241S\204\179\235\225'\183l\227\163\253\150rT\145\017\165\137\130\129\172\b\001z\168\bTC\166\148\022\n\006J(\132\171\131L_:\247\191\236\171\172\171\128\194\230\250'\028\168\159\016\190\246\t\143\202'\012\232\158\016\160zL|p0\165x\130\129\222)\194S;\166+\199\190\168tBx:'l\174r\194\129\198\t\225+\156\240\168o\194\160\186\tc\181\141q\165l\140)]cL\171\154\128\168i\1948\138\198P\237\0126T3!<-\019\246\204\248E\029\019\194W1\225Q\195\132A\005\019\198\234\023\227\207\142\175\158\156r\141\135\245\217\196Q\173\216V%Y\004\128\004\016\nb\149PT\170\136+\153\"\0004\138PW\160\"w\137\247\188t\235\229\234\018Q\185(\017\001\138D\168/GD\162\022\017\012BD(\168PD? \160\244\135\000\016\159\132z\202\019\185\n\173\134\154C\168'8D\229jC\004H\r\161\190\206\016\137\"C0*\012\193V^\"\168\180%\002JX\"\160U\133\016\148\020\130\029=\137L\141c\000\149\132POF\136\234\027M( \132\250\234A$J\007\193\168\027\004[\209\136\2243\186\214\tK4\025\2246\217Q\t\170\157\146\137\132\192xL0\b\005\195\168\020D(\169H\bhE\130]\177 \2422\187\239\165_=W/\018\151\011Fb@1\018\236KFbQ3\018\014\162\145`P\r\130?d\136\210\141\132\128p0\236)\007\145UfC\212\142\004{\226\145\184\\=\018\003\242\145`_?\018\139\002\146pT\144\132[\t!Ti\b!JD\b\209*\146 \148\145\132;:BT\157\r\019T\146\004{R\146\184\2221\135b\146`_M\018\139r\146p\212\147\132[A!\2449\243\186SV\166\201\017\191\245\142\170Pe\148\170$\004\134m\130AU\024FU!B\169JB@U\018\236\170\n\145\151\217}/\253\234\185\170\146\184\\U\018\003\170\146`_U\018\139\170\146pP\149\004\131\170\016\252!C\148\170$\004T\133aOU\136\1722\027\162\170$\216S\149\196\229\170\146\024P\149\004\251\170\146XT\149\132\163\170$\220\170\n\161JU\bQ\170B\136V\149\004\161\170$\220Q\021\162\234l\152\160\170$\216S\149\196\245\1429T\149\004\251\170\146XT\149\132\163\170$\220\170\n\161\207\153\215\157\1782M\142\248\173wT\165{\168\210\148\248\029\134l\004AO\bD5\233`\165%\241;(I\004]\029\233\168K\184\223\165W!WA\"\147\235G\196A=\"\232kG\228P9\"\n\186\017AP\141\014\252\000\223\149b\196\239\160\023\004zj\209Q\021\216\t\149\"\130\158ND&W\137\136\131FD\208W\136\200\161>D\020\213!\162V\027\186oJ\025\186\239J\023\186\239Z\021\"\128\154\016QG\017:\162\006\007G5\136\160\167\005\145\233\025'\168\003\017\244U r\168\001\017E\005\136\168\029\255\221\183g\240\159\019\240\r~\247\218\233\140\250\232\171j\216\019\000\195\140P\024\248\t\197\145\031q5\244\t\128\177O\168;\248#w\137\247\188t\235\229\142\127\162r\001 \002\020\128P_\002\136D\r \024D\128PP\129\248\245\003\002J\007\b\000!H\168\167\004\145\171\208j\168\005\132zb@T\174\006D\128\028\016\234\235\001\145(\b\004\163\"\016l%!\130J\019\"\160D!\002Z\021\bAY \216\209\133\200\2128\006P\025\b\245\164\129\168\190\209\132\226@\168\175\014D\162<\016\140\250@\176\021\136\b>\163k\157\176D\147\001n\147s\149\248y\240\147\254l\175\2509\157x+\1921\218\207*\158\1700k\170\159y\219\163\016\176\193\207$f\234;\r5\006\194\136\024\241\231\228\024\012\232\202\t\170\028\1331\170\156\000\182\011\005O\149\022$UZ\144Xi\250\254\186\181\232\132?[U{\205\022\021\192Q\184\215\218\162\130Y]{-\022\021$UN\144X9\249n\197\235u;$\249\243J}\014\003q\198\159\169\021\002H\245\024\139\127\195#u\213\235\244w7\024\136\234\167\140C\000X\136P0\019\161\158\173\136\202\rF\004X\141P4\029\193h?\130\173\017\t\004KFt\137\192\n\001eX\002\192\186\132\230&\142\004\2169\130\153\177\187\183\027\181\177#\128\198\142(\026;\162\174\177#\229\024;\018h\236\136f\198\142pf\236\b\131\177#\136\198\238\208%\002+\004\180\177#\128\198\142\168c\236\142@cw \024\251\215\214\206s\254L\015\016\128\172+\1286\172\160R\005\193\200\156\002$K\n\146\140(H\180\159|'\2111\176n_\215M\159\169\182\002Pm\005\208\181\021Tj+\024\213V\128T[ARm\005\137\181\149\239T[\006\168\007\218\191\224\021\129d\253\132\252\222\154\191\224\207\182A\191\179\249\005p\026\244\1876\191`\182A\191\139\249\005\129\006\253\158\204/\223m\131~O\r\226\239\169=\012\212\25036\167vk_;\181\175\177\246\176L\017?$\2343C\162\254\241\144\168\207\r\137L?\012i\165DS\141/\024(0\134\203\180\230\157\138\003\189\195\016\208;?\250\243\174]\216\166\160\198\187vQ;O\159\219\240H\193_\210\224\020D\141*\006\237o\221_\140&\134\200P\137%\188\1950\194;'\130\240\014\223\230z\231\190\205\245\238\204\219\\\239\248\229'n4\191\25347\128n>\188\253\004\176c\136\200\244YC\177>\213`\147\2098}\239\016\153\159\014Pv20X\203r\158\2054\168-\167qe?\rk+\026\028miH\199\162\154\239\179kV\230\\\129\1987\026Z\186g\200%:\202\158\1784\001`\227\132z\214\141\156\182kD\148E#\160mI\bZ\145`\199~\145\233\179\156b}\170\193&\163\157\b\205,t\217n\153\166\252\217\006\149/y\203$\128\019`\190\212[&\193lX\249R\182L\130@\188\2482m\153\228;\205M\012\\\177\156^r/*@w \195Ku\253J}\254\164>Kt\224\018\003\003\151NL\2242\237\221\248!i\239\150\128x\015e\\\002\192\194\132\130\153\t\245lMTnp\"\192\234\132\162\233\tF\251\019l;\129@\232\t\214z\219`\236\019O\235-\183\196{\174\016\248\132\128\234,+\253\128\230\221\022\t\232\187\bb\007*\227\171^\212(t\165\166\160?5\229u\170\230\243\158\213,t\175\166\176\1435\135\029\1739\219\219\154\129.\183\239B9v\194\206\239}\023\202)\176t\159\179r\209O.\170\188\194yE\200\163r\255P,8\137b\208S\2486\202O\004\003/\017\002|D\b\207C\132\205\253C8\240\014!\2087\132A\207\016\198\250\133\224\224\021\250m\145\204\"\232\017=o\139d\244\210\185\255\202\193>9\152\242\131\236\165\138\156\200}\128\017\240\000\198\177\255\163\213U\231\019\000=O(t;\161^\159\019\149w8\017\208\219\132bW\019\140\253L\176\237d\002\161\1359\025\2236\024\251\214K\198\183\220\018\239\185B\224\019\002\1703m.;\160y7F\002\2500\130\216\129fW\169\250\209\226\208\157\150\132^\181\164\215\185\182D\222\199\150\135\174\182$\246\184e\177\227-k\251\223r\224\006\134\188\234\177\030:\005\144\158o\152\"\203\158\231\173z\240O=\184\242\027\139\131\251X2\247\"\195\1313\025\014}\138:EySB\192\143\018\012\030\148`\207w\018\151{Mb\192_\018\140\158\146p\244\145\132[\239H(\248\133$\221C\219\209\023\220\164{ \151\217}W\025\242)CToC\174:\194y\015\019\003}K(\246j\220F\169N%\000\250\148P\232RB\189\030%*\239P\"\160?\t\197\238$\024{\147`\219\153\004B_\242~\2176\024{\210\219/[n\137\247\\!\240\t\001\213\137v\251\012h\222\133\145\128\030\140 v`l\175\234@\002\160\003\t\133\014$\212\235@\162\242\014$\002:\144P\236@\130\177\003\t\182\029H t '\156\217\006c\007z\tg\150[\226=W\b|B@u\160\205\215\0024\239\192H@\007F\016:\240}\219w\233\188\247=\247\155B\168\207\020bs\129\024\214\201@\012r6\016#\146\246\195\144\228\2530\148\018\127\024\160~\017Dr\007\222\243Y\187\0006\187\234\189=k\0234\139\223\188\231\179v\001 \002\254^\206\218\0051\177\238\247|\214\206@:k/\018\160\201\rV?\157\255(\192\171\254\198\169\190>\222\017\016\219\180\201\218\180\201\218\180WN\178\183\145\249\247\246pF\208,H\255\158\143a\004p\211E\223\203\129\139 6I\244=\031\1730\192\025\011d\215\015*\141\237\003\166\177}p\211\216>8il\0310\141\237CO\026\219\135,\141\237C\150\198\246\001\210\216>\1443p\149\169\017\244\253c{n*\159m\150\194G{B*h\150\165\240\145\207B\005p\179\020>\202\169\167 dx\001l\170\197\199V\017\2293y\171\002\180\0142\\\233\207\216\174\202mW\229\180\171\194vU=\237\170\178vU\144}\2411u\r\127\023\153\254\168R\158>\182Z\204\248\181\157\220>j\005NX,\162z\146\000h6\161^\219\137\202\r@\004X\129P\223\020D\162=\b\134\206&\020z\156\227\147\000@\223{\241I\203U\025\224\218\164\234\183I\213g\147\202\181Iu\206&\149o\147\204Q\b\182\222\130\001\215\143\028p\157\024\224\026K\160\007e\241\213DD\235*7\"\000LF\168g2\162r\147\017\001&#\2127\025\145h2\130\193\141\b\0057\138\232U\006\128\027%\212s\163\200U\025\224\218\164\234\183I\213g\147\202\181Iu\206&\149o\147\204\141\b\182n\196\233\173\182\215\149\027qz\171-\129n\148\165\1832a\179r\n\015F\243\245e\229\184\005\028S:Y9.\215cV/+\199%\209\237\156\172\028\143\187\234\129\209\017{O\139\189\018U\015|\198\182\213\143l[\157\183mu\198\182\213\143m[\157\179m\238\190\154\004'\182\135\230\158\231i\135\182g\230^\233\204\185\253\019s\162\175\218}\204\130?\211\181\002\208~@\000mvA\229\190\130\145\129\005H&\019$\217I\144h\028\249N\158\200\128\188\164u\133\239g]\185\175f]9oe]\225\011YW=\239b]e\175a]\225\027XW\248\242\213U\187\195\154\243g\155{}\197;,\001\156\220\235+\189\195\018\204\230^_\201\014K\016\200\189\190J;,\249ns\175\175\194\162zg\218G;.\2307\252>\212\021o\184\004\160a\175\000\213\026A\1655\n\147\r\151\128\212D\001R\019\005IMd\228\190\249v\191y\148\205\204U\187\005\227\250\239\177\007\246\174\193\247\142\193\247hp\216\130\t\158uD\218\130\t\128vO[0\006\014\2503V\218\252\193\018\129\143\155\135-v`\173\134K\141\003\186v\199o\237\140\223\026\199/$\189\t\158\141\235:\027\2155\140\235\147\234\190F\127F\007kr\207\225\183v\022\022\128\166\218\183v\000\245\172\144\189\181\003\004\216\003\222\218\001\024-`\222\218\001\0164\142\215\174\019\011\128\2189kW\160r\221\179kW@}\005\132\181+\192\160\133v\237jQ\165)\004\128\143\019\n\250H\1687f\137\202\007.\0170z\t\197\161J0\n'\193V=\t\132\161\156^\130\218\229\006\0021\141\224\006}\025e\149P\208\214\132:\002KT\223X\241\164\150\024\208[BQt\tF\229\141p&\191\017\222c\179\247n\127\239\251{v\223\215\179{\183g{\196\153H\191\219Q\166\tu;\024\005;\162\135\012p\155\233\235w\228\028\017\143D\141\162P\187\026W\247\171Y\221\167f\181\171f=\018O\164/u\181/u\181'u'\244\157&\003\220\161\224\205\002\202\158z.\2080ZKs8/h\206\181\167.\224XU\211h[\205eF\212dfJM\130A5\1333\136\221\182N<\024g\147\190m\171[\192\153Y\156m\171\203\245\2042\222\182\213%q\198q\182\173\030\167EX\1958X5\1353\145\230\\\213\210\005\028\237\2104*\152\2302\169\210d6Oi\018f+M\161\164)\014\181\199Pv\254\210\175\173\248c1\155\2034\1353\154\225\188yM\0238\175\001\238\028\167y\156\2334\151\205w\154\204f=E\230s\159~\161\1977\220\254\140\207\237\127\228W\251\243~\181?\227W}\243\163.r\206\245\178\185Rsg\220+\1557\021w\232\129\207\152\168g&U\1607\159*\186\246\133\178>3[\212?\154\017\234\2433B}fF\232\155su\145s\147F}n\210\168\251'\141\147\239\209M\015|fX\231\179s\1652\027*Lj\1680\159\161rS\025*'\139\161\194\004\134*\203]\168\178\180\133\n2\022*LV\168\224\157\250\n_\167\1750\137\190r\147\232+7\137\190\234O\162\175\250\146\232+7\137\190\242\147\232+?\137\190\242\146\232+7\137\1902\233\232\182\209h\n7\029\189\234OG\175\250\211\209\171\031\164\163Wg\211\209\171\254t\244\234L:zu&\029\189\234MG\175\250\211\209\171q\137{v\193aG\184\228\221\185\0006(\184\204r>\151\206Fy\217\238\142\185\167j\244\165\218u\157\218q\157\026]\007\182\185\130g.Ug.U\027\151Z\181\170#\159m\029W\172:\0028\149^i\213\017\204Vz%\170#\bTn\149TG\190[\127_\169\196\161\021f\011\173\220\020\161\149\147\023\180\194d\160UO\006\208*K\251Ya\174\207\n\019|V\003Iw_\177\130\b`\127\140oe\021D\208,*\188b\005\017\000\130\187+Q\016A\204\207\237\173XA\024 \159\029\201w\029\165\\u9\226\211\2449\229\1363\144r\196\005\200\127/ger\196\005S9\226\012\218\159\203Y\169\028qF8Gk`&\143\004\187\130B\156\163*\196\160\180\016\220\163/\196f\"C8\138'\193\168\160\246\020\007`GK#QgEk\223\018\245\025K\212\189\150\168}K\212g-Q\247X\"\215\\\194Ax\245\145\011kTv\230\2260\168\192\254\169\139C;:\156\157\1878L\166\198\249\201\139C\129&gg/9\163\148Y0\016g!<}\0226\151h\225@\165\133\240\133Zx\212ja@\174\133\000\197fB\137\182`\160\219B\128t\011\225\169\183\176\185\128\011\007\026.\004\202\1840\168\228\194X1\023\028\244\\\029\179\1531\142\199o\249\016QB*\024h\187\016 \239\138p\020^\216\\\228\021\151\235\188\144 \245B\160\218\011\131\130\207\204\222k~&\251\194\184z'\180#yB\162\234\t\211#|R \211>\161p\"\016\006\231\130\236x5g\156\025\129\185\218\187\160\2385U}\222T\2459S\213\189\166\170\127d\170\186\223T\249L!\148\157,\214\003y\239<|\230\223rH\1289+`\248y\144~\195y\221\166\215\240g\1377\1721\222\176v\226\r\164K\170\006\004@5\bu\235\0189U\161\b\156\016h\240\169X?B\243J\198\202\168J\018\000\149$\212\173d\228T%#pB\160\193\167b%\t\205+\169\\P\213T\163P]M\185uV\005T\197\021zr\209\198\173\019\182CSyc\024QM\017\012\026\"\132\219\012\166U#\024;9X\227\212\003\171/D^\2498\160U\205\t\128j\019\234\2149r\170\194\0178!\208\224S\177\158\132\230\149$\233P\181L\bT3\193n=\137T\021%\228\148!M\246l\172k\130\243\202\146\152\169\202&\004*\155`\183\178\242\007?S\213\228\015~\002\210d\207\198\202\230\127\24031\157\188\170\170\198\239P\209\b\186\213L\127\1510U)\253]B\243\189\129\231a\245\240\239\018&<\206\147\170v\004@\245\bu\235\199\127\022-U\136\255,\154\005\026|*\2141\251\179hD|\030\236\248i\2253\207\186\t\240j\021`^\028\016P\171\027\194_r\249\236\254%\151\207\206_r\249\140\127\201\229s\207_r\249\156\253%\151\207\217_r\249\012\127\201\229skE\254\220\232\207X\223\220J7\003i\236\205\224\171\194\191z/\161\223\180F\149\207\246\2547`T\129\237q\218M[I~fc{\230FW2a\177\200=\002\170\186\004\184\207\143\220.\003\160\246\132\158\187\005\180\131W\004\182Z\216\162lE\144\bz\029\012\001\213,\002\220:En\151\001\208,B\207\221\002\154\197o\026\217ja\179\1787\141\152\160\1918z\159C\186i\t\242kF\236\206\129\176\129\t?\127#l$\225M^\201\172\161\t\207\155\218-\252\143\223\2147r\218\026\183\136\248\131\240EF\186\140\189\213\237\224\150\031\021>\223t\127\185L\000\017\207[\165\155\183]\147\248sj\011\003\170\017\132\197\251\170G\017\000\207\139_\159\241\186\019\002M\006@\029\b\205*\146\130\166\244\192\r\252^\149\158-\244D\177\025\188\168\207\141\254l\031\188\241\158\169\163\181\233\193&\004X\024\240\025\175\227\149'\004^\016h2\000\234\150\015\242D`\0187W0\203\225.r\230\217\189\209\201E_\\\180\241Q\172\190\187?H,\132uR\011p\215_ \254\236\220\226\228`/\014\214x\024\212\218\219\0220\199q\030\1684\227Xk&\158\189\187\156<\240\197\003\027\023\196\170\011\147\215]'m\167z\155\156\237\194\128\207x\229\t\129\023\004\154\012\128\250e;\153D\152\228\222T9\155\219[X\2449\187\248\148!/\025\210\228\bT1\223\192$\198d\218\166:\218D\219\194\162\207\217\197\167\012y\201\144&G\160\142\249\190\133\152/\018\"\165\239\027\253\217\206\172_\228\239\143\t`b`\t\205f\222/\246\207\1391\200a\176\004Hp+!\018\211\"d\207\171\130/\028\200\020\192Y\226\127\209aK\193\236\018\255\011\006)\005\135%\254\023\014I\n`\243\205\190\168\000$\001v\12916\176\193\238B\015\140\248cl\158|\143\246W\223\165\181\002rc\021\196\198\023,\182_\190S3\005 \2033 \027\200lk\219\179\173\165R\242\020\250n\155E\160m[\002\243\006\018\147\1812\225YS\137\176\237%\016\026M(\180\028C\129wn(\240\238L(\240\206\190Y\236\162\214(\206{\197>\149\027\200\127\171\216g3c9\239\020\187\020\024\206{\163\216\227\238|\147\160)\r\231\025\244^\237\156\239q\231|\239\236\156\191v'!\211\244\217\n\228W8\247`4\019\204\175r\202\193\000D\236\025g-c$E+\024H'\024\004\192\219\213.\0125\239}\187\218-\144\183\199{\187\218\229\252V\186oW\187$\180\221{\187\154\184\157\154\245vjv\219\225\188\182sf\180\029\174\243w\184\172\223\185\203\250]\223\178~\007/\021{p\211\003\195#z^*Nt\180\208\t\129&\003\224\182\217\223\028#\226AE\195\0300\026\246\224F\195\030\156h\216\003F\195\030z\162a\015Y4\236!\139\134=@4\236A\253I\181\007\252kj\015\206\031R{\140\199t\233\179]\161<\226\161\\B\179\005\201\163:\130K\128\251K\206\143\250\192-!\176&y\148\2275\250\254\204A\001\029\003\207\162\223^\220\251Qe\168\024\000\154\234\230\167\024*o4f\167\024\212o~\150\155b`4\004d\166hP\153\004\143\230\030\221\163\185\199\190\163\185G\254\245\160\145\005\192B\206\175\007\001\149[\200\254z\016\160\190\133\224\215\131\000F\011\153_\015\178\160\178\016o\247m\147\209B\217v\159\t\251{\016#\015Fk\245\253\030\132[\192\177\156\243{\016.\215cE\239\247 \\2\179h\254{\016\030\165\173k\165\2193Zfi_\186\019\029'0ei\002\192\198\132z\214%*\183+\017`QB}[\018\137V$\024\237G\176\181\028\159\247L\012\208`\147\209N}\199;{u\234\177Ws\220~ \127\184`\175n\191\199;\239\189\155\178\178X@\221\158\131|cS\162\193K\240i}\218\179\183Q1\007U\015\183Q\177q^\182q\239\128u9{j\190\215a\174\012S\149\209a\1741\150k\156k\177\026gN\191\247\028\001\178\128zX\019\016H\213p\024\138\022z\140\174`\206\203+\127\026\164\0079\140\253\2215\195\208a\160\203\233J8|\222\177\145\016W?\132\243o\245\217v\200!\157\185j UG\160\024\127-\211\247[\197%\135`\224\142=\250 !\019\006l\156$\193\233UL\190\201^\127\198*{\241\211\131\019?=`\252\244\208\019?=d\241\211\003\198O\015\024?=p\252\148\205\242\183\"\143\170uG;\248\015\236\011\nH6W\144k\169\167\001?\226I\151`\2449\133\180\014A\128\228\163\t\220\029\148\252$\136\014-\165\t\004\128\241\t\005\167I(z\142>\te;E\240\022K\161#Qf\165\180}m\0190-\234Z\139r<\192\185\"\186\207\000\183\165\174\175\017\149;\028\017\224u\132\250\174G$\250\031\193\224\132\132\130'\154\179e0\243\223X\236\136\230A\239$\020\\4\161\232\167\t\2397\191\248&}\247\2206-\146\17376\248\221z1\174\127\019Ng\220\210r\002\160\131\t\005WN(\186\178\249-\233\210\128\183X\n]9\162\202\149\t\000W&\212\181\165\253\153g{\227}\006\184-u]9\251\149g \192\149\221_y\006\018]\217\254\2023\160\224\202\246W\158\173\153\255\198bG4\015\1862\161\224\202\tEWNx\191\249\197_\233\187\231\202)Nb\189\177\193\239\214\1491H\194\184z\128vh\rcgk\014\157\219p\153\139k\022\028]Q\183\254\021\153\211\195\137\202\212\129q\000\244\159\1688%\178\193`\015&\\\248\140\173\252\225\225\031L\1844\014\149\254\131\t\183H6l\156\131\t\151\195!\164\184l )\238o\255\146\163o\236lhi\014\007\152\225\178af\216\031u\178\026W\026u\007\158\t\164y#\168\241Q\024\138n\020\141X\029\1738b \231\136)R\220x\r\185'5\242\202\143\221\198\197oW\003~)\134\000\206q\176\168=\132\212\220\1467\t\241\251\n\190_\203~\146\128\212\225\022U\219VC\164\253f\220L\2063*\226\228\135\207\003Q\157g~\005P\000\146\005\001\156\161\249\172_\245\019\204\014\194gy\181O\0168\237yN\175\242\201w;\162\158\225\183m\158[u\025\243g{\028\244luD\208\236\144\232\153\021C\000+\019\130\195_<}fA\016\192\254\209\214g\252\161\152\019\252E\221\147\146\200\019\234\226\201\021\195\147\163\128'\148\189S\143\214\1572\129;\161\170\157P\202N\248\007\127_T\230\207\011f\254\188`\230\207\139\155\249\243\226d\254\188x\153?/\152\249\243\146e\254\188d\153?\141\250\211\190\r\254i\223\006\255\180o\227\254i\223\198\249\211\190\r\254i\223&\251\211\190M\246\167}\027\248\211\190\r\254i\223\006<\187Q\246m\208\190\r\218\183q\237\2198\246m<\2516h\223&\179o\227\216\183u\219i\250\156\220\150\001\227\182\140*\183e,\185-\003\224\182\140\179\2192\146\220\150\129\228\182\t\128\177G\019\140\242\012\002\192=\b\005\031!\212s\020\162ro!\002\\\134P\244\027\130\209y\b\182\030D \184\145\217\230\219F\171\238%\000\188\138Pp\173\132:\254ET\238d\137\200=\141\024p7B\209\231\bF\199\147\168\193\212\000\224\130^\212\192R\1853B\212\192\162\190[b\212\192\194\224\160\01650(\186*\215Ny\171`\224\176B\128\207\n\225\185\173\176\185\231\n\007\206+\004\250\1750\232\194\194X/\022\028\028\025\178\183s\171(\247\017\012\253\177y:lo\142\255\023\211\007VP" let symbol_afm () = "x\001\181ZK\147\2196\018\190\207\175\224q\183j\149\"^\004\144\156l\199\217u\237\218q\197N\156\218\027G\194H,S\164LR~\253\250\237\006\186\t\146\163\201m\203U*\205\184\027\232\199\215O\204\187\169\030\166_\250nz\029\166\161\217\143\133\254A\220\189\232\207\231\208M\197\139\254\242mh\142\167\169\248\219\254\239\133\240\206\252\003?m\252\244\248\233\203\248i\139g\135\254>\020\239\190\141S8\143\197\171n\223\015\151~\168\167p\248\161x\214\182E\127\222\127-v\194\149\197NzU\136\210\151\240!\202\226\238\247\238\016\134\182\233\194\219~l\162\222;Q\150\249\215\239O\205\254c\023\198\1770\229\221\031a\024\145\164,\197\015e\233\238\222\244S\179\015\255W\183\188\004\146C\211\029\223\237O\001\236\130\202D\197\030\154\253\221\187\233\240\175\015\133\151\248\229\143\015\1333\240\005\208\131V`\244\b_\222\189(\148,~*>\252YHS\194\1517\197x\169A\236\159\138\231EI\255~B*\149\168T\252\242\166\b_\247m}\142dB:\176\139-\164.\139\202\202D\174\019\185\021\137\252\2185\159\193>u\0279\148\128S+'\n[\154Dn\018\185)\147\012\221\245|\143\230\249J\147k%\249jl\235\241D\bF7I\163\139\nODZ\183\182\200\2470\244\t0\026h\193\018\182\002d\210\185~M\219w\129\228\181\005\166\173\236\026S\174)\167/\253\018\133f>\210\136\r\225i\b\233P\173\210\253jA\188\241\222C\127\029\146\000\241X0\196L\1696\148\016m\t\0202\157\n\198\175|\002\158\209k\218\177\249\154H\201\000\149\203\199n\194r\012\159C\151\173\005\017\t\230\156mP\173\137\195\140\204\136\006\018\130O\182\155\128o\200\182*\185L\155\133rn\237\222}\223\246I\n'\018\020 k\235\138\180\243\027,\132s\179`P\t\151R\138\153\163*\215\184l1\159G\029+\196\187\004`\202\148\212*\177\2019\159\174\148m\000\193\002\194\211@\146Qd\230J\174\137\143X:\195\240\196\201\228?\029C\234M\001Es\140\245\006\169mI\201C\130I\018\138+\189>|\223w\199\225\202\233L\136\024\1686\"/\146\147\031-^\007\228\207\218\203)\005\170\142\137X\207N\172\200\137Ue#\229\2430%B\233\241L/3\165]\159\249\226\212D\194\029\018\218rq$\185\175\018\137\240\231\208\210\153h\133\170D\184\165\160\1754\201|\2088\\Bwh\246\215\182^\020\207\202\200\204\178\169rWl\239\199=\011\182\195\018\nX5%|\161\132\2347\181n\168\225\134\186\r\169\146j\135q%\210$\225\005ic\215\137\160\2069XP\030\1443\b\188[\231\247{v\004\148\160\157\196\194\001Z\1960Ab\191)\006\148\t!\223\002\186D,2\218\167\004#Jr\177\246\169\210\028\230l\172c\255\024\155l\171K\162\022k\236\134\005\208\165L\244\216:\150\146\2329(eR\242\194I\217\161\216\208\002,\n\136(\185\232\017\218\142sb6Hm@\020\189\016\\\175\2118[\004C\b\1745(\134\208DK\030U2\137\221\244\153\024\220\161@-S\178\020\213\250\\\0169\005'\160=\202l\000\142Y\n\187\182\245\199\156\160\017\190\006PgJA\180\027'\1829C\199\246\t\004\134\246\201*>\154\221hSB;\207\201'y\188\1783<\132(\215v\238\174\\{cWf\017\173\150H7MK\191\200\213PT\208\133(\241\172\161\216\244-\023\002SB\135\129\254\140\227S\b\181\150b\202\249Z\165\150\197\229\182S\136M\2072P\19461\t\194\177\190\\Ha\214^\025\231\164\141\r\"\220g\156[\152c\147b'J\220$\180\022KZ\1876\243u\001i\027\003\017\231\144l>\174\1374\200\246\152\142\197\028_\024\183\022\165!4\t\191\174\202\253\156\189\181\140&\193T;\203\"\231`L\135\127\165h\177\020-\208\016\217\170\"Z\177>\2492.\162\\\186\1529\243\193r\029\229\223\231\252QRh\001\154\172\225\1639\016]9'\218\144G\209\216\166(h\130r\001\020\146G?J\128\247\148\\+CK\020\176!O\222\152<\031\159\159\211\184\245\233\002-\220\226\130\205|?6\176\254\225\012\014\187\134\018\155g\015h\160;\184\139\18340\190\188\242\\\135\024\144\224?=\183\014\130\027\249J\174\234\183\224|\143\157f\185 \231\r\137NM1N\174S`W\225\168\018\029\160\152|3@\227@\145G\133\212H\131z\021\007>7\243\130z\238\007\\Sq\243\159\246R\160\128\138\219\021\214\214\172Q\217t\015M\215L\223\n\234\128\209?\216%h\154\189E\181)X\015m?4\148\1991FT\132\n\143\023bn\238M:\127\223^\239\011\174\235({U\206[\000\193\r>\019\031\154\250\220\211\162D \236\177o(19\018:\185\207g\134S\128\197T\193\147\245\014\206\197\"i\020\021\149\185\211'rXP\029x\016O\139\155\n\140\138\1854\145\147s\161b\164\134\175\030\134\254\203}O\027\143\152z\r\150*\bDA\169\154\027\127\239lf\153# \014\209\006Z\011\185\224P\235\004\0219\174\151\020\234\177\177\0049\188 \141y\nX\157\159#@\251t\001 )_`n\\p\232\191t|\197\014\251\005\184\1969V\156\179 \249\248\016\142\188\\\000\203+@\1792\011T\219M)\195=\207b'\195\203\158\216\\Fz\183.\215c\216\179\151!\1400\n4\184\195*\130\168\221t%4\255\254U \184\205$~\190\182Ssi\191q\208\187\1369#\t\211\243\184@Ap\025zX\151b\228\240\r6\2306<\127\014\004\183\201\140\176D\195\157\225\161yx\224\224\217\161:\016\243\150VF\130'\136\1841\192\252\005\171\2330\177a\017\132Z\224\154\135\226\193m\n\221\161\249\2200`K\028G\r@Vs\242u\155\181X\215O\139\189\002\186\025\170\017\196~\252\255\200\176\221|~\1866\159\161\247\236hk\011\137\014\1484\176\192\212\154%\218\184\026\154\150\161\255\186\184F\199\132\141=\148\242l(\199a\196\251\156\182m O\242\202.Md8R\210\022N\240\152\177B,l}'j\139e\202d\000E\208?.\216#\027\015\029\243E\145\239\004\249\233;1\238\192\238R\226R\030\204--\025\142G\016\238\244\247\192\215\192\171\194\016\166\235\208\205\230\195Y\028\250CL\017\137\141\167\016IR\182\225r\"\132\153T\208+\145\014\141\228j]v_Av\2548\241\030\014\020\130\164dp\205\204-3\015 \130\228\225\025\198\210\018e\bG|\194\001o\012\205\003'\215\232{\1577O\146\199\025\230\218\243\243\218\130M$\016\199\029 i\194S\141#6\b\175C8\215\195\199\204\134\015\005\016\237\206\152\197mj\141}p\229\225\186'\180`\182\000(:@\136\165\183\019\249h\200I\139\1299[\128\197pt\231\165\128\2289\135\2239\014\253\148\223f|4\018\182K\138\146\165\020\027\151\183\253\017\207\007_\022y\183\001y\150\223Q$\143;\156\148\137\129\031\178d\156Z\177\2496\154\024\220M\134>%0\021\219\002\200w\218\178\006\190\184\209n\029\238\219\220q\217XR\161\227\194\189\005)\194\163\207\170#\002\174\220t\149\169'\194\247&A\238\144\226F\133\001&\234\187\128T\1989\217S\019%\165\188}\203\162\2452Q8op,#\155Iu\251\154\220}\2334\012C\219\232<+\164\215\141E\219\127\015\22110\180\176\165\168\226\1823Qo6\0201\178f\221#\180 \239\194\163\249\220\133H\158\136\030\197K\221\141s\184\200\146\194\133\165\178O\133\011sQ\239\137k\1369Z$\199=\021\189\028-\243]1V\172\\\196\138\220$\128\241\n\235\1569\231\0114\025\238\250=\150?J\228\138\223@\221\220\140\1657\208)9\020{u\188\007\247\163^\146\029\148x\130\137\219\012`r&\174_\188$\133\248\141\251\017\207\253\244\023\023\1695\211b\199I\242\129\193!\214\020\15203\233'\153H>`\130\222\024\194'Kg\158\228!\249n]T\173\2416\015\237l\187\210G;\224\171[\190\201>\193tn\230N\030\153$H\226\0213\185'\152\216xx\147\165\155f&\127\131\137=D\162\173n\153_\183\151\017\145\227T\n\014\137\220\152K~\222\150V\207\157\006\212\029\234\254\017p\176)\2408\1351\195\166\155c\006\178\153\002\204\236\156\139\129\224%\133\016\191royH\025\230Q\144\020=\007\016\191uoy\238\231\007\186\029d\164\200\")U\241\139\247\n\162Q\127\018\2060F\171\005F\249\233\2511\023\139\007\179@\132A\228b\241\220S\\$\224\237\187\252M\152.e\196\1570\002\021g_f3\229\211l\012\b\000\t\006E\226#!\141x\154\143\145w\235:y\003xK\025\181\203\224\155\239RO1\229\192\160p\130t7c\214\232\167\216\238\243\223}\2165\208w\155\006\006f1\234\169\240\153\\\197\222\219\197J\244\178;,\254Z\007\127\\\252\233\215\255\000\209\026\188\168" let zapf_dingbats_afm () = "x\001\181\154Mo\0279\018\134\239\250\021<\238\002\155\128\223,&\167|L\1769$\024\1403\201bo\026\185m\011#K^I^\140\255\253\146\205*\022\187\025\030\023\t\012G~\194\174\174\183\170\200*\250\230\186=_?\157\142\215/\211\245\188\223]\132}\1736\031N\143\143\211\241*>\156\158^\206\251\251\135\171\248\219\238\239BEp\255\200_\195\252\021\230\1751\127\141A\188\187=\2531\137\155\151\203uz\188\136\207\199\221\233\252t:o\175\211\237k\241\238p\016\191\229e.\226\183\2332\157\255\155>\228g\156\167\237u\127:\138\143\t~#\190=<\139/\219\023!\148P\238\141\178o\148\153\031P\249\223\143\251\255\028\230O?\127\2510\255D\240\143\182\143\251\195K\255_~L\179\019\190L\183\251\231\199\205\231\235\246\176\223\189;\222\031&!7\159/\159\246\127M\183\191\238\175\187\007q\183=\\\166\205\135\135\237y\187\187N\231\155\233*n\158\166\221~{\152\141y\255\254\244\151x\165\210_kD\004%@K\177\249\253x;\157\015\251\227\244\235\233\178\159]\241JI\201\031\127{\216\239\254\165\016\2132\233.\140\022o\197\143\127\t\029 }\243U\\\158\242s\222\138\247B\226\159\183\1532\133\138\193\206\212V\205\136q\"h\017M\020^\171\002Z\004\189*\160&0\233\020u\016^!\232V+&sFkzDA\022\212\016(E\180N\248\168\011\023\n\023T,\156-\156\021*\175\006)\160\189/$ \tH:Z1\197\148\b.\153 ]!#\146\017\159\173\230\197\127\202ZI\172\"\022\1525\"$\159TV\021\214\243\186\129\173\005\225]N?SXM>\173,-\171t\202\000\157_\012\nJ:\025|1U\157\170\210\202Q\218\180j,(*\229,\161\197\173:&c\149p\202\179\177\168\0218\135h\245lZ,g\1597E\002KR)rA\245\172\147\002\130\023\222\"\025\200R\131\164gK\211\1621&KK\240YX/*\135\171\162\\\209\146\165\161]5\202X\189\234\228:\164\171X*\185)&\017\028\132\130\162X\161\190\127\164\247\159u\213\172\171C\173`\246\196\028\214\005\245s\184\128jP\212*x\141\168\226\184\0149U0\174\157%\144rJ\015@\212\201\005\002\139\164\185V\166\000\201\031{_r\202\161P>\004D-\219if\127V;)\173<*\165]\251x\224\199SVQ\156j\223\130\158AJ*\135\161\167C\011rF{\202(GE\002ZP2\136\n\217\136`\243d\235\027\014\229q\014}\222<\216)\246\164Gm\156A\2474\207u\2100GIDn\172\197!\250\164\155N\175Z*\142w\148\239\154b\184-#>9\153\252\237=\021'\n\161U\197\225\016\242$\r\000VF\185DYE\015kT-Q\195\232\186\230\025\189D\1852\132Z\24206\140YT\188$pE)\137H\"c\135(%\145B\015\152e}\006~\173\128B\129&\003\252\018e\191\006\187*\250&,_\2032J\005\207b\"\025hQ\144\205\170~m\192R-h^\011\213\002*yv\169V\004Fa\229\001\171\022\206j=\016iU\180\213.\213\138\172\022P\201#[\173Y\188\022\176\001@jYT\203\218&\243\020g\020\160V\161\174\217T\007\015\\\029\128\202\029\2377\182\173\0149\007\b\180\171\240\179\129\171\2372\252\192\017\138Yea)i\243BT\240\"\214p\187\208\201\207{s\201U\160\172\n\232|\199:\165g')|,{(\212\138\135I\229X\166\020\"\1982\025W\150\186UNqDE\185\170\142\206\252\188:F\210Hb\241q\139\140\242!\007\137-(\169$\201\208EF\021\020\031\143:y K\023\025\229mc))%1\244\\X\250\148\149\138\148Q\154|\186T*rQ\139\148Q\n\149r\171\140\146\140\134UJ{9J\233\184>\242y5D\227\202\175^\183\001\232\003\151\202\212a\144\183\136E\177|\014\127\167\170XJ\214\019\031z\1927\025\149\195\207G\133\164\1665\201\2126\165\156k\2144\171\173\194\251e\170\168\198\210Z\254\200\2100\218+\202\249j>IcR{X\134\0114,mWt\234\245q\180[(Y\245Bi\195\226t\180\180\023V\235\0065\202\024%\169\006\006\1807,\178\011Lc\175\162\244\162\211TX\164\023\159R\148\162\252\162\003Zhk`s\238RJ\175H-\205\b5\171\236\014\238\231\217\173\148]\145Z\218\017J\217E\213%4\181\021\\\251\246~M.\162 \179\188\234\250t\017`\1482\165\211\153Y\220/\1942\nllXT\203\026\\\023\022\202Z\217\228\151F\181Te\155\179o\142\233j\173F\1814\029\197\160\145@\167M\145IT\203R\129\129\198\175\006dC\162X\134\188\021\171\183tJt\211\198\160\182k\022(\023{\150N\131\180o\196\216\174\235M\235\001\191bK\205\153\147\166\192\141\012\026\200\b\220;a!\131i\147Q\199\021\027\229\146\229\206V\025\148\193(:\231\182\206\005>\016+\163\214\164\029\145u\242\128\197+\170\129`4}`R\143H:\143\203\1543Mz\217\208\228\012\r *\nC\210S\188P_#\155\2442\0114\172P\024\146\168\1486\1520\176H\1964cj\188\031\215,\012Y\026B\024bc\243Z:\145\213\002\026A0\233\007$uW\193\212\230\165\205\216\172iH\135K\1434\245XttT8\217q\165\202\219\249\152I\176\233`\211naN6\197\139\186\173H\222U\\\017m\030\004\184y\203-lM\177@\236\242\028\211\230Xm\185\234\132E.7G\221\228Mm\186\024.r\200\185\b\229C\167\243\017Y*\139\020\185J\181\189\187m\246;\234\186\028\029P\021\141y\208\019\158\207=\138\250.O\205\148Z\247\147MHP\231\229\233\236U\246\203y\229\212\2066G/E\157W-\249J\015OT*\152\014Vc\216v\176\030\195\174\131\205\024\246\029l\199p\232`7\134\161\131\253\024\142\029<\236/\021ub\r<\222[k/\198p\028\195\157\130f\172 t\n\154\177\130\208)h\198\nB\167\160\025+\b\157\130f\172 t\n\154\177\130\208)h\198\nB\167\224xB\160b\167\160\025+\024;\005\205X\193\216)h\199\n\198NA;V0v\n\218\177\130\177S\208\142\021\140\157\130v\172`\236\020\180c\005c\167\160\029+\024;\005\237PA-;\005-\140\225NA\027\199p\167\160\147c\184S\208\1691\220)\232\244\024\238\020tf\012w\n:;\134;\005\157\027\195\157\130\206\143\225NA7VPu\n\186\177\130\170S\208\141\021\164\134\014\234\254\202\147\133\244\012\200#ec\145\165\017$\181(\138G\011Y\030H\n;+\017F\001\211\t\1386c_\015<\153\206\247\153L\163\130\214\213\165\027Q\210\254b\211&\154\239_\nM\018Z\162\249D\023s\167\148\014&1 K\215/\186\190`U0\215\027H\245m\030\146\2070t\011\235\225\194t\003\163\170\201|\177\147\190\133\180\1418]N\127Z\215\129$\029\210x(\1456\151\220\164z\143oG\253]\212ua\190\176\209\249\198(9\206\163\197\212\2265pd8\t\152\234\166\243\006\225* \249\"H\0220uA\249.\202\224\251Q\155WG\r\138\231\018i\209\028\004\014g~Z\215\161\023Y\193s\137|t\205\163\r\007\128\176_+\194\131\137\228`H\187\147\139\024r\186WO\015\217z{F>n\199\024\000\220=i\234\b\163\161\147-\015'\146l\144\194\201K4\151:\194Hcg\1973\135\142\165\219\025_}\198I\157\156e\211\131\003N\1914\181\133\000\021\174:'WC\138A\175Q9S\149\163d\226\177\131\205s\250\244r\150\140\176k\150{\216\142%\225j\243\000\028\017i+\000\163\231ss\129\253\026\230n\190\135Q\185:\005T<\252\176e\012\205V\192\138\213R\014\217:\001\171\183\153|\157\158\154\179\148\210^aXR\227\007|\245\206\215\249\006Y,\132\182N\182($`0\141\214\245\238\217\214W\179\156\249r\190\190u\006\149\163\219\231@W\149*\214)\191\201\163s?O:\011[\213\160\206\136[\245\188\021A\138E\011\232`\186\129n\022\182\195\133\233B\166n\t<\179y\149\188\005\249RL\209\235Q\030qLpa\211\249\194X\215kxM\247\208\205\202n\1842\221D\215\027\028\197\179\128\167\215\230\151\227m\243;'\249\159\205oI\253\015\003u\140\r" camlpdf-2.8.1/pdfafmdata.mli000066400000000000000000000012611477056064700157420ustar00rootroot00000000000000(** AFM Data for the standard 14 fonts *) val courier_afm : unit -> string val courier_oblique_afm : unit -> string val courier_bold_afm : unit -> string val courier_bold_oblique_afm : unit -> string val times_roman_afm : unit -> string val times_bold_afm : unit -> string val times_italic_afm : unit -> string val times_bold_italic_afm : unit -> string val helvetica_afm : unit -> string val helvetica_bold_afm : unit -> string val helvetica_oblique_afm : unit -> string val helvetica_bold_oblique_afm : unit -> string val symbol_afm : unit -> string val zapf_dingbats_afm : unit -> string (** We pass unit because the AFM files are parsed upon demand and then memoised. *) camlpdf-2.8.1/pdfafmdata.source.ml000066400000000000000000000026521477056064700170750ustar00rootroot00000000000000(* AFM data for standard 14 fonts *) (* This file constitutes a modification of Adobe's AFM data files. This file also constitutes a modification of Adobe's license file. This file and the 14 PostScript(R) AFM files it accompanies may be used, copied, and distributed for any purpose and without charge, with or without modification, provided that all copyright notices are retained; that the AFM files are not distributed without this file; that all modifications to this file or any of the AFM files are prominently noted in the modified file(s); and that this paragraph is not modified. Adobe Systems has no responsibility or obligation to support the use of the AFM files. *) let courier_afm () = __DATA:Courier.afm let courier_oblique_afm () = __DATA:Courier-Oblique.afm let courier_bold_afm () = __DATA:Courier-Bold.afm let courier_bold_oblique_afm () = __DATA:Courier-BoldOblique.afm let times_roman_afm () = __DATA:Times-Roman.afm let times_bold_afm () = __DATA:Times-Bold.afm let times_italic_afm () = __DATA:Times-Italic.afm let times_bold_italic_afm () = __DATA:Times-BoldItalic.afm let helvetica_afm () = __DATA:Helvetica.afm let helvetica_bold_afm () = __DATA:Helvetica-Bold.afm let helvetica_oblique_afm () = __DATA:Helvetica-Oblique.afm let helvetica_bold_oblique_afm () = __DATA:Helvetica-BoldOblique.afm let symbol_afm () = __DATA:Symbol.afm let zapf_dingbats_afm () = __DATA:ZapfDingbats.afm camlpdf-2.8.1/pdfannot.ml000066400000000000000000000252731477056064700153240ustar00rootroot00000000000000(* Read and Write Annotations *) open Pdfutil (* Annotation Border Styles *) type style = | NoStyle | Solid | Dashed | Beveled | Inset | UnderlineStyle type border = {width : float; vradius : float; hradius : float; style : style; dasharray : int array} type subtype = | Text | Link | FreeText | Line | Square | Circle | Polygon | PolyLine | Highlight | Underline | Squiggly | StrikeOut | Stamp | Caret | Ink | Popup of t | FileAttachment | Sound | Movie | Widget | Screen | PrinterMark | TrapNet | Watermark | ThreeDee | Unknown of string (* Main type. 'rest' contains the raw annotation dictionary with the exception of the entries corresponding to the other items in the record. *) and t = {subtype : subtype; annot_contents : string option; subject : string option; rectangle : float * float * float * float; border : border; colour : (int * int * int) option; annotrest : Pdf.pdfobject} (* Read a single annotation *) let rec read_annotation pdf annot = let subtype = match Pdf.lookup_direct pdf "/Subtype" annot with | Some (Pdf.Name "/Text") -> Text | Some (Pdf.Name "/FreeText") -> FreeText | Some (Pdf.Name "/Popup") -> (* Look up /Parent. If exists, include it *) begin match Pdf.direct pdf annot with | Pdf.Dictionary d -> begin match lookup "/Parent" d with | Some (Pdf.Indirect i) -> Popup (read_annotation pdf (Pdf.Indirect i)) | _ -> Unknown "" end | _ -> raise (Pdf.PDFError "read_annotation failed") end | Some (Pdf.Name "/Stamp") -> Stamp | Some (Pdf.Name "/Link") -> Link | Some (Pdf.Name "/Line") -> Line | Some (Pdf.Name "/Square") -> Square | Some (Pdf.Name "/Circle") -> Circle | Some (Pdf.Name "/Polygon") -> Polygon | Some (Pdf.Name "/PolyLine") -> PolyLine | Some (Pdf.Name "/Highlight") -> Highlight | Some (Pdf.Name "/Underline") -> Underline | Some (Pdf.Name "/Squiggly") -> Squiggly | Some (Pdf.Name "/StrikeOut") -> StrikeOut | Some (Pdf.Name "/Caret") -> Caret | Some (Pdf.Name "/Ink") -> Ink | Some (Pdf.Name "/FileAttachment") -> FileAttachment | Some (Pdf.Name "/Sound") -> Sound | Some (Pdf.Name "/Movie") -> Movie | Some (Pdf.Name "/Widget") -> Widget | Some (Pdf.Name "/Screen") -> Screen | Some (Pdf.Name "/PrinterMark") -> PrinterMark | Some (Pdf.Name "/TrapNet") -> TrapNet | Some (Pdf.Name "/Watermark") -> Watermark | Some (Pdf.Name "/3D") -> ThreeDee | Some (Pdf.Name n) -> Unknown n | _ -> Unknown "" in let contents = match Pdf.lookup_direct pdf "/Contents" annot with | Some (Pdf.String s) -> Some s | _ -> None in let subject = match Pdf.lookup_direct pdf "/Subj" annot with | Some (Pdf.String s) -> Some s | _ -> None in let rectangle = Pdf.parse_rectangle pdf (Pdf.lookup_fail "No /rect in annot" pdf "/Rect" annot) in let border = match Pdf.lookup_direct pdf "/BS" annot with | Some bsdict -> let width = match Pdf.lookup_direct pdf "/W" bsdict with | Some x -> Pdf.getnum pdf x | _ -> 1. in let style = match Pdf.lookup_direct pdf "/S" bsdict with | Some (Pdf.Name "/S") -> Solid | Some (Pdf.Name "/D") -> Dashed | Some (Pdf.Name "/B") -> Beveled | Some (Pdf.Name "/I") -> Inset | Some (Pdf.Name "/U") -> UnderlineStyle | _ -> NoStyle in let dasharray = match Pdf.lookup_direct pdf "/D" bsdict with | Some (Pdf.Array dash) -> Array.of_list (map int_of_float (map (Pdf.getnum pdf) (map (Pdf.direct pdf) dash))) | _ -> [||] in {width = width; vradius = 0.; hradius = 0.; style = style; dasharray = dasharray} | None -> match Pdf.lookup_direct pdf "/Border" annot with | Some (Pdf.Array [h; v; w]) -> {width = Pdf.getnum pdf (Pdf.direct pdf w); vradius = Pdf.getnum pdf (Pdf.direct pdf v); hradius = Pdf.getnum pdf (Pdf.direct pdf h); style = NoStyle; dasharray = [||]} | Some (Pdf.Array [h; v; w; Pdf.Array dash]) -> {width = Pdf.getnum pdf (Pdf.direct pdf w); vradius = Pdf.getnum pdf (Pdf.direct pdf v); hradius = Pdf.getnum pdf (Pdf.direct pdf h); style = NoStyle; dasharray = Array.of_list (map int_of_float (map (Pdf.getnum pdf) (map (Pdf.direct pdf) dash)))} | _ -> {width = 1.; vradius = 0.; hradius = 0.; style = NoStyle; dasharray = [||]} in let colour = match Pdf.lookup_direct pdf "/C" annot with | Some (Pdf.Array [r; g; b]) -> Some (int_of_float (Pdf.getnum pdf (Pdf.direct pdf r)), int_of_float (Pdf.getnum pdf (Pdf.direct pdf g)), int_of_float (Pdf.getnum pdf (Pdf.direct pdf b))) | _ -> None in let annotrest = match Pdf.direct pdf annot with | Pdf.Dictionary entries -> Pdf.Dictionary (lose (fun (k, _) -> mem k ["/Subtype"; "/Contents"; "/Rect"; "/Border"; "/Subj"; "/BS"; "/C"]) entries) | _ -> raise (Pdf.PDFError "Bad annotation dictionary") in {subtype = subtype; annot_contents = contents; subject = subject; rectangle = rectangle; border = border; colour = colour; annotrest = annotrest} let get_popup_parent pdf annotation = match Pdf.direct pdf annotation with | Pdf.Dictionary d -> begin match lookup "/Parent" d with | Some (Pdf.Indirect i) -> Some i | _ -> None end | _ -> raise (Pdf.PDFError "Pdfannot.get_popup_parent: not a dictionary") (* Read the annotations from a page. *) let annotations_of_page pdf page = match Pdf.lookup_direct pdf "/Annots" page.Pdfpage.rest with | Some (Pdf.Array annotations) -> (* We don't read annotations which are parents of Popup annotations - they will be caught anyway. This seems to be the right thing to do, but will need more advice. *) let popup_parents = option_map (get_popup_parent pdf) annotations in map (read_annotation pdf) (lose (function Pdf.Indirect i -> mem i popup_parents | _ -> false) annotations) | _ -> [] (* Add an annotation to a page *) let string_of_subtype = function | Text -> "/Text" | Link -> "/Link" | FreeText -> "/FreeText" | Line -> "/Line" | Square -> "/Square" | Circle -> "/Circle" | Polygon -> "/Polygon" | PolyLine -> "/PolyLine" | Highlight -> "/Highlight" | Underline -> "/Underline" | Squiggly -> "/Squiggly" | StrikeOut -> "/StrikeOut" | Stamp -> "/Stamp" | Caret -> "/Caret" | Ink -> "/Ink" | FileAttachment -> "/FileAttachment" | Sound -> "/Sound" | Movie -> "/Movie" | Widget -> "/Widget" | Screen -> "/Screen" | PrinterMark -> "/PrinterMark" | TrapNet -> "/TrapNet" | Watermark -> "/Watermark" | Unknown _ -> "/Unknown" | Popup _ -> "/Popup" | ThreeDee -> "/3D" let obj_of_annot t = let d = ["/Subtype", Pdf.Name (string_of_subtype t.subtype); "/Contents", (match t.annot_contents with None -> Pdf.Null | Some s -> Pdf.String s); "/Rect", (let a, b, c, d = t.rectangle in Pdf.Array [Pdf.Real a; Pdf.Real b; Pdf.Real c; Pdf.Real d]); "/Border", match t.border.dasharray with | [||] -> Pdf.Array [Pdf.Real t.border.hradius; Pdf.Real t.border.vradius; Pdf.Real t.border.width] | _ -> raise (Pdf.PDFError "non-empty dash array unsupported")] in let d = match t.annotrest with | Pdf.Null -> d | Pdf.Dictionary d' -> d @ d' | _ -> raise (Pdf.PDFError "Bad annotation dictionary") in let colorize d = match t.colour with | None -> d | Some (r,g,b) -> (("/C", Pdf.Array [Pdf.Integer r; Pdf.Integer g; Pdf.Integer b]))::d in let subject d = match t.subject with | None -> d | Some s -> (("/Subj", Pdf.String s)::d) in Pdf.Dictionary (subject (colorize d)) let make_border ?(vradius=0.0) ?(hradius=0.0) ?(style=NoStyle) ?(dasharray = [||]) width = {vradius; hradius; style; dasharray; width} let make ?content ?(border=make_border 0.0) ?(rectangle=(0., 0., 0., 0.)) ?colour ?subject subtype = {annot_contents = content; border; rectangle; colour; subject; subtype; annotrest = Pdf.Null} let add_annotation pdf page anno = let obj = obj_of_annot anno in match Pdf.lookup_direct pdf "/Annots" page.Pdfpage.rest with | Some (Pdf.Array annotations) -> {page with Pdfpage.rest = Pdf.add_dict_entry page.Pdfpage.rest "/Annots" (Pdf.Array (obj::annotations))} | Some _ -> raise (Pdf.PDFError "Bad annotation dictionary") | None -> {page with Pdfpage.rest = Pdf.add_dict_entry page.Pdfpage.rest "/Annots" (Pdf.Array [obj])} (* Apply transformations to any annotations in /Annots (i.e their /Rect and /QuadPoints entries). Also as a best-effort service, altering other coordinates, like the endpoints /L in a line annotation. *) let transform_annotations pdf transform rest = match Pdf.lookup_direct pdf "/Annots" rest with | Some (Pdf.Array annots) -> (* Always indirect references, so alter in place *) iter (function | Pdf.Indirect i -> let annot = Pdf.lookup_obj pdf i in let rect' = match Pdf.lookup_direct pdf "/Rect" annot with | Some rect -> Some (Pdf.transform_rect pdf transform rect) | None -> None (* malformed, but seen in the wild *) in let quadpoints' = match Pdf.lookup_direct pdf "/QuadPoints" annot with | Some qp -> Some (Pdf.transform_quadpoints pdf transform qp) | None -> None in let line' = match Pdf.lookup_direct pdf "/L" annot with | Some rect -> Some (Pdf.transform_rect pdf transform rect) | _ -> None in let annot = match rect' with None -> annot | Some rect' -> Pdf.add_dict_entry annot "/Rect" rect' in let annot = match quadpoints' with | Some qp -> Pdf.add_dict_entry annot "/QuadPoints" qp | None -> annot in let annot = match line' with | Some l -> Pdf.add_dict_entry annot "/L" l | None -> annot in Pdf.addobj_given_num pdf (i, annot) | _ -> Pdfe.log "transform_annotations: not indirect\n") annots | _ -> () camlpdf-2.8.1/pdfannot.mli000066400000000000000000000031071477056064700154650ustar00rootroot00000000000000(** Annotations *) (** Border styles *) type style = NoStyle | Solid | Dashed | Beveled | Inset | UnderlineStyle (** Annotation borders. *) type border = {width : float; vradius : float; hradius : float; style : style; dasharray : int array} (** Annotation types *) type subtype = | Text | Link | FreeText | Line | Square | Circle | Polygon | PolyLine | Highlight | Underline | Squiggly | StrikeOut | Stamp | Caret | Ink | Popup of t | FileAttachment | Sound | Movie | Widget | Screen | PrinterMark | TrapNet | Watermark | ThreeDee | Unknown of string (** Annotations. *) and t = {subtype : subtype; annot_contents : string option; subject : string option; rectangle : float * float * float * float; border : border; colour : (int * int * int) option; annotrest : Pdf.pdfobject} val annotations_of_page : Pdf.t -> Pdfpage.t -> t list (** Return the annotations on a page in a document. *) val add_annotation : Pdf.t -> Pdfpage.t -> t -> Pdfpage.t (** Add an annotation to a page in a document. *) val make_border : ?vradius:float -> ?hradius:float -> ?style:style -> ?dasharray:int array -> float -> border (** Make a border. *) val make : ?content:string -> ?border:border -> ?rectangle:float * float * float * float -> ?colour:int * int * int -> ?subject:string -> subtype -> t (** Make an annotation of a given [subtype]. *) val transform_annotations : Pdf.t -> Pdftransform.transform_matrix -> Pdf.pdfobject -> unit (** Transform all annotations in a page dictionary, e.g [/Rect] and [/QuadPoints]. *) camlpdf-2.8.1/pdfcmap.ml000066400000000000000000000144411477056064700151200ustar00rootroot00000000000000open Pdfutil open Pdfio type cmap = {map : (int * string) list; wmode : int option} (* Parse a /ToUnicode CMap to extract font mapping. *) type section = | BfChar of char list | BfRange of char list let rec getuntilend prev = function | [] -> rev prev, [] | 'e'::'n'::'d'::'b'::'f'::'c'::'h'::'a'::'r'::more -> rev prev, more | h::t -> getuntilend (h::prev) t let rec getuntilend_range prev = function | [] -> rev prev, [] | 'e'::'n'::'d'::'b'::'f'::'r'::'a'::'n'::'g'::'e'::more -> rev prev, more | h::t -> getuntilend_range (h::prev) t let rec get_section = function | [] -> None | 'b'::'e'::'g'::'i'::'n'::'b'::'f'::'c'::'h'::'a'::'r'::more -> let numbers, rest = getuntilend [] more in Some (BfChar numbers, rest) | 'b'::'e'::'g'::'i'::'n'::'b'::'f'::'r'::'a'::'n'::'g'::'e'::more -> let numbers, rest = getuntilend_range [] more in Some (BfRange numbers, rest) | _::t -> get_section t (* Read a character code. *) let rec read_number = function | x::more when Pdf.is_whitespace x -> read_number more | '<'::a::'>'::more -> int_of_string (implode ['0'; 'x'; a]), more | '<'::a::b::'>'::more -> int_of_string (implode ['0'; 'x'; a; b]), more | '<'::a::b::c::'>'::more -> int_of_string (implode ['0'; 'x'; a; b; c]), more | '<'::a::b::c::d::'>'::more -> int_of_string (implode ['0'; 'x'; a; b; c; d]), more | [] -> raise Not_found | _ -> raise (Pdf.PDFError "Unknown number in /ToUnicode") (* Read the bytes of the UTF-16BE unicode sequence as a string. *) let fail () = raise (Pdf.PDFError "Bad unicode value") let rec read_unicode = function | x::rest when Pdf.is_whitespace x -> read_unicode rest | '<'::rest -> let chars, rest = cleavewhile (neq '>') rest in let is_hex_digit = function | x when (x >= '0' && x <= '9') || (x >= 'a' && x <= 'f') || (x >= 'A' && x <= 'F') -> true | _ -> false in iter (fun x -> if not (is_hex_digit x) then fail ()) chars; if length chars > 0 && even (length chars) then let bytes = map (function | [x; y] -> char_of_int (int_of_string (implode ['0'; 'x'; x; y])) | _ -> assert false) (splitinto 2 chars) in let rest' = match rest with | [] -> [] | _ -> tl rest in implode bytes, rest' else fail () | _ -> fail () let rec get_sections chars = match get_section chars with | None -> [] | Some (sec, restchars) -> sec::get_sections restchars let pairs_of_section = function | BfChar numbers -> let results = ref [] in let numbers = ref numbers in begin try while true do let number, rest = read_number !numbers in let str, rest = read_unicode rest in numbers := rest; results =| (number, str) done; [] with Not_found -> rev !results end | BfRange numbers -> let results = ref [] in let numbers = ref numbers in begin try while true do let src1, rest = read_number !numbers in let src2, rest = read_number rest in if src1 > src2 then raise (Pdf.PDFError "Bad /ToUnicode") else match rest with | '<'::_ -> (* It's a single unicode string *) let increment_final code d = match code with | "" -> "" | s -> let chars = rev (explode s) in implode ((rev (tl chars)) @ [char_of_int (int_of_char (hd chars) + d)]) in let code, rest = read_unicode rest in results =@ rev (combine (ilist src1 src2) (map (increment_final code) (ilist 0 (src2 - src1)))); numbers := rest | '['::rest -> (* It's several. *) let rest = ref rest in results =@ combine (ilist src1 src2) (map (fun _ -> let num, rest' = read_unicode !rest in rest := rest'; num) (ilist 0 (src2 - src1))); rest := (match !rest with [] -> [] | x -> tl x); numbers := !rest | _ -> raise (Pdf.PDFError "Bad BfRange") done; [] with Not_found -> rev !results end let extract_specifics data = let wmode = ref None in let read_number t = let h, t = cleavewhile isdigit t in int_of_string (implode h), t in let rec find = function | [] -> () | '/'::'W'::'M'::'o'::'d'::'e'::' '::t -> let n, t = read_number t in wmode := Some n; find t | h::t -> find t in let chars = charlist_of_bytes data in begin try find chars with _ -> () end; !wmode let rec parse_cmap pdf cmap = match cmap with | Pdf.Stream {contents = (dict, Pdf.Got data)} -> Pdfcodec.decode_pdfstream pdf cmap; begin match cmap with | Pdf.Stream {contents = (dict, Pdf.Got data)} -> let wmode = extract_specifics data in begin try {map = flatten (map pairs_of_section (get_sections (lose Pdf.is_whitespace (charlist_of_bytes data)))); wmode} with e -> Pdfe.log (Printf.sprintf "/ToUnicode Parse Error : %s\n" (Printexc.to_string e)); raise e end | _ -> assert false end | Pdf.Stream {contents = (_, Pdf.ToGet _)} -> Pdf.getstream cmap; parse_cmap pdf cmap | e -> raise (Pdf.PDFError (Printf.sprintf "Bad /ToUnicode %s" (Pdfwrite.string_of_pdf e))) camlpdf-2.8.1/pdfcmap.mli000066400000000000000000000002611477056064700152640ustar00rootroot00000000000000(** Parsing ToUnicode and other CMaps *) type cmap = {map : (int * string) list; wmode : int option} (** Parse a CMap. *) val parse_cmap : Pdf.t -> Pdf.pdfobject -> cmap camlpdf-2.8.1/pdfcodec.ml000066400000000000000000002034031477056064700152530ustar00rootroot00000000000000open Pdfutil open Pdfio let debug = ref false (* Zlib inflate level *) let flate_level = ref 6 (* Get the next non-whitespace character in a stream. *) let rec get_streamchar s = match s.input_byte () with | x when x = Pdfio.no_more -> raise End_of_file | x -> let chr = Char.unsafe_chr x in if Pdf.is_whitespace chr then get_streamchar s else chr (* Raised if there was bad data. *) exception Couldn'tDecodeStream of string (* Raised if the codec was not supported. *) exception DecodeNotSupported of string (* ASCIIHex *) (* We build a list of decoded characters from the input stream, and then convert this to the output stream. *) let encode_ASCIIHex stream = let size = bytes_size stream in let stream' = mkbytes (size * 2 + 1) in bset stream' (size * 2) (int_of_char '>'); (* ['>'] is end-of-data *) for p = 0 to size - 1 do let chars = explode (Printf.sprintf "%02X" (bget stream p)) in bset stream' (p * 2) (int_of_char (hd chars)); bset stream' (p * 2 + 1) (int_of_char (hd (tl chars))) done; stream' (* Decode ASCIIHex *) (* Calulate a character from two hex digits a and b *) let char_of_hex a b = char_of_int (int_of_string ("0x" ^ string_of_char a ^ string_of_char b)) let decode_ASCIIHex i = let output = ref [] in let enddata = ref false in try while not !enddata do let b = get_streamchar i in let b' = get_streamchar i in match b, b' with | '>', _ -> (* Rewind for inline images *) set enddata; rewind i | c, '>' when (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') -> output =| char_of_hex c '0'; set enddata | c, c' when ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) && ((c' >= '0' && c' <= '9') || (c' >= 'a' && c' <= 'f') || (c' >= 'A' && c' <= 'F')) -> output =| char_of_hex c c' | _ -> raise Not_found (*r Bad data. *) done; bytes_of_charlist (rev !output) with | End_of_file -> (* We ran out of data. This is a normal exit. *) bytes_of_charlist (rev !output) | Not_found -> raise (Couldn'tDecodeStream "ASCIIHex") (* ASCII85 *) let decode_5bytes c1 c2 c3 c4 c5 n o = let d x p = i32mul (i32ofi (int_of_char x - 33)) (i32ofi (pow p 85)) in let total = i32add (i32add (d c1 4) (d c2 3)) (i32add (d c3 2) (i32add (d c4 1) (d c5 0))) in let extract t = char_of_int (i32toi (lsr32 (lsl32 total (24 - t)) 24)) in match n with | 4 -> extract 0::extract 8::extract 16::extract 24::o | 3 -> extract 8::extract 16::extract 24::o | 2 -> extract 16::extract 24::o | 1 -> extract 24::o | _ -> o let conso cs o = match cs with | [c1; c2; c3; c4; c5] -> decode_5bytes c1 c2 c3 c4 c5 4 o | [c1; c2; c3; c4] -> decode_5bytes c1 c2 c3 c4 '~' 3 o | [c1; c2; c3] -> decode_5bytes c1 c2 c3 '~' '>' 2 o | [c1; c2] -> decode_5bytes c1 c2 '~' '>' '!' 1 o | _ -> o let rec decode_ASCII85_i i cs o = match get_streamchar i with | 'z' -> decode_ASCII85_i i [] ('\000'::'\000'::'\000'::'\000'::conso (rev cs) o) | '~' -> bytes_of_charlist (rev (conso (rev cs) o)) | c when c >= '!' && c <= 'u' -> if length cs = 5 then (decode_ASCII85_i i [c] (conso (rev cs) o)) else (decode_ASCII85_i i (c::cs) o) | _ -> raise (Pdf.PDFError "decode_ASCII85_i") let decode_ASCII85 i = try decode_ASCII85_i i [] [] with _ -> raise (Pdf.PDFError "Error decoding ASCII85 stream") (* Encode a single symbol set. *) let encode_4bytes = function | [b1; b2; b3; b4] -> let ( * ), ( - ), ( / ), rem = Int64.mul, Int64.sub, Int64.div, Int64.rem in let numbers = [i64ofi (int_of_char b1) * i64ofi (pow 3 256); i64ofi (int_of_char b2) * i64ofi (pow 2 256); i64ofi (int_of_char b3) * i64ofi (pow 1 256); i64ofi (int_of_char b4) * i64ofi (pow 0 256)] in let t = fold_left Int64.add Int64.zero numbers in let one85 = i64ofi (pow 1 85) in let two85 = i64ofi (pow 2 85) in let three85 = i64ofi (pow 3 85) in let zero85 = i64ofi (pow 0 85) in let four85 = i64ofi (pow 4 85) in let t, c5 = t - rem t one85, rem t one85 / zero85 in let t, c4 = t - rem t two85, rem t two85 / one85 in let t, c3 = t - rem t three85, rem t three85 / two85 in let t, c2 = t - rem t four85, rem t four85 / three85 in i64toi (t / four85), i64toi c2, i64toi c3, i64toi c4, i64toi c5 | _ -> assert false (* Encode a stream. *) let encode_ASCII85 stream = let output = ref [] in let enddata = ref false in let istream = input_of_bytes stream in while not !enddata do let b1 = istream.input_char () in let b2 = istream.input_char () in let b3 = istream.input_char () in let b4 = istream.input_char () in match b1, b2, b3, b4 with | Some b1, Some b2, Some b3, Some b4 -> output := [b1; b2; b3; b4]::!output | Some b1, Some b2, Some b3, None -> set enddata; output := [b1; b2; b3]::!output | Some b1, Some b2, None, None -> set enddata; output := [b1; b2]::!output | Some b1, None, None, None -> set enddata; output := [b1]::!output | None, _, _, _ -> set enddata | _ -> assert false done; let fix k = char_of_int (k + 33) in let charlists' = rev_map (fun l -> let len = length l in if len < 4 then let l' = l @ (many '\000' (4 - len)) in let c1, c2, c3, c4, c5 = encode_4bytes l' in take [fix c1; fix c2; fix c3; fix c4; fix c5] (len + 1) else let c1, c2, c3, c4, c5 = encode_4bytes l in if c1 + c2 + c3 + c4 + c5 = 0 then ['z'] else [fix c1; fix c2; fix c3; fix c4; fix c5]) !output in bytes_of_charlist (flatten charlists' @ ['~'; '>']) (* Flate *) (* Make a bytes from a list of strings by taking the contents, in order from the items, in order. *) let rec total_length n = function | [] -> n | h::t -> total_length (n + String.length h) t let bytes_of_strings_rev strings = let len = total_length 0 strings in let s = mkbytes len and pos = ref (len - 1) in iter (fun str -> for x = String.length str - 1 downto 0 do bset_unsafe s !pos (int_of_char (String.unsafe_get str x)); decr pos done) strings; s let flate_process f data = let strings = ref [] and pos = ref 0 and inlength = bytes_size data in let input = (fun buf -> let s = Bytes.length buf in let towrite = min (inlength - !pos) s in for x = 0 to towrite - 1 do Bytes.unsafe_set buf x (Char.unsafe_chr (bget_unsafe data !pos)); incr pos done; towrite) and output = (fun buf length -> if length > 0 then strings =| Bytes.sub_string buf 0 length) in f input output; bytes_of_strings_rev !strings (* This is for reading zlib compressed things in streams where we need to commence lexing straightaway afterwards. And so, we can only supply one byte at a time, continuing until zlib has finished uncompressing. *) let decode_flate_input i = let strings = ref [] in let input = (fun buf -> let s = Bytes.length buf in if s > 0 then begin match i.input_byte () with | x when x = Pdfio.no_more -> raise End_of_file | x -> Bytes.unsafe_set buf 0 (char_of_int x); 1 end else 0) and output = (fun buf length -> if length > 0 then strings =| Bytes.sub_string buf 0 length) in Pdfflate.uncompress input output; bytes_of_strings_rev !strings (* js_of_ocaml only *) external camlpdf_caml_zlib_compress : string -> string = "camlpdf_caml_zlib_compress" external camlpdf_caml_zlib_decompress : string -> string = "camlpdf_caml_zlib_decompress" let is_js = match Sys.backend_type with Sys.Other "js_of_ocaml" -> true | _ -> false let encode_flate stream = if is_js then Pdfio.bytes_of_string (camlpdf_caml_zlib_compress (Pdfio.string_of_bytes stream)) else flate_process (Pdfflate.compress ~level:!flate_level) stream let debug_stream_serial = ref 0 let debug_stream s = Pdfe.log "First 50 bytes\n"; for x = 0 to 50 do Pdfe.log (Printf.sprintf "%C = %i\n" (char_of_int (bget s x)) (bget s x)) done (*(* Write stream to current directory as _.zlib *) let name = string_of_int (bytes_size s) ^ "_" ^ string_of_int !debug_stream_serial ^ ".zlib" in Pdfe.log (Printf.sprintf "Writing %s\n" name); debug_stream_serial += 1; let fh = open_out_bin name in for x = 0 to bytes_size s - 1 do output_byte fh (bget s x) done; close_out fh*) let decode_flate stream = if bytes_size stream = 0 then mkbytes 0 else (* Accept the empty stream. *) try if is_js then Pdfio.bytes_of_string (camlpdf_caml_zlib_decompress (Pdfio.string_of_bytes stream)) else flate_process Pdfflate.uncompress stream with Pdfflate.Error (a, b) -> if !debug then debug_stream stream; raise (Couldn'tDecodeStream ("Flate" ^ " " ^ a ^ " " ^ b ^ " length " ^ string_of_int (bytes_size stream))) (* LZW *) (* Decode LZW. *) let decode_lzw early i = let prefix_code = Array.make 8192 0 and append_character = Array.make 8192 0 and bit_count = ref 0 and bit_buffer = ref 0l and endflush = ref 4 and code_length = ref 9 and next_code = ref 258 and new_code = ref 0 and old_code = ref 256 and character = ref 0 in let rec decode_string code str = if code > 255 then decode_string prefix_code.(code) (append_character.(code)::str) else code::str and input_code stream = while !bit_count <= 24 do let streambyte = match stream.input_byte () with | b when b = Pdfio.no_more -> if !endflush = 0 then raise End_of_file else (decr endflush; 0) | b -> b in bit_buffer := lor32 !bit_buffer (lsl32 (i32ofi streambyte) (24 - !bit_count)); bit_count += 8 done; let result = Int32.to_int (lsr32 !bit_buffer (32 - !code_length)) in bit_buffer := lsl32 !bit_buffer !code_length; bit_count -= !code_length; result and strip_cleartable_codes stream = while !old_code = 256 do old_code := input_code stream done and reset_table () = next_code := 258; code_length := 9; old_code := 256 in bit_count := 0; bit_buffer := 0l; endflush := 4; reset_table (); let outstream, data = input_output_of_bytes 16034 and finished = ref false in strip_cleartable_codes i; match !old_code with | 257 -> mkbytes 0 | _ -> character := !old_code; outstream.output_byte !old_code; while not !finished do new_code := input_code i; match !new_code with | 257 -> set finished | 256 -> reset_table (); set_array prefix_code 0; set_array append_character 0; strip_cleartable_codes i; character := !old_code; outstream.output_byte !old_code | _ -> let chars = if !new_code >= !next_code then (decode_string !old_code []) @ [!character] else decode_string !new_code [] in character := hd chars; iter outstream.output_byte chars; prefix_code.(!next_code) <- !old_code; append_character.(!next_code) <- !character; incr next_code; old_code := !new_code; match !next_code + early with | 512 | 1024 | 2048 -> incr code_length | _ -> () done; extract_bytes_from_input_output outstream data (* CCITT *) (* Decode a CCITT-encoded stream. Parameter names: eol -- /EndOfLine eba -- /EncodedByteAlign eob -- /EndOfBlock bone -- /BlackIs1 dra -- /DamagedRowsBeforeError c -- /Columns r -- /Rows *) let rec write_white_code = function | -1 -> [0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 1] | 0 -> [0; 0; 1; 1; 0; 1; 0; 1] | 1 -> [0; 0; 0; 1; 1; 1] | 2 -> [0; 1; 1; 1] | 3 -> [1; 0; 0; 0] | 4 -> [1; 0; 1; 1] | 5 -> [1; 1; 0; 0] | 6 -> [1; 1; 1; 0] | 7 -> [1; 1; 1; 1] | 8 -> [1; 0; 0; 1; 1] | 9 -> [1; 0; 1; 0; 0] | 10 -> [0; 0; 1; 1; 1] | 11 -> [0; 1; 0; 0; 0] | 12 -> [0; 0; 1; 0; 0; 0] | 13 -> [0; 0; 0; 0; 1; 1] | 14 -> [1; 1; 0; 1; 0; 0] | 15 -> [1; 1; 0; 1; 0; 1] | 16 -> [1; 0; 1; 0; 1; 0] | 17 -> [1; 0; 1; 0; 1; 1] | 18 -> [0; 1; 0; 0; 1; 1; 1] | 19 -> [0; 0; 0; 1; 1; 0; 0] | 20 -> [0; 0; 0; 1; 0; 0; 0] | 21 -> [0; 0; 1; 0; 1; 1; 1] | 22 -> [0; 0; 0; 0; 0; 1; 1] | 23 -> [0; 0; 0; 0; 1; 0; 0] | 24 -> [0; 1; 0; 1; 0; 0; 0] | 25 -> [0; 1; 0; 1; 0; 1; 1] | 26 -> [0; 0; 1; 0; 0; 1; 1] | 27 -> [0; 1; 0; 0; 1; 0; 0] | 28 -> [0; 0; 1; 1; 0; 0; 0] | 29 -> [0; 0; 0; 0; 0; 0; 1; 0] | 30 -> [0; 0; 0; 0; 0; 0; 1; 1] | 31 -> [0; 0; 0; 1; 1; 0; 1; 0] | 32 -> [0; 0; 0; 1; 1; 0; 1; 1] | 33 -> [0; 0; 0; 1; 0; 0; 1; 0] | 34 -> [0; 0; 0; 1; 0; 0; 1; 1] | 35 -> [0; 0; 0; 1; 0; 1; 0; 0] | 36 -> [0; 0; 0; 1; 0; 1; 0; 1] | 37 -> [0; 0; 0; 1; 0; 1; 1; 0] | 38 -> [0; 0; 0; 1; 0; 1; 1; 1] | 39 -> [0; 0; 1; 0; 1; 0; 0; 0] | 40 -> [0; 0; 1; 0; 1; 0; 0; 1] | 41 -> [0; 0; 1; 0; 1; 0; 1; 0] | 42 -> [0; 0; 1; 0; 1; 0; 1; 1] | 43 -> [0; 0; 1; 0; 1; 1; 0; 0] | 44 -> [0; 0; 1; 0; 1; 1; 0; 1] | 45 -> [0; 0; 0; 0; 0; 1; 0; 0] | 46 -> [0; 0; 0; 0; 0; 1; 0; 1] | 47 -> [0; 0; 0; 0; 1; 0; 1; 0] | 48 -> [0; 0; 0; 0; 1; 0; 1; 1] | 49 -> [0; 1; 0; 1; 0; 0; 1; 0] | 50 -> [0; 1; 0; 1; 0; 0; 1; 1] | 51 -> [0; 1; 0; 1; 0; 1; 0; 0] | 52 -> [0; 1; 0; 1; 0; 1; 0; 1] | 53 -> [0; 0; 1; 0; 0; 1; 0; 0] | 54 -> [0; 0; 1; 0; 0; 1; 0; 1] | 55 -> [0; 1; 0; 1; 1; 0; 0; 0] | 56 -> [0; 1; 0; 1; 1; 0; 0; 1] | 57 -> [0; 1; 0; 1; 1; 0; 1; 0] | 58 -> [0; 1; 0; 1; 1; 0; 1; 1] | 59 -> [0; 1; 0; 0; 1; 0; 1; 0] | 60 -> [0; 1; 0; 0; 1; 0; 1; 1] | 61 -> [0; 0; 1; 1; 0; 0; 1; 0] | 62 -> [0; 0; 1; 1; 0; 0; 1; 1] | 63 -> [0; 0; 1; 1; 0; 1; 0; 0] | n when n >= 2560 -> [0; 0; 0; 0; 0; 0; 0; 1; 1; 1; 1; 1] @ write_white_code (n - 2560) | n when n >= 2496 -> [0; 0; 0; 0; 0; 0; 0; 1; 1; 1; 1; 0] @ write_white_code (n - 2496) | n when n >= 2432 -> [0; 0; 0; 0; 0; 0; 0; 1; 1; 1; 0; 1] @ write_white_code (n - 2432) | n when n >= 2368 -> [0; 0; 0; 0; 0; 0; 0; 1; 1; 1; 0; 0] @ write_white_code (n - 2368) | n when n >= 2304 -> [0; 0; 0; 0; 0; 0; 0; 1; 0; 1; 1; 1] @ write_white_code (n - 2304) | n when n >= 2240 -> [0; 0; 0; 0; 0; 0; 0; 1; 0; 1; 1; 0] @ write_white_code (n - 2240) | n when n >= 2176 -> [0; 0; 0; 0; 0; 0; 0; 1; 0; 1; 0; 1] @ write_white_code (n - 2176) | n when n >= 2112 -> [0; 0; 0; 0; 0; 0; 0; 1; 0; 1; 0; 0] @ write_white_code (n - 2112) | n when n >= 2048 -> [0; 0; 0; 0; 0; 0; 0; 1; 0; 0; 1; 1] @ write_white_code (n - 2048) | n when n >= 1984 -> [0; 0; 0; 0; 0; 0; 0; 1; 0; 0; 1; 0] @ write_white_code (n - 1984) | n when n >= 1920 -> [0; 0; 0; 0; 0; 0; 0; 1; 1; 0; 1] @ write_white_code (n - 1920) | n when n >= 1856 -> [0; 0; 0; 0; 0; 0; 0; 1; 1; 0; 0] @ write_white_code (n - 1856) | n when n >= 1792 -> [0; 0; 0; 0; 0; 0; 0; 1; 0; 0; 0] @ write_white_code (n - 1792) | n when n >= 1728 -> [0; 1; 0; 0; 1; 1; 0; 1; 1] @ write_white_code (n - 1728) | n when n >= 1664 -> [0; 1; 1; 0; 0; 0] @ write_white_code (n - 1664) | n when n >= 1600 -> [0; 1; 0; 0; 1; 1; 0; 1; 0] @ write_white_code (n - 1600) | n when n >= 1536 -> [0; 1; 0; 0; 1; 1; 0; 0; 1] @ write_white_code (n - 1536) | n when n >= 1472 -> [0; 1; 0; 0; 1; 1; 0; 0; 0] @ write_white_code (n - 1472) | n when n >= 1408 -> [0; 1; 1; 0; 1; 1; 0; 1; 1] @ write_white_code (n - 1408) | n when n >= 1344 -> [0; 1; 1; 0; 1; 1; 0; 1; 0] @ write_white_code (n - 1344) | n when n >= 1280 -> [0; 1; 1; 0; 1; 1; 0; 0; 1] @ write_white_code (n - 1280) | n when n >= 1216 -> [0; 1; 1; 0; 1; 1; 0; 0; 0] @ write_white_code (n - 1216) | n when n >= 1152 -> [0; 1; 1; 0; 1; 0; 1; 1; 1] @ write_white_code (n - 1152) | n when n >= 1088 -> [0; 1; 1; 0; 1; 0; 1; 1; 0] @ write_white_code (n - 1088) | n when n >= 1024 -> [0; 1; 1; 0; 1; 0; 1; 0; 1] @ write_white_code (n - 1024) | n when n >= 960 -> [0; 1; 1; 0; 1; 0; 1; 0; 0] @ write_white_code (n - 960) | n when n >= 896 -> [0; 1; 1; 0; 1; 0; 0; 1; 1] @ write_white_code (n - 896) | n when n >= 832 -> [0; 1; 1; 0; 1; 0; 0; 1; 0] @ write_white_code (n - 832) | n when n >= 768 -> [0; 1; 1; 0; 0; 1; 1; 0; 1] @ write_white_code (n - 768) | n when n >= 704 -> [0; 1; 1; 0; 0; 1; 1; 0; 0] @ write_white_code (n - 704) | n when n >= 640 -> [0; 1; 1; 0; 0; 1; 1; 1] @ write_white_code (n - 640) | n when n >= 576 -> [0; 1; 1; 0; 1; 0; 0; 0] @ write_white_code (n - 576) | n when n >= 512 -> [0; 1; 1; 0; 0; 1; 0; 1] @ write_white_code (n - 512) | n when n >= 448 -> [0; 1; 1; 0; 0; 1; 0; 0] @ write_white_code (n - 448) | n when n >= 384 -> [0; 0; 1; 1; 0; 1; 1; 1] @ write_white_code (n - 384) | n when n >= 320 -> [0; 0; 1; 1; 0; 1; 1; 0] @ write_white_code (n - 320) | n when n >= 256 -> [0; 1; 1; 0; 1; 1; 1] @ write_white_code (n - 256) | n when n >= 192 -> [0; 1; 0; 1; 1; 1] @ write_white_code (n - 192) | n when n >= 128 -> [1; 0; 0; 1; 0] @ write_white_code (n - 128) | n when n >= 64 -> [1; 1; 0; 1; 1] @ write_white_code (n - 64) | _ -> raise (Pdf.PDFError "write_white_code: unknown") let rec write_black_code = function | -1 -> [0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 1] | 0 -> [0; 0; 0; 0; 1; 1; 0; 1; 1; 1] | 1 -> [0; 1; 0] | 2 -> [1; 1] | 3 -> [1; 0] | 4 -> [0; 1; 1] | 5 -> [0; 0; 1; 1] | 6 -> [0; 0; 1; 0] | 7 -> [0; 0; 0; 1; 1] | 8 -> [0; 0; 0; 1; 0; 1] | 9 -> [0; 0; 0; 1; 0; 0] | 10 -> [0; 0; 0; 0; 1; 0; 0] | 11 -> [0; 0; 0; 0; 1; 0; 1] | 12 -> [0; 0; 0; 0; 1; 1; 1] | 13 -> [0; 0; 0; 0; 0; 1; 0; 0] | 14 -> [0; 0; 0; 0; 0; 1; 1; 1] | 15 -> [0; 0; 0; 0; 1; 1; 0; 0; 0] | 16 -> [0; 0; 0; 0; 0; 1; 0; 1; 1; 1] | 17 -> [0; 0; 0; 0; 0; 1; 1; 0; 0; 0] | 18 -> [0; 0; 0; 0; 0; 0; 1; 0; 0; 0] | 19 -> [0; 0; 0; 0; 1; 1; 0; 0; 1; 1; 1] | 20 -> [0; 0; 0; 0; 1; 1; 0; 1; 0; 0; 0] | 21 -> [0; 0; 0; 0; 1; 1; 0; 1; 1; 0; 0] | 22 -> [0; 0; 0; 0; 0; 1; 1; 0; 1; 1; 1] | 23 -> [0; 0; 0; 0; 0; 1; 0; 1; 0; 0; 0] | 24 -> [0; 0; 0; 0; 0; 0; 1; 0; 1; 1; 1] | 25 -> [0; 0; 0; 0; 0; 0; 1; 1; 0; 0; 0] | 26 -> [0; 0; 0; 0; 1; 1; 0; 0; 1; 0; 1; 0] | 27 -> [0; 0; 0; 0; 1; 1; 0; 0; 1; 0; 1; 1] | 28 -> [0; 0; 0; 0; 1; 1; 0; 0; 1; 1; 0; 0] | 29 -> [0; 0; 0; 0; 1; 1; 0; 0; 1; 1; 0; 1] | 30 -> [0; 0; 0; 0; 0; 1; 1; 0; 1; 0; 0; 0] | 31 -> [0; 0; 0; 0; 0; 1; 1; 0; 1; 0; 0; 1] | 32 -> [0; 0; 0; 0; 0; 1; 1; 0; 1; 0; 1; 0] | 33 -> [0; 0; 0; 0; 0; 1; 1; 0; 1; 0; 1; 1] | 34 -> [0; 0; 0; 0; 1; 1; 0; 1; 0; 0; 1; 0] | 35 -> [0; 0; 0; 0; 1; 1; 0; 1; 0; 0; 1; 1] | 36 -> [0; 0; 0; 0; 1; 1; 0; 1; 0; 1; 0; 0] | 37 -> [0; 0; 0; 0; 1; 1; 0; 1; 0; 1; 0; 1] | 38 -> [0; 0; 0; 0; 1; 1; 0; 1; 0; 1; 1; 0] | 39 -> [0; 0; 0; 0; 1; 1; 0; 1; 0; 1; 1; 1] | 40 -> [0; 0; 0; 0; 0; 1; 1; 0; 1; 1; 0; 0] | 41 -> [0; 0; 0; 0; 0; 1; 1; 0; 1; 1; 0; 1] | 42 -> [0; 0; 0; 0; 1; 1; 0; 1; 1; 0; 1; 0] | 43 -> [0; 0; 0; 0; 1; 1; 0; 1; 1; 0; 1; 1] | 44 -> [0; 0; 0; 0; 0; 1; 0; 1; 0; 1; 0; 0] | 45 -> [0; 0; 0; 0; 0; 1; 0; 1; 0; 1; 0; 1] | 46 -> [0; 0; 0; 0; 0; 1; 0; 1; 0; 1; 1; 0] | 47 -> [0; 0; 0; 0; 0; 1; 0; 1; 0; 1; 1; 1] | 48 -> [0; 0; 0; 0; 0; 1; 1; 0; 0; 1; 0; 0] | 49 -> [0; 0; 0; 0; 0; 1; 1; 0; 0; 1; 0; 1] | 50 -> [0; 0; 0; 0; 0; 1; 0; 1; 0; 0; 1; 0] | 51 -> [0; 0; 0; 0; 0; 1; 0; 1; 0; 0; 1; 1] | 52 -> [0; 0; 0; 0; 0; 0; 1; 0; 0; 1; 0; 0] | 53 -> [0; 0; 0; 0; 0; 0; 1; 1; 0; 1; 1; 1] | 54 -> [0; 0; 0; 0; 0; 0; 1; 1; 1; 0; 0; 0] | 55 -> [0; 0; 0; 0; 0; 0; 1; 0; 0; 1; 1; 1] | 56 -> [0; 0; 0; 0; 0; 0; 1; 0; 1; 0; 0; 0] | 57 -> [0; 0; 0; 0; 0; 1; 0; 1; 1; 0; 0; 0] | 58 -> [0; 0; 0; 0; 0; 1; 0; 1; 1; 0; 0; 1] | 59 -> [0; 0; 0; 0; 0; 0; 1; 0; 1; 0; 1; 1] | 60 -> [0; 0; 0; 0; 0; 0; 1; 0; 1; 1; 0; 0] | 61 -> [0; 0; 0; 0; 0; 1; 0; 1; 1; 0; 1; 0] | 62 -> [0; 0; 0; 0; 0; 1; 1; 0; 0; 1; 1; 0] | 63 -> [0; 0; 0; 0; 0; 1; 1; 0; 0; 1; 1; 1] | n when n >= 2560 -> [0; 0; 0; 0; 0; 0; 0; 1; 1; 1; 1; 1] @ write_black_code (n - 2560) | n when n >= 2496 -> [0; 0; 0; 0; 0; 0; 0; 1; 1; 1; 1; 0] @ write_black_code (n - 2496) | n when n >= 2432 -> [0; 0; 0; 0; 0; 0; 0; 1; 1; 1; 0; 1] @ write_black_code (n - 2432) | n when n >= 2368 -> [0; 0; 0; 0; 0; 0; 0; 1; 1; 1; 0; 0] @ write_black_code (n - 2368) | n when n >= 2304 -> [0; 0; 0; 0; 0; 0; 0; 1; 0; 1; 1; 1] @ write_black_code (n - 2304) | n when n >= 2240 -> [0; 0; 0; 0; 0; 0; 0; 1; 0; 1; 1; 0] @ write_black_code (n - 2240) | n when n >= 2176 -> [0; 0; 0; 0; 0; 0; 0; 1; 0; 1; 0; 1] @ write_black_code (n - 2176) | n when n >= 2112 -> [0; 0; 0; 0; 0; 0; 0; 1; 0; 1; 0; 0] @ write_black_code (n - 2112) | n when n >= 2048 -> [0; 0; 0; 0; 0; 0; 0; 1; 0; 0; 1; 1] @ write_black_code (n - 2048) | n when n >= 1984 -> [0; 0; 0; 0; 0; 0; 0; 1; 0; 0; 1; 0] @ write_black_code (n - 1984) | n when n >= 1920 -> [0; 0; 0; 0; 0; 0; 0; 1; 1; 0; 1] @ write_black_code (n - 1920) | n when n >= 1856 -> [0; 0; 0; 0; 0; 0; 0; 1; 1; 0; 0] @ write_black_code (n - 1856) | n when n >= 1792 -> [0; 0; 0; 0; 0; 0; 0; 1; 0; 0; 0] @ write_black_code (n - 1792) | n when n >= 1728 -> [0; 0; 0; 0; 0; 0; 1; 1; 0; 0; 1; 0; 1] @ write_black_code (n - 1728) | n when n >= 1664 -> [0; 0; 0; 0; 0; 0; 1; 1; 0; 0; 1; 0; 0] @ write_black_code (n - 1664) | n when n >= 1600 -> [0; 0; 0; 0; 0; 0; 1; 0; 1; 1; 0; 1; 1] @ write_black_code (n - 1600) | n when n >= 1536 -> [0; 0; 0; 0; 0; 0; 1; 0; 1; 1; 0; 1; 0] @ write_black_code (n - 1536) | n when n >= 1472 -> [0; 0; 0; 0; 0; 0; 1; 0; 1; 0; 1; 0; 1] @ write_black_code (n - 1472) | n when n >= 1408 -> [0; 0; 0; 0; 0; 0; 1; 0; 1; 0; 1; 0; 0] @ write_black_code (n - 1408) | n when n >= 1344 -> [0; 0; 0; 0; 0; 0; 1; 0; 1; 0; 0; 1; 1] @ write_black_code (n - 1344) | n when n >= 1280 -> [0; 0; 0; 0; 0; 0; 1; 0; 1; 0; 0; 1; 0] @ write_black_code (n - 1280) | n when n >= 1216 -> [0; 0; 0; 0; 0; 0; 1; 1; 1; 0; 1; 1; 1] @ write_black_code (n - 1216) | n when n >= 1152 -> [0; 0; 0; 0; 0; 0; 1; 1; 1; 0; 1; 1; 0] @ write_black_code (n - 1152) | n when n >= 1088 -> [0; 0; 0; 0; 0; 0; 1; 1; 1; 0; 1; 0; 1] @ write_black_code (n - 1088) | n when n >= 1024 -> [0; 0; 0; 0; 0; 0; 1; 1; 1; 0; 1; 0; 0] @ write_black_code (n - 1024) | n when n >= 960 -> [0; 0; 0; 0; 0; 0; 1; 1; 1; 0; 0; 1; 1] @ write_black_code (n - 960) | n when n >= 896 -> [0; 0; 0; 0; 0; 0; 1; 1; 1; 0; 0; 1; 0] @ write_black_code (n - 896) | n when n >= 832 -> [0; 0; 0; 0; 0; 0; 1; 0; 0; 1; 1; 0; 1] @ write_black_code (n - 832) | n when n >= 768 -> [0; 0; 0; 0; 0; 0; 1; 0; 0; 1; 1; 0; 0] @ write_black_code (n - 768) | n when n >= 704 -> [0; 0; 0; 0; 0; 0; 1; 0; 0; 1; 0; 1; 1] @ write_black_code (n - 704) | n when n >= 640 -> [0; 0; 0; 0; 0; 0; 1; 0; 0; 1; 0; 1; 0] @ write_black_code (n - 640) | n when n >= 576 -> [0; 0; 0; 0; 0; 0; 1; 1; 0; 1; 1; 0; 1] @ write_black_code (n - 576) | n when n >= 512 -> [0; 0; 0; 0; 0; 0; 1; 1; 0; 1; 1; 0; 0] @ write_black_code (n - 512) | n when n >= 448 -> [0; 0; 0; 0; 0; 0; 1; 1; 0; 1; 0; 1] @ write_black_code (n - 448) | n when n >= 384 -> [0; 0; 0; 0; 0; 0; 1; 1; 0; 1; 0; 0] @ write_black_code (n - 384) | n when n >= 320 -> [0; 0; 0; 0; 0; 0; 1; 1; 0; 0; 1; 1] @ write_black_code (n - 320) | n when n >= 256 -> [0; 0; 0; 0; 0; 1; 0; 1; 1; 0; 1; 1] @ write_black_code (n - 256) | n when n >= 192 -> [0; 0; 0; 0; 1; 1; 0; 0; 1; 0; 0; 1] @ write_black_code (n - 192) | n when n >= 128 -> [0; 0; 0; 0; 1; 1; 0; 0; 1; 0; 0; 0] @ write_black_code (n - 128) | n when n >= 64 -> [0; 0; 0; 0; 0; 0; 1; 1; 1; 1] @ write_black_code (n - 64) | _ -> raise (Pdf.PDFError "write_black_code: unknown") let rec read_white_code i = let a = getbitint i in let b = getbitint i in let c = getbitint i in let d = getbitint i in match a, b, c, d with | 0, 1, 1, 1 -> 2 | 1, 0, 0, 0 -> 3 | 1, 0, 1, 1 -> 4 | 1, 1, 0, 0 -> 5 | 1, 1, 1, 0 -> 6 | 1, 1, 1, 1 -> 7 | _ -> let e = getbitint i in match a, b, c, d, e with | 1, 0, 0, 1, 1 -> 8 | 1, 0, 1, 0, 0 -> 9 | 0, 0, 1, 1, 1 -> 10 | 0, 1, 0, 0, 0 -> 11 | 1, 1, 0, 1, 1 -> 64 + read_white_code i | 1, 0, 0, 1, 0 -> 128 + read_white_code i | _ -> let f = getbitint i in match a, b, c, d, e, f with | 0, 0, 0, 1, 1, 1 -> 1 | 0, 0, 1, 0, 0, 0 -> 12 | 0, 0, 0, 0, 1, 1 -> 13 | 1, 1, 0, 1, 0, 0 -> 14 | 1, 1, 0, 1, 0, 1 -> 15 | 1, 0, 1, 0, 1, 0 -> 16 | 1, 0, 1, 0, 1, 1 -> 17 | 0, 1, 0, 1, 1, 1 -> 192 + read_white_code i | 0, 1, 1, 0, 0, 0 -> 1664 + read_white_code i | _ -> let g = getbitint i in match a, b, c, d, e, f, g with | 0, 1, 0, 0, 1, 1, 1 -> 18 | 0, 0, 0, 1, 1, 0, 0 -> 19 | 0, 0, 0, 1, 0, 0, 0 -> 20 | 0, 0, 1, 0, 1, 1, 1 -> 21 | 0, 0, 0, 0, 0, 1, 1 -> 22 | 0, 0, 0, 0, 1, 0, 0 -> 23 | 0, 1, 0, 1, 0, 0, 0 -> 24 | 0, 1, 0, 1, 0, 1, 1 -> 25 | 0, 0, 1, 0, 0, 1, 1 -> 26 | 0, 1, 0, 0, 1, 0, 0 -> 27 | 0, 0, 1, 1, 0, 0, 0 -> 28 | 0, 1, 1, 0, 1, 1, 1 -> 256 + read_white_code i | _ -> let h = getbitint i in match a, b, c, d, e, f, g, h with | 0, 0, 1, 1, 0, 1, 0, 1 -> 0 | 0, 0, 0, 0, 0, 0, 1, 0 -> 29 | 0, 0, 0, 0, 0, 0, 1, 1 -> 30 | 0, 0, 0, 1, 1, 0, 1, 0 -> 31 | 0, 0, 0, 1, 1, 0, 1, 1 -> 32 | 0, 0, 0, 1, 0, 0, 1, 0 -> 33 | 0, 0, 0, 1, 0, 0, 1, 1 -> 34 | 0, 0, 0, 1, 0, 1, 0, 0 -> 35 | 0, 0, 0, 1, 0, 1, 0, 1 -> 36 | 0, 0, 0, 1, 0, 1, 1, 0 -> 37 | 0, 0, 0, 1, 0, 1, 1, 1 -> 38 | 0, 0, 1, 0, 1, 0, 0, 0 -> 39 | 0, 0, 1, 0, 1, 0, 0, 1 -> 40 | 0, 0, 1, 0, 1, 0, 1, 0 -> 41 | 0, 0, 1, 0, 1, 0, 1, 1 -> 42 | 0, 0, 1, 0, 1, 1, 0, 0 -> 43 | 0, 0, 1, 0, 1, 1, 0, 1 -> 44 | 0, 0, 0, 0, 0, 1, 0, 0 -> 45 | 0, 0, 0, 0, 0, 1, 0, 1 -> 46 | 0, 0, 0, 0, 1, 0, 1, 0 -> 47 | 0, 0, 0, 0, 1, 0, 1, 1 -> 48 | 0, 1, 0, 1, 0, 0, 1, 0 -> 49 | 0, 1, 0, 1, 0, 0, 1, 1 -> 50 | 0, 1, 0, 1, 0, 1, 0, 0 -> 51 | 0, 1, 0, 1, 0, 1, 0, 1 -> 52 | 0, 0, 1, 0, 0, 1, 0, 0 -> 53 | 0, 0, 1, 0, 0, 1, 0, 1 -> 54 | 0, 1, 0, 1, 1, 0, 0, 0 -> 55 | 0, 1, 0, 1, 1, 0, 0, 1 -> 56 | 0, 1, 0, 1, 1, 0, 1, 0 -> 57 | 0, 1, 0, 1, 1, 0, 1, 1 -> 58 | 0, 1, 0, 0, 1, 0, 1, 0 -> 59 | 0, 1, 0, 0, 1, 0, 1, 1 -> 60 | 0, 0, 1, 1, 0, 0, 1, 0 -> 61 | 0, 0, 1, 1, 0, 0, 1, 1 -> 62 | 0, 0, 1, 1, 0, 1, 0, 0 -> 63 | 0, 0, 1, 1, 0, 1, 1, 0 -> 320 + read_white_code i | 0, 0, 1, 1, 0, 1, 1, 1 -> 384 + read_white_code i | 0, 1, 1, 0, 0, 1, 0, 0 -> 448 + read_white_code i | 0, 1, 1, 0, 0, 1, 0, 1 -> 512 + read_white_code i | 0, 1, 1, 0, 1, 0, 0, 0 -> 576 + read_white_code i | 0, 1, 1, 0, 0, 1, 1, 1 -> 640 + read_white_code i | _ -> let j = getbitint i in match a, b, c, d, e, f, g, h, j with | 0, 1, 1, 0, 0, 1, 1, 0, 0 -> 704 + read_white_code i | 0, 1, 1, 0, 0, 1, 1, 0, 1 -> 768 + read_white_code i | 0, 1, 1, 0, 1, 0, 0, 1, 0 -> 832 + read_white_code i | 0, 1, 1, 0, 1, 0, 0, 1, 1 -> 896 + read_white_code i | 0, 1, 1, 0, 1, 0, 1, 0, 0 -> 960 + read_white_code i | 0, 1, 1, 0, 1, 0, 1, 0, 1 -> 1024 + read_white_code i | 0, 1, 1, 0, 1, 0, 1, 1, 0 -> 1088 + read_white_code i | 0, 1, 1, 0, 1, 0, 1, 1, 1 -> 1152 + read_white_code i | 0, 1, 1, 0, 1, 1, 0, 0, 0 -> 1216 + read_white_code i | 0, 1, 1, 0, 1, 1, 0, 0, 1 -> 1280 + read_white_code i | 0, 1, 1, 0, 1, 1, 0, 1, 0 -> 1344 + read_white_code i | 0, 1, 1, 0, 1, 1, 0, 1, 1 -> 1408 + read_white_code i | 0, 1, 0, 0, 1, 1, 0, 0, 0 -> 1472 + read_white_code i | 0, 1, 0, 0, 1, 1, 0, 0, 1 -> 1536 + read_white_code i | 0, 1, 0, 0, 1, 1, 0, 1, 0 -> 1600 + read_white_code i | 0, 1, 0, 0, 1, 1, 0, 1, 1 -> 1728 + read_white_code i | _ -> let k = getbitint i in let l = getbitint i in match a, b, c, d, e, f, g, h, j, k, l with | 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 -> 1792 + read_white_code i | 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 -> 1856 + read_white_code i | 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1 -> 1920 + read_white_code i | _ -> let m = getbitint i in match a, b, c, d, e, f, g, h, j, k, l, m with | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 -> -1 | 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0 -> 1984 + read_white_code i | 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1 -> 2048 + read_white_code i | 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0 -> 2112 + read_white_code i | 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1 -> 2176 + read_white_code i | 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0 -> 2240 + read_white_code i | 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1 -> 2304 + read_white_code i | 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0 -> 2368 + read_white_code i | 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1 -> 2432 + read_white_code i | 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0 -> 2496 + read_white_code i | 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 -> 2560 + read_white_code i | _ -> raise (Failure "bad white code") let rec read_black_code i = let a = getbitint i in let b = getbitint i in match a, b with | 1, 1 -> 2 | 1, 0 -> 3 | _ -> let c = getbitint i in match a, b, c with | 0, 1, 0 -> 1 | 0, 1, 1 -> 4 | _ -> let d = getbitint i in match a, b, c, d with | 0, 0, 1, 1 -> 5 | 0, 0, 1, 0 -> 6 | _ -> let e = getbitint i in match a, b, c, d, e with | 0, 0, 0, 1, 1 -> 7 | _ -> let f = getbitint i in match a, b, c, d, e, f with | 0, 0, 0, 1, 0, 1 -> 8 | 0, 0, 0, 1, 0, 0 -> 9 | _ -> let g = getbitint i in match a, b, c, d, e, f, g with | 0, 0, 0, 0, 1, 0, 0 -> 10 | 0, 0, 0, 0, 1, 0, 1 -> 11 | 0, 0, 0, 0, 1, 1, 1 -> 12 | _ -> let h = getbitint i in match a, b, c, d, e, f, g, h with | 0, 0, 0, 0, 0, 1, 0, 0 -> 13 | 0, 0, 0, 0, 0, 1, 1, 1 -> 14 | _ -> let j = getbitint i in match a, b, c, d, e, f, g, h, j with | 0, 0, 0, 0, 1, 1, 0, 0, 0 -> 15 | _ -> let k = getbitint i in match a, b, c, d, e, f, g, h, j, k with | 0, 0, 0, 0, 1, 1, 0, 1, 1, 1 -> 0 | 0, 0, 0, 0, 0, 1, 0, 1, 1, 1 -> 16 | 0, 0, 0, 0, 0, 1, 1, 0, 0, 0 -> 17 | 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 -> 18 | 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 -> 64 + read_black_code i | _ -> let l = getbitint i in match a, b, c, d, e, f, g, h, j, k, l with | 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1 -> 19 | 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0 -> 20 | 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0 -> 21 | 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1 -> 22 | 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0 -> 23 | 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1 -> 24 | 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0 -> 25 | 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 -> 1792 + read_black_code i | 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 -> 1856 + read_black_code i | 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1 -> 1920 + read_black_code i | _ -> let m = getbitint i in match a, b, c, d, e, f, g, h, j, k, l, m with | 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0 -> 26 | 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1 -> 27 | 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 -> 28 | 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1 -> 29 | 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0 -> 30 | 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1 -> 31 | 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0 -> 32 | 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1 -> 33 | 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0 -> 34 | 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1 -> 35 | 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0 -> 36 | 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1 -> 37 | 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0 -> 38 | 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1 -> 39 | 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0 -> 40 | 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1 -> 41 | 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0 -> 42 | 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1 -> 43 | 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0 -> 44 | 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1 -> 45 | 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0 -> 46 | 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1 -> 47 | 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0 -> 48 | 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1 -> 49 | 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0 -> 50 | 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1 -> 51 | 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0 -> 52 | 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1 -> 53 | 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0 -> 54 | 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1 -> 55 | 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0 -> 56 | 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0 -> 57 | 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1 -> 58 | 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1 -> 59 | 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0 -> 60 | 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0 -> 61 | 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0 -> 62 | 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1 -> 63 | 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0 -> 128 + read_black_code i | 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1 -> 192 + read_black_code i | 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1 -> 256 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1 -> 320 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0 -> 384 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1 -> 448 + read_black_code i | 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0 -> 1984 + read_black_code i | 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1 -> 2048 + read_black_code i | 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0 -> 2112 + read_black_code i | 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1 -> 2176 + read_black_code i | 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0 -> 2240 + read_black_code i | 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1 -> 2304 + read_black_code i | 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0 -> 2368 + read_black_code i | 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1 -> 2432 + read_black_code i | 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0 -> 2496 + read_black_code i | 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 -> 2560 + read_black_code i | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 -> -1 | _ -> let n = getbitint i in match a, b, c, d, e, f, g, h, j, k, l, m, n with | 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0 -> 512 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1 -> 576 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0 -> 640 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1 -> 704 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0 -> 768 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1 -> 832 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0 -> 896 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1 -> 960 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0 -> 1024 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1 -> 1088 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0 -> 1152 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1 -> 1216 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0 -> 1280 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1 -> 1344 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0 -> 1408 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1 -> 1472 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0 -> 1536 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1 -> 1600 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0 -> 1664 + read_black_code i | 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1 -> 1728 + read_black_code i | _ -> raise (Failure "bad black code") (* Group 4 Fax decoder. *) type modes = | Pass | Horizontal | Vertical of int | Uncompressed | EOFB let read_mode i = let a = getbitint i in match a with | 1 -> Vertical 0 | _ -> let b = getbitint i in let c = getbitint i in match a, b, c with | 0, 1, 1 -> Vertical (-1) | 0, 1, 0 -> Vertical 1 | 0, 0, 1 -> Horizontal | _ -> let d = getbitint i in match a, b, c, d with | 0, 0, 0, 1 -> Pass | _ -> let e = getbitint i in let f = getbitint i in match a, b, c, d, e, f with | 0, 0, 0, 0, 1, 1 -> Vertical (-2) | 0, 0, 0, 0, 1, 0 -> Vertical 2 | _ -> let g = getbitint i in match a, b, c, d, e, f, g with | 0, 0, 0, 0, 0, 1, 1 -> Vertical (-3) | 0, 0, 0, 0, 0, 1, 0 -> Vertical 3 | _ -> let h = getbitint i in let j = getbitint i in let k = getbitint i in let l = getbitint i in let m = getbitint i in match a, b, c, d, e, f, g, h, j, k, l, m with | 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 -> Uncompressed | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 -> let a = getbitint i in let b = getbitint i in let c = getbitint i in let d = getbitint i in let e = getbitint i in let f = getbitint i in let g = getbitint i in let h = getbitint i in let j = getbitint i in let k = getbitint i in let l = getbitint i in let m = getbitint i in begin match a, b, c, d, e, f, g, h, j, k, l, m with | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 -> EOFB | _ -> raise (Failure "Not a valid code on EOFB") end | _ -> raise (Failure "Not a valid code") let decode_CCITTFax k eol eba c r eob bone dra input = if k > 0 then raise (DecodeNotSupported "CCITTFax k > 0") else let whiteval, blackval = if bone then 0, 1 else 1, 0 in let output = make_write_bitstream () in let b = bitbytes_of_input input in let column = ref 0 in let row = ref 0 in let refline = ref (Array.make c whiteval) in let currline = ref (Array.make c 0) in let white = ref true in let output_line line = Array.iter (putbit output) line; align_write output in let output_span l v = if l < 0 then raise (Failure "Bad CCITT stream") else begin for x = !column to !column + l - 1 do let r = !currline in r.(x) <- v done; column += l end in let find_b1 () = let pos = ref !column in let curr, opp = if !white then whiteval, blackval else blackval, whiteval in let find v = while let r = !refline in if !pos >= 0 && !pos < Array.length r then r.(!pos) <> v else false do incr pos done; !pos in try (* Careful to skip imaginary black at beginning *) ignore (if !column = 0 && !white then 0 else find curr); find opp with _ -> c in let find_b2 () = let pos = ref !column in let curr, opp = if !white then whiteval, blackval else blackval, whiteval in let find v = while let r = !refline in if !pos >=0 && !pos < Array.length r then r.(!pos) <> v else false do incr pos done; !pos in try (* Careful to skip imaginary black at beginning *) ignore (if !column = 0 && !white then 0 else find curr); ignore (find opp); find curr with _ -> c in try while true do if !column >= c then begin output_line !currline; refline := !currline; column := 0; set white; if eba then align b; incr row; if !row >= r && r > 0 then raise End_of_file end else begin if k < 0 then (* Group 4 *) match read_mode b with | Pass -> output_span (find_b2 () - !column) (if !white then whiteval else blackval) | Horizontal -> if !white then begin output_span (read_white_code b) whiteval; output_span (read_black_code b) blackval; end else begin output_span (read_black_code b) blackval; output_span (read_white_code b) whiteval; end | Vertical n -> output_span (find_b1 () - !column - n) (if !white then whiteval else blackval); flip white | EOFB -> raise End_of_file | Uncompressed -> raise (DecodeNotSupported "CCITT Uncompressed") else if k = 0 then (* Group 3 *) begin match (if !white then read_white_code else read_black_code) b with | -1 -> (* Pad it out *) if !column > 0 then output_span (c - !column) whiteval | l -> begin output_span l (if !white then whiteval else blackval); flip white end end else raise (DecodeNotSupported "CCITT k") end done; mkbytes 0 with | End_of_file -> bytes_of_write_bitstream output | _ -> raise (Failure "Bad CCITT Stream") (* CCITT Group 3 encoder *) (* Data comes in as bytes, with each scanline padded with zeroes. In addition, it is padded to bytes at the end. (Why though? Check for our case.) Output is suitable for /CCITTFaxDecode /Columns /K 0 with all other dictionary entries as default. i.e: *) (* Return colour of run, and non-zero length of run (must make progress) *) let read_run maxcols i = let nbits = ref 1 in let iswhite = ref (Pdfio.getbit i) in let fin = ref false in while !nbits < maxcols && not !fin do let pos = ref (Pdfio.bitstream_pos i) in let newbit = Pdfio.getbit i in if newbit = !iswhite then nbits += 1 else (Pdfio.bitstream_seek i !pos; set fin) done; (!iswhite, !nbits) let encode_ccitt columns stream = let i = Pdfio.bitbytes_of_input (Pdfio.input_of_bytes stream) in let o = Pdfio.make_write_bitstream () in try let cols_left = ref columns in while true do let iswhite, length = read_run !cols_left i in let bits = (if iswhite then write_white_code else write_black_code) length in iter (Pdfio.putbit o) bits; if not iswhite && !cols_left = columns then iter (Pdfio.putbit o) (write_black_code 0); cols_left -= length; if !cols_left = 0 then cols_left := columns; done; mkbytes 0 with End_of_file -> iter (Pdfio.putbit o) (write_white_code ~-1); iter (Pdfio.putbit o) (write_white_code ~-1); Pdfio.align_write o; bytes_of_write_bitstream o (* CCITT Group 4 encoder *) (* Data comes in as bytes, with each scanline padded with zeroes. In addition, it is padded to bytes at the end. (Why though? Check for our case.) Output is suitable for /CCITTFaxDecode /Columns /K -1 with all other dictionary entries as default. *) let encode_ccittg4 columns stream = stream (* Tester. *) (*let _ = Printf.printf "Running test_encode_ccitt\n"; let data = contents_of_file "/Users/john/Desktop/CCITT/out.dat" in let g4 = encode_ccitt 2592 (Pdfio.bytes_of_string data) in let fh = open_out_bin "/Users/john/Desktop/CCITT/g4.dat" in output_string fh (Pdfio.string_of_bytes g4); close_out fh*) (* PNG and TIFF Predictors *) (* Get the value at index i from an int array a, giving zero if the index is too low. Fails in the usual manner if the index is too high. *) let get0 a i = if i < 0 then 0 else a.(i) (* TIFF prediction. 8bpp only for now. *) let decode_tiff_predictor colors bpc columns stream = match bpc with | 1 -> raise (DecodeNotSupported "TIFF Predictor for 1bpc not supported") | 2 -> raise (DecodeNotSupported "TIFF Predictor for 2bpc not supported") | 4 -> raise (DecodeNotSupported "TIFF Predictor for 4bpc not supported") | 8 -> let scanline_width = (colors * bpc * columns + 7) / 8 in for line = 0 to bytes_size stream / scanline_width - 1 do let linestart = line * scanline_width in let p = ref colors in while !p < scanline_width do bset stream (linestart + !p) ((bget stream (linestart + !p - colors) + bget stream (linestart + !p)) mod 256); p := !p + 1 done done; stream | 16 -> raise (DecodeNotSupported "TIFF Predictor for 16bpc not supported") | _ -> raise (DecodeNotSupported "Tiff predictor for unknown color depth") (* Given two scanlines, the previous and current, and the predictor function p, calculate the output scanline as a list of bytes. *) let decode_scanline_pair prior_encoded prior_decoded current pred bpc cols = let output = Array.copy current in begin match pred with | 0 -> (* None *) () | 1 -> (* Sub *) for x = 0 to Array.length output - 1 do output.(x) <- (get0 current x + get0 output (x - cols)) mod 256 done | 2 -> (* Up *) for x = 0 to Array.length output - 1 do output.(x) <- (get0 current x + get0 prior_decoded x) mod 256 done | 3 -> (* Average -- No test case yet found. *) for x = 0 to Array.length output - 1 do output.(x) <- (get0 current x + (get0 output (x - cols) + get0 prior_decoded x) / 2) mod 256 done | 4 -> (* Paeth *) let paeth a b c = let p = a + b - c in let pa = abs (p - a) in let pb = abs (p - b) in let pc = abs (p - c) in if pa <= pb && pa <= pc then a else if pb <= pc then b else c in for x = 0 to Array.length output - 1 do output.(x) <- let curr = get0 current x in let currback = get0 output (x - cols) in let decoded = get0 prior_decoded x in let decodedback = get0 prior_decoded (x - cols) in (curr + paeth currback decoded decodedback) mod 256 done | _ -> raise (DecodeNotSupported "unknown PNG predictor") end; output (* Main function. Given predictor, number of channels, bits-per-channel, columns and the stream data, perform the decoding. *) let decode_predictor pred colors bpc columns stream = if pred = 2 then decode_tiff_predictor colors bpc columns stream else let i = input_of_bytes stream in let scanline_width = (colors * bpc * columns + 7) / 8 in let blank () = ref (Array.make scanline_width 0) in let prev, curr, prior_decoded = blank (), blank (), blank () in let outputlines = ref [] in let finished = ref false in let pred = ref 0 in let got_predictor = ref false in while not !finished do clear got_predictor; begin match i.input_byte () with | x when x = Pdfio.no_more -> set finished | x -> pred := x end; if !finished then () else begin set got_predictor; prev := !curr; for x = 0 to scanline_width - 1 do match i.input_byte () with | x when x = Pdfio.no_more -> set finished | b -> (!curr).(x) <- b done end; (* We allow an unfinished final line only if we managed to get a predictor byte *) if !got_predictor then begin prior_decoded := decode_scanline_pair !prev !prior_decoded !curr !pred bpc ((bpc * colors + 7) / 8); outputlines =| !prior_decoded end done; bytes_of_arraylist (rev !outputlines) (* A couple of special-purpose encoders for prediction. *) let encode_predictor pred colors bpc columns stream = let get0 a i = if i < 0 then 0 else bget a i in match pred with | 11 -> (* Just for recompressing inline images. Restricted to bpc = 8, colors = 3 for now. *) let o, bytes = Pdfio.input_output_of_bytes 4096 in for scanline = 0 to bytes_size stream / (columns * 3) - 1 do o.Pdfio.output_byte 1; (* tag for Sub *) for byte = 0 to columns * 3 - 1 do o.Pdfio.output_byte ((get0 stream (scanline * columns + byte)) - (if byte < 3 then 0 else get0 stream (scanline * columns + byte - 3)) mod 256) done done; Pdfio.extract_bytes_from_input_output o bytes | 12 -> (* Just for XRef streams. *) let o, bytes = Pdfio.input_output_of_bytes 4096 in for scanline = 0 to bytes_size stream / columns - 1 do o.Pdfio.output_byte 2; (* tag for Up *) for byte = 0 to columns - 1 do o.Pdfio.output_byte ((get0 stream (scanline * columns + byte) - get0 stream ((scanline - 1) * columns + byte)) mod 256) done done; Pdfio.extract_bytes_from_input_output o bytes | n -> raise (Pdf.PDFError ("encode_predictor: not supported - " ^ string_of_int n)) (* Run Length Encoding *) let encode_runlength stream = let i = input_of_bytes stream in let data_in = ref [] in begin try while true do data_in =| begin match i.input_byte () with | x when x = Pdfio.no_more -> raise End_of_file | x -> x end done with End_of_file -> data_in := rev !data_in end; let rec runs_of_data prev = function | [] -> rev prev | h::t -> let same, rest = cleavewhile (eq h) (h::t) in runs_of_data ((length same, hd same)::prev) rest in let runs = ref (runs_of_data [] !data_in) in let outbytes = ref [] in let chunksize = ref 0 in let chunkdata = ref [] in let writechunk () = if !chunksize > 0 then begin outbytes =| !chunksize - 1; iter (( =| ) outbytes) (rev !chunkdata); chunkdata := []; chunksize := 0; end in while !runs <> [] do begin match hd !runs with | (l, _) when l < 1 -> assert false | (l, x) when l < 3 -> if l + !chunksize > 128 then writechunk (); chunkdata =@ many x l; chunksize += l | (l, x) -> writechunk (); let l = ref l in while !l > 0 do outbytes =| 257 - min !l 128; outbytes =| x; l -= 128 done end; runs := tl !runs done; writechunk (); outbytes =| 128; (*r End-of-data *) bytes_of_list (rev !outbytes) let decode_runlength i = let o, data = input_output_of_bytes 4096 in let eod = ref false in begin try while not !eod do let l = match i.input_byte () with | x when x = Pdfio.no_more -> raise End_of_file | x -> x in if l < 128 then for x = 1 to l + 1 do o.output_byte begin match i.input_byte () with | x when x = Pdfio.no_more -> raise End_of_file | x -> x end done else if l > 128 then let towrite = begin match i.input_byte () with | x when x = Pdfio.no_more -> raise End_of_file | x -> x end; in for x = 1 to 257 - l do o.output_byte towrite done else set eod done with End_of_file -> Pdfe.log "Warning: Missing EOD marker in runlength decode...\n" end; extract_bytes_from_input_output o data (* Decoding PDF streams *) type source = | StreamSource of bytes | InputSource of input let decode_identity i = Pdfio.bytes_of_input i 0 i.in_channel_length let decoder pdf dict source name = let input_of_source = function | InputSource i -> i | StreamSource s -> input_of_bytes s in let i = input_of_source source in match name with | "/Crypt" -> decode_identity i | "/ASCIIHexDecode" | "/AHx" -> decode_ASCIIHex i | "/ASCII85Decode" | "/A85" -> decode_ASCII85 i | "/FlateDecode" | "/Fl" -> begin match source with | StreamSource s -> decode_flate s | InputSource i -> decode_flate_input i end | "/RunLengthDecode" | "/RL" -> decode_runlength i | "/LZWDecode" | "/LZW" -> let early = match Pdf.lookup_direct_orelse pdf "/DecodeParms" "/DP" dict with | Some (Pdf.Array (Pdf.Null::_)) -> 1 | Some (Pdf.Dictionary _ as d) | Some (Pdf.Array (Pdf.Dictionary _ as d::_)) -> begin match Pdf.lookup_direct pdf "/EarlyChange" d with | Some (Pdf.Integer n) -> n | None -> 1 | _ -> raise (Pdf.PDFError "malformed /EarlyChange") end | _ -> 1 in decode_lzw early i | "/CCITTFaxDecode" | "/CCF" -> begin match Pdf.lookup_direct_orelse pdf "/DecodeParms" "/DP" dict with | None -> decode_CCITTFax 0 false false 1728 0 true false 0 i | Some (Pdf.Dictionary _ as dparms) | Some (Pdf.Array (dparms::_)) -> (* Copes with null ok, because lookup_direct used below *) let dparms = Pdf.direct pdf dparms in let k = match Pdf.lookup_direct pdf "/K" dparms with | Some (Pdf.Integer i) -> i | _ -> 0 in let eol = match Pdf.lookup_direct pdf "/EndOfLine" dparms with | Some (Pdf.Boolean b) -> b | _ -> false in let eba = match Pdf.lookup_direct pdf "/EncodedByteAlign" dparms with | Some (Pdf.Boolean b) -> b | _ -> false in let c = match Pdf.lookup_direct pdf "/Columns" dparms with | Some (Pdf.Integer i) -> i | _ -> 1728 in let r = match Pdf.lookup_direct pdf "/Rows" dparms with | Some (Pdf.Integer i) -> i | _ -> 0 in let eob = match Pdf.lookup_direct pdf "/EndOfBlock" dparms with | Some (Pdf.Boolean b) -> b | _ -> true in let bone = match Pdf.lookup_direct pdf "/BlackIs1" dparms with | Some (Pdf.Boolean b) -> b | _ -> false in let dra = match Pdf.lookup_direct pdf "/DamagedRowsBeforeError" dparms with | Some (Pdf.Integer i) -> i | _ -> 0 in decode_CCITTFax k eol eba c r eob bone dra i | _ -> raise (Pdf.PDFError "bad Decodeparms") end | name -> raise (DecodeNotSupported (Printf.sprintf "Unknown: %s" name)) (* Decode at most one stage. *) let decode_one pdf dict source = match Pdf.lookup_direct_orelse pdf "/Filter" "/F" dict with | None | Some (Pdf.Array []) -> begin match source with | StreamSource s -> s | InputSource _ -> raise (DecodeNotSupported "decode_one") end | Some (Pdf.Name n) | Some (Pdf.Array (Pdf.Name n::_)) -> let decoded = decoder pdf dict source n in let decodeparms = match Pdf.lookup_direct_orelse pdf "/DecodeParms" "/DP" dict with | Some (Pdf.Dictionary d) | Some (Pdf.Array (Pdf.Dictionary d::_)) -> Pdf.Dictionary d | _ -> Pdf.Dictionary [] in begin match Pdf.lookup_direct pdf "/Predictor" decodeparms with | None | Some (Pdf.Integer 1) -> decoded | Some (Pdf.Integer pred) -> let colors = match Pdf.lookup_direct pdf "/Colors" decodeparms with | Some (Pdf.Integer n) -> n | None -> 1 | _ -> raise (Pdf.PDFError "malformed /Colors") in let bits_per_component = match Pdf.lookup_direct pdf "/BitsPerComponent" decodeparms with | Some (Pdf.Integer n) -> n | None -> 8 | _ -> raise (Pdf.PDFError "malformed /BitsPerComponent") in let columns = match Pdf.lookup_direct pdf "/Columns" decodeparms with | Some (Pdf.Integer n) -> n | None -> 1 | _ -> raise (Pdf.PDFError "malformed /Columns") in begin try decode_predictor pred colors bits_per_component columns decoded with _ -> raise (Couldn'tDecodeStream "Predictor") end | _ -> raise (Pdf.PDFError "Malformed /Predictor") end | _ -> raise (Pdf.PDFError "PDF.decode: Bad filter specification") (* Need to make sure /Filter, /F, /DecodeParms, /DP are not indirect. d on entry is a name -> pdfobject map *) let prepare_decoder pdf d = map (function (("/Filter" | "/F" | "/DecodeParms" | "/DP") as k, v) -> k, Pdf.direct pdf v | x -> x) d (* Remove a single decoder from a filter list. Also remove the first entry of a DecodeParms array *) let remove_decoder d = let d' = match lookup "/Filter" d, lookup "/F" d with | None, None -> d | Some (Pdf.Name _ | Pdf.Array [_]), None -> lose (fun (n, _) -> n = "/Filter") d | None, Some (Pdf.Name _ | Pdf.Array [_]) -> lose (fun (n, _) -> n = "/F") d | Some (Pdf.Array (_::t)), _ -> replace "/Filter" (Pdf.Array t) d | _, Some (Pdf.Array (_::t)) -> replace "/F" (Pdf.Array t) d | _ -> raise (Pdf.PDFError "PDF.remove_decoder: malformed /Filter") in match lookup "/DecodeParms" d', lookup "/DP" d' with | None, None -> d' | Some (Pdf.Dictionary _ | Pdf.Array []), _ -> remove "/DecodeParms" d' | _, Some (Pdf.Dictionary _ | Pdf.Array []) -> remove "/DP" d' | Some (Pdf.Array (_::t)), _ -> replace "/DecodeParms" (Pdf.Array t) d' | _, Some (Pdf.Array (_::t)) -> replace "/DP" (Pdf.Array t) d' | _ -> raise (Pdf.PDFError "PDF.remove_decoder: malformed /DecodeParms") (* Decode at most one stage. *) let decode_pdfstream_onestage pdf stream = Pdf.getstream stream; match stream with | Pdf.Stream ({contents = (Pdf.Dictionary d as dict, Pdf.Got s)} as stream_contents) -> begin match Pdf.direct pdf (Pdf.lookup_fail "no /Length" pdf "/Length" dict) with | Pdf.Integer _ -> () (*i if l <> bytes_size s then raise (PDFError "Wrong /Length") i*) | _ -> raise (Pdf.PDFError "No /Length") end; let stream' = decode_one pdf dict (StreamSource s) in let d' = replace "/Length" (Pdf.Integer (bytes_size stream')) (remove_decoder (prepare_decoder pdf d)) in stream_contents := (Pdf.Dictionary d', Pdf.Got stream') | _ -> raise (Pdf.PDFError "Pdf.decode_pdfstream: not a valid Stream") let string_of_pdf = ref (fun _ -> "") (* Decode until there's nothing left to do. *) let rec decode_pdfstream pdf = function | Pdf.Stream {contents = d, _} as stream -> Pdf.getstream stream; begin match Pdf.lookup_direct_orelse pdf "/Filter" "/F" d with | None -> () | Some (Pdf.Name _ | Pdf.Array _) -> begin decode_pdfstream_onestage pdf stream; match stream with | Pdf.Stream {contents = d', _} -> if !string_of_pdf d = !string_of_pdf d' then () else decode_pdfstream pdf stream | _ -> assert false end | _ -> raise (Pdf.PDFError "Pdf.remove_decoder: malformed /Filter") end | Pdf.Indirect i -> decode_pdfstream pdf (Pdf.direct pdf (Pdf.Indirect i)) | _ -> raise (Pdf.PDFError "Pdf.decode_pdfstream: malformed Stream") (* Decode a stream until a decoding isn't supported. *) let decode_pdfstream_until_unknown pdf s = try decode_pdfstream pdf s with DecodeNotSupported _ -> () (* Decode from an input. *) let decode_from_input i dict = match Pdf.lookup_direct_orelse (Pdf.empty ()) "/F" "/Filter" dict with | Some (Pdf.Name _) -> Some (decode_one (Pdf.empty ()) dict (InputSource i)) | Some (Pdf.Array (_::t)) -> let stream = decode_one (Pdf.empty ()) dict (InputSource i) in let rec decode_rest stream = function | [] -> stream | Pdf.Name _::more -> let filters = Pdf.lookup_direct_orelse (Pdf.empty ()) "/F" "/Filter" dict in let decodeparms = Pdf.lookup_direct_orelse (Pdf.empty ()) "/DP" "/DecodeParms" dict in let dict = Pdf.remove_dict_entry dict "/Filter" in let dict = Pdf.remove_dict_entry dict "/F" in let dict = Pdf.remove_dict_entry dict "/DP" in let dict = Pdf.remove_dict_entry dict "/DecodeParms" in let strip = function | Some (Pdf.Array (_::t)) -> Pdf.Array t | _ -> Pdf.Array [] in let decodeparms = strip decodeparms and filters = strip filters in let dict = Pdf.add_dict_entry dict "/DP" decodeparms in let dict = Pdf.add_dict_entry dict "/F" filters in let stream = decode_one (Pdf.empty ()) dict (StreamSource stream) in decode_rest stream more | _ -> raise (Pdf.PDFError "Malformed filter array") in Some (decode_rest stream t) | _ -> raise (Couldn'tDecodeStream "No or bad filter") (* Encoding streams *) (* Supported encodings. *) type encoding = | ASCIIHex | ASCII85 | RunLength | Flate type predictor = TIFF2 | PNGNone | PNGSub | PNGUp | PNGAverage | PNGPaeth | PNGOptimum (* The name of an encoding. *) let name_of_encoding = function | ASCIIHex -> "/ASCIIHexDecode" | ASCII85 -> "/ASCII85Decode" | RunLength -> "/RunLengthDecode" | Flate -> "/FlateDecode" (* Add an encoding to the dictionary d. *) let add_encoding length pdf encoding d = let filter' = match Pdf.lookup_direct pdf "/Filter" d with | None -> Pdf.Name (name_of_encoding encoding) | Some (Pdf.Name n) -> Pdf.Array (Pdf.Name (name_of_encoding encoding)::[Pdf.Name n]) | Some (Pdf.Array a) -> Pdf.Array (Pdf.Name (name_of_encoding encoding)::a) | _ -> raise (Pdf.PDFError "Malformed /Filter") in Pdf.replace_dict_entry (Pdf.add_dict_entry d "/Filter" filter') "/Length" (Pdf.Integer length) (* Find the encoding function. *) let encoder_of_encoding = function | ASCIIHex -> encode_ASCIIHex | ASCII85 -> encode_ASCII85 | RunLength -> encode_runlength | Flate -> encode_flate (* For now, just for xref streams *) let process_prediction_data predictor predictor_columns d = match predictor with PNGUp -> encode_predictor 12 1 8 predictor_columns d | _ -> raise (Pdf.PDFError "process_prediction_data") let process_prediction predictor predictor_columns stream = match stream with {contents = d, Pdf.Got s} -> begin match predictor with Some PNGUp -> let data = process_prediction_data PNGUp predictor_columns s and d' = let decodeparms = Pdf.Dictionary [("/Columns", Pdf.Integer predictor_columns); ("/Predictor", Pdf.Integer 12)] in Pdf.add_dict_entry d "/DecodeParms" decodeparms in (d', data) | _ -> raise (Pdf.PDFError "Encode predictor not supported") end | _ -> assert false (* Encode a PDF stream with an encoding. *) let encode_pdfstream pdf encoding ?(only_if_smaller=false) ?predictor ?(predictor_columns = 1) stream = Pdf.getstream stream; match stream with | Pdf.Stream ({contents = d, Pdf.Got s} as stream) -> let d', predicted = if predictor <> None then process_prediction predictor predictor_columns stream else d, s in let data = encoder_of_encoding encoding predicted in let d'' = add_encoding (bytes_size data) pdf encoding d' in if not only_if_smaller || bytes_size data + 20 < bytes_size s then stream := d'', Pdf.Got data | _ -> raise (Pdf.PDFError "Pdf.encode_pdfstream: malformed Stream") camlpdf-2.8.1/pdfcodec.mli000066400000000000000000000052321477056064700154240ustar00rootroot00000000000000(** Encoding and Decoding PDF Streams *) (** {b Currently supported:} - Decoders: ASCIIHexDecode, ASCII85Decode, FlateDecode, LZWDecode, RunLengthDecode, CCITTFaxDecode. - Encoders: ASCIIHexDecode, ASCII85Decode, FlateDecode, RunLengthDecode, CCITTFaxDecode. - Decode predictors: PNG (all), TIFF (8-bit only). *) (** {2 Types} *) (** Supported encodings. *) type encoding = | ASCIIHex | ASCII85 | RunLength | Flate (** Predictors. *) type predictor = TIFF2 | PNGNone | PNGSub | PNGUp | PNGAverage | PNGPaeth | PNGOptimum (** There was bad data. *) exception Couldn'tDecodeStream of string (** CamlPDF doesn't support this encoding or its predictor. *) exception DecodeNotSupported of string (** {2 Encoding} *) (** Encode a PDF stream with an encoding. The only predictor supported is PNGUp. *) val encode_pdfstream : Pdf.t -> encoding -> ?only_if_smaller:bool -> ?predictor:predictor -> ?predictor_columns:int -> Pdf.pdfobject -> unit (** {2 Decoding} *) (** Given a document and stream, decode. The pdf document is updated with the decoded stream. May raise either of the exceptions above. *) val decode_pdfstream : Pdf.t -> Pdf.pdfobject -> unit (** Given a document and stream decode just one stage. May raise either of the exceptions above. *) val decode_pdfstream_onestage : Pdf.t -> Pdf.pdfobject -> unit (** Given a document and stream decode until there's an unknown decoder. May raise [Couldn'tDecodeStream]. *) val decode_pdfstream_until_unknown : Pdf.t -> Pdf.pdfobject -> unit (** Given a [Pdfio.input] with pointer at the first byte and an inline image stream dictionary, decode the first decoder and its predictor. Return the data, or [None] if this decoder isn't supported but the data pointer has been left in the right place. The exceptions above can both be raised, in the case of bad data or a completely unknown encoding. *) val decode_from_input : Pdfio.input -> Pdf.pdfobject -> Pdfio.bytes option (** {2 Low level functionality} *) (** Setting this changes globally the FlateDecode compression level. Default 6. *) val flate_level : int ref (** Encode data in FlateDecode. *) val encode_flate : Pdfio.bytes -> Pdfio.bytes (** Decode data in FlateDecode. *) val decode_flate : Pdfio.bytes -> Pdfio.bytes (** Encode data in CCITTDecode Group 3. *) val encode_ccitt : int -> Pdfio.bytes -> Pdfio.bytes (** Encode data in CCITTDecode Group 4. *) val encode_ccittg4 : int -> Pdfio.bytes -> Pdfio.bytes (** Setting this boolean prints some debug information. *) val debug : bool ref (**/**) (* Inter-module recursion. *) val string_of_pdf : (Pdf.pdfobject -> string) ref val encode_predictor : int -> int -> int -> int -> Pdfio.bytes -> Pdfio.bytes camlpdf-2.8.1/pdfcrypt.ml000066400000000000000000001372301477056064700153430ustar00rootroot00000000000000(* Encryption and Decryption *) open Pdfutil open Pdfio let crypt_debug = ref false (* Find a key, given a password, O entry, P entry, id entry, and key length in bits. *) let paddings = [| 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 |] let pad_password password = let pw = Array.make 32 0 in Array.iteri (fun i v -> if i < 32 then pw.(i) <- v) password; let n = Array.length password in if n < 32 then for x = n to 31 do pw.(x) <- paddings.(x - n) done; pw let find_key no_encrypt_metadata password r o p id keylength = let password = int_array_of_string password in let o = int_array_of_string o in let id = int_array_of_string id in let pw = pad_password password in let from_p = [| i32toi (land32 p 0x000000ffl); i32toi (lsr32 (land32 p 0x0000ff00l) 8); i32toi (lsr32 (land32 p 0x00ff0000l) 16); i32toi (lsr32 (land32 p 0xff000000l) 24) |] in let rev4_no_metadata = if r >= 4 && no_encrypt_metadata then [|255; 255; 255; 255|] else [||] in let todigest = [pw; o; from_p; id; rev4_no_metadata] in let hash_input = string_of_int_arrays todigest in let hashed = Digest.string hash_input in let hashed' = if r >= 3 then let h = ref hashed in for x = 1 to 50 do let hashed = Digest.string !h in h := string_of_int_array (Array.sub (int_array_of_string hashed) 0 (keylength / 8)) done; !h else hashed in Array.sub (int_array_of_string hashed') 0 (keylength / 8) (* Authenticate the user password, given the password string and U, O, P, id and key length entry. *) let authenticate_user no_encrypt_metadata password r u o p id keylength = (*flprint "AUTHENTICATE_USER\n"; Printf.printf "no_encrypt_metadata: %b\n" no_encrypt_metadata; Printf.printf "user_pw = %S\n" password; Printf.printf "r = %i\n" r; Printf.printf "u = %S\n" u; Printf.printf "o = %S\n" o; Printf.printf "p = %li\n" p; Printf.printf "id = %S\n" id; Printf.printf "keylength = %i\n" keylength; flprint "END_AUTHENTICATE_USER\n";*) let u = int_array_of_string u in let key = find_key no_encrypt_metadata password r o p id keylength in if r >= 3 then let id = int_array_of_string id in let todigest = [paddings; id] in let hash_input = string_of_int_arrays todigest in let hashed = Digest.string hash_input in let encrypted_hashed = int_array_of_bytes (Pdfcryptprimitives.crypt key (bytes_of_string hashed)) in let u' = ref [||] in u' := encrypted_hashed; for x = 1 to 19 do let key' = Array.make (keylength / 8) 0 in for k = 0 to (keylength / 8) - 1 do key'.(k) <- key.(k) lxor x done; u' := int_array_of_bytes (Pdfcryptprimitives.crypt key' (bytes_of_int_array !u')) done; Array.sub u 0 16 = !u' else u = int_array_of_bytes (Pdfcryptprimitives.crypt key (bytes_of_int_array paddings)) (* Decrypt a PDF file, given the user password. *) (* For debug. Filled in by Pdfwrite *) let string_of_pdf : (Pdf.pdfobject -> string) ref = ref (function _ -> "") let rec decrypt crypt_type pdf no_encrypt_metadata encrypt obj gen key keylength r file_encryption_key l = match l with | Pdf.String s -> (* Avoid decrypting an object which came from an object stream, since the object stream has been decrypted en-masse already. *) begin match fst (Pdf.pdfobjmap_find obj pdf.Pdf.objects.Pdf.pdfobjects) with | {contents = Pdf.ParsedAlreadyDecrypted _} -> Pdf.String s | _ (* Will always be Parsed for now...*) -> let f = (if crypt_type = Pdfcryptprimitives.AESV2 then (if encrypt then Pdfcryptprimitives.aes_encrypt_data 4 else Pdfcryptprimitives.aes_decrypt_data 4) else if (match crypt_type with Pdfcryptprimitives.AESV3 _ -> true | _ -> false) then (if encrypt then Pdfcryptprimitives.aes_encrypt_data 8 else Pdfcryptprimitives.aes_decrypt_data 8) else Pdfcryptprimitives.crypt) in let s_ints = bytes_of_string s in if r = 5 || r = 6 then let key = match file_encryption_key with Some k -> k | None -> raise (Pdf.PDFError "decrypt: no key B") in Pdf.String (string_of_bytes (f (int_array_of_string key) s_ints)) else let hash = Pdfcryptprimitives.find_hash crypt_type (i32ofi obj) (i32ofi gen) key keylength in Pdf.String (string_of_bytes (f hash s_ints)) end | (Pdf.Stream _) as stream -> decrypt_stream crypt_type pdf no_encrypt_metadata encrypt obj gen key keylength r file_encryption_key stream | Pdf.Array a -> begin match fst (Pdf.pdfobjmap_find obj pdf.Pdf.objects.Pdf.pdfobjects) with | {contents = Pdf.ParsedAlreadyDecrypted _} -> Pdf.Array a | _ -> Pdf.recurse_array (decrypt crypt_type pdf no_encrypt_metadata encrypt obj gen key keylength r file_encryption_key) a end | Pdf.Dictionary d -> begin match fst (Pdf.pdfobjmap_find obj pdf.Pdf.objects.Pdf.pdfobjects) with | {contents = Pdf.ParsedAlreadyDecrypted _} -> Pdf.Dictionary d | _ -> Pdf.recurse_dict (decrypt crypt_type pdf no_encrypt_metadata encrypt obj gen key keylength r file_encryption_key) d end | x -> x and is_identity no_encrypt_metadata pdf d = let identity_crypt_filter_present = match Pdf.lookup_direct pdf "/Filter" d with | Some (Pdf.Name "/Crypt") | Some (Pdf.Array (Pdf.Name "/Crypt"::_)) -> begin match Pdf.lookup_direct pdf "/DecodeParms" d with | Some (Pdf.Dictionary decodeparmsdict) | Some (Pdf.Array (Pdf.Dictionary decodeparmsdict::_)) -> begin match Pdf.lookup_direct pdf "/Name" (Pdf.Dictionary decodeparmsdict) with | Some (Pdf.Name "/Identity") | None -> true | _ -> false end | _ -> true end | _ -> false in (no_encrypt_metadata && (match Pdf.lookup_direct pdf "/Type" d with Some (Pdf.Name "/Metadata") -> true | _ -> false)) || identity_crypt_filter_present and decrypt_stream crypt_type pdf no_encrypt_metadata encrypt obj gen key keylength r file_encryption_key stream = begin match stream with | Pdf.Stream {contents = (Pdf.Dictionary dict as d, data)} -> if is_identity no_encrypt_metadata pdf d then stream else let data' = let rec f unhashed_key key data = let crypt = Pdf.ToDecrypt {Pdf.crypt_type = crypt_type; Pdf.file_encryption_key = file_encryption_key; Pdf.obj = obj; Pdf.gen = gen; Pdf.key = unhashed_key; Pdf.keylength = keylength; Pdf.r = r} in match data with Pdf.Got data -> (*Printf.printf "decrypt_stream: Got, encrypt = %b\n" encrypt;*) (if crypt_type = Pdfcryptprimitives.AESV2 then (if encrypt then Pdf.Got (Pdfcryptprimitives.aes_encrypt_data 4 key data) else Pdf.ToGet (Pdf.toget ~crypt (Pdfio.input_of_bytes data) 0 (bytes_size data))) else if (match crypt_type with Pdfcryptprimitives.AESV3 _ -> true | _ -> false) then (if encrypt then Pdf.Got (Pdfcryptprimitives.aes_encrypt_data 8 key data) else Pdf.ToGet (Pdf.toget ~crypt (Pdfio.input_of_bytes data) 0 (bytes_size data))) else if encrypt then Pdf.Got (Pdfcryptprimitives.crypt key data) else Pdf.ToGet (Pdf.toget ~crypt (Pdfio.input_of_bytes data) 0 (bytes_size data))) | Pdf.ToGet toget -> (*Printf.printf "decrypt_stream: ToGet, encrypt = %b\n" encrypt;*) if encrypt then (* If encrypting, call getstream, then go again *) begin Pdf.getstream stream; match stream with Pdf.Stream {contents = (_, data)} -> f unhashed_key key data | _ -> assert false end else (* Otherwise, do the deferred decryption magic *) let crypt = Pdf.ToDecrypt {Pdf.crypt_type = crypt_type; Pdf.file_encryption_key = file_encryption_key; Pdf.obj = obj; Pdf.gen = gen; Pdf.key = unhashed_key; Pdf.keylength = keylength; Pdf.r = r} in Pdf.ToGet (Pdf.toget ~crypt (Pdf.input_of_toget toget) (Pdf.position_of_toget toget) (Pdf.length_of_toget toget)) in if r = 5 || r = 6 then let key = match file_encryption_key with Some k -> k | None -> raise (Pdf.PDFError "decrypt: no key C") in f (int_array_of_string key) (int_array_of_string key) data else let hash = Pdfcryptprimitives.find_hash crypt_type (i32ofi obj) (i32ofi gen) key keylength in f key hash data in let dict' = Pdf.recurse_dict (decrypt crypt_type pdf no_encrypt_metadata encrypt obj gen key keylength r file_encryption_key) dict in let dict'' = match data' with Pdf.Got data' -> Pdf.replace_dict_entry dict' "/Length" (Pdf.Integer (bytes_size data')) | _ -> dict' in Pdf.Stream {contents = (dict'', data')} | _ -> assert false end let process_cryption no_encrypt_metadata encrypt pdf crypt_type user_pw r u o p id keylength file_encryption_key = let encryption_object_number = match pdf.Pdf.trailerdict with | Pdf.Dictionary d -> begin match lookup "/Encrypt" d with | Some (Pdf.Indirect i) -> i | _ -> -1 end | _ -> -1 in let do_encryption key = Pdf.objiter_gen (fun objnum gennum obj -> if objnum <> encryption_object_number then begin ignore (Pdf.addobj_given_num pdf (objnum, decrypt crypt_type pdf no_encrypt_metadata encrypt objnum gennum key keylength r file_encryption_key obj)) end) pdf; let trailerdict' = Pdf.remove_dict_entry pdf.Pdf.trailerdict "/Encrypt" in pdf.Pdf.trailerdict <- trailerdict'; Some pdf in if r = 5 || r = 6 then (* AESV3 *) begin match file_encryption_key with | Some k -> do_encryption (int_array_of_string k) | None -> None end else if authenticate_user no_encrypt_metadata user_pw r u o p id keylength then do_encryption (find_key no_encrypt_metadata user_pw r o p id keylength) else None (*let printable_of_string s = String.concat "" (map (fun c -> Printf.sprintf "%02x" (int_of_char c)) (explode s))*) let get_encryption_values pdf = match Pdf.lookup_direct pdf "/Encrypt" pdf.Pdf.trailerdict with | None -> raise (Pdf.PDFError "get_encryption_values: unencrypted pdf") | Some encryptdict -> let crypt_type = match Pdf.lookup_direct pdf "/Filter" encryptdict, Pdf.lookup_direct pdf "/V" encryptdict, Pdf.lookup_direct pdf "/Length" encryptdict, Pdf.lookup_direct pdf "/R" encryptdict with | Some (Pdf.Name "/Standard"), Some (Pdf.Integer 1), _, Some (Pdf.Integer r) | Some (Pdf.Name "/Standard"), Some (Pdf.Integer 2), None, Some (Pdf.Integer r) -> Some (Pdfcryptprimitives.ARC4 (40, r)) | Some (Pdf.Name "/Standard"), Some (Pdf.Integer 2), Some (Pdf.Integer n), _ when n mod 8 = 0 && n >= 40 && n <= 128 -> Some (Pdfcryptprimitives.ARC4 (n, 3)) | Some (Pdf.Name "/Standard"), Some (Pdf.Integer (4 | 5)), length, Some (Pdf.Integer r) -> begin match Pdf.lookup_direct pdf "/CF" encryptdict with | Some cfdict -> begin match Pdf.lookup_direct pdf "/StdCF" cfdict with | Some stdcfdict -> begin match Pdf.lookup_direct pdf "/CFM" stdcfdict with | Some (Pdf.Name "/V2") -> begin match length with | Some (Pdf.Integer i) -> Some (Pdfcryptprimitives.ARC4 (i, 4)) | _ -> begin match Pdf.lookup_direct pdf "/Length" cfdict with | Some (Pdf.Integer i) -> Some (Pdfcryptprimitives.ARC4 (i, 4)) | _ -> None end end | Some (Pdf.Name "/AESV2") -> Some Pdfcryptprimitives.AESV2 | Some (Pdf.Name "/AESV3") -> Some (Pdfcryptprimitives.AESV3 (r = 6)) | _ -> None end | _ -> None end | _ -> None end | _ -> None in let chop_string3248 n s = let need = match crypt_type with Some (Pdfcryptprimitives.AESV3 _) -> 48 | _ -> 32 in if String.length s < need then raise (Pdf.PDFError (n ^ ": too small in get_encryption_values")) else String.sub s 0 need in match crypt_type with | None -> raise (Pdf.PDFError "No encryption method") | Some crypt_type -> let o = match Pdf.lookup_direct pdf "/O" encryptdict with | Some (Pdf.String o) -> chop_string3248 "/O" o | _ -> raise (Pdf.PDFError "Bad or missing /O entry") and u = match Pdf.lookup_direct pdf "/U" encryptdict with | Some (Pdf.String u) -> chop_string3248 "/U" u | _ -> raise (Pdf.PDFError "Bad or missing /U entry") and p = match Pdf.lookup_direct pdf "/P" encryptdict with | Some (Pdf.Integer flags) -> i32ofi flags | _ -> raise (Pdf.PDFError "Bad or missing /P entry") and id = match Pdf.lookup_direct pdf "/ID" pdf.Pdf.trailerdict with | Some (Pdf.Array [Pdf.String s; _]) -> s | _ -> raise (Pdf.PDFError "Bad or missing /ID element") and oe = match Pdf.lookup_direct pdf "/OE" encryptdict with | Some (Pdf.String s) -> Some s | _ -> None and ue = match Pdf.lookup_direct pdf "/UE" encryptdict with | Some (Pdf.String s) -> Some s | _ -> None in (*Printf.printf "Encryption Values...\n"; Printf.printf "crypt_type = %s\n" (string_of_encryption crypt_type); Printf.printf "p = %li\n" p; Printf.printf "u = %s\n" (printable_of_string u); Printf.printf "o = %s\n" (printable_of_string o); if ue <> None then Printf.printf "ue = %s\n" (printable_of_string (unopt ue)); if oe <> None then Printf.printf "oe = %s\n" (printable_of_string (unopt oe));*) crypt_type, u, o, p, id, ue, oe (* Permissions *) type permission = | NoEdit (* R2, Bit 4 *) | NoPrint (* R2, Bit 3 *) | NoCopy (* R2, Bit 5 *) | NoAnnot (* R2, Bit 6 *) | NoForms (* R3 only, Bit 9 *) | NoExtract (* R3 only, Bit 10 *) | NoAssemble (* R3 only, Bit 11 *) | NoHqPrint (* R3 only, Bit 12 *) (*let string_of_permission = function | NoEdit -> "NoEdit" | NoPrint -> "NoPrint" | NoCopy -> "NoCopy" | NoAnnot -> "NoAnnot" | NoForms -> "NoForms" | NoExtract -> "NoExtract" | NoAssemble -> "NoAssemble" | NoHqPrint -> "NoHqPrint"*) (*let string_of_bans bans = fold_left ( ^ ) "" (interleave " " (map string_of_permission bans))*) let p_of_banlist toban = let p = ref 0l in let setbit n b = if b then p := Int32.logor !p (Int32.shift_left 1l (n - 1)) in let notin = notpred (mem' toban) in setbit 3 (notin NoPrint); setbit 4 (notin NoEdit); setbit 5 (notin NoCopy); setbit 6 (notin NoAnnot); setbit 7 true; setbit 8 true; setbit 9 (notin NoForms); setbit 10 (notin NoExtract); setbit 11 (notin NoAssemble); setbit 12 (notin NoHqPrint); iter (fun x -> setbit x true) (ilist 13 32); !p let banlist_of_p p = let l = ref [] in let bitset n = Int32.logand (Int32.shift_right p (n - 1)) 1l = 0l in if bitset 3 then l =| NoPrint; if bitset 4 then l =| NoEdit; if bitset 5 then l =| NoCopy; if bitset 6 then l =| NoAnnot; if bitset 9 then l =| NoForms; if bitset 10 then l =| NoExtract; if bitset 11 then l =| NoAssemble; if bitset 12 then l =| NoHqPrint; !l (*let print_string name s = flprint name; iter (Printf.printf "%i ") (map int_of_char (explode s)); flprint "\n"*) (* New r = 6 algorithm (2.B in the standard) *) (* modulus 3 of the first 16 bytes of a string taken as a 128 bit big-endian number. Since (xy mod n) is equal to (x mod n + y mod n) and 256 mod 3 is 1, we can just sum the bytes and take the modulus afterward. Logic due to Jay Birkenbilt. *) let mod3 b = let x = ref 0 in for i = 0 to 15 do x += int_of_char b.[i] done; !x mod 3 let prs s = String.iter (fun x -> Printf.printf "%02x" (int_of_char x)) (if String.length s > 16 then String.sub s 0 16 else s); flprint "\n" let shamix_cache = Hashtbl.create 16 let shamix password udata s = try Hashtbl.find shamix_cache (password, udata, s) with Not_found -> let i = input_of_string s in if !crypt_debug then begin flprint "Beginning of shamix\n Password is\n"; prs password; flprint "udata is\n"; prs (match udata with None -> "" | Some x -> x); end; let k = ref (Pdfcryptprimitives.sha256 i) and fin = ref false and round = ref 0 and last_e = ref 0 in while not !fin do round += 1; let k1 = password ^ !k ^ match udata with None -> "" | Some x -> x in let k1_64 = String.concat "" (many k1 64) in let e = let key = int_array_of_string (String.sub !k 0 16) and firstblock = int_array_of_string (String.sub !k 16 16) in let raw = string_of_bytes (Pdfcryptprimitives.aes_encrypt_data ~firstblock:firstblock 4 key (Pdfio.bytes_of_string k1_64)) in String.sub raw 16 (String.length raw - 32) in last_e := int_of_char e.[String.length e - 1]; k := (match mod3 e with 0 -> Pdfcryptprimitives.sha256 | 1 -> Pdfcryptprimitives.sha384 | _ -> Pdfcryptprimitives.sha512) (Pdfio.input_of_string e); fin := !round >= 64 && !last_e <= !round - 32 done; let result = String.sub !k 0 32 in if !crypt_debug then begin flprint "RESULT:\n"; prs result end; Hashtbl.add shamix_cache (password, udata, s) result; result (* Conversion via unicode and SASLprep required here for complicated passwords. *) let make_utf8 pw = if String.length pw > 127 then String.sub pw 0 127 else pw let zero_iv = String.make 16 '\000' (* Part of Algorithm 3.2a - making the intermediate key using owner password. *) let file_encryption_key_aesv3 ?digest iso utf8pw o oe u = if String.length o < 48 || String.length u < 48 then raise (Pdf.PDFError "/O too short in make_intermediate_owner_key_aesv3") else let d = match digest with | Some d -> if Array.length d <> 32 then Pdfe.log (Printf.sprintf "file_encryption_key_aesv3 pre-made length %i\n" (Array.length d)); d | None -> let i = int_array_of_string ((if iso then shamix utf8pw (Some u) else (fun x -> Pdfcryptprimitives.sha256 (Pdfio.input_of_string x))) (String.concat "" [utf8pw; String.sub o 40 8; String.sub u 0 48])) in if Array.length i <> 32 then Pdfe.log (Printf.sprintf "file_encryption_key_aesv3 made length %i\n" (Array.length i)); i in Pdfcryptprimitives.aes_decrypt_data ~remove_padding:false 8 d (bytes_of_string (zero_iv ^ oe)) let file_encryption_key_aesv3_user iso utf8pw u ue = if String.length u < 48 then raise (Pdf.PDFError "/U too short in file_encryption_key_aesv3_user") else Pdfcryptprimitives.aes_decrypt_data ~remove_padding:false 8 (int_array_of_string ((if iso then shamix utf8pw None else (fun x -> Pdfcryptprimitives.sha256 (Pdfio.input_of_string x))) (String.concat "" [utf8pw; String.sub u 40 8]))) (bytes_of_string (zero_iv ^ ue)) (* Algorithm 3.12 - Authenticating the owner password. *) let authenticate_owner_password_aesv3 iso utf8pw u o = if String.length o < 48 || String.length u < 48 then raise (Pdf.PDFError "/O too short in authenticate_owner_password") else (if iso then shamix utf8pw (Some u) else (fun x -> Pdfcryptprimitives.sha256 (Pdfio.input_of_string x))) (String.concat "" [utf8pw; String.sub o 32 8; String.sub u 0 48]) = String.sub o 0 32 (* Algorithm 3.11 - Authenticating the user password. *) let authenticate_user_password_aesv3 iso utf8pw u = if String.length u < 48 then raise (Pdf.PDFError "/U too short in authenticate_owner_password") else (if iso then shamix utf8pw None else (fun x -> Pdfcryptprimitives.sha256 (Pdfio.input_of_string x))) (String.concat "" [utf8pw; String.sub u 32 8]) = String.sub u 0 32 (* Part of algorithm 3.2a - return p from perms so we can check they match *) let p_of_perms key perms = if String.length perms < 16 then raise (Pdf.PDFError "Wrong length in /Perms") else let ps = Pdfcryptprimitives.aes_decrypt_data_ecb ~remove_padding:false 8 (int_array_of_bytes key) (bytes_of_string perms) in let ints = int_array_of_bytes ps in if ints.(9) <> int_of_char 'a' || ints.(10) <> int_of_char 'd' || ints.(11) <> int_of_char 'b' then None else Some (lor32 (lor32 (lsl32 (i32ofi ints.(0)) 0) (lsl32 (i32ofi ints.(1)) 8)) (lor32 (lsl32 (i32ofi ints.(2)) 16) (lsl32 (i32ofi ints.(3)) 24))) (* Main function for decryption. *) let decrypt_pdf ?keyfromowner user_pw pdf = match Pdf.lookup_direct pdf "/Encrypt" pdf.Pdf.trailerdict with | None -> Some pdf, [] | Some encrypt_dict -> let crypt_type, u, o, p, id, ue, oe = get_encryption_values pdf in let r, keylength, file_encryption_key = match crypt_type with | Pdfcryptprimitives.AESV2 -> 4, 128, None | Pdfcryptprimitives.AESV3 iso -> begin match oe, ue with | Some _, Some ue -> begin match keyfromowner with | Some k -> 5, 256, Some k | None -> let perms = match Pdf.lookup_direct pdf "/Perms" encrypt_dict with | Some (Pdf.String s) -> s | _ -> raise (Pdf.PDFError "Missing /Perms in encryption dictionary") in let auth = authenticate_user_password_aesv3 iso (make_utf8 user_pw) u in if not auth then 5, 256, None else let key = file_encryption_key_aesv3_user iso (make_utf8 user_pw) u ue in match p_of_perms key perms with | None -> raise (Failure "/Perms file permissions corrupted") | Some x when x = p -> 5, 256, Some (string_of_bytes key) | Some _ -> raise (Failure "Mismatched /Perms and /P permissions") end | _ -> raise (Failure "decrypt_pdf: no oe") end | Pdfcryptprimitives.ARC4 (k, r) -> r, k, None in let encrypt_metadata = match Pdf.lookup_direct pdf "/EncryptMetadata" encrypt_dict with | Some (Pdf.Boolean false) -> false | _ -> true in let perms = match Pdf.lookup_direct pdf "/Perms" encrypt_dict with | Some (Pdf.String s) -> s | _ -> "" in pdf.Pdf.saved_encryption <- Some {Pdf.from_get_encryption_values = (crypt_type, u, o, p, id, ue, oe); Pdf.encrypt_metadata = encrypt_metadata; Pdf.perms = perms}; if !crypt_debug then Pdfe.log "decrypt_pdf: ready to call process_cryption\n"; (process_cryption (not encrypt_metadata) false pdf crypt_type user_pw r u o p id keylength file_encryption_key, banlist_of_p p) (* Calculate the owner key from the padded owner password (as calculated by pad_password) *) let owner_key padded_owner keylength r = let digest1 = Digest.string (string_of_int_array padded_owner) in let digest2 = if r >= 3 then let d = ref digest1 in for x = 1 to 50 do d := Digest.string !d done; !d else digest1 in int_array_of_string (String.sub digest2 0 (keylength / 8)) (* Calculate XOR keys *) let mkkey key x = let key' = Array.copy key in for k = 0 to Array.length key - 1 do key'.(k) <- key.(k) lxor x done; key' (* Just decrypt a single stream, given the user password, and pdf. This is used to decrypt cross-reference streams during the reading of a file -- the PDF is only partially formed at this stage. *) let decrypt_single_stream user_pw owner_pw pdf obj gen stream = (*i Printf.printf "decrypt_single_stream\n"; begin match user_pw with None -> flprint "no user password\n" | Some x -> Printf.printf "user password |%s|\n" x end; begin match owner_pw with None -> flprint "no owner password\n" | Some x -> Printf.printf "owner password |%s|\n" x end; i*) match Pdf.lookup_direct pdf "/Encrypt" pdf.Pdf.trailerdict with | None -> stream | Some encrypt_dict -> let crypt_type, u, o, p, id, ue, oe = get_encryption_values pdf in let r, keylength = match crypt_type with | Pdfcryptprimitives.AESV2 -> 4, 128 | Pdfcryptprimitives.AESV3 b -> (if b then 6 else 5), 256 | Pdfcryptprimitives.ARC4 (k, r) -> r, k in let no_encrypt_metadata = match Pdf.lookup_direct pdf "/EncryptMetadata" encrypt_dict with | Some (Pdf.Boolean false) -> true | _ -> false in match r, keylength, ue, oe with | (5 | 6), 256, Some ue, Some oe -> let owner_pw = match owner_pw with Some x -> x | None -> "" and user_pw = match user_pw with Some x -> x | None -> "" in (* Generate a file encryption key from either the owner or user password *) let file_encryption_key = if authenticate_user_password_aesv3 (r = 6) (make_utf8 user_pw) u then file_encryption_key_aesv3_user (r = 6) (make_utf8 user_pw) u ue else if authenticate_owner_password_aesv3 (r = 6) (make_utf8 owner_pw) u o then file_encryption_key_aesv3 (r = 6) (make_utf8 owner_pw) o oe u else raise (Pdf.PDFError "Encryption: Could not decrypt single stream: Bad or not supplied AESV3 user or owner password") in decrypt_stream crypt_type pdf no_encrypt_metadata false obj gen (int_array_of_bytes file_encryption_key) keylength r (Some (string_of_bytes file_encryption_key)) stream | _ -> if owner_pw <> None then (* Decode with owner password *) let owner_pw_string = unopt owner_pw in (* Authenticate the owner password and calculate the key *) let padded_owner = pad_password (int_array_of_string owner_pw_string) in let key = owner_key padded_owner keylength r in let user_pw = if r = 2 then string_of_bytes (Pdfcryptprimitives.crypt key (bytes_of_string o)) else (* r >= 3 *) begin let acc = ref (bytes_of_string o) in for x = 19 downto 0 do acc := Pdfcryptprimitives.crypt (mkkey key x) !acc done; string_of_bytes !acc end in if authenticate_user no_encrypt_metadata user_pw r u o p id keylength then let key = find_key no_encrypt_metadata user_pw r o p id keylength in decrypt_stream crypt_type pdf no_encrypt_metadata false obj gen key keylength r None stream else raise (Pdf.PDFError "Encryption: Bad or not supplied owner password when decrypting single stream") else (* We're using user password. If none, assume it's blank *) let user_pw_string = match user_pw with None -> "" | Some x -> x in if authenticate_user no_encrypt_metadata user_pw_string r u o p id keylength then let key = find_key no_encrypt_metadata user_pw_string r o p id keylength in decrypt_stream crypt_type pdf no_encrypt_metadata false obj gen key keylength r None stream else raise (Pdf.PDFError "Encryption: Bad or not supplied password when decrypting single stream") let key_or_user_password_from_owner ?encryption_values owner_pw pdf = let padded_owner = pad_password (int_array_of_string owner_pw) in let crypt_type, u, o, oe = match encryption_values with Some e -> e | None -> let crypt_type, u, o, _, _, _, oe = get_encryption_values pdf in crypt_type, u, o, oe in let r, keylength = match crypt_type with | Pdfcryptprimitives.AESV2 -> 4, 128 | Pdfcryptprimitives.AESV3 x -> (if x then 6 else 5), 256 | Pdfcryptprimitives.ARC4 (k, r) -> r, k in if r = 5 || r = 6 then if authenticate_owner_password_aesv3 (r = 6) (make_utf8 owner_pw) u o then begin match oe with | None -> raise (Pdf.PDFError "decrypt_pdf_owner: No /OE entry found") | Some oe -> let key = string_of_bytes (file_encryption_key_aesv3 (r = 6) (make_utf8 owner_pw) o oe u) in Some (key, "") end else None else let user_pw = let key = owner_key padded_owner keylength r in if r = 2 then string_of_bytes (Pdfcryptprimitives.crypt key (bytes_of_string o)) else (* r >= 3 *) begin let acc = ref (bytes_of_string o) in for x = 19 downto 0 do acc := Pdfcryptprimitives.crypt (mkkey key x) !acc done; string_of_bytes !acc end in Some ("", user_pw) (* Decrypt with the owner password. *) let decrypt_pdf_owner owner_pw pdf = (*Printf.printf "decrypt_pdf_owner with owner pw A%sA\n" owner_pw; flprint "\n";*) match Pdf.lookup_direct pdf "/Encrypt" pdf.Pdf.trailerdict with None -> Some pdf | _ -> match key_or_user_password_from_owner owner_pw pdf with None -> None | Some (key, user_pw) -> fst (decrypt_pdf user_pw ~keyfromowner:key pdf) (* Make an owner password *) let mk_owner r owner_pw user_pw keylength = let padded_owner = let source = if owner_pw = "" then user_pw else owner_pw in pad_password (int_array_of_string source) in let key = owner_key padded_owner keylength r in let padded_user = pad_password (int_array_of_string user_pw) in if r = 2 then string_of_bytes (Pdfcryptprimitives.crypt key (bytes_of_int_array padded_user)) else (* r >= 3 *) let acc = ref (Pdfcryptprimitives.crypt key (bytes_of_int_array padded_user)) in for x = 1 to 19 do acc := Pdfcryptprimitives.crypt (mkkey key x) !acc done; string_of_bytes !acc (* Make a user password *) let mk_user no_encrypt_metadata user_pw o p id r keylength = let key = find_key no_encrypt_metadata user_pw r o p id keylength in if r = 2 then string_of_bytes (Pdfcryptprimitives.crypt key (bytes_of_int_array paddings)) else (* r >= 3 *) let digest_input = [paddings; int_array_of_string id] in let d = Digest.string (string_of_int_arrays digest_input) in let acc = ref (Pdfcryptprimitives.crypt key (bytes_of_string d)) in for x = 1 to 19 do acc := Pdfcryptprimitives.crypt (mkkey key x) !acc done; string_of_bytes !acc ^ (implode (many '\000' 16)) (* Get the ID, or add one if there's not one there. Return the updated pdf and the ID *) let get_or_add_id pdf = match Pdf.lookup_direct pdf "/ID" pdf.Pdf.trailerdict with | Some (Pdf.Array [Pdf.String s; _]) -> s, pdf | _ -> let idobj = Pdf.generate_id pdf "" (fun () -> Random.float 1.) in let pdf' = {pdf with Pdf.trailerdict = Pdf.add_dict_entry pdf.Pdf.trailerdict "/ID" idobj} in match idobj with | Pdf.Array [Pdf.String s; _] -> s, pdf' | _ -> assert false (* 40bit encryption *) let encrypt_pdf_40bit_inner owner user p user_pw id pdf = let crypt_dict = Pdf.Dictionary ["/Filter", Pdf.Name "/Standard"; "/V", Pdf.Integer 1; "/R", Pdf.Integer 2; "/O", Pdf.String owner; "/U", Pdf.String user; "/P", Pdf.Integer (i32toi p)] in match process_cryption false true pdf (Pdfcryptprimitives.ARC4 (40, 2)) user_pw 2 user owner p id 40 None with | Some pdf -> let crypt_dict_num = Pdf.addobj pdf crypt_dict in {pdf with Pdf.trailerdict = Pdf.add_dict_entry pdf.Pdf.trailerdict "/Encrypt" (Pdf.Indirect crypt_dict_num)} | None -> raise (Pdf.PDFError "Encryption 40 failed") let encrypt_pdf_40bit user_pw owner_pw banlist pdf = let p = p_of_banlist banlist in let owner = mk_owner 2 owner_pw user_pw 40 in let id, pdf = get_or_add_id pdf in let user = mk_user false user_pw owner p id 2 40 in encrypt_pdf_40bit_inner owner user p user_pw id pdf (* 128bit encryption *) let encrypt_pdf_128bit_inner owner user p user_pw id pdf = let crypt_dict = Pdf.Dictionary ["/Filter", Pdf.Name "/Standard"; "/V", Pdf.Integer 2; "/R", Pdf.Integer 3; "/O", Pdf.String owner; "/U", Pdf.String user; "/Length", Pdf.Integer 128; "/P", Pdf.Integer (i32toi p)] in match process_cryption false true pdf (Pdfcryptprimitives.ARC4 (128, 3)) user_pw 3 user owner p id 128 None with | Some pdf -> let crypt_dict_num = Pdf.addobj pdf crypt_dict in {pdf with Pdf.trailerdict = Pdf.add_dict_entry pdf.Pdf.trailerdict "/Encrypt" (Pdf.Indirect crypt_dict_num)} | None -> raise (Pdf.PDFError "Encryption 128 failed") let encrypt_pdf_128bit_inner_r4 owner user p user_pw id pdf encrypt_metadata = let crypt_dict = Pdf.Dictionary ["/Filter", Pdf.Name "/Standard"; "/V", Pdf.Integer 4; "/CF", Pdf.Dictionary ["/StdCF", Pdf.Dictionary ["/Length", Pdf.Integer 16; "/AuthEvent", Pdf.Name "/DocOpen"; "/CFM", Pdf.Name "/V2"]]; "/EncryptMetadata", Pdf.Boolean encrypt_metadata; "/Length", Pdf.Integer 128; "/R", Pdf.Integer 4; "/O", Pdf.String owner; "/U", Pdf.String user; "/P", Pdf.Integer (i32toi p); "/StrF", Pdf.Name "/StdCF"; "/StmF", Pdf.Name "/StdCF"] in match process_cryption (not encrypt_metadata) true pdf (Pdfcryptprimitives.ARC4 (128, 4)) user_pw 4 user owner p id 128 None with | Some pdf -> let crypt_dict_num = Pdf.addobj pdf crypt_dict in {pdf with Pdf.trailerdict = Pdf.add_dict_entry pdf.Pdf.trailerdict "/Encrypt" (Pdf.Indirect crypt_dict_num)} | None -> raise (Pdf.PDFError "Encryption 128 r4 failed") let encrypt_pdf_128bit user_pw owner_pw banlist pdf = let p = p_of_banlist banlist in let owner = mk_owner 3 owner_pw user_pw 128 in let id, pdf = get_or_add_id pdf in let user = mk_user false user_pw owner p id 3 128 in encrypt_pdf_128bit_inner owner user p user_pw id pdf (* AES Encryption. *) let encrypt_pdf_AES_inner owner user p user_pw id encrypt_metadata pdf = let crypt_dict = Pdf.Dictionary ["/Filter", Pdf.Name "/Standard"; "/V", Pdf.Integer 4; "/CF", Pdf.Dictionary ["/StdCF", Pdf.Dictionary ["/Length", Pdf.Integer 16; "/AuthEvent", Pdf.Name "/DocOpen"; "/CFM", Pdf.Name "/AESV2"]]; "/EncryptMetadata", Pdf.Boolean encrypt_metadata; "/Length", Pdf.Integer 128; "/R", Pdf.Integer 4; "/O", Pdf.String owner; "/U", Pdf.String user; "/P", Pdf.Integer (i32toi p); "/StrF", Pdf.Name "/StdCF"; "/StmF", Pdf.Name "/StdCF"] in match process_cryption (not encrypt_metadata) true pdf Pdfcryptprimitives.AESV2 user_pw 4 user owner p id 128 None with | Some pdf -> let crypt_dict_num = Pdf.addobj pdf crypt_dict in {pdf with Pdf.trailerdict = Pdf.add_dict_entry pdf.Pdf.trailerdict "/Encrypt" (Pdf.Indirect crypt_dict_num)} | None -> raise (Pdf.PDFError "Encryption AES failed") let encrypt_pdf_AES encrypt_metadata user_pw owner_pw banlist pdf = let p = p_of_banlist banlist in let owner = mk_owner 4 owner_pw user_pw 128 in let id, pdf = get_or_add_id pdf in let user = mk_user (not encrypt_metadata) user_pw owner p id 4 128 in encrypt_pdf_AES_inner owner user p user_pw id encrypt_metadata pdf let encrypt_pdf_AES256_inner iso encrypt_metadata owner user p perms oe ue id key pdf = if !crypt_debug then Pdfe.log (Printf.sprintf "encrypt_pdf_AES256_inner, ISO = %b\n" iso); let crypt_dict = Pdf.Dictionary ["/Filter", Pdf.Name "/Standard"; "/V", Pdf.Integer 5; "/CF", Pdf.Dictionary ["/StdCF", Pdf.Dictionary ["/Length", Pdf.Integer 32; "/AuthEvent", Pdf.Name "/DocOpen"; "/CFM", Pdf.Name "/AESV3"]]; "/EncryptMetadata", Pdf.Boolean encrypt_metadata; "/Length", Pdf.Integer 256; "/R", Pdf.Integer (if iso then 6 else 5); "/O", Pdf.String owner; "/U", Pdf.String user; "/P", Pdf.Integer (i32toi p); "/StrF", Pdf.Name "/StdCF"; "/StmF", Pdf.Name "/StdCF"; "/Perms", Pdf.String perms; "/OE", Pdf.String oe; "/UE", Pdf.String ue] in match process_cryption (not encrypt_metadata) true pdf (Pdfcryptprimitives.AESV3 iso) "" (if iso then 6 else 5) user owner p id 256 (Some key) with | Some pdf -> let crypt_dict_num = Pdf.addobj pdf crypt_dict in {pdf with Pdf.trailerdict = Pdf.add_dict_entry pdf.Pdf.trailerdict "/Encrypt" (Pdf.Indirect crypt_dict_num)} | None -> raise (Pdf.PDFError "256 bit Encryption AES failed") (* Algorithm 3.10 *) let perms_of_p ?digest iso encrypt_metadata p utf8pw o oe u = let extendedp = lor64 0xFFFFFFFF00000000L (i64ofi32 p) in let b = Array.make 16 0 in for n = 0 to 7 do b.(n) <- i64toi (land64 0x00000000000000FFL (lsr64 (land64 (lsl64 0xFFL (n * 8)) extendedp) (n * 8))) done; b.(8) <- int_of_char (if encrypt_metadata then 'T' else 'F'); b.(9) <- int_of_char 'a'; b.(10) <- int_of_char 'd'; b.(11) <- int_of_char 'b'; for n = 12 to 15 do b.(n) <- 0 done; let key = (int_array_of_string (string_of_bytes (file_encryption_key_aesv3 ?digest iso utf8pw o oe u))) in Pdfcryptprimitives.aes_encrypt_data_ecb 8 key (bytes_of_string (string_of_int_array b)) (* Algorithm 3.8. Returns u, ue. *) let make_ue iso file_encryption_key user_pw user_validation_salt user_key_salt = let hash = if iso then shamix user_pw None else (fun x -> Pdfcryptprimitives.sha256 (Pdfio.input_of_string x)) in let u = String.concat "" [(hash (String.concat "" [user_pw; user_validation_salt])); user_validation_salt; user_key_salt] in let ue = Pdfcryptprimitives.aes_encrypt_data ~firstblock:(int_array_of_string zero_iv) 8 (int_array_of_string (hash (String.concat "" [user_pw; user_key_salt]))) file_encryption_key in u, String.sub (string_of_bytes ue) 16 32 (* Algorithm 3.9 *) let make_oe iso file_encryption_key owner_pw owner_validation_salt owner_key_salt u = let hash = if iso then shamix owner_pw (Some u) else (fun x -> Pdfcryptprimitives.sha256 (Pdfio.input_of_string x)) in let o = String.concat "" [(hash (String.concat "" [owner_pw; owner_validation_salt; u])); owner_validation_salt; owner_key_salt] in let digest = int_array_of_string (hash (String.concat "" [owner_pw; owner_key_salt; u])) in let oe = Pdfcryptprimitives.aes_encrypt_data ~firstblock:(int_array_of_string zero_iv) 8 digest file_encryption_key in o, String.sub (string_of_bytes oe) 16 32, digest let mksalt () = let s = Array.make 8 0 in for x = 0 to 7 do s.(x) <- Random.int 255 done; string_of_int_array s let mkfilekey () = let s = Array.make 32 0 in for x = 0 to 31 do s.(x) <- Random.int 255 done; string_of_int_array s let encrypt_pdf_AES256_call iso encrypt_metadata user_pw owner_pw banlist pdf = let user_pw = make_utf8 user_pw and owner_pw = make_utf8 owner_pw and user_validation_salt = mksalt () and user_key_salt = mksalt () and owner_validation_salt = mksalt () and owner_key_salt = mksalt () and file_encryption_key = bytes_of_string (mkfilekey ()) and p = p_of_banlist banlist in let u, ue = make_ue iso file_encryption_key user_pw user_validation_salt user_key_salt in let o, oe, digest = make_oe iso file_encryption_key owner_pw owner_validation_salt owner_key_salt u in let id, pdf = get_or_add_id pdf in let perms = perms_of_p ~digest:digest iso encrypt_metadata p owner_pw o oe u in encrypt_pdf_AES256_inner iso encrypt_metadata o u p (string_of_bytes perms) oe ue id (string_of_bytes file_encryption_key) pdf let encrypt_pdf_AES256 = encrypt_pdf_AES256_call false let encrypt_pdf_AES256ISO = encrypt_pdf_AES256_call true (* Is a file encrypted? *) let is_encrypted pdf = some (Pdf.lookup_direct pdf "/Encrypt" pdf.Pdf.trailerdict) (* recrypt_pdf pdf password re-encrypts a PDF document which was decrypted with the user or owner password given using that same user password *) let recrypt_pdf_user pdf pw = let (crypt_type, u, o, p, id, ue, oe), encrypt_metadata, perms = match pdf.Pdf.saved_encryption with None -> raise (Pdf.PDFError "recrypt_pdf: no saved encryption") | Some x -> (x.Pdf.from_get_encryption_values, x.Pdf.encrypt_metadata, x.Pdf.perms) in match crypt_type with | Pdfcryptprimitives.AESV3 iso -> let oe = match oe with Some oe -> oe | None -> raise (Pdf.PDFError "recrypt_pdf: bad /oe") and ue = match ue with Some ue -> ue | None -> raise (Pdf.PDFError "recrypt_pdf: bad /ue") in let key = if authenticate_user_password_aesv3 iso (make_utf8 pw) u then file_encryption_key_aesv3_user iso (make_utf8 pw) u ue else raise (Pdf.PDFError "recrypt_pdf: failed AESV3 fek.") in encrypt_pdf_AES256_inner iso encrypt_metadata o u p perms oe ue id (string_of_bytes key) pdf | Pdfcryptprimitives.AESV2 -> encrypt_pdf_AES_inner o u p pw id encrypt_metadata pdf | Pdfcryptprimitives.ARC4 (40, _) -> encrypt_pdf_40bit_inner o u p pw id pdf | Pdfcryptprimitives.ARC4 (128, 4) -> encrypt_pdf_128bit_inner_r4 o u p pw id pdf encrypt_metadata | Pdfcryptprimitives.ARC4 (128, _) -> encrypt_pdf_128bit_inner o u p pw id pdf | _ -> raise (Pdf.PDFError "recrypt_pdf: bad encryption") (* recrypt_pdf_owner password re-encrypts a PDF document which was decrypted with the user or owner password given using that same owner password *) let recrypt_pdf_owner pdf owner_pw = let (crypt_type, u, o, p, id, ue, oe), encrypt_metadata, perms = match pdf.Pdf.saved_encryption with None -> raise (Pdf.PDFError "recrypt_pdf: no saved encryption") | Some x -> (x.Pdf.from_get_encryption_values, x.Pdf.encrypt_metadata, x.Pdf.perms) in let key, pw = match key_or_user_password_from_owner ~encryption_values:(crypt_type, u, o, oe) owner_pw pdf with None -> raise (Pdf.PDFError "Recrypt with owner password failed.") | Some (key, pw) -> (key, pw) in match crypt_type with | Pdfcryptprimitives.AESV3 iso -> let oe = match oe with Some oe -> oe | None -> raise (Pdf.PDFError "recrypt_pdf: bad /oe") and ue = match ue with Some ue -> ue | None -> raise (Pdf.PDFError "recrypt_pdf: bad /ue") in encrypt_pdf_AES256_inner iso encrypt_metadata o u p perms oe ue id key pdf | Pdfcryptprimitives.AESV2 -> encrypt_pdf_AES_inner o u p pw id encrypt_metadata pdf | Pdfcryptprimitives.ARC4 (40, _) -> encrypt_pdf_40bit_inner o u p pw id pdf | Pdfcryptprimitives.ARC4 (128, 4) -> encrypt_pdf_128bit_inner_r4 o u p pw id pdf encrypt_metadata | Pdfcryptprimitives.ARC4 (128, _) -> encrypt_pdf_128bit_inner o u p pw id pdf | _ -> raise (Pdf.PDFError "recrypt_pdf_owner: bad encryption") let recrypt_pdf ?(renumber=true) pdf pw = let pdf = if renumber then Pdf.renumber (Pdf.changes pdf) pdf else pdf in try try recrypt_pdf_user pdf pw with _ -> recrypt_pdf_owner pdf pw with _ -> raise (Pdf.PDFError "recrypt_pdf failed. Wrong password?") camlpdf-2.8.1/pdfcrypt.mli000066400000000000000000000052271477056064700155140ustar00rootroot00000000000000(** Decrypting PDF files *) (** Note that encryption depends on fixed object and generation numbers: don't change these (for example by calling [Pdf.remove_unreferenced] on the PDF) before writing. Encryption support is part of the [Pdfwrite] module, since files are encrypted when they're written. *) (** If this is set, various debug is produced on standard output. On startup, is set to false *) val crypt_debug : bool ref (* Permissions. *) type permission = | NoEdit | NoPrint | NoCopy | NoAnnot | NoForms | NoExtract | NoAssemble | NoHqPrint (** Decrypt a PDF document, given the user password, returning the permissions under which the document was encrypted. *) val decrypt_pdf : ?keyfromowner:string -> string -> Pdf.t -> Pdf.t option * permission list (** Decrypt a PDF document, given the owner password. *) val decrypt_pdf_owner : string -> Pdf.t -> Pdf.t option (** Is a PDF encrypted? *) val is_encrypted : Pdf.t -> bool (** [recrypt_pdf decrypted_and_modified] re-encrypts a PDF document which was decrypted using the user password and owner password from the original encrypted file and the same permissions and encryption parameters. *) val recrypt_pdf : ?renumber:bool -> Pdf.t -> string -> Pdf.t (** Encrypt a PDF documnent, using 40 bit encryption, with given user and owner passwords. *) val encrypt_pdf_40bit : string -> string -> permission list -> Pdf.t -> Pdf.t (** Ditto for 128 bit encryption *) val encrypt_pdf_128bit : string -> string -> permission list -> Pdf.t -> Pdf.t (** Encrypt a file using the AESV2 Crypt filter *) val encrypt_pdf_AES : bool -> string -> string -> permission list -> Pdf.t -> Pdf.t (** Encrypt a file using the AESV3 Crypt filter *) val encrypt_pdf_AES256 : bool -> string -> string -> permission list -> Pdf.t -> Pdf.t (** Encrypt a file using the AESV4 (ISO) Crypt filter *) val encrypt_pdf_AES256ISO : bool -> string -> string -> permission list -> Pdf.t -> Pdf.t (**/**) (* For inter-module recursion...*) val string_of_pdf : (Pdf.pdfobject -> string) ref (** Just decrypt a single stream, given the user password, and pdf. This is used to decrypt cross-reference streams during the reading of a file -- the PDF is only partially formed at this stage. For internal use by Pdfread. *) val decrypt_single_stream : string option -> string option -> Pdf.t -> int -> int -> Pdf.pdfobject -> Pdf.pdfobject (** Read encryption parameters from an encrypted PDF. They are the encryption type, *) val get_encryption_values : Pdf.t -> Pdfcryptprimitives.encryption * string * string * int32 * string * string option * string option (** Parse a /P value, giving the permissions *) val banlist_of_p : int32 -> permission list camlpdf-2.8.1/pdfcryptprimitives.ml000066400000000000000000000226651477056064700174640ustar00rootroot00000000000000(* Pdfcrypt primitives, split out *) open Pdfutil open Pdfio type encryption = | ARC4 of int * int | AESV2 | AESV3 of bool (* true = iso, false = old algorithm *) external aes_cook_encrypt_key : string -> string = "camlpdf_caml_aes_cook_encrypt_key" external aes_cook_decrypt_key : string -> string = "camlpdf_caml_aes_cook_decrypt_key" external aes_encrypt : string -> caml_bytes -> int -> caml_bytes -> int -> unit = "camlpdf_caml_aes_encrypt" external aes_decrypt : string -> caml_bytes -> int -> caml_bytes -> int -> unit = "camlpdf_caml_aes_decrypt" external sha_256 : string -> string = "camlpdf_caml_sha256" external sha_384 : string -> string = "camlpdf_caml_sha384" external sha_512 : string -> string = "camlpdf_caml_sha512" let key_expansion nk key = aes_cook_encrypt_key (string_of_int_array key) let key_expansion_decrypt nk key = aes_cook_decrypt_key (string_of_int_array key) (* 40bit / 128bit Encryption/Decryption Primitives *) (* Encryption / Decryption given a key. *) let ksa s key = let keylength = Array.length key in for i = 0 to 255 do s.(i) <- i done; let j = ref 0 in for i = 0 to 255 do j := (!j + s.(i) + key.(i mod keylength)) mod 256; swap s i !j done let prga s pi pj = pi := (!pi + 1) mod 256; pj := (!pj + s.(!pi)) mod 256; swap s !pi !pj; s.((s.(!pi) + s.(!pj)) mod 256) let crypt key data = let s, pi, pj, out = Array.make 256 0, ref 0, ref 0, mkbytes (bytes_size data) in ksa s key; for x = 0 to bytes_size data - 1 do bset out x (bget data x lxor prga s pi pj) done; out let _ = Random.self_init () (* Pad the input data (RFC2898, PKCS #5), then encrypt using a 16 byte AES cipher in cipher block chaining mode, with a random initialisation vector, which is stored as the first 16 bytes of the result. *) let ran255 () = Random.int 255 let mkiv () = let r = ran255 in [| r (); r (); r (); r (); r (); r (); r (); r (); r (); r (); r (); r (); r (); r (); r (); r () |] (* Build blocks for encryption, including padding. *) let get_blocks data = let l = bytes_size data in let fullblocks = if l < 16 then [] else let blocks = ref [] in for x = 0 to l / 16 - 1 do blocks =| let a = Array.make 16 0 in for y = 0 to 15 do Array.unsafe_set a y (bget_unsafe data (x * 16 + y)) done; a done; rev !blocks in let lastblock = let getlast n = if n = 0 then [] else let bytes = ref [] in for x = 0 to n - 1 do bytes =| bget data (l - 1 - x) done; !bytes in let pad n = many n n in let overflow = l mod 16 in Array.of_list (getlast overflow @ pad (16 - overflow)) in fullblocks @ [lastblock] (* Flatten a list of blocks into a bytes *) let bytes_of_blocks blocks = let len = 16 * length blocks in let s = mkbytes len in let p = ref 0 in iter (fun a -> Array.iter (fun v -> bset s !p v; incr p) a) blocks; s (* These two functions strip the padding from a stream once it's been decoded.*) let get_padding s = let l = bytes_size s in assert (l >= 16); let potential = bget s (l - 1) in if potential > 0x10 || potential < 0x01 then ((*Pdfe.log "potential out of range\n";*) None) else let rec elts_equal p f t = if f = t then p = bget s t else p = bget s f && elts_equal p (f + 1) t in if elts_equal potential (l - potential) (l - 1) then Some potential else ((*Pdfe.log "Padding bytes not equal\n";*) None) let cutshort s = if bytes_size s = 0 then mkbytes 0 else if bytes_size s < 16 then s else match get_padding s with | None -> s | Some padding -> let s' = mkbytes (bytes_size s - padding) in for x = 0 to bytes_size s' - 1 do bset_unsafe s' x (bget_unsafe s x) done; s' (* Decrypt data *) let aes_decrypt_data ?(remove_padding = true) nk key data = let key = key_expansion_decrypt nk key in let len = bytes_size data in if len <= 16 then mkbytes 0 else let output = mkbytes (len - 16) and prev_ciphertext = mkbytes 16 in for x = 0 to 15 do bset_unsafe prev_ciphertext x (bget_unsafe data x) done; let pos = ref 16 in while !pos < len do let i = Bytes.make 16 ' ' and o = Bytes.make 16 ' ' in for x = 0 to 15 do Bytes.set i x (char_of_int (bget_unsafe data (x + !pos))) done; aes_decrypt key i 0 o 0; for x = 0 to 15 do bset_unsafe output (x + !pos - 16) (int_of_char (Bytes.get o x)) done; for x = 0 to 15 do bset_unsafe output (x + !pos - 16) (bget_unsafe prev_ciphertext x lxor bget_unsafe output (x + !pos - 16)); bset_unsafe prev_ciphertext x (bget_unsafe data (x + !pos)) done; pos += 16 done; if remove_padding then cutshort output else output (* With ECB instead. Data on input must be a multiple of 16. *) let aes_decrypt_data_ecb ?(remove_padding = true) nk key data = let key = key_expansion_decrypt nk key in let size = bytes_size data in if size = 0 then mkbytes 0 else let output = mkbytes size and pos = ref 0 in while !pos < size do let i = Bytes.make 16 ' ' and o = Bytes.make 16 ' ' in for x = 0 to 15 do Bytes.set i x (char_of_int (bget_unsafe data (x + !pos))) done; aes_decrypt key i 0 o 0; for x = 0 to 15 do bset_unsafe output (x + !pos) (int_of_char (Bytes.get o x)) done; pos += 16 done; (if remove_padding then cutshort else ident) output (* Encrypt data *) let aes_encrypt_data ?(firstblock = mkiv ()) nk key data = let key = key_expansion nk key in let outblocks = ref [] in let prev_ciphertext = ref firstblock in iter (fun block -> let ciphertext = let src = let a = array_map2 (lxor) block !prev_ciphertext in Bytes.init (Array.length a) (fun i -> Char.unsafe_chr a.(i)) and dst = Bytes.make 16 ' ' in aes_encrypt key src 0 dst 0; Array.init (Bytes.length dst) (fun i -> int_of_char (Bytes.unsafe_get dst i)) in prev_ciphertext := ciphertext; outblocks =| ciphertext) (get_blocks data); bytes_of_blocks (firstblock::rev !outblocks) (* With ECB instead. Input length is multiple of 16. *) let aes_encrypt_data_ecb nk key data = let key = key_expansion nk key in let size = bytes_size data in if size = 0 then mkbytes 0 else let output = mkbytes size and pos = ref 0 in while !pos < size do let i = Bytes.make 16 ' ' and o = Bytes.make 16 ' ' in for x = 0 to 15 do Bytes.set i x (char_of_int (bget data (x + !pos))) done; aes_encrypt key i 0 o 0; for x = 0 to 15 do bset output (x + !pos) (int_of_char (Bytes.get o x)) done; pos += 16 done; output let string_of_input i = let b = Buffer.create 100 in try while true do match i.input_char () with Some c -> Buffer.add_char b c | None -> raise End_of_file done; assert false with End_of_file -> Buffer.contents b let sha256 i = sha_256 (string_of_input i) let sha384 i = sha_384 (string_of_input i) let sha512 i = sha_512 (string_of_input i) (* Given an object number, generation number, input key and key length in bits, apply Algorithm 3.1 from the PDF Reference manual to obtain the hash to be used by the encryption function. *) let find_hash crypt_type obj gen key keylength = let from_obj = [| i32toi (land32 obj 0x000000ffl); i32toi (lsr32 (land32 obj 0x0000ff00l) 8); i32toi (lsr32 (land32 obj 0x00ff0000l) 16) |] in let from_gen = [| i32toi (land32 gen 0x000000ffl); i32toi (lsr32 (land32 gen 0x0000ff00l) 8) |] in let extra = if crypt_type = AESV2 then [| 0x73; 0x41; 0x6C; 0x54 |] else [| |] in let digest_input = string_of_int_arrays [key; from_obj; from_gen; extra] in int_array_of_string (String.sub (Digest.string digest_input) 0 (min 16 (keylength / 8 + 5))) let decrypt_stream_data crypt_type encrypt file_encryption_key obj gen key keylength r data = let f = (if crypt_type = AESV2 then (if encrypt then aes_encrypt_data 4 else aes_decrypt_data 4) else if (match crypt_type with AESV3 _ -> true | _ -> false) then (if encrypt then aes_encrypt_data 8 else aes_decrypt_data 8) else crypt) in if r = 5 || r = 6 then let key = match file_encryption_key with Some k -> k | None -> failwith "decrypt: no key C" in f (int_array_of_string key) data else let hash = find_hash crypt_type (i32ofi obj) (i32ofi gen) key keylength in f hash data camlpdf-2.8.1/pdfcryptprimitives.mli000066400000000000000000000036301477056064700176240ustar00rootroot00000000000000(** Generic encryption primitives for ARC4, AES and the SHA family of digests *) (** ARC4 encryption (40 bit and 128 bit) given a key and some data *) val crypt : int array -> Pdfio.bytes -> Pdfio.bytes (** [aes_decrypt_data nk key data] decrypts AES data for the given key length, key, and data. If [remove_padding] is [true] (which it is by default), padding wil be removed from the output *) val aes_decrypt_data : ?remove_padding:bool -> int -> int array -> Pdfio.bytes -> Pdfio.bytes (** As [aes_decrypt_data] above, but in ECB instead of CBC mode *) val aes_decrypt_data_ecb : ?remove_padding:bool -> int -> int array -> Pdfio.bytes -> Pdfio.bytes (** [aes_encrypt_data nk key data] encryptes with AES, given a key length, key and data. The first block (by default a random one) can be overridden by specifying [firstblock], an array of length 16. *) val aes_encrypt_data : ?firstblock:int array -> int -> int array -> Pdfio.bytes -> Pdfio.bytes (** As [aes_encrypt_data], but in ECB instead of CBC mode *) val aes_encrypt_data_ecb : int -> int array -> Pdfio.bytes -> Pdfio.bytes (** SHA256 digest *) val sha256 : Pdfio.input -> string (** SHA344 digest *) val sha384 : Pdfio.input -> string (** SHA512 digest *) val sha512 : Pdfio.input -> string (** Types of encryption *) type encryption = | ARC4 of int * int | AESV2 | AESV3 of bool (** true = iso, false = old algorithm *) (** Given an object number, generation number, input key and key length in bits, apply Algorithm 3.1 from the PDF Reference manual to obtain the hash to be used by the encryption function. *) val find_hash : encryption -> int32 -> int32 -> int array -> int -> int array (** Calling [decrypt_stream_data crypt_type encrypt file_encryption_key obj gen key keylength r data] decrypts data. *) val decrypt_stream_data : encryption -> bool -> string option -> int -> int -> int array -> int -> int -> Pdfio.bytes -> Pdfio.bytes camlpdf-2.8.1/pdfdate.ml000066400000000000000000000063301477056064700151130ustar00rootroot00000000000000open Pdfutil type t = {year : int; month : int; day : int; hour : int; minute : int; second : int; hour_offset : int; minute_offset : int} exception BadDate let check_date d = try assert (d.year >= 0 && d.year <= 9999); assert (d.month >= 1 && d.month <= 12); assert (d.day >= 1 && d.day <= 31); assert (d.hour >= 0 && d.hour <= 23); assert (d.minute >= 0 && d.minute <= 59); assert (d.second >= 0 && d.second <= 59); assert (d.hour_offset >= -23 && d.hour_offset <= 23); assert (d.minute_offset >= -59 && d.minute_offset <= 59); with _ -> raise BadDate (* For now, no detection of default values which could be omitted. *) let string_of_date d = check_date d; let ostr = if d.hour_offset < 0 then Printf.sprintf "-%02i'%02i'" (abs d.hour_offset) (abs d.minute_offset) else if d.hour_offset > 0 then Printf.sprintf "+%02i'%02i'" (abs d.hour_offset) (abs d.minute_offset) else "Z" in Printf.sprintf "D:%04i%02i%02i%02i%02i%02i%s" d.year d.month d.day d.hour d.minute d.second ostr let date_of_string s = let safe_int_string chars = try int_of_string (implode chars) with _ -> raise BadDate in let hour_offset = ref 0 in let minute_offset = ref 0 in let o = ref 0 in let rec optional_twochar def cs = match cs with | ('-' | '+' | 'Z')::_ -> parse_local_time cs; def, [] | a::b::more -> safe_int_string [a;b], more | _ -> def, [] and parse_local_time cs = let o_got, cs = match cs with | '+'::more -> 1, more | '-'::more -> -1, more | 'Z'::more -> 0, more | _ -> 0, [] in let h, cs = optional_twochar 0 cs in match cs with | [] -> () | _ -> let m, cs = optional_twochar 0 (tl cs) in hour_offset := h; minute_offset := m; o := o_got in let cs = explode s in let cs = match cs with | 'D'::':'::more -> more | _ -> cs in let year, cs = match cs with | '1'::'9'::'1'::'0'::'0'::more -> 2000, more (* Adobe Distiller 3 Y2K Bug *) | a::b::c::d::more -> safe_int_string [a;b;c;d], more | _ -> raise BadDate in let month, cs = optional_twochar 1 cs in let day, cs = optional_twochar 1 cs in let hour, cs = optional_twochar 0 cs in let minute, cs = optional_twochar 0 cs in let second, cs = optional_twochar 0 cs in parse_local_time cs; let date = {year = year; month = month; day = day; hour = hour; minute = minute; second = second; hour_offset = !hour_offset * !o; minute_offset = !minute_offset * !o} in check_date date; date camlpdf-2.8.1/pdfdate.mli000066400000000000000000000007171477056064700152670ustar00rootroot00000000000000(** Representing and Parsing PDF Dates *) (** The type of a date. *) type t = {year : int; month : int; day : int; hour : int; minute : int; second : int; hour_offset : int; minute_offset : int} (** Raised when [date_of_string] fails. *) exception BadDate (** Build a date by parsing a PDF date string. Raises [BadDate] on failure. *) val date_of_string : string -> t (** Build a string from a date. *) val string_of_date : t -> string camlpdf-2.8.1/pdfdest.ml000066400000000000000000000175511477056064700151440ustar00rootroot00000000000000(* Read and Write Destinations *) open Pdfutil type targetpage = | PageObject of int | OtherDocPageNumber of int type t = | Action of Pdf.pdfobject | NullDestination | NamedDestination of string | StringDestination of string | XYZ of targetpage * float option * float option * float option | Fit of targetpage | FitH of targetpage * float option | FitV of targetpage * float option | FitR of targetpage * float * float * float * float | FitB of targetpage | FitBH of targetpage * float option | FitBV of targetpage * float option (* Read the destination - it's either direct, or in /Dests in the document catalog, or in /Dests in the document name tree. *) let read_targetpage = function | Pdf.Indirect i -> PageObject i | Pdf.Integer i -> OtherDocPageNumber i | _ -> assert false (* ruled out in read_destination *) let rec read_destination ?(shallow=false) pdf pdfobject = let option_getnum = function | Pdf.Null -> None | x -> Some (Pdf.getnum pdf x) in match Pdf.direct pdf pdfobject with | Pdf.Dictionary d -> begin (* We're discarding any other dictionary entries here... *) match Pdf.lookup_direct pdf "/D" (Pdf.Dictionary d) with | Some dest -> read_destination ~shallow pdf dest | None -> NullDestination end | Pdf.Array [(Pdf.Indirect _ | Pdf.Integer _) as p; Pdf.Name "/XYZ"; l; t; z] -> XYZ (read_targetpage p, option_getnum l, option_getnum t, option_getnum z) | Pdf.Array (* Read common malformed one. *) [(Pdf.Indirect _ | Pdf.Integer _) as p; Pdf.Name "/XYZ"; l; t] -> XYZ (read_targetpage p, option_getnum l, option_getnum t, None) | Pdf.Array (* Read common malformed one. *) [(Pdf.Indirect _ | Pdf.Integer _) as p; Pdf.Name "/XYZ"; l] -> XYZ (read_targetpage p, option_getnum l, None, None) | Pdf.Array [(Pdf.Indirect _ | Pdf.Integer _) as p; Pdf.Name "/Fit"] -> Fit (read_targetpage p) | Pdf.Array [(Pdf.Indirect _ | Pdf.Integer _) as p; Pdf.Name "/FitH"; t] -> FitH (read_targetpage p, option_getnum t) | Pdf.Array [(Pdf.Indirect _ | Pdf.Integer _) as p; Pdf.Name "/FitV"; l] -> FitV (read_targetpage p, option_getnum l) | Pdf.Array [(Pdf.Indirect _ | Pdf.Integer _) as p; Pdf.Name "/FitR"; l; b; r; t] -> FitR (read_targetpage p, Pdf.getnum pdf l, Pdf.getnum pdf b, Pdf.getnum pdf r, Pdf.getnum pdf t) | Pdf.Array [(Pdf.Indirect _ | Pdf.Integer _) as p; Pdf.Name "/FitB"] -> FitB (read_targetpage p) | Pdf.Array [(Pdf.Indirect _ | Pdf.Integer _) as p; Pdf.Name "/FitBH"; t] -> FitBH (read_targetpage p, option_getnum t) | Pdf.Array [(Pdf.Indirect _ | Pdf.Integer _) as p; Pdf.Name "/FitBV"; l] -> FitBV (read_targetpage p, option_getnum l) | Pdf.Name n -> if shallow then NamedDestination n else begin match Pdf.lookup_direct pdf "/Root" pdf.Pdf.trailerdict with | Some catalog -> begin match Pdf.lookup_direct pdf "/Dests" catalog with | Some dests -> begin match Pdf.lookup_direct pdf n dests with | Some dest' -> read_destination ~shallow pdf dest' | None -> NamedDestination n end | None -> NamedDestination n end | None -> raise (Pdf.PDFError "read_destination: no catalog") end | Pdf.String s -> if shallow then StringDestination s else let rootdict = Pdf.lookup_obj pdf pdf.Pdf.root in begin match Pdf.lookup_direct pdf "/Names" rootdict with | Some namedict -> begin match Pdf.lookup_direct pdf "/Dests" namedict with | Some destsdict -> begin match Pdf.nametree_lookup pdf (Pdf.String s) destsdict with | None -> StringDestination s | Some dest -> read_destination ~shallow pdf (Pdf.direct pdf dest) end | _ -> StringDestination s end | _ -> StringDestination s end | p -> Pdfe.log (Printf.sprintf "Warning: Could not read destination %s\n" (Pdfwrite.string_of_pdf p)); NullDestination let pdf_of_targetpage = function | PageObject i -> Pdf.Indirect i | OtherDocPageNumber i -> Pdf.Integer i let pos_null = function None -> Pdf.Null | Some x -> Pdf.Real x let pdfobject_of_destination = function | Action a -> a | NullDestination -> Pdf.Null | NamedDestination s -> Pdf.Name s | StringDestination s -> Pdf.String s | XYZ (p, left, top, zoom) -> Pdf.Array [pdf_of_targetpage p; Pdf.Name "/XYZ"; pos_null left; pos_null top; pos_null zoom] | Fit p -> Pdf.Array [pdf_of_targetpage p; Pdf.Name "/Fit"] | FitH (p, top) -> Pdf.Array [pdf_of_targetpage p; Pdf.Name "/FitH"; pos_null top] | FitV (p, left) -> Pdf.Array [pdf_of_targetpage p; Pdf.Name "/FitV"; pos_null left] | FitR (p, left, bottom, right, top) -> Pdf.Array [pdf_of_targetpage p; Pdf.Name "/FitR"; Pdf.Real left; Pdf.Real bottom; Pdf.Real right; Pdf.Real top] | FitB p -> Pdf.Array [pdf_of_targetpage p; Pdf.Name "/FitB"] | FitBH (p, top) -> Pdf.Array [pdf_of_targetpage p; Pdf.Name "/FitBH"; pos_null top] | FitBV (p, left) -> Pdf.Array [pdf_of_targetpage p; Pdf.Name "/FitBV"; pos_null left] (* Transform destinations by a given matrix. Where we have a proper pair making a point, it is easy. Where we do not, we improvise. It is likely only to be sensible for scaling / shifting / uprighting anyway. For example, a vertical flip of a page is hardly likely to make a paragraph come up in the right position. Careful to preserve nulls, and handle all combinations. *) (* Acrobat doesn't like /OpenActions (at least) which contain numbers outside the float range -32768...32768. This is the old (pre-ISO) float range. *) let clip_pair (a, b) = let clip f = if f < -32768.0 then -32768.0 else if f > 32768.0 then 32768.0 else f in (clip a, clip b) let rec transform_destination pdf t = function | FitH (PageObject _ as p, Some top) -> let (_, top) = clip_pair (Pdftransform.transform_matrix t (0., top)) in FitH (p, Some top) | FitV (PageObject _ as p, Some left) -> let (left, _) = clip_pair (Pdftransform.transform_matrix t (left, 0.)) in FitV (p, Some left) | FitBH (PageObject _ as p, Some top) -> let (_, top) = clip_pair (Pdftransform.transform_matrix t (0., top)) in FitBH (p, Some top) | FitBV (PageObject _ as p, Some left) -> let (left, _) = clip_pair (Pdftransform.transform_matrix t (left, 0.)) in FitBV (p, Some left) | XYZ (PageObject _ as p, Some left, Some top, zoom) -> let left, top = clip_pair (Pdftransform.transform_matrix t (left, top)) in XYZ (p, Some left, Some top, zoom) | XYZ (PageObject _ as p, None, Some top, zoom) -> let _, top = clip_pair (Pdftransform.transform_matrix t (0., top)) in XYZ (p, None, Some top, zoom) | XYZ (PageObject _ as p, Some left, None, zoom) -> let left, _ = clip_pair (Pdftransform.transform_matrix t (left, 0.)) in XYZ (p, Some left, None, zoom) | FitR (PageObject _ as p, left, bottom, right, top) -> let left, top = clip_pair (Pdftransform.transform_matrix t (left, top)) in let right, bottom = clip_pair (Pdftransform.transform_matrix t (right, bottom)) in FitR (p, left, bottom, right, top) | Action a -> begin match Pdf.lookup_direct pdf "/S" a, Pdf.lookup_direct pdf "/D" a with | Some (Pdf.Name "/GoTo"), Some d -> Action (Pdf.add_dict_entry a "/D" (pdfobject_of_destination (transform_destination pdf t (read_destination ~shallow:true pdf d)))) | _ -> Action a end | x -> x camlpdf-2.8.1/pdfdest.mli000066400000000000000000000022361477056064700153070ustar00rootroot00000000000000(** Destinations *) (** The target of a destination is either a page object in the same PDF (given by object number of page object), or a page number in an external file. *) type targetpage = | PageObject of int | OtherDocPageNumber of int (** Destinations (and actions) *) type t = | Action of Pdf.pdfobject | NullDestination | NamedDestination of string | StringDestination of string | XYZ of targetpage * float option * float option * float option | Fit of targetpage | FitH of targetpage * float option | FitV of targetpage * float option | FitR of targetpage * float * float * float * float | FitB of targetpage | FitBH of targetpage * float option | FitBV of targetpage * float option (** Read a destination given a PDF and destination object. If [shallow] is true, actions will be kept in PDF form, rather than followed to their destinations. *) val read_destination : ?shallow:bool -> Pdf.t -> Pdf.pdfobject -> t (** Write a destination to a [Pdf.pdfobject]. *) val pdfobject_of_destination : t -> Pdf.pdfobject (** Transform a destination by a matrix *) val transform_destination : Pdf.t -> Pdftransform.transform_matrix -> t -> t camlpdf-2.8.1/pdfe.ml000066400000000000000000000002121477056064700144130ustar00rootroot00000000000000(* Errors. *) type logger = string -> unit let default s = prerr_string s; flush stderr let logger = ref default let log s = !logger s camlpdf-2.8.1/pdfe.mli000066400000000000000000000004671477056064700146000ustar00rootroot00000000000000(** Errors *) (** The type of loggers. Subject to change. *) type logger = string -> unit (** Default error logger, writes the string to stderr and flushes. *) val default : logger (** The current error logger, set to [default] upon startup. *) val logger : logger ref (** Log a string. *) val log : logger camlpdf-2.8.1/pdfflate.ml000066400000000000000000000053341477056064700152740ustar00rootroot00000000000000(* From CamlZip. See README.md *) exception Error of string * string let _ = Callback.register_exception "Pdfflate.Error" (Error("","")) type stream type flush_command = Z_NO_FLUSH | Z_SYNC_FLUSH | Z_FULL_FLUSH | Z_FINISH external deflate_init: int -> bool -> stream = "camlpdf_camlzip_deflateInit" external deflate: stream -> bytes -> int -> int -> bytes -> int -> int -> flush_command -> bool * int * int = "camlpdf_camlzip_deflate_bytecode" "camlpdf_camlzip_deflate" external deflate_end: stream -> unit = "camlpdf_camlzip_deflateEnd" external inflate_init: bool -> stream = "camlpdf_camlzip_inflateInit" external inflate: stream -> bytes -> int -> int -> bytes -> int -> int -> flush_command -> bool * int * int = "camlpdf_camlzip_inflate_bytecode" "camlpdf_camlzip_inflate" external inflate_end: stream -> unit = "camlpdf_camlzip_inflateEnd" let buffer_size = 1024 let compress ?(level = 6) ?(header = true) refill flush = let inbuf = Bytes.create buffer_size and outbuf = Bytes.create buffer_size in let zs = deflate_init level header in let rec compr inpos inavail = if inavail = 0 then begin let incount = refill inbuf in if incount = 0 then compr_finish() else compr 0 incount end else begin let (_, used_in, used_out) = deflate zs inbuf inpos inavail outbuf 0 buffer_size Z_NO_FLUSH in flush outbuf used_out; compr (inpos + used_in) (inavail - used_in) end and compr_finish () = let (finished, _, used_out) = deflate zs inbuf 0 0 outbuf 0 buffer_size Z_FINISH in flush outbuf used_out; if not finished then compr_finish() in compr 0 0; deflate_end zs let uncompress ?(header = true) refill flush = let inbuf = Bytes.create buffer_size and outbuf = Bytes.create buffer_size in let zs = inflate_init header in let rec uncompr inpos inavail = if inavail = 0 then begin let incount = refill inbuf in if incount = 0 then uncompr_finish true else uncompr 0 incount end else begin let (finished, used_in, used_out) = inflate zs inbuf inpos inavail outbuf 0 buffer_size Z_SYNC_FLUSH in flush outbuf used_out; if not finished then uncompr (inpos + used_in) (inavail - used_in) end and uncompr_finish first_finish = (* Gotcha: if there is no header, inflate requires an extra "dummy" byte after the compressed stream in order to complete decompression and return finished = true. *) let dummy_byte = if first_finish && not header then 1 else 0 in let (finished, _, used_out) = inflate zs inbuf 0 dummy_byte outbuf 0 buffer_size Z_SYNC_FLUSH in flush outbuf used_out; if not finished then uncompr_finish false in uncompr 0 0; inflate_end zs camlpdf-2.8.1/pdfflate.mli000066400000000000000000000017371477056064700154500ustar00rootroot00000000000000(** Interface to miniz.c via Zlib-like functions This is very slightly modified from Leroy's CamlZip. *) (** Raised on an error in either compression or decompression. *) exception Error of string * string (** Compress data. The [string -> int] function is an input: given a buffer, it writes some data to it, returning the number of bytes written. The [string -> int -> unit] function is an output: giving a buffer and a number of compressed bytes written. The optional argument [level] gives the zlib compression level (the default is 6). The optional argument [header] will, if [true], output a zlib header (the default is [true]). *) val compress: ?level: int -> ?header: bool -> (bytes -> int) -> (bytes -> int -> unit) -> unit (** Uncompress data. The input and output functions are as described for [compress]. If [header] is [true], a zlib header is expected (the default is [true]). *) val uncompress: ?header: bool -> (bytes -> int) -> (bytes -> int -> unit) -> unit camlpdf-2.8.1/pdffun.ml000066400000000000000000000666011477056064700147750ustar00rootroot00000000000000open Pdfutil open Pdfio (* Types *) (* Postscript calculator functions. *) type calculator = | If of calculator list | IfElse of calculator list * calculator list | Bool of bool | Float of float | Int of int32 | Abs | Add | Atan | Ceiling | Cos | Cvi | Cvr | Div | Exp | Floor | Idiv | Ln | Log | Mod | Mul | Neg | Round | Sin | Sqrt | Sub | Truncate | And | Bitshift | Eq | Ge | Gt | Le | Lt | Ne | Not | Or | Xor | Copy | Exch | Pop | Dup | Index | Roll (* Sampled functions. *) type sampled = {size : int list; order : int; encode : float list; decode : float list; bps : int; samples : int32 array} (* Interpolation functions. *) and interpolation = {c0 : float list; c1 : float list; n : float} (* Stitching functions. *) and stitching = {functions : t list; bounds : float list; stitch_encode : float list} (* Collect the above types into a single type. *) and pdf_fun_kind = | Interpolation of interpolation | Stitching of stitching | Sampled of sampled | Calculator of calculator list (* Main type. *) and t = {func : pdf_fun_kind; domain : float list; range : float list option} (* Printing functions *) (* Build a string of a calculator function. For debug only, since could exceed string length limit. *) let rec string_of_calculator_inner = function | If l -> string_of_calculator l ^ " if" | IfElse (l, l') -> string_of_calculator l ^ " " ^ string_of_calculator l' ^ " ifelse" | Bool true -> "true" | Bool false -> "false" | Float f -> string_of_float f | Int i -> Int32.to_string i | Abs -> "abs" | Add -> "add" | Atan -> "atan" | Ceiling -> "ceiling" | Cos -> "cos" | Cvi -> "cvi" | Cvr -> "cvr" | Div -> "div" | Exp -> "exp" | Floor -> "floor" | Idiv -> "idiv" | Ln -> "ln" | Log -> "log" | Mod -> "mod" | Mul -> "mul" | Neg -> "neg" | Round -> "round" | Sin -> "sin" | Sqrt -> "sqrt" | Sub -> "sub" | Truncate -> "truncate" | And -> "and" | Bitshift -> "bitshift" | Eq -> "eq" | Ge -> "ge" | Gt -> "gt" | Le -> "le" | Lt -> "lt" | Ne -> "ne" | Not -> "not" | Or -> "or" | Xor -> "xor" | Copy -> "copy" | Exch -> "exch" | Pop -> "pop" | Dup -> "dup" | Index -> "index" | Roll -> "roll" and string_of_calculator cs = let ops = fold_right ( ^ ) (interleave " " (map string_of_calculator_inner cs)) "" in "{" ^ ops ^ "}" (* Print a function out for debug. *) let rec print_function f = print_string "Domain...\n"; print_floats f.domain; begin match f.range with | None -> print_string "null range\n" | Some values -> print_floats values end; match f.func with | Sampled s -> print_string "Sampled\n"; print_string "size: "; print_ints s.size; print_string "order: "; print_int s.order; print_string "\nencode:\n"; print_floats s.encode; print_string "decode:\n"; print_floats s.decode; print_string "original bits per sample..\n"; print_int s.bps; print_string "\ndata:\n"; print_int32s (Array.to_list s.samples) | Interpolation i -> print_string "Interpolation\n"; print_string "C0:\n"; print_floats i.c0; print_string "C1:\n"; print_floats i.c1; Printf.printf "n = %f\n" i.n; | Stitching s -> print_string "Stitching\n"; iter print_function s.functions; print_string "Bounds:\n"; print_floats s.bounds; print_string "Encode:\n"; print_floats s.stitch_encode; | Calculator c -> print_string "Calculator:\n"; print_string (string_of_calculator c) (* Parsing Calculator Functions *) let keyword_of_string = function | "abs" -> Abs | "add" -> Add | "atan" -> Atan | "ceiling" -> Ceiling | "cos" -> Cos | "cvr" -> Cvr | "div" -> Div | "exp" -> Exp | "floor" -> Floor | "idiv" -> Idiv | "ln" -> Ln | "log" -> Log | "mod" -> Mod | "mul" -> Mul | "neg" -> Neg | "round" -> Round | "sin" -> Sin | "sqrt" -> Sqrt | "sub" -> Sub | "truncate" -> Truncate | "and" -> And | "bitshift" -> Bitshift | "eq" -> Eq | "ge" -> Ge | "gt" -> Gt | "le" -> Le | "lt" -> Lt | "ne" -> Ne | "not" -> Not | "or" -> Or | "xor" -> Xor | "copy" -> Copy | "exch" -> Exch | "pop" -> Pop | "dup" -> Dup | "index" -> Index | "roll" -> Roll | s -> Pdfe.log (Printf.sprintf "%s" ("Bad keyword " ^ s)); assert false let parse_calculator s = let lexemes = Pdfgenlex.lex (Pdfio.input_of_string s) in let rec strip_outer_braces = function | Pdfgenlex.LexName ("{" | "}")::t -> rev (strip_outer_braces (rev t)) | x -> x and group_operators = function | [] -> [] | Pdfgenlex.LexName "{"::t -> let ops, rest = cleavewhile (neq (Pdfgenlex.LexName "}")) t in ops::group_operators (tl rest) | h::t -> [h]::group_operators t and parse = function | [] -> [] | l::l'::[Pdfgenlex.LexName "ifelse"]::t -> IfElse (procss l, procss l')::parse t | l::[Pdfgenlex.LexName "if"]::t -> If (procss l)::parse t | [Pdfgenlex.LexName "true"]::t -> Bool true::parse t | [Pdfgenlex.LexName "false"]::t -> Bool false::parse t | [Pdfgenlex.LexReal f]::t -> (* If the float is actually a whole number, convert to an Int. This will be accepted as a float (where any number is ok) and as an int (where an integer is required. Sometimes, buggy code has things like 1.000000 where 1 is required. *) (*(if f = floor f then Int (Int32.of_float f) else *) Float f::parse t | [Pdfgenlex.LexInt i]::t-> Int (i32ofi i)::parse t (* FIXME: range *) | [Pdfgenlex.LexName x]::t -> keyword_of_string x::parse t | h::_ -> (* Pdfe.log (Printf.sprintf ((Cgenlex.string_of_tokens h))); *) raise (Failure "Bad lexeme") and procss lexemes = try parse (group_operators (strip_outer_braces lexemes)) with _ -> raise (Pdf.PDFError "Cannot parse Type 4 function") in procss lexemes (* Parsing functions *) let rec parse_function pdf f = let f = Pdf.direct pdf f in let getnum_direct o = Pdf.getnum pdf o in let domain = match Pdf.lookup_fail "No /Domain" pdf "/Domain" f with | Pdf.Array ns -> map getnum_direct ns | _ -> raise (Pdf.PDFError "Bad /Domain") in let range = match Pdf.lookup_direct pdf "/Range" f with | Some (Pdf.Array ns) -> Some (map getnum_direct ns) | _ -> None in let func = match Pdf.lookup_fail "no /FunctionType" pdf "/FunctionType" f with | Pdf.Integer 0 -> let size = match Pdf.lookup_fail "no /Size (sampled fun)" pdf "/Size" f with | Pdf.Array ns -> map (function | Pdf.Integer n -> n | _ -> raise (Pdf.PDFError "bad /Size (sampled fun)")) ns | _ -> raise (Pdf.PDFError "Bad /Size (sampled fun)") in let order = match Pdf.lookup_direct pdf "/Order" f with | Some (Pdf.Integer n) -> n | _ -> 1 in let encode = match Pdf.lookup_direct pdf "/Encode" f with | Some (Pdf.Array ns) when length ns = 2 * length size -> map getnum_direct ns | _ -> interleave_lists (many 0. (length size)) (map (fun x -> float (x - 1)) size) in let decode = match Pdf.lookup_direct pdf "/Decode" f with | Some (Pdf.Array ns) -> map getnum_direct ns | _ -> match range with | Some r -> r | None -> raise (Pdf.PDFError "No /Range") in let bitspersample = match Pdf.lookup_fail "no /BitsPerSample" pdf "/BitsPerSample" f with | Pdf.Integer i -> i | _ -> raise (Pdf.PDFError "Bad /BitsPerSample") in let data = Pdfcodec.decode_pdfstream pdf f; let samples = fold_left ( * ) 1 size * (length decode / 2) in let bitstream = match f with | Pdf.Stream {contents = _, Pdf.Got data} -> Pdfio.bitbytes_of_input (Pdfio.input_of_bytes data) | _ -> assert false in let data = Array.make samples 1l in for i = 0 to Array.length data - 1 do data.(i) <- Pdfio.getval_32 bitstream bitspersample done; data in Sampled {size = size; order = order; encode = encode; decode = decode; bps = bitspersample; samples = data} | Pdf.Integer 2 -> let c0 = match Pdf.lookup_direct pdf "/C0" f with | Some (Pdf.Array ns) -> map getnum_direct ns | _ -> [0.] in let c1 = match Pdf.lookup_direct pdf "/C1" f with | Some (Pdf.Array ns) -> map getnum_direct ns | _ -> [1.] in let n = getnum_direct (Pdf.lookup_fail "No /N in Type 2 fun" pdf "/N" f) in Interpolation {c0 = c0; c1 = c1; n = n} | Pdf.Integer 3 -> let functions = match Pdf.lookup_fail "no /Functions" pdf "/Functions" f with | Pdf.Array fs -> fs | _ -> raise (Pdf.PDFError "Bad /Functions") in let bounds = match Pdf.lookup_fail "no /Bounds" pdf "/Bounds" f with | Pdf.Array fs -> fs | _ -> raise (Pdf.PDFError "Bad /Bounds") in let encode = match Pdf.lookup_fail "no /Encode" pdf "/Encode" f with | Pdf.Array fs -> fs | _ -> raise (Pdf.PDFError "Bad /Bounds") in Stitching {functions = map (parse_function pdf) functions; bounds = map getnum_direct bounds; stitch_encode = map getnum_direct encode} | Pdf.Integer 4 -> (* Read contents of stream, build string, parse. *) Pdfcodec.decode_pdfstream pdf f; begin match f with | Pdf.Stream {contents = _, Pdf.Got data} -> Calculator (parse_calculator (string_of_bytes data)) | _ -> raise (Pdf.PDFError "This is not a function") end | _ -> raise (Pdf.PDFError "Unknown function type") in {domain = domain; range = range; func = func} (* Evaluating Sampled Functions *) (* Inappropriate inputs have been given to a function. *) exception BadFunctionEvaluation of string let interpolate x xmin xmax ymin ymax = ymin +. ((x -. xmin) *. ((ymax -. ymin) /. (xmax -. xmin))) (* Evaluate a sampled function. We support only linear interpolation and then only sensibly for one-dimensional functions. Although results will be produced for higher dimensions, the results will not be fully accurate. *) let eval_function_sampled f s clamped_inputs = (* 1. Encode the input values *) (*i Printf.printf "eval_function_sampled: length of clamped_inputs %i input is * %f\n" (length clamped_inputs) (hd clamped_inputs); i*) let range = match f.range with | None -> raise (BadFunctionEvaluation "No Range") | Some r -> r in let d, d' = split (pairs_of_list f.domain) in let e, e' = split (pairs_of_list s.encode) in let dec, dec' = split (pairs_of_list s.decode) in let r, r' = split (pairs_of_list range) in let encoded_inputs = map5 interpolate clamped_inputs d d' e e' in (* 2. Clip to the size of the table dimension *) let clamped_encoded_inputs = map2 (fun i s -> fmin (fmax i 0.) (float s -. 1.)) encoded_inputs s.size in let read_table inputs = let vals_to_read = length range / 2 in let size = s.size in if length size <> length inputs then raise (BadFunctionEvaluation "Incompatible /Size with inputs"); let pos = let multipliers = let inputs' = if length inputs = 1 then [] else ilist 1 (length inputs - 1) in 1:: map (function x -> fold_left ( * ) 1 (take size x)) inputs' (* (ilist_fail_null 1 (length inputs - 1)) *) in (*i Printf.printf "%i inputs and %i multipliers" (length inputs) (length multipliers); i*) sum (map2 ( * ) inputs multipliers) * vals_to_read in Array.to_list (Array.sub s.samples pos vals_to_read) in (* 3. Read values from table. For now, just linear iterpolation. *) let ceilings = map (fun x -> toint (ceil x)) clamped_encoded_inputs in let floors = map (fun x -> toint (floor x)) clamped_encoded_inputs in let outputs = let ceiling_results = read_table ceilings in let floor_results = read_table floors in (*i Printf.printf "length of floors: %i, length of ceilings %i\n" (List.length ceiling_results) (List.length floor_results); i*) map2 (fun x y -> Int32.to_float x /. 2. +. Int32.to_float y /. 2.) ceiling_results floor_results in (* 4. Decode output values *) let outputs_decoded = map5 interpolate outputs (many 0. (length outputs)) (many (2. ** float s.bps -. 1.) (length outputs)) dec dec' in map3 (fun x r r' -> fmin (fmax x r) r') outputs_decoded r r' (* Evaluating Calculator Functions *) let eval_function_calculator clamped_inputs ops = let s = ref (map (fun i -> Float i) (rev clamped_inputs)) in let typecheck () = raise (BadFunctionEvaluation "Type error") in let rec getfloat () = match !s with | Int i::r -> s := r; i32tof i | Float f::r -> s := r; f | _ -> typecheck () and getint () = match !s with | Int i::r -> s := r; i | _ -> typecheck () and getfloats () = let x = getfloat () in x, getfloat () and getints () = let x = getint () in x, getint () in let rec eval k = (* flprint (string_of_calculator !s); Printf.printf "Now op %s\n\n" (string_of_calculator [k]); *) match k with | If l -> begin match !s with | Bool b::r -> s := r; if b then iter eval l | _ -> typecheck () end | IfElse (l, l') -> begin match !s with | Bool b::r -> s := r; iter eval (if b then l else l') | _ -> typecheck () end | (Bool _ | Float _ | Int _) as immediate -> s =| immediate | Abs -> begin match !s with | Float f::r -> s := Float (fabs f)::r | Int i::r -> let out = if i = Int32.min_int then (Float (i32tof Int32.max_int)) else (Int (Int32.abs i)) in s := out::r | _ -> typecheck () end | Add -> begin match !s with | Int i::Int i'::r -> s := Int (i32add i i')::r (*r FIXME: Overflow to float *) | Int i::Float f::r | Float f::Int i::r -> s := Float (i32tof i +. f)::r | Float f::Float f'::r -> s := Float (f +. f')::r | _ -> typecheck () end | Atan -> let num, den = getfloats () in let result = atan2 num den in s := Float result::tl (tl !s) | Ceiling -> begin match !s with | Float f::r -> s := Float (ceil f)::r | Int _::_ -> () | _ -> typecheck () end | Cos -> let f = getfloat () in s := Float (cos (rad_of_deg f))::!s | Cvi -> begin match !s with | Int _::r -> () | Float f::r -> s := Int (Int32.of_float (floor f))::r | _ -> typecheck () end | Cvr -> begin match !s with | Int i::r -> s := Float (i32tof i)::r | Float f::r -> () | _ -> typecheck () end | Div -> let n, n' = getfloats () in s := Float (n /. n')::!s | Exp -> let bse, exponent = getfloats () in s := Float (bse ** exponent)::!s | Floor -> begin match !s with | Int i::r -> () | Float f::r -> s := Int (Int32.of_float (floor f))::r | _ -> typecheck () end | Idiv -> let i, i' = getints () in s := Int (i32div i i')::!s | Ln -> let f = getfloat () in s := Float (log f)::!s | Log -> let f = getfloat () in s := Float (log10 f)::!s | Mod -> let i, i' = getints () in s := Int (Int32.rem i i')::!s | Mul -> begin match !s with | Int i::Int i'::r -> s := Int (i32mul i i')::r (*r FIXME: Overflow to float *) | Int i::Float f::r | Float f::Int i::r -> s := Float (i32tof i *. f)::r | Float f::Float f'::r -> s := Float (f *. f')::r | _ -> typecheck () end | Neg -> begin match !s with | Float f::r -> s := Float (-.f)::r | Int i::r -> let out = if i = Int32.min_int then (Float (i32tof Int32.max_int)) else (Int (Int32.neg i)) in s := out::r | _ -> typecheck () end | Round -> begin match !s with | Int _::_ -> () | Float f::r -> s := Int (Int32.of_float (round f))::r | _ -> typecheck () end | Sin -> let f = getfloat () in s := Float (sin (rad_of_deg f))::!s | Sqrt -> let f = getfloat () in s := Float (sqrt f)::!s | Sub -> begin match !s with | Int i::Int i'::r -> s := Int (i32sub i' i)::r (*r \FIXME{Overflow to float} *) | Int i::Float f::r -> s := Float (f -. i32tof i)::r | Float f::Int i::r -> s := Float (i32tof i -. f)::r | Float f::Float f'::r -> s := Float (f' -. f)::r | _ -> typecheck () end | Truncate -> begin match !s with | Int _::_ -> () | Float f::r -> s := Int (i32ofi (toint f))::r | _ -> typecheck () end | And -> begin match !s with | Int i::Int i'::r -> s := Int (Int32.logand i i')::r | Bool b::Bool b'::r -> s := Bool (b && b')::r | _ -> typecheck () end | Bitshift -> let i = getint () in let shift = i32toi (getint ()) in let r = if i < 0l then Int32.shift_left i shift else Int32.shift_right_logical i (abs shift) in s := Int r::!s | Eq -> begin match !s with | a::b::r -> s := Bool (a = b)::r | _ -> typecheck () end | Ge -> begin match !s with | a::b::r -> s := Bool (a >= b)::r | _ -> typecheck () end | Gt -> begin match !s with | a::b::r -> s := Bool (a > b)::r | _ -> typecheck () end | Le -> begin match !s with | a::b::r -> s := Bool (a <= b)::r | _ -> typecheck () end | Lt -> begin match !s with | a::b::r -> s := Bool (a < b)::r | _ -> typecheck () end | Ne -> begin match !s with | a::b::r -> s := Bool (a <> b)::r | _ -> typecheck () end | Not -> begin match !s with | Int i::r -> s := Int (Int32.lognot i)::r | Bool b::Bool b'::r -> s := Bool (not b)::r | _ -> typecheck () end | Or -> begin match !s with | Int i::Int i'::r -> s := Int (Int32.logor i i')::r | Bool b::Bool b'::r -> s := Bool (b || b')::r | _ -> typecheck () end | Xor -> begin match !s with | Int i::Int i'::r -> s := Int (Int32.logxor i i')::r | Bool b::Bool b'::r -> s := Bool (b |&| b')::r | _ -> typecheck () end | Copy -> begin match !s with | Int i::r when i >= 0l -> s := take r (i32toi i) @ r | _ -> typecheck () end | Exch -> begin match !s with | a::b::r -> s := b::a::r | _ -> typecheck () end | Pop -> begin match !s with | a::r -> s := r | _ -> typecheck () end | Dup -> begin match !s with | a::r -> s := a::a::r | _ -> typecheck () end | Index -> begin match !s with | Int i::r when i >= 0l -> let v = select (i32toi i + 1) r in s := v::r | _ -> typecheck () end | Roll -> let rec rotate j l = if j = 0 then l else match l with | [] -> [] | h::t -> rotate (j - 1) (t @ [h]) and rotate_o j l = if j = 0 then l else match rev l with | [] -> [] | h::t -> rotate (j - 1) ([h] @ rev t) in begin match !s with | Int j::Int n::r when n >= 1l -> let j = i32toi j in let n = i32toi n in let vals, rest = cleave r n in let newvals = if j > 0 then rotate j vals else rotate_o (-j) vals in s := newvals @ rest | _ -> typecheck () end in try iter eval ops; rev_map (function | Float x -> x | Int i -> Int32.to_float i (* Added as a FIX, but we should look at this again...*) | _ -> raise (BadFunctionEvaluation "Type 4-a")) !s with e -> flprint (Printexc.to_string e); raise (BadFunctionEvaluation "Type 4-b") (* Evaluating functions *) (* Evaluate a function on some inputs. *) let rec eval_function f inputs = let rec clampvals vals domain = let clampval v d d' = if v < d then d else if v > d' then d' else v in match vals, domain with | [], [] -> [] | v::vs, d::d'::ds -> clampval v d d'::clampvals vs ds | _ -> raise (BadFunctionEvaluation "Domain wrong") in let clamped_inputs = clampvals inputs f.domain in let outputs = match f.func with | Calculator ops -> eval_function_calculator clamped_inputs ops | Sampled s -> eval_function_sampled f s clamped_inputs | Interpolation f -> let interp n c0 c1 i = try map2 (fun c0 c1 -> c0 +. i ** n *. (c1 -. c0)) c0 c1 with Invalid_argument _ -> raise (BadFunctionEvaluation "Interpolation") in flatten (map (interp f.n f.c0 f.c1) clamped_inputs) | Stitching s -> (* iPrintf.printf "First input to function: %f\n" (hd * clamped_inputs); *) match clamped_inputs, f.domain with | [i], [d0; d1] -> let points = [d0] @ s.bounds @ [d1] in (*i flprint "points: "; iter (Printf.printf "%f ") points; flprint "\n"; flprint "s.stitch_encode: "; iter (Printf.printf "%f ") s.stitch_encode; flprint "\n"; i*) let rec extract_subfunction points funs n = match points, funs with | p::p'::_, f::_ when i >= p && i < p' -> p, p', f, n | p::p'::_, f::_ when i = p' -> p, p', f, n | _::ps, _::fs -> extract_subfunction ps fs (n + 1) | _ -> raise (BadFunctionEvaluation "stitching: funs") in let d0', d1', f, n = extract_subfunction points s.functions 0 in (*i Printf.printf "d0 = %f, d1 = %f, n = %i\n" d0' d1' n; * i*) let encode = try let a, b, c, d = select (n + 1) points, select (n + 2) points, select (n * 2 + 1) s.stitch_encode, select (n * 2 + 2) s.stitch_encode in (* Printf.printf "a = %f, b %f, c = %f, d = %f\n" a b * c d; *) fun x -> interpolate x a b c d with Invalid_argument _ (*"select"*) -> raise (BadFunctionEvaluation "stitching: encode/domain") in eval_function f [encode i] | _ -> raise (BadFunctionEvaluation "stitching: Bad arity") in let outputs = match f.range with | None -> outputs | Some range -> clampvals outputs range in (* iter (Printf.printf "%f ") outputs; flprint "\n"; *) outputs (*i let eval_function f vals = Printf.printf "eval_function\n"; iter (Printf.printf "%f ") vals; flprint "\n"; print_function f; flprint "\n"; let vals = eval_function f vals in iter (Printf.printf "%f ") vals; flprint "\n"; vals i*) let funtype_of_function f = match f.func with | Interpolation _ -> 2 | Stitching _ -> 3 | Sampled _ -> 0 | Calculator _ -> 4 let mkreal x = Pdf.Real x let entries_of_interpolation i = ["/C0", Pdf.Array (map mkreal i.c0); "/C1", Pdf.Array (map mkreal i.c1); "/N", Pdf.Real i.n] let rec entries_of_stitching pdf i = (* Add the functions as objects. *) let numbers = map (fun f -> Pdf.Indirect (Pdf.addobj pdf (pdfobject_of_function pdf f))) i.functions in ["/Functions", Pdf.Array numbers; "/Bounds", Pdf.Array (map mkreal i.bounds); "/Encode", Pdf.Array (map mkreal i.stitch_encode)] and extra_entries_of_function pdf f = match f.func with | Interpolation i -> entries_of_interpolation i | Stitching s -> entries_of_stitching pdf s | Sampled s -> [] | Calculator c -> [] and pdfobject_of_function pdf f = let domain = Pdf.Array (map (function x -> Pdf.Real x) f.domain) in let range = match f.range with | None -> [] | Some fs -> ["/Range", Pdf.Array (map (function x -> Pdf.Real x) fs)] in Pdf.Dictionary (["/FunctionType", Pdf.Integer (funtype_of_function f); "/Domain", domain] @ range @ extra_entries_of_function pdf f) camlpdf-2.8.1/pdffun.mli000066400000000000000000000031501477056064700151340ustar00rootroot00000000000000(** Parsing and Evaluating PDF Functions. *) type calculator = | If of calculator list | IfElse of calculator list * calculator list | Bool of bool | Float of float | Int of int32 | Abs | Add | Atan | Ceiling | Cos | Cvi | Cvr | Div | Exp | Floor | Idiv | Ln | Log | Mod | Mul | Neg | Round | Sin | Sqrt | Sub | Truncate | And | Bitshift | Eq | Ge | Gt | Le | Lt | Ne | Not | Or | Xor | Copy | Exch | Pop | Dup | Index | Roll type sampled = {size : int list; order : int; encode : float list; decode : float list; bps : int; samples : int32 array} and interpolation = {c0 : float list; c1 : float list; n : float} and stitching = {functions : t list; bounds : float list; stitch_encode : float list} and pdf_fun_kind = | Interpolation of interpolation | Stitching of stitching | Sampled of sampled | Calculator of calculator list and t = {func : pdf_fun_kind; domain : float list; range : float list option} (** The type of functions. *) (** Parse a function given a document and function object. *) val parse_function : Pdf.t -> Pdf.pdfobject -> t (** Raised from [eval_function] (see below) in the case of inputs which don't match the evaluation *) exception BadFunctionEvaluation of string (** Evaluate a function given a list of inputs. *) val eval_function : t -> float list -> float list (** Flatten a function to its PDF representation *) val pdfobject_of_function : Pdf.t -> t -> Pdf.pdfobject (** Print a function to Standard Output. For debug only. *) val print_function : t -> unit camlpdf-2.8.1/pdfgenlex.ml000066400000000000000000000144641477056064700154670ustar00rootroot00000000000000(* A simple lexer, which distinguishes integers, floats and single character delimiters. Quoted strings are also distinguished, and allow escaped quotes. Any other non-whitespace-including string is returned as an [Ident]. *) open Pdfutil (* To avoid too much storage allocation (and hence garbage collection), we use the same data type for this very basic lexing module as for the main lexing in Pdfread. Eventually, we may unify this with the parsing type too. *) type t = | LexNull | LexBool of bool | LexInt of int | LexReal of float | LexString of string | LexName of string | LexLeftSquare | LexRightSquare | LexLeftDict | LexRightDict | LexStream of Pdf.stream | LexEndStream | LexObj | LexEndObj | LexR | LexComment of string | StopLexing | LexNone let string_of_token = function | LexInt i -> "Int " ^ string_of_int i | LexReal f -> "Float " ^ string_of_float f | LexString s -> "String " ^ s | LexName s -> "Ident " ^ s | LexNull -> "Nothing" | _ -> "GenLexNone" let string_of_tokens ts = fold_left (fun a b -> a ^ "\n " ^ b) "" (map string_of_token ts) let is_delimiter = function | '(' | ')' | '<' | '>' | '[' | ']' | '{' | '}' | '%' | '/' -> true | _ -> false let is_not_whitespace = function | '\000' | '\009' | '\010' | '\012' | ' ' | '\013' -> false | _ -> true let is_whitespace_or_delimiter = function | '\000' | '\009' | '\010' | '\012' | ' ' | '\013' | '(' | ')' | '<' | '>' | '[' | ']' | '{' | '}' | '%' | '/' -> true | _ -> false (* Because String.copy has been removed from OCaml. *) let string_copy s = Bytes.unsafe_to_string (Bytes.copy (Bytes.unsafe_of_string s)) let lex_item s = let len = String.length s in if len = 0 then LexNull else try match String.unsafe_get s 0 with | 'a'..'z' | 'A'..'Z' -> LexName (string_copy s) | '\"' when len >= 2 -> LexString (String.sub s 1 (len - 2)) | _ -> let rec isint s pos = pos = ~-1 || match String.unsafe_get s pos with | '.' -> false | _ -> isint s (pos - 1) in if isint s (len - 1) then begin try LexInt (int_of_string s) with _ -> begin try (* Detect malformed numbers "--2" etc. which can appear in some PDFs. *) if len > 1 && String.unsafe_get s 0 = '-' && String.unsafe_get s 1 = '-' then LexInt (int_of_string (String.sub s 1 (len - 1))) else raise Exit (* nothing we can salvage *) with _ -> LexReal (float_of_string s) (* Integer > 2^30 on 32 bit system, int_of_string would fail. *) end end else begin try LexReal (float_of_string s) with _ -> (* Detect malformed numbers "--2.5" etc. which can appear in some PDFs. *) if len > 1 && String.unsafe_get s 0 = '-' && String.unsafe_get s 1 = '-' then LexReal (float_of_string (String.sub s 1 (len - 1))) else raise Exit (* nothing we can salvage *) end with _ -> LexName (string_copy s) (* Return the string between and including the current position and before the next character satisfying a given predicate, leaving the position at the character following the last one returned. End of input is considered a delimiter, and the characters up to it are returned if it is reached. *) let rec lengthuntil i n = match i.Pdfio.input_byte () with | x when x = Pdfio.no_more -> n | x -> if is_whitespace_or_delimiter (Char.unsafe_chr x) then n else lengthuntil i (n + 1) (* Pre-built strings to prevent allocation just to do int_of_string, float_of_string etc. What we actually need is int_of_substring etc, but this will require patching OCaml. *) let strings = Array.init 17 (fun i -> Bytes.make i ' ') let getuntil i = let p = i.Pdfio.pos_in () in let l = lengthuntil i 0 in i.Pdfio.seek_in p; let s = if l <= 16 then Array.unsafe_get strings l else Bytes.create l in Pdfio.setinit_string i s 0 l; Bytes.unsafe_to_string s (* Will never be altered, but copied or discarded by get_string_inner. *) (* The same, but don't return anything. *) let rec ignoreuntil f i = match i.Pdfio.input_byte () with | x when x = Pdfio.no_more -> () | x -> if f (Char.unsafe_chr x) then Pdfio.rewind i else ignoreuntil f i (* Position on the next non-whitespace character. *) let dropwhite i = ignoreuntil is_not_whitespace i (* Get a quoted string, including the quotes. Any quotes inside must be escaped. *) let rec get_string_inner b i = match i.Pdfio.input_byte () with | x when x = Pdfio.no_more -> raise End_of_file | x when x = int_of_char '\"' -> Buffer.add_char b '\"' | x when x = int_of_char '\\' -> begin match i.Pdfio.input_byte () with | x when x = Pdfio.no_more-> raise End_of_file | x when x = int_of_char '\"' -> Buffer.add_char b '\"'; get_string_inner b i | x -> Buffer.add_char b '\\'; Buffer.add_char b (Char.unsafe_chr x); get_string_inner b i end | x -> Buffer.add_char b (Char.unsafe_chr x); get_string_inner b i let b = Buffer.create 30 let get_string i = Pdfio.nudge i; Buffer.clear b; Buffer.add_char b '\"'; get_string_inner b i; Buffer.contents b (* Repeatedly take a whitespace-or-delimiter-delimited section from the input, and scan it *) let get_section i = match Pdfio.peek_byte i with | x when x = Pdfio.no_more -> "" | _ -> dropwhite i; match Pdfio.peek_byte i with | x when x = Pdfio.no_more -> "" | x when Char.unsafe_chr x = '\"' -> get_string i | x -> let x = Char.unsafe_chr x in if is_delimiter x then (Pdfio.nudge i; string_of_char x) else getuntil i let lex_single i = lex_item (get_section i) let rec lex_inner prev i = match lex_item (get_section i) with | LexNull -> rev prev | x -> lex_inner (x::prev) i let lex = lex_inner [] let lex_string s = lex (Pdfio.input_of_string s) camlpdf-2.8.1/pdfgenlex.mli000066400000000000000000000017101477056064700156260ustar00rootroot00000000000000(** A very fast lexer for very basic tokens *) (** To avoid too much storage allocation (and hence garbage collection), we use the same data type for this very basic lexing module as for the main lexing in [Pdfread]. Eventually, we may unify this with the parsing type too. *) type t = | LexNull | LexBool of bool | LexInt of int | LexReal of float | LexString of string | LexName of string | LexLeftSquare | LexRightSquare | LexLeftDict | LexRightDict | LexStream of Pdf.stream | LexEndStream | LexObj | LexEndObj | LexR | LexComment of string | StopLexing | LexNone (** For debug only. *) val string_of_token : t -> string (** For debug only. *) val string_of_tokens : t list -> string (** Lex a single token from a [Pdfio.input]. *) val lex_single : (Pdfio.input -> t) (** Lex all the token in a [Pdfio.input]. *) val lex : (Pdfio.input -> t list) (** Lex all the tokens from a string. *) val lex_string : string -> t list camlpdf-2.8.1/pdfglyphlist.ml000066400000000000000000003171431477056064700162240ustar00rootroot00000000000000open Pdfutil let glyphlist_src = "x\001\133\189\217\150#7\146-\250\238_\145k\245\203=k\221\238\162\207\206\214\019G\149JURuI\170\233\141\017\193\b\186\130\164\1358d(\242\235\207\222\006\192`p2\251\1642E\183mp\1920\027\012\006\248\127|\250as\216\254\247'\2533{\026\030\182\159\190\221\127\188\237>\253\185?_\178\255\248\244\243\230a\191\253\244y{:\247\195\241\191?\021\2555\001\184\220\\\236k?m\223.\219\195\195\246\244\169\152\252\255\2487)\178\255@\168\159\182\219O\187\203\229\237\191\255\240\135\183\205\233rD\028\255\181a\n\255\2458\028\254\1769\031\255\240\180\253\188\221\015o\219\211\031.\031o\219\231\225t=\252\225z\236\031\135\167\237\203\241\191v\151\195^\"Z\015\167\195\230\242\223\136\240\000\222~8\254\231\211v\223\031\250\203\246\233\211s\191\221?\157\255\027\161\204\159\255/\255?\159^$\023Gdp\196+\254\207\167_\\\026\159\206\143\155\253\230\244\233\243f\127\221f\179o&\147*\207f+\252.\026\252n\030\175\151\2377\147|\189\000q\216<\158\134#\168U\001\234|\216\236\247\223\172\219\021\194\249`\147E\238\159\149\t\224\225\132,\226-\020\137{v\161\243\213l\229\129\199\143S\191\223\247\143\223L\170\229\196cO\195\229\001\005\243\142p\243\198c/\167\205g\1908\015\129v\195\240\186y\024\028\024\162\191\244\251'\001\170l\246\184q\018/\150x\238O\143\251\2377E\197\248H\\\015\207\251\237\239\020\187\176\128\138WY\212\2003[XF\016j\150\196j%\155u\150\163E\147$\026\132\158\205\1282\253u\179\152\186\199\240\130\228'\150T\142Bxz\216\187\228'hq \251\237i{\238\207\204R\021I[\188E\132\181:\151\171\b\170t|\223dy\"dl\001\160}\202\147Ex\214w\001$\249G\162}R\201\136\188?\162C\161\245\250\214Q\176u\236\223v\155o&\2294w\143\151\2258 /e\135\146\213\148\153\207\003\025o\155G\148\210\186@\224\225e8n_\201D\196\167\254\248B\169j\247\168-x\230\232\144#\198CZ\133F\248\240\220 NW!\136\167\244\207\026\016\192\199\195\230t\216\030\251\r$\170\203<\155\179\223\020\217<6\1776\155\163\1886\143\143\219\227\133\169\021Bk\226U6\183\005\146#\138\237\209\198\137\240\219\139\020\006\158X\152\200B\135P\251\254\184\213X\154l\158\020\005\130\1784\189\164\205\026\169h\150\192\187\012o\144\155\017\021\217\130\018\151\217bc\019]\129\246\197\133\184\023\210w\208\014g\238Q\163\173\179E\232W\147\005\158\183O\200\199\134e\213*\021:\209\164SH\011\144\161\180\160:G\132\190\152\243\005\148\020\159f\242\228\203\208\209iL|ygsPM\001l7\015\175\187\205\025\136)\225\249\130\028\003\020-\001T+b\127\218\158\238\190\179J\130XN#\156\219\254\133\"\007cgE*\137 \242\215\205y\020\255bN\022\187A\143A\248|9\r\175VB\201]\143&0\163\168\190\t\224q<\1464kH\147\180\003$9\024\017\234<[h;(\179%\171\190\202\150\255f\175\200\241\171\131$\192\164=\144~>A8r\187i\182\212j_\225\217W{\190\194H\180\140\021:u\132\01914\213\188\000z\0266\172G\006O\250\198Lhm\213\139l\153\244\rH\177\197\\\245v!Y\174\144\244v\143\174Q\020h\163\242\248r\218\178\247\151S\132\012\229\1328\195`\136\022\177\015\174\"iCAj;\234C\007Y\157\239\230\002\194K/\159\161[i/\135\020njo\249`j\182#\173\162\225\149\011\222\157@%\198Cx{M*h\184\011\255\172\253\006\233]O\1957\197\004:\234\234\011S\134&\130\135\208\1411z\13029DS\\sLh\178u\236\186\243lm\007\232|\149\173\1479\173Fh;$W\217\218\143\187P\221\214=\222\140E\208\022@\144\\hQ\b\1554\bD5\\O\202.\179\181\150S\147}K\209\218\236\219\249\249\183\235\230\180\253\166,1\001~\171*]\133g\140\205,\202\210=\198\233jJ\230\241\165\223D1g\217\183:\180\173\178o\181L\144\142\23409\148\168ocI,\028\161\218IN``B\161k3\188\235\244h;\223\218NO:\153\200 \227n\243du\003\188\187\195\130\238\233i\191\029\181g\138\191\219\222\232\004Sy\227\250v\185\158l7B+\2556\212\000R\233\015\182U\001Hg,\000\190Sc%\1357\147\250@\249\134\249p\229\030\181>\016T\159[\255\236R-\166s\208\",\011\180\202\254\200\138\235\178?\230\029\210\255\166\168\023ky\174\248\140N\193\231:\231\243<\251#&\242V\240<\251\227_\181\1621\192\254qso\162\195\156\252\199\205]\165\172\000\227\244t\238_l\240\002\169\185\t\021M\237\143R\255\161\183\144\021\181\152\002\241\198\138_:B+\030C\244\031u\248G`\196e\187\bZ\193\031\205\000\207\208I\169\"n\171\145U\019\208'\211\131\192\215\162\197\243\021\235\022\024\002\246\155\235\133\021\177N\016\213\"\016\240\139\150\023\154\192w,\244i\246\157]%\022\235\236\187?A~,(\190\251\197\226\171\236;U\002\150\254Y\167\028\000\161\167\020\139\236;\213>\016Y,\162\149#\226\004\159\000\026\023Q\211\248\154\236;;\171v \205\172\186\142d\152d(\233\029M\027\141\236\187\155\t\152\175K_,'\242\164}\209\211\170F\204\178\239\1827\166\007\136\150\244\215:\251\238\249\180yE_\195\200\132%\218w:G/\252\179&\012 Q;\144\173\222FEz<'C\134\254\188\027N\023\027\016\213\167\019.\218\167'l\190Q\145I\211\194\027hU\166\191\207\179\239\006[\226\016\\gF\022\230\224&\159\169<\153\001\179\017 \214F\137\142JD'$\144\218H\241\182\246w\204c\223\249\229r\142\150\254]2%\177\253|\217\245\151s2)T\001\012m\1932\155\236Ol\201\179\236O\201\218.\207\254\020\027\223\218\017\218?\177V\249S2\200u\217\159F\011\177y\246\167\164\224\016\191fg\150}\207$\231\217\247f\170\169\179\239\191\143\227\2092\251~\243\000\157\253\181Of\248\t`\223RKy6\149\137X\239\142TS2\198\nL\t\236\237M\170\134\236\219\161\127\005\244\171\139\197\233\"\251^'\180\014\207:\161\149\r\168Pn\208\148\191O\231/\178M\207\1928\241}:\215W\000\018\211\196:\251~g\179\t\157\238\251\157U\007\016c\152\140 I:\247@L\187ZB\181}\159T\nj`@)\152W\186\137\131t\005\134r8\219\206\213\016\b\0219\207\254\204\138\\d\127\230\168\007\173\240\207\127\198P\137\230\242\231\1605\148S<\031\030\158\164\164\017<\148Z\185\196s,5r\180\212rG\164\139\148\018\137\140\202\018/\249\241g-O\145\227h}\181\137\164N\197P\255\254\220\191'E\141\020~e6\192I\139\017yH\138q\150\2539)F\188\024\022\152\2327\238Y\231\r\188\172\229\181\200\254\194\242Zf\1271\r\191\201\254\226\132Z7P>\221\179.\137\215\004|\131_e\127\137\133Td\127\177S\"\230\184\191\152,C\215\249K\210\142`\130\248K\"3dP\177\240L\021GTT4\237\191\\YY\139\236\007\202\186\202~\144\186\157e?\132:\133\145\229\135P\143\208\023\127\136\245\136\197\238\015Q\196\210\017i=b\160\249!\173G\190\148d\165\018Z_h\178\031\216\192\247\219g\134\158.\179\031P\023\170\194v\217\015Ris\252&\149\134tl\165A?\250!)\000dlx\183%\132t\180D\192\012&\201e\238\159uM\000@Jh\153\253\200\018Zg?b\161\159\215\005~\181\214g\217\143a\194_\150\254Y#\000\000%\233\148\172r0\140x\240\222\244\139\232\130\138\128\026\2491\148>d\251\145\165\134\023\158\194\1560\133<\177\014*G\168\218\176L\128\208\180\208\238~\188k\001Xv\150\017\214\157\176k\255x\223\002\144F\175\025N\208\176\158\130\006\240\163\029\191\145/\204O\161\145\213\019!UuY\128\140\170\011\223\189WN\006\214\196\137\025e\004\017\201\252\172U5\007\224U\rf,Q5`\014\2501\025\159k\208\007\180;\168\164?&:\200\138\244\137\149\130IJ\030\181pg\1426B\172\n\007i\129.\028\157\020\165\1431\020\215\138\209ZU\213\149Q\207\020\017\221\141\194\131\215U\183\193\b\253cjL`kM\141\t\140\236\176}\217\248\204\241\209\014\251\158\027\230\005,\177\133>\r\215\163m\198\237\204\225\151\254\178\183zQ\187\240xPo\208J\177\183vr\150\002%\148\205\224\182\183\"\132\233\244\016F\149,\246\rG\196\253\018\188\237-\018\024]\127\244c\243\132\141Y\158uI\187\242\128V7C\1321\000I\186\137\223\006\183\234cK:\140\018\181\127\014\005\204\"\023\192\172c\170\240\130\166Wg\127\197\203(\250\191j\197T\217_c\247\005\223\014\1410\005\2525Q\154\215\160\019\181k\006\224\238\018\023\027f\127u\246m>8\133\001\166\157\191\n\132\244\251\247\147m\231e\246W[\254P\182\254z\150\160\029\031l!\144\227\179\131\231\255av\242\236\127b\022\154\236\127\146\152\192\212\240y\2467\134/\178\191%\186\231\002t\024\006\170\236oa\180\171;<\235\\\131\178\248[L\165\005\145\204*d\155\241\003\134\223\191%%\217\t\029:d=\139\164\170\b5\228H\1813Db\214(`\239\006\150\t\178\017\247\182\026\236\222\254m\220\027a\205\251\155\157\141\234U\246\183\164T\192\215R\t\207!\018\188\143\205\168\020;_\177\137\221\015Xi\023\216\030\249\137\165Xf?\173\185c7\153`y\143\241\018T\225)\024\nA\149\129\154\144\170\002\213\145\170=U\202{\141\167\n\161\218\192\147X\186\240\158\240\166!$y\146\184\164\206\020r\149\165 \021Bb\187\239\167u\017B6\228\021!$*\rT\144\026\131-\168 u\195\252\021A\234Zb\tR\215-\169 u\189$\021\164\174)g\017\164\174\231\160J\r\185\"\165!\215\1644\228\140T\144\186f\254*\149zJ*H\221P\234*H\2210\239U\144\186\022*H\221P\150*H\221P\234*\200\210\176\030\170 K#\233\005Y\026\150D\165\1780\245:\200R\243\189ZK\144\229Yk\t\178\204j-A\230\189VY\144?\237e\225\217v\017\138\1769\188\245a\200\199\004\244S\232\138MxN^h<\168=\001\021a:,\n\251q\247\206G\140\254\242h\237\001\157\131\238m\163C\186\216\211;G\232Z\148\245\155t\253\130-:\145k\"t\232{lr\129L\130\225\181t0\133\248\137}\030\249K7@[\002vq\134(v\143)\132\202J\214kH}\151\132\192\150\194O;\024\017c\016\228\168\127\017K\235\012\021\216\255\174\002\160\025$\163\006\184\195\243el\131\195\235:\150 \196\133q\233zn\150\253\204\193\162\202~\222P\137\197\020\240\1793\216!w?k\245\002\141\021\135\002\2519\150\255\212\017\169V\143\145\255\231t\252\229KI\233\206\132\214JXd?'\027\196\b~w\243w\198\128\177\n\144\250\246rN6n!\235\206\239\222wx\244S\219\130\143\212\199&P\164\228Q']\210(\014\141\019I\155I\185!?]\025B\197\255\217\142\222X\030\252\156\212\003D\176\006G,z\127\134B\242\220\139\194\014\1796\169s\207\214\218UB\\\222\007\n\217f?\159\182\2081\130\026M\012q'\249\1312\246\2439\221Y\156\003\t\021\140\248\222\183{c\242\007\243}P*\207~au\215\217/\186\028\153\249g-\015\000aq\129j\249E\023\023%\158\181\218g\142\136\011\137\185\005\180\0294\022\213\020\024\214\228\b\017\027M\031m\231\023;SW \141\166\191\136dxc\217FLS.\"\1669\152\026\204\184\rL\"\236S\205\153\157[W\157:\130\154\023\202c4yH\171\171\135\169\127\214\176\000\172J\143\229\201/a\145\176v\143A\237\195\242\239\151\209\"\129b\218E\002\020\221_\198\139\004\012\021\191$\139\132\021\232t\145\192\226\181\144-\b\148\217\141\166\002\025\173\222\216B0-\016t\226_nm\164\171\000\026U\183eH\219EP\148\170\178\179\174t\155pV\007\"\231\248\164,)\025\230\245\252qx\024\246:\128\149\026@\141\169\243<`\214\158:\031\131w\"\171B\152\200K\132\208\245\b\242\232\\\157rt\254_\198\134\228\t\177\208#\145\031\172\0276\220%\182\227\216*\194\183\206'\168\163\176~\1994\244K\178\146h\003\160M\189\202\254\206N\221d\127\143\253s\158\253\221\180\029,M\254\158,\020\n\208\137\181\003\001\252\136\131\157\156\191'U\133x\147\237\147.\251\187f\014\188\208\214\176\164\251\007\197h\179\127\004Q\187\"\251G\020i\225\b\157\169!\247?L\019\233H\154\025\002K\181\127\152,`\179\248\031\161\233\195*\249\143DD\164\169\"\181\217?)F\151\2533&\189\204\254iSZ\128\180)\205\178\127&3=\172\145\255\228\234\006V\223\127&\233 RM\167\203\254\197t\166\217\191t(]\250g\237\240\004l\173cn\249W\148j\229\136X M\246\175\216bs\166p3\220\172\129Y\209WB\235\024Qe\255\194:\192\014\174s\"\215{\195\030\162\015\005\138\158\255\175P\253\165{\012C\n\236%\255\178;\0280\207\253\203&0iA'\211#t\206\127%\165\134\"\210R\195sh0\020\224z~\232_l\001\205\1972\001M\210\012\253\192\162\236A\015G\236\229\191\218\166\189N\184&BL\1716\163\200\254\195\2406\028\134\231\225\155\146\254[\027u\196.\253\179z:\175=`\203=\247\152\245[j=\166\142\216!P\226\144\020\162W7\021\136\162[\200\200\156\182e\024y7\137\n\135\165\200\230\142#vmQ\235\149\188\180\012u\196n-\1548\"O-G]\174\231Yh\017\208\220\229Q\018x<<\160\169\231\173\131\028\133\205TG\r\t\233k\160\246\175\211d3\208H\130\206*\000&m\031A\1977b)\195\138\181\1776ep\159\1586\175\166\141\181\132|\027E9\024=\020\138\222\221\181i\025\225\1687B\016[p\185\144\209<\tZz\004Zy4.\162t\183\175\195i\139vW\210\178\187\217\198\023\144\200s\223O\184\131\255\r\196\174\029\217M\171\156\206G\149\144\176\000\228\173\243T\015d\231\156\157\0039u\138\128'\139\137\243\146\td\238\188?\003Y\184=\249@\150no;\144\149\027^\002Y\187\001.\144\141\219\132\015d\235\182\218\003\217\185\205\218@N\157+\156'\203\137\243c\011d\238\220\214\002Y\184\141\130@\150\206\006\026\200\202\249\148\005\178v\206b\129l\22023\144\173[\137\004\178s\158\129\129\156\186\173VOV\019\183\016\011$\165*4\191U\225\150\254\129,\221\178?\144\149\243\139\td\237&\233@6n\197\030\200\2149\188\005\178s\206#\129\156:\031\019O\214\019\231\140\020HJ5\209\012\214\133\243>\n\164\212\160f\176\166T\019\205`];o\145@6n\162\015d\235\246\248\003\217\185M\209@N\221v\155'\155\137[\162\0062w\027\209\129,\156\186\028\200\146\0307*US\145T\169\154\218wZOR\170R+\180\161T\165\230\183\161T\165\230\183\161T\165\198\220R\170Rcn)U\173Q\181\148\170\212\236\183,\171R\179\223\178\172J\205~+Ri\246[\145J\179\223\138T\154\253V\164\210\236\183\"\149\214o'Riit\148\170\212\250\237(U\165\217\239(U\1652w\148\170\210\236w\148\170\210\236w\148\170\210\236w\148\170\210\236w\148\170\210\252v\148\170\210\252N)U\165\249\157R\170J\243;\021\1694\191S\145J\243;\021\1694\191S\145J\243;\021\1694\191S\145J\243;\165TS\205\224\148R\213!\131\000H\150JJ\rVJR\170\186V\146R\213\141\146\148\170n\149\164Tu\167$\165\170\167JR\170z\166$\165\170\231J\138T!\131\176q\147\0129\202\165wO\214J6n\r\016H\198\220F\1461\183\154\005\020,\026\191\202,\005[kTR\176\141f_\n\182\141$\019jC\246;\012\155\136\170URb\014\249\237D\170\165\203o\129R\134\181\216e\160\164ax\226\197\199tK\194\213]\221\150l\156M3S\018\1947\190_\131d\171h\154\137\146%\201\\\201\138d\161dM\178T\178!Y)\217\146\172\149dBM\163\228\148d\235\201\138\173\162i:%E\200\169\146\020\195O.$\025\179\159/H2\170\"\bY\177*\155\162P\146Q\021\165\146\204`Q)\201\152\139ZIf\176h\148d\006\011\0212g\006\011\021\146\211tS\168\144\156\166\155b\166\164H\1652\023\"\213BI\145j\169\164H\181RR\164\210\012r\154n\202\137\146\148\170\212\252r\154nJ\205/\167\233\166\212\252r\154nJ\205/\167\233\166\212\252r\154nJ\205/\167\233\166\212\252r\154nJ\205/\167\233\166\212\252\150\"\149\230\151skS\169\144\156[\155J\133\228\220\218T*$\231\214\166R!9\1836\149\n\201\222\215T*$\219yS\169\144\236nM\165Rq2m*\149\170\0221T\170Z\196\208Z\168E\012\173\133Z\196\208Z\168E\012\173\133Z\196\208Z\224d\218\212\154AN\166M\173\025\228d\218\212\154\193V\196\b%Ys\164jf\149\146\140\170])\201\168\186FIF5\237\148d\006gA\140Z\218s;U\1469\2344\176\180\231i\174$s4\159)\201\168\150A\200Zjp\025\202\025\237\128Zh\b\220\176\022\234y\016\178a\006\235E\1682\244s\144\203\137\146\012\188\204\149lH\022J\182$\227\187\140jY)9%\169b\176\232\234e\163dN\178U\178 \217)Y\146\156*)Ri\022Z\145j\174\164H\181PR\164Z*)Ri~[\145*\020{\195)\190^i~9\138\214+\205/\167\248z\165\249\229\020_\1754\191\156\226\235\149\230\151S|\189\210\252r\138\175W\154_N\241\245J\243\203\241\185^i~9\197\215+\205\239T\164\210\252b|^\207\139H\214$C\246\177%\t\178\138$\185:\138\182\028\220\234\245DI\138\177\206\149\164\024\235\144\193\022\003\212z\174\195H\203i\162\158WJ2\191\243\200\149\134\212(\201\132\230*\006\167\137z\222)\201\132\230\173\146\204\239>\1566\143\175\219\139\248\226b\181\208\221\160\193e\030\005\199\133\172\225\158\184\243\197\151\166\183\176y\171\242)I\018EY\248\208\238m\208\"\019\205\206\226\133\137\030|\028`\002\220\246,\219\014}\226x}\218\\.\193\136G\197\234x=\127fmFcm\004\131\173/\"v\220\003\026/;@\133\190mPm\209\254\234\229D\145\016\243\178PH\"^\134\136]\028\2112\146>\146\2334B!\022*\212\001{\223\245(\012\136\232\195\161\174\159\136{\251s\029QF\232\209\"\162\018\167\135\203\b_\223<\230\243\137\221\229\254\011L\244\235\142\250\028\145 \223$\146\200\149\201\182G\252~L\193+X\020\199\000z\n\185\161}!\224\154\027\143i\142\011C'\145\174\r\003\130\127\254\248\166h\167+\0032)/k\200\140\224\154\148/\204\011/\249qM\162RD[\132/G\169\180i\030\136'\169\180:\146\015gF9\235\020AM2i\027i1\206F\158\188h\153\133c\158\182\143\151\128\205|d\018\246\182p`J\188e\219\162\245%/#\185\1752\185\187\192\163\253\030\225\1599(\020M(\129\024\204\023\221\249\130a\164h\216\243I^\223\222n\243U\025\222M\190\226\139^B\017\199\138Y\141CX\166\020\203\241\021cS\193\226\179\215\020\181\160\007\180\212\162\198\210\248!Y\226\225\173\225\129V\141\222\143\143\216\027\127\024l\243G\209\014\182\249\131\214u\007z\205oq\149\135dQ\215[\209R\176n\021\194\157\155\156\180\243H>\\\200/#p\232\159\136\020\006\177\163\176y5L\181\022\187\188\241\229<\002\182\145\181\014v\173\019b,\r\237\228X\025\196\011b\003%\146X\134\138\1780\160\147\197\"V\152.\179\157\014\147\221\220\002N\156\137\133\156\190\183\182P2)&\239K\218\171U\150tH$\178L\016\151\202<\193\\\133\205\018,I'\141\194e\018\195\189\183O-\187,^\181\225<_\138\149\131\188#M\227(5l\153\128\235\148\229\253p\242\020}\026\174P\216\029\175!\175\127zI\146\155y\236N\n%yX@\028\221,?\131,\2346\214\161\180\173.\136\160\241J.4\208\171\237\007x\241j\251\001i,\255.4u\022\254Y\210\231\204N[\191\131x\221'\214\237'\170\172S\193\206\219\015\025\146W\217#\245\1612{\180\158\130\r`3\143aM\252\168\247\244\181x\014J#q\1714::*\141\164\247\241\152w\007\242\248\196\201\251\248d\244\210.\183\184/\253\137\197\130\141\"\th\205\020d\188\157\221\248\194\227\144\143Hqxv\182d\239\tV,Z\247h\235l\225 \223D\132\194h\246\178=m\169D\227}\152\226\031\173\233\022Y\208;\233\150x\214\171\b\177Dz\028_E8\005\164\186Z\225\136x\239 \185\215\211\158\179=\018\241W\016\206\229)^AH:\014n\b\167\t\194\238\239\t\159\023\b /\209\172\202\167\254\133\198\029\150A\233\232\227shd\216\155!b\251\023\236\018\132\134\253\211\249\242A\211L\235\163\177m\019a\146\211?\208\240\030\173\1943\157\147\014\173C\b\219<<\016\219\007\001[\186\021\232\251\183).\201y|\229\218\003\011nl\t<&~\158\216.|\252\127]\174\184N\130X\142{\249\142\187pM\134\245\146n%\225\251\151+.\200\250\250\229\138,*:X\179\025\238\250\237\149g\164\164q\004\187T\209F\142Ln\202\200\1491z\163\153\006F4\151\207\002\148\198\193\230\182\027\0165\151p2\201Nf\001\t@\231\128>\006\241/\r\219\0000\147\254\198C\132f:7\185h<>\202\131\135\1999\240\177D\249=0\146\222\163\215Q\164\016Gu\217\185\127>\\\247\151\254m\015\195L\001K\134\195\208\185@M=\245\182\191\210\214\bC\138\167a\158\220\236\165m\149\024\220=\250\014m\132s\026\205\007\162\242pD\157\024\166\154\014\149\155g\182\139\023\139&\027\157\015\242]uip?\246\160\179\237\183T\222\164#S\167\223\236?o\177\014\226<\176(\028\244\132\254\136i\028\192\196\001\\&\157\028\146;D\015S\017Ck\221_\031\184\224sO\231k\127\241\194Z\200\155y\232S\242xx\196\200\028\135\028l\188?&\186\026\222\2426u\019\b\210\216\227\018\028\142\0079\218\002\227\190{<\240\196\215\230\244\193m\242\\!\1416\247\193h\0010AT\191\169\029\237TM*\244,vg1\\\230c\158\199)\148\\\214\198=Bw2\143\027)~~)\r$\021\233\241:\179\135\248\214\205\"\004\012\235\225I\136\204\152\184\151\0142#\236*wPb\022\242o\134\219\240\1728U\202\242vr\031\175\022\131\207\146\029\146\011\0079\155\143\1411a\248\248\230\196\2220tq\rAi\142/\167+\243)v\243G\030\246\185\158\184`y9\137\253\t*\020\193\211\000\130\206\230\158\152-xy\0174*O\207W\188\003\135\154\129\167y\024\155]\214\145\139\217\015\223\208\021Wi\158x\231\236\233\200\229\"';\143tA\186\136tI\186\140tE\186RZRo\215J\255yE\254$\208+^8\003\181'\144?\240\128\254\164V\250G\158\006\157ht\171\159\022\012?W\250g^\182\156\183\145\230Y\155X\024k^g(U\235H\230=W\242[!5\175\127\148\180T\150?\203\187\179@\2540c\185\230*\218\223\228e\173\131\159\190ch\205\231O\188ze\018\185.\031Zl?99\181X\127\250E\242\161\137\253\244/\169\021\173\196_$1\141\253\239\018\027K\225\237#\168\241\179i$\177\209v\166\174o!4\202gj\023\196\208\234F\203{)\163\017\156\152f\139[\190\221\021\203S\182n\166-\239\224I\188\229\157\0006bI\247m8\185\243\raP\147\006\021U/\214?^z}\137\016\138N\023\161\168\134\211\245\203\182wwa\"F(\000\219\011\213\n\154f\24024\189\015na\022\244\209\023J\212q*\224\215\019\"y\252`\001\163\021~\156\228Nm\150cNj\205\177|M\215#\016\015\129%\001\159=\171\206\1845\218T\217S\162\196\1476\198\168\006\228S\244\017\016\210\155\166\22895\241\205W\196\198&>(Q@\199\254\002\147\204[\206\196\r$1\155\005\228\1336\144I1\241\207\178s3)r\146\198\"\214\b\029\rb\164\205\242\167\225\235f\249#\t\239\163\165\146\194\237\157\185\175t\143\209\162\151\000\209\166\231alFo\220\254\182\188\252I\228N|\220\017\157\183\026`\203Q\030\227\012\239\129\216(\177c(\136V-S\143\128\223\209\162\201\193\217\024\138v\154\187\000\190\020\027\031\193\022\011\233\016G\155+\022\2506f\027\133\216\193\159\216\223\167\0143e\017\1961%\025\018\128\209\254\245\170\127\217\rW\148K\017 \186\2188\239\027\206\169s\135b\178\026P\254o\187\222[\014\202\162\2409\213!\031\182n\031Gb \245\152\025\240C\185\134\204\181>\017\205Y\183V\192\171Ok\255J\184\027\171\245\137\235xWLZ\031$8@\147\028\159\005\224[wn\029A\225Z7\188.\146\137s?\218\224\235pD)\218K\007\004\012'\255A\216\175\196`\139\025\138\216\193\217)\161Vl\229\1471\177\173\204<\162\005\177\n\128\214q\225\017\2058\223\217\247o\236t\005\157\202\003\165\011\027\216>\017M\212\001\202@\232\183h\218\128\232\183hP\000\246[4\176\176n\015O\162\140\208\\\233\158\237\202\t\r4\209+\248\254\027'\128\243\248\014\14299\151\143\243V\138\000\225\018Ov\200fg\012\172\230\176\197\229\211-\253\179M\183 v\239\1629\006\150o\224\204\249`\147`\146\163\143\226\016\026\223)\143\2029\186\236\200\023)\183\241\0119\232eC\172a$\228n\167-\1525>>\238\135\1793\150\205\028\016\191\025\131I?\1334l\189J\025A!F\001\132\198\128\189\137\173^\180\133U\2546\189\213\n\139\004\231l\137q\202?&\221\206c\170S5\1586\029fA\168\255\140u\251\145\249.\026T\235\201\150\029\222\177\165\\A\"\155\185.\1466\020R\182{\145\156\197\239\127\242\007\005H\211[\209\149|\240\250D\215\144\024Na\128\132V\234\232\155I[\002\006\001\246\195\240\198\171\217f\004\169\027^\140\164\028=o\028p[\143\217\158?\198\018k,\163\190\136\211\254\019\143/P.\163m\1610\221\n\171\229\131\153\142:\210ZkxK>U\180FY\234\173/K\255\172S\026L\221\179\029\027\022\030s6\213RI\186wO\184\149\022i\189S?\128\201\162\"\128z~\134\000\150j\244\029\144\017\017\171/\183v\229xj\190\241\180\022\2025\188\169\132\177\031|\154\018p*t\014#\20335\213&{Vk\195\n\207f*\016\026\017\028w\219\158\214!\216U\158\185\182\1386\180\149\003\018+\156\199\018[\219<{\182\246\153.{\142\170c\157='_\156Zg\207\198\231\021\157\2379\209\134\208\157\158\199N\1760[=\223:\193\194\162\243|\227\244\nM\245\217\154\030\144:\230\014J\194c\223\207\2164\153O\248\219\243\001\017<\239\249\128\151\004\1280\253s\162\218@\027\241\144j6\133\":\233Afz\131n\195T\192 \251=\230\241\225w\2312\232H\2500:\247E\201\223\235\230\217\029\004\014T\180\161\143\177hF\143\156hV\141X4$\207\156\1778e\152WR\182\026{g\206\162\155\224\163\183<\023\214P\021\158\161\011\030\148]\145}\226P\202\235\188\241|\165\141\007\022K>\197rt\180\169\223\153\000\177~KC\223\171\223\165\240C\253\186\183mu\006$V\167C\210\234\172<\022\171\211!\247\170\211Id\171\211\133M\170\211A\247L\160\173plE\187\176Z\209.@\172\232y\160CE\187\240Z\209N\030[\209.@:f.\021\211A3\143\144\142\154\181\195|\027\241\017\237F\189\025\018\169\130\137H\1763\194\189c\158\236\169H\029\0319\247\151\025O\017b)\251b]\228H\134\003\1335\158\131\183\028\241x\182y\182&\153\154\2331\181\190\240Po2\225\204\167\021\209t\194\153O\025\179u\189k\133\142\158w\164\173\026\183\000mU8\210\238K\135\243\210=\238\017\147W \176`\242\160\185\131\1275\001\148~\255p\158\2175\004\172I/jjB\246T}\128,\230s\136\1369N\211\141#\226\231\016\017\199\232s\136\b\239?\135\152\203S\228\128N\246\n\016\210\1540`\014~\177\011\2149\233\225\192\029\174\228\016V\205x`\159\217\185\152\163\002\184\240\184\"\235\210#\135\235oOf\023v\186$\142\198\202\147\132\1884uM\026\017~\240\206\2434\210Ud\197xQ\197\208~\189\r\028K\186\151\196\233\178#m?\243\216\022\130\248\134%l\219\022<\016\027\131\000\246\254\128\153\003F7\b\172\028zs\135\192\218\225c\157\007\237\225k\223\154\172\201\186\253\164\0243v\231[\147(\255]\220\156\154\te\021F\"n\225\2150M\243\137BDh7\023\160%\190\216\205\133\025i\171K\179YcCp\239n`\145\199\168\253$@T}<\028\181\b\000\233\182\003\"\221\195\136\189\137_\174\208+CW\129\133\r\1457j\207\149\005\204\215/\160\204\025\134?+;\177\152Y\168\177|o\025\254\165\252\030\207\246\227D\132 j1\203oa\147$\182\000_\2267>\0176\153E\209\195\237\030\bF\213\023\187\007\130\237\180\023\029N\011>G\215Bt\178\019\175\151t\198\1596\011\230KV5\031\173Y\191\201\236F\177\015\016n\206\244dhF\165#\227\205\153+\007$r\251w\204m\154D\182t\186\228T\190\nD\024*\160\020Yd8q{\003\248r\030\240d\138\212\247\135\147\154\016\152\205\182\140\012\031C\219*\244\217\164\167\168\026( \129\030\162\197:\244%~$\021\028\187aQ#+W.\000\014C8\011\002S\130B\193\231k\238\176s\127|\241\231\204'\2294B~s\148~\158/v\251c\206\216O\155C\220`\226(\243\017\247\199\167\025\215\239X\214\239\238\127tuJF\234P\129\166k\199\1899\131\220\245\231.\179xb\148\129\236]\183\142\1427\234\1466\135\029\151$Gn \005\177\241\1687+\005\141\251?k\210\1631\016{\188\024\025/f\151m\150\237\018\015\166\181\161\173\153\164c\192=tIk\205\167p\188\166D\165\205\029\144z\169\020\249'qK\137,\187*v\220\133\227\166\011k\199Z\025\214\237\139s\199M.B\201\021{\221\156O\163\248\208\204\018\238m\148>W\231\235\235u\196\170Y\242\244\233\149\133\234\137\150\021\022\232\205'w+\022\214\233m\024\228\018\003\236\207=\200\185\249\249\"\192\238\212Q\192\023\020)\182D\190l\188\191\230\133\161\229f\167\004)\202\027\228y\140D\2237\139\030\253e\007\247x\020\006\189\248>\019mb{\195\2095\181\180v\005\242\135\027\168\232n\160\178\186\129b\002\t<\022:a\222H\157pS\177=+\248{\205sC\203\133Y\tRTc\164\156\140\145\024\183E\199\002[\222\141\188\150\153\138\011\142\255\136s\155\217m0l\179\237\210o:\163G\152o:c8\137\218k\235\136\248M\231:\219\217o:\131\159|\211\185\020ZcFhq]C\155\231^.\247\145j\247\152\248\241\027L}8 \2546j.\149RQm!\182\1873\192Z+XKR\245\026y\195\r\141\246\181\245|\214Z\206\229}\208\241\015k\207\221\216l\230\176\175\220\1834\159\213)w|\020|>\0191\194h<\018\164\179\134\017\200\177E\197\197Q\163e\164\246$^g\232d _\146q\189$\247\182\151\r\192\163j\173,\191\211\213L\019\156\149\156\031+Y\198S\020dx\169q\143\246+h\168\190~{\189=W4\247\248\232\240\140\135\199'r\150\014\142'rV\014\024\157\200a0[\170\024\151\146\019\234\150N\n\132\201:GW\232}\242\152W\134(rK<\025\"\246N\015\140\251\186\135o\186\185\199\211\030\0140\185\230\031\229\153\232~\168P{\166\165\197\164\001\029\246\205\027\006\216\237\147\019\202\164m\246-\157d\031\165\233\253v\169\139\2401\159\026\162h\012Q\022\134\136\162{`\156}\015\223d\223\227i\246\t\030\135\215\22158*\021\020\204o\232\007\157y*\208\163%\222h\b\128\002\246%\245\243\204\133\169\135\143,\171 +\250\213W\164\237\167\232\167B\127\025x\180\201\187]\214\132\252\169L6\211\225r~\227\205Krw\005+Fn\174\224\161\169\157\174\0270x\218\190\128\234\210{P8D&\199hI\247\189\185\200\n\182\129]r\176\1826tR}\024\012\146\143\011\021\176+'\223\022r\133\005\161?\211\158\136x>\222v\220\233\228\213\132\238\217zw\005~\178\017\019\002\170R_\006\192\236\1485\030\227w\180\n\030w\233\169OO\179^]\128\150|6Z\210:3\151\018vmf\2535\n\146\2228\003A{\253~\020\226\141\019Z\151\245\169\195\205*\179\223E\169\155\172\183^.\016&X\015\197\025\201GT\022\221:r`,\223F\198<3\006G\186\220bU\176\r\134\199rm\185d+g\150pP*&R\204)\150\201\205c\186\0186\t*G\197J\158\151\025\163\178\234\193\198e\149r\184\237\127\185\238\229\208\136\138\209\166aN\220[\137r\148\150+%\162&\213$g\2429c4\248s\204\2492\225\255\254\184\221s\173\168QO\019\2543wX\177\154\012oc\213j\185\152pa\022\221\236\227\219\205]\190&>b\159T\172\"\169\174\221\230s\020\184H8\208\191c1$\005\217\243\000c\248\236\b+ \169\172=\134\163S\148\179\187\225iz)\011U\022\211K*\133\227\146r\146\140q\218\127\164\127\184\178\167)\251\018\139\004\131\165e\r\177\t\020IK\219\132\028\029S\"}\227\152\137\026\188q\171Cq\246\227\207\234\177\031\223\189wwb\241\224B\146\128\214\135\004\140_\233\129\141~h\237\223UvWE\135.\223Gg\022\188#7\207\021K\148\232\254\250\017\015X\128V\0079N\005\183\223E,3\185\175\019\219\160\247\238\234\172\133=\250\196\021\154^\162\135\163\000\142\024\131\130\251\031\134\236\163\236\129\241|?,\168x\180\006|Ha\142\006E\234a\224!\002\158\226\200#vIiw\005M\1734M\242\b0\137\128\161a\247\246{~EA\017/}\188\021\149Q|\014\023\179\240\022\022\144\234\192\190d\232\207\188\207i\027os\234\237\135\226\177\225\212\171\227\028\187\226\224\\\162\166\242d\190\239\b\211\149E\130w\020\135\007\192\178aG\237\215\189\167\190S\136P\149f4\128\147m\172\172\249\027\023\175\210c\182\229\140\177\196\197\011\025>c\011\203\238\249BR\221J\016\190\209d14\005%\192$;5\176=R@\216\127'\146\005\159x|qDNn8D\128\171U\129\209^\238}.m\157\221\244\165\210b\214\128\012\252\011\204,\231\196}\163\014\160\030V3\2046\251\149\170\249,\2515\185;%\007mv\241\022 \195\150\029\159\237\142\157\163\227\134\029h\235k=\201~\r\250\250\154\207\170\175O\029\161\006(\012\198\191\162\139\158\177g\227\2074\160\148\127\245\1990\180~\234u\150n`u\160\183\135h\155]\b=\186\018p%\224\205\157\128k\129\199vqHi\012MS&\176\027\157I\155g\191&\187\156K\210\161\128\132\176%\228\129XD\004\210\171[\016!zM\201\163\254\191&#\012*F;\004\n\200\174\"\139\140\215\132bT\193\204\1769\239^\251\196\2432'\028%\172A\250\t\180$\203\014\2273\208w?C8\023\134\203\021#\016\231+\130\209\023\000\0290q\195\154gw<\176\004\0289\1681Q\227\144%An\252\213\004\029\239\221.\b\166w\027.\001\217\018\175\133\142\005N\218\142\026\140w\236\030\\\001\179\163\200\220\208\201\004\212\128\241\246&\163\222\204=\166\2475\162\153\003\253\216\014\215\227\001z\192Ag\1716W\198\027\173Vo\209\142\213U\145EN|\167S\198\249\140\253\134\017w\n.6\226z3\192\179,\206\187\254i\131\005\255\016\235iba4\176\158#\147\187B:\r3\026M\215,\187xM\022\229\180\251(\245$\187\217:\145\234\184\221A_g\140\150\213\128\233v/\238H\167\215\164d\025\215W/)B7z\181\198\238U\246\154\\\2245%\237\1896\248\172^\027X\248\190\198a\007U\150:i\144m\020G\168!\175\169{eE\192\236M\162\022\019\215\012K'\217\129\020\233\133\159(\129\027\135\2285\154\019[\206\017\027jO\204h\014\005\2385\025]\026\210v\166\168\t\132\142)\\\219\248=\016[\191\000f\031q%\244h#\209\005\186\217Il\005\030\015\145\148\208\250\1402T\244\130\152\ne\189 \136\160\225\190\222\154\127;\229\140tme\140\181\237Y`D}{\030\160\145\198\205\1600#\234\213\141X\206\n0\232\173R\181\003\174\155p\166dR:\228=\190T\0179\\\245\212\tSs\215LM\153/\232\143\175\246\230*\022\164q\243@\235H\148y\180\226D\205\181t\210zP\166\253i\024oT\215\130\030\182\216\24776{V1\224HC\230\030\131\198\235\184\188\155U`\140\138*\224\227\240\019\143kas\246\016d\020A\bx\238\135s\012\140\210L\167k\012\222\214\178\141I\255\213\156lE\165\143\239xB\206\146\t\017\165\127{\199\019\2345\241\225(I\155\207+@8dYk4\0232\246\224\210\208I\029\160\001\r\024rb\185\162\152\006\012\248&G\029#cv\207\023^\018\128\253_\247\153r\180\23759\1951\028:\230T\169sy\195\231\152\001$t\182\1398\014\021\151(?\169`0\1342\243j\r\1980\157\190Z\243\240\204\210InP\186\1595\2069\168\247H\1732\0303i\022\217\222z1\020 \189? \180\132\189:.\016\183z\167\163\227:\137\244\171\244\138\143\205\016\\N\235\140\135\003n>\127\178^\004\252k\2239Yw\183!\198{o\171u\155\004\186\243\213\147\245\2366\196m4\211\016\232\1505\015\172\175}\249\004c\249M\136\219h\\9\232dY\145|x\018}b\238\159\2131f*\b\235\157\031\184\146\199\168k%@\212\182<\028u\171\000\132+Y\022\238\222\149\b\234\r9\158\245In\198\025\243M\132wC\141\249d\141\148\190\021\177\219if\177\144\170\185Q\255\214D\239h\238\139\133D\254z/&)0\145f7.\250\229\154\237r\172\239\175&\014\220\222\017l\217u\129y\147\208\"p\238--\150\235O\136\185\250$\203\t\031\238\222\252j\1941\165\211\139\250\206\215\176}\237\2216\255\020\165\131\214*^SH\213*A \131\210\003\187\233\222(=\228\168\2103wDz\202\024v\251\253H\021\194K\206_\021\170\224\222\250\171zZ_m#\169\158u0\007\209\182-\247\177\216\203\222f\002\143\143\185#\187\244\030\155\240P\016\159\212m\172\138\228p\n\014m\176g\206\004O|\212\220\155c\007\181\194\163\241]\168\236\002Y\2394\007\233.\022S\149\227C\152!yi\162\191@\001)${\135\012\128b\195\232\235\190\236\188O\143\128\179zh\203b\251L\231=\000\252z=f\162}\028FK\018v\028%`gG\212\155\t\142\228\246\159\007(\189\253\163q\201\207#\026\252\236\rt\199\162\176*\239\176\195\171\2249\183Xo\199(\176\190LN\029V\200b\156Y\177\005\135\162\218q\171\201\239\212\130=\188P\129w\023\138a\239\206\211\199A\220\248\022\134V\031\205\130w\234z\\\174\030+\208<\134}\188\236\179\192\1609p\143u\146cZ\r\023\232\200^\148\\\173\179^\193|\146\222\171S\004\154G\140\144\006\130\160\230\134/(\0079\231\130\246\164\1791\132\244\031X\200\177W\1607\156\243d\237\222Z\131\144\198E/\233@)\135O1\021hM75\195\198\147V\204$\"\247\234\165\200\190Z-`\253\030\011\189\204x\224\014\r\241`\239hYe\193\224I\029\192=\219{\158s\143\249]\224\202\147\209\203t\233\145\228\234\221\146\1607\0280\214p\t\012S\179w\1928:^\001C\154J\1899\2198\171\020K\239\145\018\220l\129\243]n\217a\208x\167s\158\140\031,\233u\135\165}\202;\233\129p0+\203\012z\199\220\130\241\214y\255\n\243\215o_\211TPu\001\181\241ws\007\135\152;G\142\227\196\158\tph?\180\031X\1882x\248\218\006k\165\135\193\011\139\016\027t\026\225\144Z+\016\166\218T\212u\132\019YW\030\015\175O=}#\237R\024\024\170\210\130.\"\156\148q\238\241\016\239\204\2117%;!\227cs\024\180\188\026 \214\145ae\232\196\145\129yr'\016)\197\241\252a}4X\014\191\025\219\209\156\209\156\206!4F~\191\234\137\r\140\241EK\001\170\220\206\161\136/\222\141\181D\029\197y\019\205`\180\028A\243\179nqU.t\024\176\161\226\031\1725\018:\239\225\198\026\137~~G\161X\173\220\187c\237\164\242\232\173\006\178\204#k\252Q\0186\205\209\026\017\163\223\193\2181:\190\222\127I=\199P\148\214\182\177\202\rmk\136\173\195\157f\228\027\135\168\147\0262j\164\002F\245\144\164\1575[\230\145\166\160Xa\181G^\183\207\152[\"\222$x:\138\004^\138\"&\239\149\006\243\219\193\174\204\145\005\153\233\204\181@\201NA-|\153\181\230h#4\229\221\152/\n\143\143\140\023\030\030/\166\171,5\b\178\245\016xC\019\183\203f\024\194<\158,\177\253\235\169\t\016\250\138\160I\004X>\030\018\0078\210\182\231Y:\169W\166|\148\027\168%\019x\180\238R\158\027:\b\1573\004\2407\021\181\142\242WXc\242$I\167O\188\138\231S\255\144x\026r\232\000\024i\012Q\156\229\247\219\023]\237\178(\140\129\000\233\141{$RI\244\0194\243\027\003\001l\143\007k \232\n\210\198@\128\138\176\022\001v\209\187\022\001N\023C\148g\ty\134\131\234>\140\133\026M\020\174M\016#5\250\167j\031\242\028Y\152db\012P\t\015V\003AF\162\235\024\136+['Z\2345\015\015f\160C.\174\143\187\168\007C\151#\224\143m\192\146v\184>\199\208\024\236\174\193\134=\023\"\242P\168\214\230\208\161V\172\205ae\233\164\188P$WS\127\020\208\223\128>\153\176\189\\\205\tVJw4\030\234\172Z\002i\135&x\246\n\164\248\019\207, \023\r4\146Q`\207\024\021\221\181\221\252@\154@\220\251{\011\024\011\208\1485\203\203XHP\185Wc\"A\145|>l_b\249b\137{0\193\145\155\247\148\143\232\205\251\203\140\170\025\250\235\209jm\029I,\217\228\000\2091X[`\0218\170\170\197 V\213rtT\181H\219\211\030\179\236\152\156\227\176t2\205\214`\232\231/\153\234\020@\172\244<\1797\185L\230 ]/\131\1309\201\142a\225\137\185\230\024\023\158\152\228\227\185\214\229\210\017\233\194\019\026\2171]x\242\165dZ\173\133\214\023P2\201m\137\1366\185\030\209\210I\014!\218\246\029\234\255oN\157v\031B?\154F\015Q\146\019\176S\210\193\180.\1325\173{ \154\214\t`\196\n:\026\171\208n\019\151\153\220B\227\1420q\1828\142W\147-\130\208Y\228\198P\187\246\248h\014\240p\250]\002XQ=\154\198\145;8u\153.\027\135F\160r\192x\022\194V\184\199\019\t|\164i\208\214\129\151\254u{\189D\152I\217zCi'\023(Z:\1697\190(\246\018\171?\179\248=\0264JT<\151\127\019\158\251\226S<3\238h\179\186Z\011\016\143\\w\134\190w\137W!\252\176\000so\219\163\235\001\137G\215\029\146\030]\159z,\030]w\200\189\163\235N\"{t\221\133Ml\030\014\178\007\212\029\162\007\212\023\142\2123\227\147@\135\003\234.\188\030Pw\169\218\003\234.@z_Y\161\152\030Po\"\164\137\205\028\230wJ\016\145XC Rj\rA0\187\005VF2\153\014j/\196\226!\193\195\209W\137\172\127\146\143\249\185\bY&\151\160b\173\002a\163\146$y}\240~\191\021W\176F\128\019\175\157\148\011c;\tq\190>\184;\213`7\016\018\179#TH\002\185\003\216\169]\b\150\221\187]R!J\213/!\163Qr\240\174\237\236\200o\248z\235\026\172+\149?\020jr}(\2024\185>\212\210IKo\201\184\216\029\164\133C\130\t\211\147\214\230\169P\220>\"tx\224\136\245\"\135\019JC'\135\017,C?D\178\206\220\197\030\206;\202+\180Xc\026T\190\155\168\172\218\177\006\026\252Pnr\007\0154Z<\232\186\1822dt;\0170^\174\003\210\168\131\136\213(\127\232\r\031V\207X\145\014z\134\016V\207\240@\2123V\217@\221q\157\r\225\004\005\006\205!\238:\023\203l\192f\193\201\173\153\234@Xw\199i\000\2399\207\206\193\140\194!j\235\194E\166?~\129\205\198!\185\1345\207\003`\229W\240\198\011tz\195\177\174\160\194\245\135;\n<\171\030\185r\132\030\238XW\022\b\006\202enQ\163@.\167\150\017\238D\132\029u\184\127o*\198\162\225\246\222T\172W\172+$\204\026\003\175\139\247*{\157\011\169\007LP#\161\140\144\142qj\198.\225p\175\014\016\187u`\198\251\018-^6\215O\206\178\224}\201\131\251\238\217/\206\187l\b\254\197\216\232\026l} \142\196\165\005\217\179;\200\1364q0^\147>\177\022f\185{\212\018\158;\218\b\186*\029\164\165\186ttR\158>\198P\146+F\155\028U\146\226\227E\204\152\133\135\027\239c\188nw\184g\217\253\237zd+\150\020\138\211\154\000!\184\250\003Cm\028\210\0113Y\202\233\133\153\148\231\016\127\016\\(\024\144\185 \231\199\225\180u{\127\195\189C\025s\003\135\242\183\152\157\135\231\217\027?[6\201\2226\155\195[T\030;Ax\150+\250D\021\bl\215X3\144aT\173\241\028\150O\196_\182r\243g\145cB %W^`r\127K\214a\018\210,\195H[cv\014\026\027KX\014\132M\168\130\209Y\2516\131\248\179\192\226\164?\2504ME6\246\173\019?\232\005372\1963^$\204\225\132\r\189\201\172\218\206\220\157\182G\127A\r\230_%\211\163\251\203r\021Y\242}atV\005\2207\140\023\017\176\227\148\t\151(\190&-\213{\167\0063\n\190\137\194}\001y\030\001{\241\178\207M\184[\167\152\026z\156\159\181\225\185\015&w\006qgUZ\131\216,\173\012\158\228\201&\168\153\154Y\208\228\202\198\226\190\183\220\024\196\230Kp\1744\159\250gY\255\021\000\206\219xb_\234\253\156\220\170KQ\162A\158\148\191\127\165u\143yn\137'C\020\027C\196-J\015\140O\197{\248\230T\188\199\211S\241\004\191\152P\208\205\222\172}\022\025\141\n3j\200\026T\161\r\185\155C\209\242\147\019p\b\023/\227\168*\165\226\"\135\216\246K\220\165)\209~\156\223\2198d\tFt3f\021\165\135\028f\153\189\176\148\241\142\206U\136\148c\227\196\188\238\004\141\253_\226\025]*\200\214\159\220y\193@w/x\1551\145\244\248\000%=\249\015\020\179W;\"j\029\179\000%\237U\003\170\019\145\132\163\"\128hV\254\217\170\221S\143\185\169\128\170!w\022\029\150\204Z\185\007\237i\252\0160\145!\164\162\253\165\b\128\2173\234\004;\163\165@\018Y\245z\135T\t\140\137\255\169\127\228\183I\2099f\146)z\t\156\197\127\007\019\019\1283\239\189.xw\246\1551\157#\183\2017\130\230\164\195h/\132\029\212=\016Gu\002=\181\213\134\015\162O\215\153?\023q\179\207:S\206h\167U\025c\219\247\"\027\159\177\192\236\237\161\145E[\130\134\019i\176\135\130\130Y.\216\226JI\"=\226!\146:\031\240\153<\190\197/\021c\173.\192U\023\2319\019\024\206\027\222\159\031\2201\160\146\190I\238\249\011\153nr\\z|\148_\015\167\246\127X{<\154\150A\237\224\145\0077l\185\233\022r\229\129Q\177\248\183eB\028\197P\025\150\198b\192\209>@\235\163\186\176\248/\177F\176.r\248(83i;\141B\163\176\142\225\175\255w\208D\161QXa\132\239\188:\168Vh\020\022\012\029T\023\153o\141\193\201\005\005\021\242Ba\2299\239,U\212\150*sK\197\214\027\144q\239\t\248M'\b\140\180\019\016\229E>\226m\140ED\160td\202-\022\191\007\178R\212\127\002d\190N\144\240y\015\003\2356M|71\220\197\144\225e\145\199\251\002a\250/\148z\216\156\229+\172+E\252\173\177\249B\145d\162\143\175\202\172\197\233p\149B:\145\149\252\146z`\133\155g\003\020\146\233\"if\192|\238\224{P\136hj\232\163s\213\017@.\186\r\249\154\025\140\166\160\162\181@\146\1796\163\189\017\170\224)9\247\191\000mv\239& \195\246F\157\233\166OI\252\201ox\"UO8K\134\132\027\185\193\173F\152q\132[\147\021\201e\198\165\025\155\216:3\1394O\219}\195I\150\222\205A\218\186\168MA[\0235K'^\006(\138\141l\bbn\020\019\1661\254\230\224y/\209[&S<\156\221N\t\157;\229>\b*\023Mf\191\177\132=\197S\216\213\1942\245\020}\165\176\222\141\223R\192\158\200)\245\138\"\219\236(aR9%k\250\169\208a\031\006\246\245\211\205\153\156\026\229\185\197\026\146\159\127\018\133\014\250\214\156\016*+*L\141\"QaB\218\219\023~`\199\173SY\133\158\230&\000+\186\139\136l\t\192\166\143\166`,\000\176\148\159\210\163\212\019\002\163\131\199\140\216\214\219\130\244\199V\252x\237A\1852\255\180^\173K\252\175[}\146ss\167\196Uya\232\164~)\148\156n\019\137\207\187\241\180\234\208t^\237\220\204\1532\226x=f\235\204\209\185\1853e\140\222\243\236\b::L\174\157\155C\021\027\189\2379az\237\220,\170\216(\180\227\164\217j#6\n\2378q\138\237\220D\026\193Qx\207\210I\182sSi\004G\225\029+-\172&b\163\208\158\019&\218\206\205\167\138\141B;\142N\181\157\155Q\021\027\133&\199\r\182\206\216_\240\022;@\189Q\233Z\007\208)vc\234\203\225\230P\147\028^:\241\011:\193\209|\021Is\r=\140\201'k0\193\194\235\020\015\205\147\024\184\252\200\249\224\226Y\186\199\232\012=\183\128\189\011\164&ct\r\133D\0043(\223\240kY\b\134\245\246\254\198\216\144{|dl\240\240\216\172P:xt\019\235\196\161\227\227\2263\011\167N\131S\207\210\176\030H\157\2289^\017\189qO\\\004<\177Zx\225\198\198\031\232\004\014O,\031\229\194\160i\236>\213\2448\251\210\129c;F\233\203u\236\254\232\243\142\156\159\250\145\023f\195\168hY\151\169Z\246\204\156-{tLr\234\225S\031Br\"\180\214\145\142\169\216\129\208\210\201@\136\238\218\211\139\142g)\249d=\251kA\252^\148c\243]\239\185*iF\196jt\211\132cE_$\156h\243,\150\165r\252nC1_\165\144=\1836MY6\162\130\172\212W g\228\151\228\228\011VY'\2354X#7\254\156\001;\213B\169\216\209P\002\201:\r\t%\231\007P{\201y\001K'e\142f\004Q\244\132\000\132S\029\031\239Xe\011\027\226\167\168a\229$\236\021\026\228\218k\137r\161G\247\0181\202\219\019\162\147\136\134\237z\003\217-x\003\223\219B\172\238\176\195V\226=\158\221R\004\223n\187B\252K8e;E\178\177\232\167\129\176\227\027\222N\206\031\160X\147\243\007\150N\202\031\177!\026\209}\140\230V84\205\222\186$\218\243\171\221\r\199f=\220\137\196o\015w\206\179Q\153N\"bo\220\139\232\189\018-\179\175\022\232\029\150-\2072\163\169\018\166\210\179U\216\187\236\172\n\251\220?[\157\017&\225\243\230)\234TB\250&\199w\159R\229\012&)~?ndK\1543\230\167\145-i\190\000h\245\243N\232\168\159\147\182wt0i{\t\135\165\019\175\030\166\006}\025\127\177-\129\020?v\216\249\022\232\016O\246S\208\195\246U\180\156\220?GsJ\138D\213/\224Q; \130%Q\232\176e\225\232\224\147Qy~\127\224\223\189^)\130\230\031\241k\252\204Z\233\224C\136\206\211\129\156\b\169\145;\178\239\237\233\204\198c\225\149\218\2096\136\135B\b'\138\158\251t9\184n\183\246\149.\128\225\165\214\0036P\192B\024'\138\238\139\2488\148\158fg\187\234\001\025V=\216\207r\207ISD\244f)\180\006\181{\223\2083e\234\030\237\197\157\030\186\2276\183\156;V\248\188.\026B\\R\021\142\208;\230\160e\157\1475VA1\019\169r\161\195T\001]G\201$\024^\219\162y\239\247v\166B\023\216>\014n\223\172\244\207\163\143\179\205\178p7\227\132\251i\231\237\214|\218\170\020z\212\005\011\001o\250\160\011;\238\132\168\251\240\017\139\198=\230\165%\158\rQ<\026\"\174\179=06\016y\248\198>\228q\187{^dw>Z\193p\201n\240\146\128\025\015P\143\201\181Z\150N\198\131\021\024\135\254q\216;\227\211<\146\209\250d\192\196Xdp\2212\173\004\251<\244h\141\156'\188\000\211\197\029<\153[\208d\183\246n\205\162\200F\1741\172\164\207r\193:;\024\031\227\166\178\007\204<\189tHt\192k,p\239\140\202\196\005\b\179\186\143\192|@s\229\016;\199/\003\020\029\237<\148\186\218\181\001\140\254u\030\186\231a\231E\181\142\030>tR\254\030\179\238t\030R\135\186\153\167\213\165n\165@p\170\243\175\168\027\157O\220\238\192\249 \233!\150I\004\245\020Ke0=\198\210y\208;\226!\178\231\139\222\149\015\197\237\188K\172f-\0013\0117\164\237\133m\029\001\222\b\164\215\230\229\030\177\159GZ/\154\004\142w\234\173\023\172I\225\216\207\"\225\133\137\133\237%|\181\255$\146c\219K\251\240Va\225$\153u\166\247[\184@<\133!JZ\233\200\189\179H\242\250\011\1619\002]\015&\188S&\164\b\172:\224\129\168\015\b\176\199R~o>\"\"\169\216Y\004s\219\2381-L\012\189\187d\216\172\0280\0267\027\135\222\012\156\173\195\199#'\171\200^iGAxl\208\029\025t\207^\204\128\136]b>q\143\016\213R\150(\nKl\r\017\135G\015\140G]\015\223\140\186\030O\135X\130IQq\012\221\241\230c\205\021\155n/\231\027\166\242\020U$KG\005\201\162\242\004{\199z^,na}'e\234+\203\0274\190\225yCl\007\139\\\160\168\1519A\140\b3\011\196\168<\172\193\230\134\142\161\136:}\001\155\197\208\172\229c\162T\169\249HW\148\133\135\165M\025z\127=n`OO\r-\228\217\153\012-\204.\200\231\150Nf2\148T\191\191\154o\199,\029\144\028x\022\240\208;\255\028\170\024\163\146b\234\195\249\198\164S9xd\209q\232\200{d\229\193\212\202\211d\247\160}\167\238\238\211\016Lg\200R\017\157\031[\129\252\236\136\180\188\015w\177v\143\201N\0191wx\179\245\143V\145\134\129$\185n\028\237+1\188 q\238\006\159M/Y\b\150\206\199\220Q\029}w\015\245\151\220\t\201P\182WZ:\233\149\144r\216\247OW\145U|\1737\031^\193\239\002K\220\217S\030\202\132F'uIFA\162\255\197\139\177\248\2389\172\202`,\000\021\237B\200\182?\023ZL\220\163my\030|\146\157`\255\152|f\205`\250\153\181*;\171\169\t=\\tR\187X\153{\236\241\145\023`T\129:\240\220\236\210Sa\211K\238\229\134~\241\184\227\215\0141\217\207\166>D\252E\2390\212Kb\210iI\007\181J\b\171V\t\192OR\216\017\157\2116\209\212\228L;\001\209\244c\021\216\147\019tl\183/\028\156\142\236\141\143b\228?X:4\157\025\026\007\142\198vv!k\007D2\238T\004?G\206\146\240Tr\007\025jQ\206p\220v\200\198s\238\244G\136j<\194\220\1799\248\011\179\185\195\226\193\\\014\210\241\144-g\177\235\227\142j5\029\211H\217\225\004E\156|S\214\210\201p\178\204\210\175\135\214\020\134\218\189\243D\195&\203\249\202\203H8\181'\014k\129\178B\207\0215b\163\rD\1592\152\145\207\031\195\245}\147\220\235\180\200\232\219\012\165\192\030\206\157\145||uG2\nO9W\005~\015JO\237\022\228X_^GGW^\210f\219\183%9\250>wA\236\230\235\220evIl\130k\210#\205|\193\216{\230)\201\2092\187$\230\195\181\161\1473\201\0190.\2390\127m\204=\231\151\r\015:K\212\159\169^\206\248 \202)\181\222H\237Fd\212\140\005\140\250)HwY'\214\205\023\235\149\015\134\154\193j\227\208\016\187s\233\235\172\b\140\241\197\001\147\00597\031~h\005\141\007\220%\226{7\028`\002\t\156\155\168\231d\029\248\225\222\139\249\174\240\212\160#\241+a\165\173\027\166\134\203\221\026Z\204*\229\220$\189\"\235\2466\004\236\006\\\146{q\026C'\157\130\001\247\219\183\029\207\133\022<\179\166d\208)$\141}\207E;v\016\236\029l\147\192\248mK\211Ad0\235F\225\020\242\158r,\012Ut\151B\169jIQ\162e\135A\169Z\242Ci\023\247\213Q\022\216%^8g\200x\225\156\128\241\1949!\207\182\025b\183\225\130\205\253\184\162\158\206\029\144,\189\b&G\028j\210aT\020\194\014\139\030\136\227\162\000q\220\129\185\159\244\200\255eA\144\166\166W\2044\163;\024\187\017/\185\136\177\181\204`\237Ob\187\185\146\017\237\193\1422\197\\\232Q3\157\tx\211g\\\216q\243ez\024\011\182\191\247\231\139\220\191Q:\224\153\135\017\011~W\014\164\251DP\231\030\229\164G\238\158GN\252Deg\253f5;U\206hA\171\140\241\242u\158\141w\233\165l\004\026\173L%\232)]--\020\211u\208$B\218Z\153=h\149\162\175\196\1876sf\196\031\015Y\242\241MN\147(\187 F\175\177\201z\149\185\215\204\249\145\214C\nL\0280\196\003%\157C\204\017\019\214\172;\180c\239\166/\020=\203\247\228\184\214\139\203\217\197\029n\\b\n\0275\195ux\233\030\227\171\0300k\241\169Cb\t\022\022\184\183\030\247\241\135\021\185\143\192\024\175}\000\187J\159\006(\174\211=\148\174\212\203\000\198\181\186\135\238\rH^T\187^\247\161\147\021\187\199\238\029\018o\028\203.\231}h\029\231|\144\184\164\159)\016\022\245\254\021o\237\147\163(\171\020\226\221\154g\217\160\246\012\029)}\030\236ar\031]X\167\1474\215_\162\233&ws\161\205&wsY:\153;\132\129nt\211I'\1291\234\163\001\031w\209\"\027/\014Z\143\140:(\003\234g\222\226G\181\188\162?q\144\247])=5$\228\211p}\216\251 \141\127\129GDX\141\206\172\230\160d\005Q90\172\230<\138\130\239\015[sx\136B\243\164c\1566\026\143\164\147\137\160o\201\023\205(\137\185\250\193\159(\161\204\201\181\2260I\\\172\003\011l9\201QDla]\236\247\160\217'\146\171\1700^$WUY:\169[F\132tP\252\191_\232N\251\178s\158c\171:a\232\157\209\236\144\0147a\155\128\197`]\128\014\253\147\135Z\129\158{\185W\006\214\024Rb\246\227B\149\004?\030\140\001T^\149{-\156tqw\1411\208\1411\220/\012S\211\133\203\192\030\003\r\182\021\246\015'\140\t[\185A\142\238\217\213W\185\186\021\184\252j\016{\162xz7\148se*\249\129\232\175\1785\161\213\215\195\216\1480D@\181\214y\0031\251c\237av\153g\0235\242 \247\244\031rn\1909\007\181@\006\143\221\153\129\130\203.b\208\251\b\131M\028E~\130\229\231\t\209\242\019\015B\236\159yiz\229\136\019w\128\2303G\240\016?\189a\233\003\202\207\214\242Ks=\215D\2541.\164\018 .\165<\028\023S\004\146E\131\000\226\216I\197\141\143ya\t\203)\030\012\017\173\232\030\024o\176x\248f\131\197\227\233\006\011\193]r\145\029J\207Z3\208s\237\002\027;\196\023]E\231B\216[y<\016\175\236 `OPO\133N\215\128\\_\222.i\230\236\2267\171\1399\007\130T\131\157\b\016TXGY\0296 Q\137%\018\156\179`j\184$7\131\161=$7\131Y:\025X\208<\174\227\219<8K_\199\215y,n\192\228d4\138\232}\187\255l\244\140\185Gt\162\rA\162\150VzD'Ky\231x\249\136[\195\165GTc\168\203\170\242\152j\128m\0004fF\196\155\185`.\195C\212?\1324\218QG:\202\156G\242\158f$\177\006\189H^\029\221\172S{\236k\136\029C&\228X\029\170s@\212\160\004H\245\167\194AQ{\018\224\158\238$Y\177\154\147\132L\244&A\238iM\"\180\213\153$\164V\164\176\163\1904\245d\208\150$\176V\169\200\161\223\205\153K\017ZeHB\007U\200\019\253\233I\020\205*\2275\202H\239\170\183\171\205\178\171\216s\n${5n\127\164\204e/\029H\1275\026,\029W\189\188\0121F\195\138'\226\229es\011\168\165\165\205\146\207\129\150\217\245i\019\135\143:\007\029o\027k\029\169gC {\240C\132\136\246\182\177E$\195\203X\016+\166\201\151\017\211l\204\012\022E[\231\017\246\002\228K\147\140\222I\180l\000\154\155\194 \164\222P\006)\173\155\164\144\241\187\196 \237\181?\136\199^'\006\221\225\234/(\195\166\247\213^P\182\154:\218$Kq\237\005e\171\185\163\147\024\151\014\211\011\202\214\160\211\011\202X\226\022\178\005\130\178\187\241C\134\140\246\150\162&\187o\030\198\171\246v\n\140\249\215x\135\025\nU\011\019\003\221\245\246#\198\235\000\026\147\\+!G7?A\250DeD]\208\002\023n\r\130\2335\210r\137\246\1329P\200\190[\218\176v\168)\r\030.'bX\255)\226\025\0319\218\137\217z\130\154\211\011\173X\012\161\223\179J\223\244\011<$\208\139\147-ot(\158\200\150\235\207\022u \236\199\135\231c0\232\144\018\185p\194\133\015X\135yD\239OCcx\027;\226\007\204\159\164\128\bI\2492\003\206\187\158\151\239_\199\159\202\134\194w3\253a\239\252f\246\155\141\177d\242C\219\192\b\183\017/xc9]G\248\230\171\153s\212{\248$1\223O\238\179j\003\160\131\000\146\183\163\029\138F\135\021>\219\030\235\232\216eI\223\180\186\002\224=\191\231\004\015\030\207\th}\157\193\184\023I\158\221\198a1\027E\158}\230\016\223d\159u/\173\198\179\221JsttP\"mo)nAs\179`IF\220\030(\r\217\212# \154$\005\140&IG\202).h\192s\165\162V,\152}g=!\2421\196/\187ad\251\028\167\025DiF=\168A\201\151\1581\183~6\186%\172\203\159oT\2039\177\027\205rAt\172X.\001\218\194\153\130\150\239Fpw%\140\t2\131N\218\133\002\\\196\154O\131M\150\t\199\158G\153&\156\248\141\1624.\015v\000\147\219oW\217\231\176\150A\158\172Yc\141\176\232\130\246\195I\232\238\014\nm(\208\182\253\016;oN\246\174x\172\211=\022\186\136\002\182\159\000L\006^4A\187Vo!\144\184\152\222\253\206\248j\204\180Y\tL\235\180:\207\254\023\135U\190`#\152e\159u\208ES\n\147\031L\242\159\163\202\143\018\183s1\236F\159\237\196\182\174\178wVr\155\189\135a\005Y\198\246c\156\197\166 \237\225\1415h{x\195\210\137\188\01124\154\014\212x\012\237V\001\180\017\018\188\024?\220\154\194}\150\139\245\184@g\180\159?\238Oa\200\205\230=\238\0202\205\209g$%\246\247\248%\202hM\175RF\250\026v\244\222\205g\134\150\217{\236\185\141#\212M\029\195\240\187\153\207;\146f\139\r\235\144w\211\211\161;\189\219\221,l\161\188o\2416\231\004\222B\157\195\\\252\158tV\006\136\229\138\252l\205\189\169\144,hJ0\245\137\203\130\189\024R\000\253H!&Z\003\248\181\012\240\229\212\227\208\169\182\167\212\016\131\157\165\251\178\151T\144\163u\025\\g\031F\001\172f$\229F\2488\133-\139\b\166\186!\203r\188S\188\150\208\247f\194&e\140f\194Y\202\029\2394\163a%\252\209\1503\020\146\143\219\237i,\193?nv\167\161\155|\220w\174\192\252\251\241\021\231\n4\215\143{\206\021S\137\204mY\014\023g7\137\005\1356a\026\"\243/\174\169,\243\180O\0191\179\173\1447\167\195;F\128\253\023t\129\015\244\205\232b1K\240\244\195X\194\179\023\151U,\200\211]\011\014:\028\160\212\0170Wl|\212\158M\217\179R\156\r\224\210\199%\202\0202\004\229\1295\226\183)\230\149{\012\214\022,\165>z\171\003\163\020\172\2245\249\209\233\016\169\244\199\015\140\211\152+\216\135\211\2051\n\145\0127\200\219 \031\204\150\135\184N3d\\\150\t\024\151eB&K\172\194#\246\190\140\245\028\166\250\143\228@8\026\205\016E\238\024\143\237\246\157\161\147\145\165!C[\003*\236\230\206kh{\0317\151^\175n\192d\028\193x$\031+q\231\019P\017\131\029'EX3\160I\n\031\186\141V0\203\031\241\219\187X\165\169\t\1565\2496\188lQ\201\007\214\000\239e\154\165\144\189`\020\245J\1598\024\191>\194d\133\146\177\147\021D\t\203\0146\2028q!\011\201\137oDq5\005\140A 9\000\222\024:)\224\154\012mJ\019P\231\135\254\197\142\177s\143\245\195\165\127\238\147\143f`J\003o\223_\160\135X\184\141\240\189\183\166d\143\171\177\014\160\021\251\006L\170\145\169\155a\133\003\227\213\142\030\028I\237<\185\\\147\014\006\227u\246\133s\235,\251b\015\171A\223\248\162Fd\242B\2409\158\237\133\003\164\141SgGr\228\212\201\168n\157:[A\163S\167\132\026;u2\186\222\156\225*\132\030\029\225\154\000\180>\158\140\233\183\2373\022\220\230\192*jX\208\244\174@\140\214_6\167\223\204\166\186o\172\195.\242\197~c\221\211a\190\198\174\213\151\196\128\131\212\238zN\162K}\217\222;\025\141\006\144\156\176E\252\201\t[\210'\217\189\154\200S\220\254q\180\217\191j\004\b[R\142\178{J\001\137\155J\014Iw\149\\\180v\179\200!\201n\145\131\236\174\144C\204\206\143\003\236y\023\135\132\237\029GI7\250u\224\183\206\168\011\172#x\028\142\030\135\021z\017q'\0030\180}\239\180\134l$\231\017Q)\187\173\237N3\002b\244\183W\201\023Dm\2291\158\251\181\215\n\231N\245-\179/\201\17724\224\228X\025\233\227`\238\003G\019\180^\"\236\024\201\196\bQ\147\0191\b\159\156\136\001\173\227<\222\029\187\005`A\244%n\176!C\137?<\"O\252\225g\217\127\252\231\127\"\179\255\023e5<\198" let parse_glyphlist i = let parse_line l = let len = String.length l in if len = 0 then None else if l.[0] = '#' then None else (* Find semicolon. Bail or extract name *) let semipos = try Some (String.index l ';') with Not_found -> None in match semipos with | None -> None | Some semipos -> let name = String.sub l 0 semipos in (* Read codes, one or more, space-delimited, four chars each. *) let codes = ref [] and pos = ref (semipos + 1) in try while true do codes := int_of_string ("0x" ^ String.sub l !pos 4)::!codes; pos += 5 done; Some ("", []) with _ -> Some ("/" ^ name, rev !codes) in let out = ref [] in try while true do match parse_line (Pdfio.read_line i) with | None -> () | Some (s, is) -> out := (s, is)::!out done; [] with End_of_file -> rev !out let glyphmap = memoize (fun () -> parse_glyphlist (Pdfio.input_of_string (Pdfio.string_of_bytes (Pdfcodec.decode_flate (Pdfio.bytes_of_string glyphlist_src))))) (*let _ = iter (fun (k, v) -> Printf.printf "%s = " k; iter (Printf.printf "%X ") v; flprint "\n") glyphmap*) let name_to_pdf = [ (* New items from ISO Standard D.3... These appear in annotation text, even though it's a text string. *) (* FIXME: Should we add all the codepoints, even those called undefined, to allow failures to be tracked? *) "/controlCR", 0o015; "/controlLF", 0o012; "/controlHT", 0o013; (* Original items from 1.6 spec *) "/A", 0o101; "/AE", 0o306; "/Aacute", 0o301; "/Acircumflex", 0o302; "/Adieresis", 0o304; "/Agrave", 0o300; "/Aring", 0o305; "/Atilde", 0o303; "/B", 0o102; "/C", 0o103; "/Ccedilla", 0o307; "/D", 0o104; "/E", 0o105; "/Eacute", 0o311; "/Ecircumflex", 0o312; "/Edieresis", 0o313; "/Egrave", 0o310; "/Eth", 0o320; "/Euro", 0o240; "/F", 0o106; "/G", 0o107; "/H", 0o110; "/I", 0o111; "/Iacute", 0o315; "/Icircumflex", 0o316; "/Idieresis", 0o317; "/Igrave", 0o314; "/J", 0o112; "/K", 0o113; "/L", 0o114; "/Lslash", 0o225; "/M", 0o115; "/N", 0o116; "/Ntilde", 0o321; "/O", 0o117; "/OE", 0o226; "/Oacute", 0o323; "/Ocircumflex", 0o324; "/Odieresis", 0o326; "/Ograve", 0o322; "/Oslash", 0o330; "/Otilde", 0o325; "/P", 0o120; "/Q", 0o121; "/R", 0o122; "/S", 0o123; "/Scaron", 0o227; "/T", 0o124; "/Thorn", 0o336; "/U", 0o125; "/Uacute", 0o332; "/Ucircumflex", 0o333; "/Udieresis", 0o334; "/Ugrave", 0o331; "/V", 0o126; "/W", 0o127; "/X", 0o130; "/Y", 0o131; "/Yacute", 0o335; "/Ydieresis", 0o230; "/Z", 0o132; "/Zcaron", 0o231; "/a", 0o141; "/aacute", 0o341; "/acircumflex", 0o342; "/acute", 0o264; "/adieresis", 0o344; "/ae", 0o346; "/agrave", 0o340; "/ampersand", 0o046; "/aring", 0o345; "/asciicircum", 0o136; "/asciitilde", 0o176; "/asterisk", 0o052; "/at", 0o100; "/atilde", 0o343; "/b", 0o142; "/backslash", 0o134; "/bar", 0o174; "/braceleft", 0o173; "/braceright", 0o175; "/bracketleft", 0o133; "/bracketright", 0o135; "/breve", 0o030; "/brokenbar", 0o246; "/bullet", 0o200; "/c", 0o143; "/caron", 0o031; "/ccedilla", 0o347; "/cedilla", 0o270; "/cent", 0o242; "/circumflex", 0o032; "/colon", 0o072; "/comma", 0o054; "/copyright", 0o251; "/currency", 0o244; "/d", 0o144; "/dagger", 0o201; "/daggerdbl", 0o202; "/degree", 0o260; "/dieresis", 0o250; "/divide", 0o367; "/dollar", 0o044; "/dotaccent", 0o033; "/dotlessi", 0o232; "/e", 0o145; "/eacute", 0o351; "/ecircumflex", 0o352; "/edieresis", 0o353; "/egrave", 0o350; "/eight", 0o070; "/ellipsis", 0o203; "/emdash", 0o204; "/endash", 0o205; "/equal", 0o075; "/eth", 0o360; "/exclam", 0o041; "/exclamdown", 0o241; "/f", 0o146; "/fi", 0o223; "/five", 0o065; "/fl", 0o223; "/florin", 0o206; "/four", 0o064; "/fraction", 0o207; "/g", 0o147; "/germandbls", 0o337; "/grave", 0o140; "/greater", 0o076; "/guillemotleft", 0o253; "/guillemotright", 0o273; "/guilsinglleft", 0o210; "/guilsinglright", 0o211; "/h", 0o150; "/hungarumlaut", 0o034; "/hyphen", 0o055; "/i", 0o151; "/iacute", 0o355; "/icircumflex", 0o356; "/idieresis", 0o357; "/igrave", 0o354; "/j", 0o152; "/k", 0o153; "/l", 0o154; "/less", 0o074; "/logicalnot", 0o254; "/lslash", 0o233; "/m", 0o155; "/macron", 0o257; "/minus", 0o212; "/mu", 0o265; "/multiply", 0o327; "/n", 0o156; "/nine", 0o071; "/ntilde", 0o361; "/numbersign", 0o043; "/o", 0o157; "/oacute", 0o363; "/ocircumflex", 0o364; "/odieresis", 0o366; "/oe", 0o234; "/ogonek", 0o035; "/ograve", 0o362; "/one", 0o061; "/onehalf", 0o275; "/onequarter", 0o274; "/onesuperior", 0o271; "/ordfeminine", 0o252; "/ordmasculine", 0o272; "/oslash", 0o370; "/otilde", 0o365; "/p", 0o160; "/paragraph", 0o266; "/parenleft", 0o050; "/parenright", 0o051; "/percent", 0o045; "/period", 0o056; "/periodcentered", 0o267; "/perthousand", 0o213; "/plus", 0o053; "/plusminus", 0o261; "/q", 0o161; "/question", 0o077; "/questiondown", 0o277; "/quotedbl", 0o042; "/quotedblbase", 0o214; "/quotedblleft", 0o215; "/quotedblright", 0o216; "/quoteleft", 0o217; "/quoteright", 0o220; "/quotesinglbase", 0o221; "/quotesingle", 0o047; "/r", 0o162; "/registered", 0o256; "/ring", 0o036; "/s", 0o163; "/scaron", 0o235; "/section", 0o247; "/semicolon", 0o073; "/seven", 0o067; "/six", 0o066; "/slash", 0o057; "/space", 0o040; "/sterling", 0o243; "/t", 0o164; "/thorn", 0o376; "/three", 0o063; "/threequarters", 0o276; "/threesuperior", 0o263; "/tilde", 0o037; "/trademark", 0o222; "/two", 0o062; "/twosuperior", 0o262; "/u", 0o165; "/uacute", 0o372; "/ucircumflex", 0o373; "/udieresis", 0o374; "/ugrave", 0o371; "/underscore", 0o137; "/v", 0o166; "/w", 0o167; "/x", 0o170; "/y", 0o171; "/yacute", 0o375; "/ydieresis", 0o377; "/yen", 0o245; "/z", 0o172; "/zcaron", 0o236; "/zero", 0o060] (* Standard encoding *) let name_to_standard = ["/A", 0o101; "/AE", 0o341; "/B", 0o102; "/C", 0o103; "/D", 0o104; "/E", 0o105; "/F", 0o106; "/G", 0o107; "/H", 0o110; "/I", 0o111; "/J", 0o112; "/K", 0o113; "/L", 0o114; "/Lslash", 0o350; "/M", 0o115; "/N", 0o116; "/O", 0o117; "/OE", 0o352; "/Oslash", 0o351; "/P", 0o120; "/Q", 0o121; "/R", 0o122; "/S", 0o123; "/T", 0o124; "/U", 0o125; "/V", 0o126; "/W", 0o127; "/X", 0o130; "/Y", 0o131; "/Z", 0o132; "/a", 0o141; "/acute", 0o302; "/ae", 0o361; "/ampersand", 0o046; "/asciicircum", 0o136; "/asciitilde", 0o176; "/asterisk", 0o052; "/at", 0o100; "/b", 0o142; "/backslash", 0o134; "/bar", 0o174; "/braceleft", 0o173; "/braceright", 0o175; "/bracketleft", 0o133; "/bracketright", 0o135; "/breve", 0o306; "/bullet", 0o267; "/c", 0o143; "/caron", 0o317; "/cedilla", 0o313; "/cent", 0o242; "/circumflex", 0o303; "/colon", 0o072; "/comma", 0o054; "/currency", 0o250; "/d", 0o144; "/dagger", 0o262; "/daggerdbl", 0o263; "/dieresis", 0o310; "/dollar", 0o044; "/dotaccent", 0o307; "/dottlessi", 0o365; "/e", 0o145; "/eight", 0o070; "/ellipsis", 0o274; "/emdash", 0o320; "/endash", 0o261; "/equal", 0o075; "/exclam", 0o041; "/exclamdown", 0o241; "/f", 0o146; "/fi", 0o256; "/five", 0o065; "/fl", 0o257; "/florin", 0o246; "/four", 0o064; "/fraction", 0o244; "/g", 0o147; "/germandbls", 0o373; "/grave", 0o301; "/greater", 0o076; "/guillemotleft", 0o253; "/guillemotright", 0o273; "/guilsinglleft", 0o254; "/guilsinglright", 0o255; "/h", 0o150; "/hungarumlaut", 0o315; "/hyphen", 0o055; "/i", 0o151; "/j", 0o152; "/k", 0o153; "/l", 0o154; "/less", 0o074; "/lslash", 0o370; "/m", 0o155; "/macron", 0o305; "/n", 0o156; "/nine", 0o071; "/numbersign", 0o043; "/o", 0o157; "/oe", 0o372; "/ogonek", 0o316; "/one", 0o061; "/ordfeminine", 0o343; "/ordmasculine", 0o353; "/oslash", 0o361; "/p", 0o160; "/paragraph", 0o266; "/parenleft", 0o050; "/parenright", 0o051; "/percent", 0o045; "/period", 0o056; "/periodcentered", 0o264; "/perthousand", 0o275; "/plus", 0o053; "/q", 0o161; "/question", 0o077; "/questiondown", 0o277; "/quotedbl", 0o042; "/quotedblbase", 0o271; "/quotedblleft", 0o252; "/quotedblright", 0o272; "/quoteleft", 0o140; "/quoteright", 0o047; "/quotesinglbase", 0o270; "/quotesingle", 0o251; "/r", 0o162; "/ring", 0o312; "/s", 0o163; "/section", 0o247; "/semicolon", 0o073; "/seven", 0o067; "/six", 0o066; "/slash", 0o057; "/space", 0o040; "/sterling", 0o243; "/t", 0o164; "/three", 0o063; "/tilde", 0o304; "/two", 0o062; "/u", 0o165; "/underscore", 0o137; "/v", 0o166; "/w", 0o167; "/x", 0o170; "/y", 0o171; "/yen", 0o245; "/z", 0o172; "/zero", 0o060] (* Mac Roman Encoding *) let name_to_macroman = ["/A", 0o101; "/AE", 0o256; "/Aacute", 0o347; "/Acircumflex", 0o345; "/Adieresis", 0o200; "/Agrave", 0o313; "/Aring", 0o201; "/Atilde", 0o314; "/B", 0o102; "/C", 0o103; "/Ccedilla", 0o202; "/D", 0o104; "/E", 0o105; "/Eacute", 0o203; "/Ecircumflex", 0o346; "/Edieresis", 0o350; "/Egrave", 0o351; "/F", 0o106; "/G", 0o107; "/H", 0o110; "/I", 0o111; "/Iacute", 0o352; "/Icircumflex", 0o353; "/Idieresis", 0o354; "/Igrave", 0o355; "/J", 0o112; "/K", 0o113; "/L", 0o114; "/M", 0o115; "/N", 0o116; "/Ntilde", 0o204; "/O", 0o117; "/OE", 0o316; "/Oacute", 0o356; "/Ocircumflex", 0o357; "/Odieresis", 0o205; "/Ograve", 0o361; "/Oslash", 0o257; "/Otilde", 0o315; "/P", 0o120; "/Q", 0o121; "/R", 0o122; "/S", 0o123; "/T", 0o124; "/U", 0o125; "/Uacute", 0o362; "/Ucircumflex", 0o363; "/Udieresis", 0o206; "/Ugrave", 0o364; "/V", 0o126; "/W", 0o127; "/X", 0o130; "/Y", 0o131; "/Ydieresis", 0o331; "/Z", 0o132; "/a", 0o141; "/aacute", 0o207; "/acircumflex", 0o211; "/acute", 0o253; "/adieresis", 0o212; "/ae", 0o276; "/agrave", 0o210; "/ampersand", 0o046; "/aring", 0o214; "/asciicircum", 0o136; "/asciitilde", 0o176; "/asterisk", 0o052; "/at", 0o100; "/atilde", 0o213; "/b", 0o142; "/backslash", 0o134; "/bar", 0o174; "/braceleft", 0o173; "/braceright", 0o175; "/bracketleft", 0o133; "/bracketright", 0o135; "/breve", 0o371; "/bullet", 0o245; "/c", 0o143; "/caron", 0o377; "/ccedilla", 0o215; "/cedilla", 0o374; "/cent", 0o242; "/circumflex", 0o366; "/colon", 0o072; "/comma", 0o054; "/copyright", 0o251; "/currency", 0o333; "/d", 0o144; "/dagger", 0o240; "/daggerdbl", 0o340; "/degree", 0o241; "/dieresis", 0o254; "/divide", 0o326; "/dollar", 0o044; "/dotaccent", 0o372; "/dotlessi", 0o365; "/e", 0o145; "/eacute", 0o216; "/ecircumflex", 0o220; "/edieresis", 0o221; "/egrave", 0o217; "/eight", 0o070; "/ellipsis", 0o311; "/emdash", 0o321; "/endash", 0o320; "/equal", 0o075; "/exclam", 0o041; "/exclamdown", 0o301; "/f", 0o146; "/fi", 0o336; "/five", 0o065; "/fl", 0o337; "/florin", 0o304; "/four", 0o064; "/fraction", 0o332; "/g", 0o147; "/germandbls", 0o247; "/grave", 0o140; "/greater", 0o076; "/guillemotleft", 0o307; "/guillemotright", 0o310; "/guilsinglleft", 0o334; "/guilsinglright", 0o335; "/h", 0o150; "/hungrumlaut", 0o375; "/hyphen", 0o055; "/i", 0o151; "/iacute", 0o222; "/icircumflex", 0o224; "/idieresis", 0o225; "/igrave", 0o223; "/j", 0o152; "/k", 0o153; "/l", 0o154; "/less", 0o074; "/logicalnot", 0o302; "/m", 0o155; "/macron", 0o370; "/mu", 0o265; "/n", 0o156; "/nine", 0o071; "/ntilde", 0o226; "/numbersign", 0o043; "/o", 0o157; "/oacute", 0o227; "/ocircumflex", 0o231; "/odieresis", 0o232; "/oe", 0o317; "/ogonek", 0o376; "/one", 0o061; "/ordfeminine", 0o273; "/ordmasculine", 0o274; "/oslash", 0o277; "/otilde", 0o233; "/p", 0o160; "/paragraph", 0o246; "/parenleft", 0o050; "/parenright", 0o051; "/percent", 0o045; "/period", 0o056; "/periodcentered", 0o341; "/perthousand", 0o344; "/plus", 0o053; "/plusminus", 0o261; "/q", 0o161; "/question", 0o077; "/questiondown", 0o300; "/quotedbl", 0o042; "/quotedblbase", 0o343; "/quotedblleft", 0o322; "/quotedblright", 0o323; "/quoteleft", 0o324; "/quoteright", 0o325; "/quotesinglbase", 0o342; "/quotesingle", 0o047; "/r", 0o162; "/registered", 0o250; "/ring", 0o373; "/s", 0o163; "/section", 0o244; "/semicolon", 0o073; "/seven", 0o067; "/six", 0o066; "/slash", 0o057; "/space", 0o040; "/sterling", 0o243; "/t", 0o164; "/three", 0o063; "/tilde", 0o367; "/trademark", 0o252; "/two", 0o062; "/u", 0o165; "/uacute", 0o234; "/ucircumflex", 0o236; "/udieresis", 0o237; "/ugrave", 0o235; "/underscore", 0o137; "/v", 0o166; "/w", 0o167; "/x", 0o170; "/y", 0o171; "/ydieresis", 0o330; "/yen", 0o264; "/z", 0o172; "/zero", 0o060; (*"/space", 0o312*)] (*FIXME: see below*) (* Win Ansi Encoding *) let name_to_win = ["/A", 0o101; "/AE", 0o306; "/Aacute", 0o301; "/Acircumflex", 0o302; "/Adieresis", 0o304; "/Agrave", 0o300; "/Aring", 0o305; "/Atilde", 0o303; "/B", 0o102; "/C", 0o103; "/Ccedilla", 0o307; "/D", 0o104; "/E", 0o105; "/Eacute", 0o311; "/Ecircumflex", 0o312; "/Edieresis", 0o313; "/Egrave", 0o310; "/Eth", 0o320; "/Euro", 0o200; "/F", 0o106; "/G", 0o107; "/H", 0o110; "/I", 0o111; "/Iacute", 0o315; "/Icircumflex", 0o316; "/Idieresis", 0o317; "/Igrave", 0o314; "/J", 0o112; "/K", 0o113; "/L", 0o114; "/M", 0o115; "/N", 0o116; "/Ntilde", 0o321; "/O", 0o117; "/OE", 0o214; "/Oacute", 0o323; "/Ocircumflex", 0o324; "/Odieresis", 0o326; "/Ograve", 0o322; "/Oslash", 0o330; "/Otilde", 0o325; "/P", 0o120; "/Q", 0o121; "/R", 0o122; "/S", 0o123; "/Scaron", 0o212; "/T", 0o124; "/Thorn", 0o336; "/U", 0o125; "/Uacute", 0o332; "/Ucircumflex", 0o333; "/Udieresis", 0o334; "/Ugrave", 0o331; "/V", 0o126; "/W", 0o127; "/X", 0o130; "/Y", 0o131; "/Yacute", 0o335; "/Ydieresis", 0o237; "/Z", 0o132; "/Zcaron", 0o216; "/a", 0o141; "/aacute", 0o341; "/acircumflex", 0o342; "/acute", 0o264; "/adieresis", 0o344; "/ae", 0o346; "/agrave", 0o340; "/ampersand", 0o046; "/aring", 0o345; "/asciicircum", 0o136; "/asciitilde", 0o176; "/asterisk", 0o052; "/at", 0o100; "/atilde", 0o343; "/b", 0o142; "/backslash", 0o134; "/bar", 0o174; "/braceleft", 0o173; "/braceright", 0o175; "/bracketleft", 0o133; "/bracketright", 0o135; "/brokenbar", 0o246; "/bullet", 0o225; "/c", 0o143; "/ccedilla", 0o347; "/cedilla", 0o270; "/cent", 0o242; "/circumflex", 0o210; "/colon", 0o072; "/comma", 0o054; "/copyright", 0o251; "/currency", 0o244; "/d", 0o144; "/dagger", 0o206; "/daggerdbl", 0o207; "/degree", 0o260; "/dieresis", 0o250; "/divide", 0o367; "/dollar",0o044; "/e", 0o145; "/eacute", 0o351; "/ecircumflex", 0o352; "/edieresis", 0o353; "/egrave", 0o350; "/eight", 0o070; "/ellipsis", 0o205; "/emdash", 0o227; "/endash", 0o226; "/equal", 0o075; "/eth", 0o360; "/exclam", 0o041; "/exclamdown", 0o241; "/f", 0o146; "/five", 0o065; "/florin", 0o203; "/four", 0o064; "/g", 0o147; "/germandbls", 0o337; "/grave", 0o140; "/greater", 0o076; "/guillemotleft", 0o253; "/guillemotright", 0o273; "/guilsinglleft", 0o213; "/guilsinglright", 0o233; "/h", 0o150; "/hyphen", 0o055; "/i", 0o151; "/iacute", 0o355; "/icircumflex", 0o356; "/idieresis", 0o357; "/igrave", 0o354; "/j", 0o152; "/k", 0o153; "/l", 0o154; "/less", 0o074; "/logicalnot", 0o254; "/m", 0o155; "/macron", 0o257; "/mu", 0o265; "/multiply", 0o327; "/n", 0o156; "/nine", 0o071; "/ntilde", 0o361; "/numbersign", 0o043; "/o", 0o157; "/oacute", 0o363; "/ocircumflex", 0o364; "/odieresis", 0o366; "/oe", 0o234; "/ograve", 0o362; "/one", 0o061; "/onehalf", 0o275; "/onequarter", 0o274; "/onesuperior", 0o271; "/ordfeminine", 0o252; "/ordmasculine", 0o272; "/oslash", 0o370; "/otilde", 0o365; "/p", 0o160; "/paragraph", 0o266; "/parenleft", 0o050; "/parenright", 0o051; "/percent", 0o045; "/period", 0o056; "/periodcentered", 0o267; "/perthousand", 0o211; "/plus", 0o053; "/plusminus", 0o261; "/q", 0o161; "/question", 0o077; "/questiondown", 0o277; "/quotedbl", 0o042; "/quotedblbase", 0o204; "/quotedblleft", 0o223; "/quotedblright", 0o224; "/quoteleft", 0o221; "/quoteright", 0o222; "/quotesinglbase", 0o202; "/quotesingle", 0o047; "/r", 0o162; "/registered", 0o256; "/s", 0o163; "/scaron", 0o232; "/section", 0o247; "/semicolon", 0o073; "/seven", 0o067; "/six", 0o066; "/slash", 0o057; "/space", 0o040; "/sterling", 0o243; "/t", 0o164; "/thorn", 0o376; "/three", 0o063; "/threequarters", 0o276; "/threesuperior", 0o263; "/tilde", 0o230; "/trademark", 0o231; "/two", 0o062; "/twosuperior", 0o262; "/u", 0o165; "/uacute", 0o372; "/ucircumflex", 0o373; "/udieresis", 0o374; "/ugrave", 0o371; "/underscore", 0o137; "/v", 0o166; "/w", 0o167; "/x", 0o170; "/y", 0o171; "/yacute", 0o375; "/ydieresis", 0o377; "/yen", 0o245; "/z", 0o172; "/zcaron", 0o236; "/zero", 0o060;(* "/space", 0o240; "/hyphen", 0o255*)] (*FIXME: need these rules back in, but only in the reverse.. To make 1-to-1?*) (* Mac Expert Encoding *) let name_to_macexpert = ["/AEsmall", 0o276; "/Aacutesmall", 0o207; "/Acircumflexsmall", 0o211; "/Acutesmall", 0o047; "/Adieresissmall", 0o212; "/Agravesmall", 0o210; "/Aringsmall", 0o214; "/Asmall", 0o141; "/Atildesmall", 0o213; "/Brevesmall", 0o363; "/Bsmall", 0o142; "/Caronsmall", 0o256; "/Ccedillasmall", 0o215; "/Cedillasmall", 0o311; "/Circumflexsmall", 0o136; "/Csmall", 0o143; "/Dieresissmall", 0o254; "/Dotaccentsmall", 0o372; "/Dsmall", 0o144; "/Eacutesmall", 0o216; "/Ecircumflexsmall", 0o220; "/Edieresissmall", 0o221; "/Egravesmall", 0o217; "/Esmall", 0o145; "/Ethsmall", 0o104; "/Fsmall", 0o146; "/Gravesmall", 0o140; "/Gsmall", 0o147; "/Hsmall", 0o150; "/Hungarumlautsmall", 0o042; "/Iacutesmall", 0o222; "/Icircumflexsmall", 0o224; "/Idieresissmall", 0o225; "/Igravesmall", 0o223; "/Ismall", 0o151; "/Jsmall", 0o152; "/Ksmall", 0o153; "/Lslashsmall", 0o302; "/Lsmall", 0o154; "/Macronsmall", 0o364; "/Msmall", 0o155; "/Nsmall", 0o156; "/Ntildesmall", 0o226; "/OEsmall", 0o317; "/Oacutesmall", 0o227; "/Ocircumflexsmall", 0o231; "/Odieresissmall", 0o232; "/Ogoneksmall", 0o362; "/Ogravesmall", 0o230; "/Oslashsmall", 0o277; "/Osmall", 0o157; "/Otildesmall", 0o233; "/Psmall", 0o160; "/Qsmall", 0o161; "/Ringsmall", 0o373; "/Rsmall", 0o162; "/Scaronsmall", 0o247; "/Ssmall", 0o163; "/Thornsmall", 0o271; "/Tildesmall", 0o176; "/Tsmall", 0o164; "/Uacutesmall", 0o234; "/Ucircumflexsmall", 0o236; "/Udieresissmall", 0o237; "/Ugravesmall", 0o235; "/Usmall", 0o165; "/Vsmall", 0o166; "/Wsmall", 0o167; "/Xsmall", 0o170; "/Yacutesmall", 0o264; "/Ydieresissmall", 0o330; "/Ysmall", 0o171; "/Zcaronsmall", 0o275; "/Zsmall", 0o172; "/ampersandsmall", 0o046; "/asuperior", 0o201; "/bsuperior", 0o365; "/centinferior", 0o251; "/centoldstyle", 0o043; "/centsuperior", 0o202; "/colon", 0o072; "/colonmonetary", 0o173; "/comma", 0o054; "/commainferior", 0o262; "/commasuperior", 0o370; "/dollarinferior", 0o266; "/dollaroldstyle", 0o044; "/dsuperior", 0o353; "/eightinferior", 0o245; "/eightoldstyle", 0o070; "/eightsuperior", 0o241; "/esuperior", 0o344; "/exclamdownsmall", 0o326; "/exclamsmall", 0o041; "/ff", 0o126; "/ffi", 0o131; "/ffl", 0o132; "/fi", 0o127; "/figuredash", 0o320; "/fiveeighths", 0o114; "/fiveinferior", 0o260; "/fiveoldstyle", 0o065; "/fivesuperior", 0o336; "/fl", 0o130; "/fourinferior", 0o242; "/fouroldstyle", 0o064; "/foursuperior", 0o335; "/fraction", 0o057; "/hyphen", 0o055; "/hypheninferior", 0o137; "/hyphensuperior", 0o137; "/isuperior", 0o351; "/lsuperior", 0o361; "/msuperior", 0o367; "/nineinferior", 0o273; "/nineoldstyle", 0o071; "/ninesuperior", 0o341; "/nsuperior", 0o366; "/onedotenleader", 0o053; "/oneeighth", 0o112; "/onefitted", 0o174; "/onehalf", 0o110; "/oneinferior", 0o301; "/oneoldstyle", 0o061; "/onequarter", 0o107; "/onesuperior", 0o332; "/onethird", 0o116; "/osuperior", 0o257; "/parenleftinferior", 0o133; "/parenleftsuperior", 0o050; "/parenrightinferior", 0o135; "/parenrightsuperior", 0o051; "/period", 0o056; "/periodinferior", 0o263; "/periodsuperior", 0o371; "/questiondownsmall", 0o300; "/questionsmall", 0o077; "/rsuperior", 0o345; "/rupiah", 0o175; "/semicolon", 0o073; "/seveneighths", 0o115; "/seveninferior", 0o246; "/sevenoldstyle", 0o067; "/sevensuperior", 0o340; "/sixinferior", 0o244; "/sixoldstyle", 0o066; "/sixsuperior", 0o337; "/space", 0o040; "/ssuperior", 0o352; "/threeeighths", 0o113; "/threeinferior", 0o243; "/threeoldstyle", 0o063; "/threequarters", 0o111; "/threequartersemdash", 0o075; "/threesuperior", 0o334; "/tsuperior", 0o346; "/twodotenleader", 0o052; "/twoinferior", 0o252; "/twooldstyle", 0o062; "/twosuperior", 0o333; "/twothirds", 0o117; "/zeroinferior", 0o274; "/zerooldstyle", 0o060; "/zerosuperior", 0o342] (* Symbol Encoding *) let name_to_symbol = ["/Alpha", 0o101; "/Beta", 0o102; "/Chi", 0o103; "/Delta", 0o104; "/Epsilon", 0o105; "/Eta", 0o110; "/Euro", 0o240; "/Gamma", 0o107; "/Ifraktur", 0o301; "/Iota", 0o111; "/Kappa", 0o113; "/Lambda", 0o114; "/Mu", 0o115; "/Nu", 0o116; "/Omega", 0o127; "/Omicron", 0o117; "/Phi", 0o106; "/Pi", 0o120; "/Psi", 0o131; "/Rfraktur", 0o302; "/Rho", 0o122; "/Sigma", 0o123; "/Tau", 0o124; "/Theta", 0o121; "/Upsilon", 0o125; "/Upsilon1", 0o241; "/Xi", 0o130; "/Zeta", 0o132; "/aleph", 0o300; "/alpha", 0o141; "/ampersand", 0o046; "/angle", 0o320; "/angleleft", 0o341; "/angleright", 0o361; "/approxequal", 0o273; "/arrowboth", 0o253; "/arrowdblboth", 0o333; "/arrowdbldown", 0o337; "/arrowdblleft", 0o334; "/arrowdblright", 0o336; "/arrowhorizex", 0o276; "/arrowleft", 0o254; "/arrowright", 0o256; "/arrowup", 0o255; "/arrowvertex", 0o275; "/asteriskmath", 0o052; "/bar", 0o174; "/beta", 0o142; "/braceleft", 0o173; "/braceright", 0o175; "/bracelefttp", 0o354; "/braceleftmid", 0o355; "/braceleftbt", 0o376; "/bracerighttp", 0o374; "/bracerightmid", 0o375; "/bracerightbt", 0o376; "/braceex", 0o357; "/bracketleft", 0o133; "/bracketright", 0o135; "/bracketlefttp", 0o351; "/bracketleftex", 0o352; "/bracketleftbt", 0o353; "/bracketrighttp", 0o371; "/brackerrightex", 0o372; "/bracketrightbt", 0o373; "/bullet", 0o267; "/carriagereturn", 0o277; "/chi", 0o143; "/circlemultiply", 0o304; "/circleplus", 0o305; "/club", 0o247; "/colon", 0o072; "/comma", 0o054; "/congruent", 0o100; "/copyrightsans", 0o343; "/copyrightserif", 0o323; "/degree", 0o260; "/delta", 0o144; "/diamond", 0o250; "/divide", 0o270; "/dotmath", 0o327; "/eight", 0o070; "/element", 0o316; "/ellipsis", 0o274; "/emptyset", 0o306; "/epsilon", 0o145; "/equal", 0o075; "/equivalence", 0o272; "/eta", 0o150; "/exclam", 0o041; "/existential", 0o044; "/five", 0o065; "/florin", 0o246; "/four", 0o064; "/fraction", 0o244; "/gamma", 0o147; "/gradient", 0o321; "/greater", 0o076; "/greaterequal", 0o263; "/heart", 0o251; "/infinity", 0o245; "/integral", 0o362; "/integraltp", 0o363; "/integralex", 0o364; "/integralbt", 0o365; "/intersection", 0o307; "/iota", 0o151; "/kappa", 0o153; "/lambda", 0o154; "/less", 0o074; "/lessequal", 0o243; "/logicaland", 0o331; "/logicalnot", 0o330; "/logicalor", 0o332; "/lozenge", 0o340; "/minus", 0o055; "/minute", 0o242; "/mu", 0o155; "/multiply", 0o264; "/nine", 0o071; "/notelement", 0o317; "/notequal", 0o271; "/notsubset", 0o313; "/nu", 0o156; "/numbersign", 0o043; "/omega", 0o167; "/omega1", 0o166; "/omicron", 0o157; "/one", 0o061; "/parenleft", 0o050; "/parenright", 0o051; "/parenlefttp", 0o346; "/parenleftex", 0o347; "/parenleftbt", 0o350; "/parenrighttp", 0o366; "/parenrightex", 0o367; "/parenrightbt", 0o370; "/partialdiff", 0o266; "/percent", 0o045; "/period", 0o056; "/perpendicular", 0o136; "/phi", 0o146; "/phi1", 0o152; "/pi", 0o160; "/plus", 0o153; "/plusminus", 0o261; "/product", 0o325; "/propersubset", 0o314; "/propersuperset", 0o311; "/proportional", 0o265; "/psi", 0o171; "/question", 0o077; "/radical", 0o326; "/radicalex", 0o140; "/reflexsubset", 0o315; "/reflexsuperset", 0o312; "/registersans", 0o342; "/registerserif", 0o322; "/rho", 0o162; "/second", 0o262; "/semicolon", 0o073; "/seven", 0o067; "/sigma", 0o163; "/sigma1", 0o126; "/similar", 0o176; "/six", 0o066; "/slash", 0o157; "/space", 0o040; "/spade", 0o252; "/suchthat", 0o047; "/summation", 0o345; "/tau", 0o164; "/therefore", 0o134; "/theta", 0o161; "/theta1", 0o112; "/three", 0o063; "/trademarksans", 0o344; "/trademarkserif", 0o324; "/two", 0o062; "/underscore", 0o137; "/union", 0o310; "/universal", 0o042; "/upsilon", 0o165; "/weierstrass", 0o303; "/xi", 0o303; "/zero", 0o060; "/zeta", 0o172] (* 6. Dingbats encoding *) let name_to_dingbats = ["/space", 0o040; "/a1", 0o041; "/a2", 0o042; "/a202", 0o043; "/a3", 0o044; "/a4", 0o045; "/a5", 0o046; "/a119", 0o047; "/a118", 0o050; "/a117", 0o051; "/a11", 0o052; "/a12", 0o053; "/a13", 0o054; "/a14", 0o055; "/a15", 0o056; "/a16", 0o057; "/a105", 0o060; "/a17", 0o061; "/a18", 0o062; "/a19", 0o063; "/a20", 0o064; "/a21", 0o065; "/a22", 0o066; "/a23", 0o067; "/a24", 0o070; "/a25", 0o071; "/a26", 0o072; "/a27", 0o073; "/a28", 0o074; "/a6", 0o075; "/a7", 0o076; "/a8", 0o077; "/a9", 0o100; "/a10", 0o101; "/a29", 0o102; "/a30", 0o103; "/a31", 0o104; "/a32", 0o105; "/a33", 0o106; "/a34", 0o107; "/a35", 0o110; "/a36", 0o111; "/a37", 0o112; "/a38", 0o113; "/a39", 0o114; "/a40", 0o115; "/a41", 0o116; "/a42", 0o117; "/a43", 0o120; "/a44", 0o121; "/a45", 0o122; "/a46", 0o123; "/a47", 0o124; "/a48", 0o125; "/a49", 0o126; "/a50", 0o127; "/a51", 0o130; "/a52", 0o131; "/a53", 0o132; "/a54", 0o133; "/a55", 0o134; "/a56", 0o135; "/a57", 0o136; "/a58", 0o137; "/a59", 0o140; "/a60", 0o141; "/a61", 0o142; "/a62", 0o143; "/a63", 0o144; "/a64", 0o145; "/a65", 0o146; "/a66", 0o147; "/a67", 0o150; "/a68", 0o151; "/a69", 0o152; "/a70", 0o153; "/a71", 0o154; "/a72", 0o155; "/a73", 0o156; "/a74", 0o157; "/a203", 0o160; "/a75", 0o161; "/a204", 0o162; "/a76", 0o163; "/a77", 0o164; "/a78", 0o165; "/a79", 0o166; "/a81", 0o167; "/a82", 0o170; "/a83", 0o171; "/a84", 0o172; "/a97", 0o173; "/a98", 0o174; "/a99", 0o175; "/a100", 0o176; "/a101", 0o241; "/a102", 0o242; "/a103", 0o243; "/a104", 0o244; "/a106", 0o245; "/a107", 0o246; "/a108", 0o247; "/a112", 0o250; "/a111", 0o251; "/a110", 0o252; "/a109", 0o253; "/a120", 0o254; "/a121", 0o255; "/a122", 0o256; "/a123", 0o257; "/a124", 0o260; "/a125", 0o261; "/a126", 0o262; "/a127", 0o263; "/a128", 0o264; "/a129", 0o265; "/a130", 0o266; "/a131", 0o267; "/a132", 0o270; "/a133", 0o271; "/a134", 0o272; "/a135", 0o273; "/a136", 0o274; "/a137", 0o275; "/a138", 0o276; "/a139", 0o277; "/a140", 0o300; "/a141", 0o301; "/a142", 0o302; "/a143", 0o303; "/a144", 0o304; "/a145", 0o305; "/a146", 0o306; "/a147", 0o307; "/a148", 0o310; "/a149", 0o311; "/a150", 0o312; "/a151", 0o313; "/a152", 0o314; "/a153", 0O315; "/a154", 0o316; "/a155", 0o317; "/a156", 0o320; "/a157", 0o321; "/a158", 0o322; "/a159", 0o323; "/a160", 0o324; "/a161", 0o325; "/a163", 0o326; "/a164", 0o327; "/a196", 0o330; "/a165", 0o331; "/a192", 0o332; "/a166", 0o333; "/a167", 0o334; "/a168", 0o335; "/a169", 0o336; "/a170", 0o337; "/a171", 0o340; "/a172", 0o341; "/a173", 0o342; "/a162", 0o343; "/a174", 0o344; "/a175", 0o345; "/a176", 0o346; "/a177", 0o347; "/a178", 0o350; "/a179", 0o351; "/a193", 0o352; "/a180", 0o353; "/a199", 0o354; "/a181", 0o355; "/a200", 0o356; "/a182", 0o357; "/a201", 0o361; "/a183", 0o362; "/a184", 0o363; "/a197", 0o364; "/a185", 0o365; "/a194", 0o366; "/a198", 0o367; "/a186", 0o370; "/a195", 0o371; "/a187", 0o372; "/a188", 0o373; "/a189", 0o374; "/a190", 0o375; "/a191", 0o376] (* Unicode equivalents for some of the PDF ZapfDingbats Encoding (Heuristic!). *) let dingbatmap_arr = [|"/a100", [0x275E]; "/a101", [0x2761]; "/a102", [0x2762]; "/a103", [0x2763]; "/a104", [0x2764]; "/a105", [0x2710]; "/a106", [0x2765]; "/a107", [0x2766]; "/a108", [0x2767]; "/a109", [0x2660]; "/a10", [0x2721]; "/a110", [0x2665]; "/a111", [0x2666]; "/a112", [0x2663]; "/a117", [0x2709]; "/a118", [0x2708]; "/a119", [0x2707]; "/a11", [0x261B]; "/a120", [0x2460]; "/a121", [0x2461]; "/a122", [0x2462]; "/a123", [0x2463]; "/a124", [0x2464]; "/a125", [0x2465]; "/a126", [0x2466]; "/a127", [0x2467]; "/a128", [0x2468]; "/a129", [0x2469]; "/a12", [0x261E]; "/a130", [0x2776]; "/a131", [0x2777]; "/a132", [0x2778]; "/a133", [0x2779]; "/a134", [0x277A]; "/a135", [0x277B]; "/a136", [0x277C]; "/a137", [0x277D]; "/a138", [0x277E]; "/a139", [0x277F]; "/a13", [0x270C]; "/a140", [0x2780]; "/a141", [0x2781]; "/a142", [0x2782]; "/a143", [0x2783]; "/a144", [0x2784]; "/a145", [0x2785]; "/a146", [0x2786]; "/a147", [0x2787]; "/a148", [0x2788]; "/a149", [0x2789]; "/a14", [0x270D]; "/a150", [0x278A]; "/a151", [0x278B]; "/a152", [0x278C]; "/a153", [0x278D]; "/a154", [0x278E]; "/a155", [0x278F]; "/a156", [0x2790]; "/a157", [0x2791]; "/a158", [0x2792]; "/a159", [0x2793]; "/a15", [0x270E]; "/a160", [0x2794]; "/a161", [0x2192]; "/a162", [0x27A3]; "/a163", [0x2194]; "/a164", [0x2195]; "/a165", [0x2799]; "/a166", [0x279B]; "/a167", [0x279C]; "/a168", [0x279D]; "/a169", [0x279E]; "/a16", [0x270F]; "/a170", [0x279F]; "/a171", [0x27A0]; "/a172", [0x27A1]; "/a173", [0x27A2]; "/a174", [0x27A4]; "/a175", [0x27A5]; "/a176", [0x27A6]; "/a177", [0x27A7]; "/a178", [0x27A8]; "/a179", [0x27A9]; "/a17", [0x2711]; "/a180", [0x27AB]; "/a181", [0x27AD]; "/a182", [0x27AF]; "/a183", [0x27B2]; "/a184", [0x27B3]; "/a185", [0x27B5]; "/a186", [0x27B8]; "/a187", [0x27BA]; "/a188", [0x27BB]; "/a189", [0x27BC]; "/a18", [0x2712]; "/a190", [0x27BD]; "/a191", [0x27BE]; "/a192", [0x279A]; "/a193", [0x27AA]; "/a194", [0x27B6]; "/a195", [0x27B9]; "/a196", [0x2798]; "/a197", [0x27B4]; "/a198", [0x27B7]; "/a199", [0x27AC]; "/a19", [0x2713]; "/a1", [0x2701]; "/a200", [0x27AE]; "/a201", [0x27B1]; "/a202", [0x2703]; "/a203", [0x2750]; "/a204", [0x2752]; "/a205", [0x276E]; "/a206", [0x2770]; "/a20", [0x2714]; "/a21", [0x2715]; "/a22", [0x2716]; "/a23", [0x2717]; "/a24", [0x2718]; "/a25", [0x2719]; "/a26", [0x271A]; "/a27", [0x271B]; "/a28", [0x271C]; "/a29", [0x2722]; "/a2", [0x2702]; "/a30", [0x2723]; "/a31", [0x2724]; "/a32", [0x2725]; "/a33", [0x2726]; "/a34", [0x2727]; "/a35", [0x2605]; "/a36", [0x2729]; "/a37", [0x272A]; "/a38", [0x272B]; "/a39", [0x272C]; "/a3", [0x2704]; "/a40", [0x272D]; "/a41", [0x272E]; "/a42", [0x272F]; "/a43", [0x2730]; "/a44", [0x2731]; "/a45", [0x2732]; "/a46", [0x2733]; "/a47", [0x2734]; "/a48", [0x2735]; "/a49", [0x2736]; "/a4", [0x260E]; "/a50", [0x2737]; "/a51", [0x2738]; "/a52", [0x2739]; "/a53", [0x273A]; "/a54", [0x273B]; "/a55", [0x273C]; "/a56", [0x273D]; "/a57", [0x273E]; "/a58", [0x273F]; "/a59", [0x2740]; "/a5", [0x2706]; "/a60", [0x2741]; "/a61", [0x2742]; "/a62", [0x2743]; "/a63", [0x2744]; "/a64", [0x2745]; "/a65", [0x2746]; "/a66", [0x2747]; "/a67", [0x2748]; "/a68", [0x2749]; "/a69", [0x274A]; "/a6", [0x271D]; "/a70", [0x274B]; "/a71", [0x25CF]; "/a72", [0x274D]; "/a73", [0x25A0]; "/a74", [0x274F]; "/a75", [0x2751]; "/a76", [0x25B2]; "/a77", [0x25BC]; "/a78", [0x25C6]; "/a79", [0x2756]; "/a7", [0x271E]; "/a81", [0x25D7]; "/a82", [0x2758]; "/a83", [0x2759]; "/a84", [0x275A]; "/a85", [0x276F]; "/a86", [0x2771]; "/a87", [0x2772]; "/a88", [0x2773]; "/a89", [0x2768]; "/a8", [0x271F]; "/a90", [0x2769]; "/a91", [0x276C]; "/a92", [0x276D]; "/a93", [0x276A]; "/a94", [0x276B]; "/a95", [0x2774]; "/a96", [0x2775]; "/a97", [0x275B]; "/a98", [0x275C]; "/a99", [0x275D]; "/a9", [0x2720]|] let dingbatmap = Array.to_list dingbatmap_arr (* Ditto truetype. Heuristic! *) let truetypemap_arr = [|"/G20", [0x0020]; "/G21", [0x0021]; "/G22", [0x0022]; "/G23", [0x0023]; "/G24", [0x0024]; "/G25", [0x0025]; "/G26", [0x0026]; "/G27", [0x0027]; "/G28", [0x0028]; "/G29", [0x0029]; "/G2a", [0x002A]; "/G2b", [0x002B]; "/G2c", [0x002C]; "/G2d", [0x002D]; "/G2e", [0x002E]; "/G2f", [0x002F]; "/G30", [0x0030]; "/G31", [0x0031]; "/G32", [0x0032]; "/G33", [0x0033]; "/G34", [0x0034]; "/G35", [0x0035]; "/G36", [0x0036]; "/G37", [0x0037]; "/G38", [0x0038]; "/G39", [0x0039]; "/G3a", [0x003A]; "/G3b", [0x003B]; "/G3c", [0x003C]; "/G3d", [0x003D]; "/G3e", [0x003E]; "/G3f", [0x003F]; "/G40", [0x0040]; "/G41", [0x0041]; "/G42", [0x0042]; "/G43", [0x0043]; "/G44", [0x0044]; "/G45", [0x0045]; "/G46", [0x0046]; "/G47", [0x0047]; "/G48", [0x0048]; "/G49", [0x0049]; "/G4a", [0x004A]; "/G4b", [0x004B]; "/G4c", [0x004C]; "/G4d", [0x004D]; "/G4e", [0x004E]; "/G4f", [0x004F]; "/G50", [0x0050]; "/G51", [0x0051]; "/G52", [0x0052]; "/G53", [0x0053]; "/G54", [0x0054]; "/G55", [0x0055]; "/G56", [0x0056]; "/G57", [0x0057]; "/G58", [0x0058]; "/G59", [0x0059]; "/G5a", [0x005A]; "/G5b", [0x005B]; "/G5c", [0x005C]; "/G5d", [0x005D]; "/G5e", [0x005E]; "/G5f", [0x005F]; "/G60", [0x0060]; "/G61", [0x0061]; "/G62", [0x0062]; "/G63", [0x0063]; "/G64", [0x0064]; "/G65", [0x0065]; "/G66", [0x0066]; "/G67", [0x0067]; "/G68", [0x0068]; "/G69", [0x0069]; "/G6a", [0x006A]; "/G6b", [0x006B]; "/G6c", [0x006C]; "/G6d", [0x006D]; "/G6e", [0x006E]; "/G6f", [0x006F]; "/G70", [0x0070]; "/G71", [0x0071]; "/G72", [0x0072]; "/G73", [0x0073]; "/G74", [0x0074]; "/G75", [0x0075]; "/G76", [0x0076]; "/G77", [0x0077]; "/G78", [0x0078]; "/G79", [0x0079]; "/G7a", [0x007A]; "/G7b", [0x007B]; "/G7c", [0x007C]; "/G7d", [0x007D]; "/G7e", [0x007E]; "/Ga0", [0x00A0]; "/Ga1", [0x00A1]; "/Ga2", [0x00A2]; "/Ga3", [0x00A3]; "/Ga4", [0x00A4]; "/Ga5", [0x00A5]; "/Ga6", [0x00A6]; "/Ga7", [0x00A7]; "/Ga8", [0x00A8]; "/Ga9", [0x00A9]; "/Gaa", [0x00AA]; "/Gab", [0x00AB]; "/Gac", [0x00AC]; "/Gad", [0x00AD]; "/Gae", [0x00AE]; "/Gaf", [0x00AF]; "/Gb0", [0x00B0]; "/Gb1", [0x00B1]; "/Gb2", [0x00B2]; "/Gb3", [0x00B3]; "/Gb4", [0x00B4]; "/Gb5", [0x00B5]; "/Gb6", [0x00B6]; "/Gb7", [0x00B7]; "/Gb8", [0x00B8]; "/Gb9", [0x00B9]; "/Gba", [0x00BA]; "/Gbb", [0x00BB]; "/Gbc", [0x00BC]; "/Gbd", [0x00BD]; "/Gbe", [0x00BE]; "/Gbf", [0x00BF]; "/Gc0", [0x00C0]; "/Gc1", [0x00C1]; "/Gc2", [0x00C2]; "/Gc3", [0x00C3]; "/Gc4", [0x00C4]; "/Gc5", [0x00C5]; "/Gc6", [0x00C6]; "/Gc7", [0x00C7]; "/Gc8", [0x00C8]; "/Gc9", [0x00C9]; "/Gca", [0x00CA]; "/Gcb", [0x00CB]; "/Gcc", [0x00CC]; "/Gcd", [0x00CD]; "/Gce", [0x00CE]; "/Gcf", [0x00CF]; "/Gd0", [0x00D0]; "/Gd1", [0x00D1]; "/Gd2", [0x00D2]; "/Gd3", [0x00D3]; "/Gd4", [0x00D4]; "/Gd5", [0x00D5]; "/Gd6", [0x00D6]; "/Gd7", [0x00D7]; "/Gd8", [0x00D8]; "/Gd9", [0x00D9]; "/Gda", [0x00DA]; "/Gdb", [0x00DB]; "/Gdc", [0x00DC]; "/Gdd", [0x00DD]; "/Gde", [0x00DE]; "/Gdf", [0x00DF]; "/Ge0", [0x00E0]; "/Ge1", [0x00E1]; "/Ge2", [0x00E2]; "/Ge3", [0x00E3]; "/Ge4", [0x00E4]; "/Ge5", [0x00E5]; "/Ge6", [0x00E6]; "/Ge7", [0x00E7]; "/Ge8", [0x00E8]; "/Ge9", [0x00E9]; "/Gea", [0x00EA]; "/Geb", [0x00EB]; "/Gec", [0x00EC]; "/Ged", [0x00ED]; "/Gee", [0x00EE]; "/Gef", [0x00EF]; "/Gf0", [0x00F0]; "/Gf1", [0x00F1]; "/Gf2", [0x00F2]; "/Gf3", [0x00F3]; "/Gf4", [0x00F4]; "/Gf5", [0x00F5]; "/Gf6", [0x00F6]; "/Gf7", [0x00F7]; "/Gf8", [0x00F8]; "/Gf9", [0x00F9]; "/Gfa", [0x00FA]; "/Gfb", [0x00FB]; "/Gfc", [0x00FC]; "/Gfd", [0x00FD]; "/Gfe", [0x00FE]; "/Gff", [0x00FF]; "/G82", [0x201A]; "/G83", [0x0192]; "/G84", [0x201E]; "/G85", [0x2026]; "/G86", [0x2020]; "/G87", [0x2021]; "/G88", [0x02C6]; "/G89", [0x2030]; "/G8a", [0x0160]; "/G8b", [0x2039]; "/G8c", [0x0152]; "/G91", [0x2018]; "/G92", [0x2019]; "/G93", [0x201C]; "/G94", [0x201D]; "/G95", [0x2022]; "/G96", [0x2013]; "/G97", [0x2014]; "/G98", [0x02DC]; "/G99", [0x2122]; "/G9a", [0x0161]; "/G9b", [0x203A]; "/G9c", [0x0153]; "/G9f", [0x0178]; "/G2A", [0x002A]; "/G2B", [0x002B]; "/G2C", [0x002C]; "/G2D", [0x002D]; "/G2E", [0x002E]; "/G2F", [0x002F]; "/G3A", [0x003A]; "/G3B", [0x003B]; "/G3C", [0x003C]; "/G3D", [0x003D]; "/G3E", [0x003E]; "/G3F", [0x003F]; "/G4A", [0x004A]; "/G4B", [0x004B]; "/G4C", [0x004C]; "/G4D", [0x004D]; "/G4E", [0x004E]; "/G4F", [0x004F]; "/G5A", [0x005A]; "/G5B", [0x005B]; "/G5C", [0x005C]; "/G5D", [0x005D]; "/G5E", [0x005E]; "/G5F", [0x005F]; "/G6A", [0x006A]; "/G6B", [0x006B]; "/G6C", [0x006C]; "/G6D", [0x002D]; "/G6E", [0x006E]; "/G6F", [0x006F]; "/G7A", [0x007A]; "/G7B", [0x007B]; "/G7C", [0x007C]; "/G7D", [0x007D]; "/G7E", [0x007E]; "/G8A", [0x008A]; "/G8B", [0x008B]; "/G8C", [0x008C]; "/G9A", [0x009A]; "/G9B", [0x009B]; "/G9C", [0x009C]; "/GA0", [0x00A0]; "/GA1", [0x00A1]; "/GA2", [0x00A2]; "/GA3", [0x00A3]; "/GA4", [0x00A4]; "/GA5", [0x00A5]; "/GA6", [0x00A6]; "/GA7", [0x00A7]; "/GA8", [0x00A8]; "/GA9", [0x00A9]; "/GAA", [0x00AA]; "/GAB", [0x00AB]; "/GAC", [0x00AC]; "/GAD", [0x00AD]; "/GAE", [0x00AE]; "/GAF", [0x00AF]; "/GB0", [0x00B0]; "/GB1", [0x00B1]; "/GB2", [0x00B2]; "/GB3", [0x00B3]; "/GB4", [0x00B4]; "/GB5", [0x00B5]; "/GA6", [0x00B6]; "/GB7", [0x00B7]; "/GB8", [0x00B8]; "/GB9", [0x00B9]; "/GBA", [0x00BA]; "/GBB", [0x00BB]; "/GBC", [0x00BC]; "/GBD", [0x00BD]; "/GBE", [0x00BE]; "/GBF", [0x00BF]; "/GC0", [0x00C0]; "/GC1", [0x00C1]; "/GC2", [0x00C2]; "/GC3", [0x00C3]; "/GC4", [0x00C4]; "/GC5", [0x00C5]; "/GC6", [0x00C6]; "/GC7", [0x00C7]; "/GC8", [0x00C8]; "/GC9", [0x00C9]; "/GCA", [0x00CA]; "/GCB", [0x00CB]; "/GCC", [0x00CC]; "/GCD", [0x00CD]; "/GCE", [0x00CE]; "/GCF", [0x00CF]; "/GD0", [0x00D0]; "/GD1", [0x00D1]; "/GD2", [0x00D2]; "/GD3", [0x00D3]; "/GD4", [0x00D4]; "/GD5", [0x00D5]; "/GD6", [0x00D6]; "/GD7", [0x00D7]; "/GD8", [0x00D8]; "/GD9", [0x00D9]; "/GDA", [0x00DA]; "/GDB", [0x00DB]; "/GDC", [0x00DC]; "/GDD", [0x00DD]; "/GDE", [0x00DE]; "/GDF", [0x00DF]; "/GE0", [0x00E0]; "/GE1", [0x00E1]; "/GE2", [0x00E2]; "/GE3", [0x00E3]; "/GE4", [0x00E4]; "/GE5", [0x00E5]; "/GE6", [0x00E6]; "/GE7", [0x00E7]; "/GE8", [0x00E8]; "/GE9", [0x00E9]; "/GEA", [0x00EA]; "/GEB", [0x00EB]; "/GEC", [0x00EC]; "/GED", [0x00ED]; "/GEE", [0x00EE]; "/GEF", [0x00EF]; "/GF0", [0x00F0]; "/GF1", [0x00F1]; "/GF2", [0x00F2]; "/GF3", [0x00F3]; "/GF4", [0x00F4]; "/GF5", [0x00F5]; "/GF6", [0x00F6]; "/GF7", [0x00F7]; "/GF8", [0x00F8]; "/GF9", [0x00F9]; "/GFA", [0x00FA]; "/GFB", [0x00FB]; "/GFC", [0x00FC]; "/GFD", [0x00FD]; "/GFE", [0x00FE]; "/GFF", [0x00FF]|] let truetypemap = Array.to_list truetypemap_arr (* The reverse glyph map is not a 1-1 mapping. So we need special version of hashtable_of_dictionary which a) prefers glyphs with alphabetic names over those earlier in the map which have numeric names b) Doesn't overwrite any entry already there, preserving any intelligence which might be in the ordering of the glyph map *) let revglyph_hashtable_of_dictionary pairs = let contains_digit s = mem true (map isdigit (explode s)) in let table = Hashtbl.create (length pairs) in iter (fun (k, v) -> try if contains_digit (Hashtbl.find table k) && not (contains_digit v) then Hashtbl.replace table k v with Not_found -> Hashtbl.add table k v) pairs; table let glyph_hashes = memoize (fun () -> hashtable_of_dictionary (glyphmap () @ dingbatmap @ truetypemap)) let reverse_glyph_hashes = memoize (fun () -> revglyph_hashtable_of_dictionary (map (fun (a, b) -> (b, a)) (glyphmap ()))) let name_to_pdf_hashes = hashtable_of_dictionary name_to_pdf let reverse_name_to_pdf_hashes = hashtable_of_dictionary (map (fun (a, b) -> (b, a)) name_to_pdf) camlpdf-2.8.1/pdfglyphlist.mli000066400000000000000000000025201477056064700163630ustar00rootroot00000000000000(** Glyph Lists *) (** The Adobe Glyph List, which maps character names to sequences of unicode codepoints. The source list is parsed into a hash table when called. *) val glyph_hashes : unit -> (string, int list) Hashtbl.t (** The reverse of [glyph_hashes]. The glyph list is not necessarily a one-to-one map, so this reversal is heuristic. *) val reverse_glyph_hashes : unit -> (int list, string) Hashtbl.t (** Convert a glyph name to a PDF encoding number *) val name_to_pdf : (string * int) list (** Convert a glyph name to a PDF encoding number, hash table version *) val name_to_pdf_hashes : (string, int) Hashtbl.t (** Convert a PDF encoding number to glyph name, hash table version. *) val reverse_name_to_pdf_hashes : (int, string) Hashtbl.t (** Convert a glyph name to a Windows encoding number *) val name_to_win : (string * int) list (** Convert a glyph name to a Standard encoding number *) val name_to_standard : (string * int) list (** Convert a glyph name to a MacRoman encoding number *) val name_to_macroman : (string * int) list (** Convert a glyph name to a MacExpert encoding number *) val name_to_macexpert : (string * int) list (** Convert a glyph name to a Symbol encoding number *) val name_to_symbol : (string * int) list (** Convert a glyph name to a Dingbats encoding number *) val name_to_dingbats : (string * int) list camlpdf-2.8.1/pdfglyphlist.source.ml000066400000000000000000001137201477056064700175160ustar00rootroot00000000000000open Pdfutil let glyphlist_src = __DATA:glyphlist.txt let parse_glyphlist i = let parse_line l = let len = String.length l in if len = 0 then None else if l.[0] = '#' then None else (* Find semicolon. Bail or extract name *) let semipos = try Some (String.index l ';') with Not_found -> None in match semipos with | None -> None | Some semipos -> let name = String.sub l 0 semipos in (* Read codes, one or more, space-delimited, four chars each. *) let codes = ref [] and pos = ref (semipos + 1) in try while true do codes := int_of_string ("0x" ^ String.sub l !pos 4)::!codes; pos += 5 done; Some ("", []) with _ -> Some ("/" ^ name, rev !codes) in let out = ref [] in try while true do match parse_line (Pdfio.read_line i) with | None -> () | Some (s, is) -> out := (s, is)::!out done; [] with End_of_file -> rev !out let glyphmap = memoize (fun () -> parse_glyphlist (Pdfio.input_of_string (Pdfio.string_of_bytes (Pdfcodec.decode_flate (Pdfio.bytes_of_string glyphlist_src))))) (*let _ = iter (fun (k, v) -> Printf.printf "%s = " k; iter (Printf.printf "%X ") v; flprint "\n") glyphmap*) let name_to_pdf = [ (* New items from ISO Standard D.3... These appear in annotation text, even though it's a text string. *) (* FIXME: Should we add all the codepoints, even those called undefined, to allow failures to be tracked? *) "/controlCR", 0o015; "/controlLF", 0o012; "/controlHT", 0o013; (* Original items from 1.6 spec *) "/A", 0o101; "/AE", 0o306; "/Aacute", 0o301; "/Acircumflex", 0o302; "/Adieresis", 0o304; "/Agrave", 0o300; "/Aring", 0o305; "/Atilde", 0o303; "/B", 0o102; "/C", 0o103; "/Ccedilla", 0o307; "/D", 0o104; "/E", 0o105; "/Eacute", 0o311; "/Ecircumflex", 0o312; "/Edieresis", 0o313; "/Egrave", 0o310; "/Eth", 0o320; "/Euro", 0o240; "/F", 0o106; "/G", 0o107; "/H", 0o110; "/I", 0o111; "/Iacute", 0o315; "/Icircumflex", 0o316; "/Idieresis", 0o317; "/Igrave", 0o314; "/J", 0o112; "/K", 0o113; "/L", 0o114; "/Lslash", 0o225; "/M", 0o115; "/N", 0o116; "/Ntilde", 0o321; "/O", 0o117; "/OE", 0o226; "/Oacute", 0o323; "/Ocircumflex", 0o324; "/Odieresis", 0o326; "/Ograve", 0o322; "/Oslash", 0o330; "/Otilde", 0o325; "/P", 0o120; "/Q", 0o121; "/R", 0o122; "/S", 0o123; "/Scaron", 0o227; "/T", 0o124; "/Thorn", 0o336; "/U", 0o125; "/Uacute", 0o332; "/Ucircumflex", 0o333; "/Udieresis", 0o334; "/Ugrave", 0o331; "/V", 0o126; "/W", 0o127; "/X", 0o130; "/Y", 0o131; "/Yacute", 0o335; "/Ydieresis", 0o230; "/Z", 0o132; "/Zcaron", 0o231; "/a", 0o141; "/aacute", 0o341; "/acircumflex", 0o342; "/acute", 0o264; "/adieresis", 0o344; "/ae", 0o346; "/agrave", 0o340; "/ampersand", 0o046; "/aring", 0o345; "/asciicircum", 0o136; "/asciitilde", 0o176; "/asterisk", 0o052; "/at", 0o100; "/atilde", 0o343; "/b", 0o142; "/backslash", 0o134; "/bar", 0o174; "/braceleft", 0o173; "/braceright", 0o175; "/bracketleft", 0o133; "/bracketright", 0o135; "/breve", 0o030; "/brokenbar", 0o246; "/bullet", 0o200; "/c", 0o143; "/caron", 0o031; "/ccedilla", 0o347; "/cedilla", 0o270; "/cent", 0o242; "/circumflex", 0o032; "/colon", 0o072; "/comma", 0o054; "/copyright", 0o251; "/currency", 0o244; "/d", 0o144; "/dagger", 0o201; "/daggerdbl", 0o202; "/degree", 0o260; "/dieresis", 0o250; "/divide", 0o367; "/dollar", 0o044; "/dotaccent", 0o033; "/dotlessi", 0o232; "/e", 0o145; "/eacute", 0o351; "/ecircumflex", 0o352; "/edieresis", 0o353; "/egrave", 0o350; "/eight", 0o070; "/ellipsis", 0o203; "/emdash", 0o204; "/endash", 0o205; "/equal", 0o075; "/eth", 0o360; "/exclam", 0o041; "/exclamdown", 0o241; "/f", 0o146; "/fi", 0o223; "/five", 0o065; "/fl", 0o223; "/florin", 0o206; "/four", 0o064; "/fraction", 0o207; "/g", 0o147; "/germandbls", 0o337; "/grave", 0o140; "/greater", 0o076; "/guillemotleft", 0o253; "/guillemotright", 0o273; "/guilsinglleft", 0o210; "/guilsinglright", 0o211; "/h", 0o150; "/hungarumlaut", 0o034; "/hyphen", 0o055; "/i", 0o151; "/iacute", 0o355; "/icircumflex", 0o356; "/idieresis", 0o357; "/igrave", 0o354; "/j", 0o152; "/k", 0o153; "/l", 0o154; "/less", 0o074; "/logicalnot", 0o254; "/lslash", 0o233; "/m", 0o155; "/macron", 0o257; "/minus", 0o212; "/mu", 0o265; "/multiply", 0o327; "/n", 0o156; "/nine", 0o071; "/ntilde", 0o361; "/numbersign", 0o043; "/o", 0o157; "/oacute", 0o363; "/ocircumflex", 0o364; "/odieresis", 0o366; "/oe", 0o234; "/ogonek", 0o035; "/ograve", 0o362; "/one", 0o061; "/onehalf", 0o275; "/onequarter", 0o274; "/onesuperior", 0o271; "/ordfeminine", 0o252; "/ordmasculine", 0o272; "/oslash", 0o370; "/otilde", 0o365; "/p", 0o160; "/paragraph", 0o266; "/parenleft", 0o050; "/parenright", 0o051; "/percent", 0o045; "/period", 0o056; "/periodcentered", 0o267; "/perthousand", 0o213; "/plus", 0o053; "/plusminus", 0o261; "/q", 0o161; "/question", 0o077; "/questiondown", 0o277; "/quotedbl", 0o042; "/quotedblbase", 0o214; "/quotedblleft", 0o215; "/quotedblright", 0o216; "/quoteleft", 0o217; "/quoteright", 0o220; "/quotesinglbase", 0o221; "/quotesingle", 0o047; "/r", 0o162; "/registered", 0o256; "/ring", 0o036; "/s", 0o163; "/scaron", 0o235; "/section", 0o247; "/semicolon", 0o073; "/seven", 0o067; "/six", 0o066; "/slash", 0o057; "/space", 0o040; "/sterling", 0o243; "/t", 0o164; "/thorn", 0o376; "/three", 0o063; "/threequarters", 0o276; "/threesuperior", 0o263; "/tilde", 0o037; "/trademark", 0o222; "/two", 0o062; "/twosuperior", 0o262; "/u", 0o165; "/uacute", 0o372; "/ucircumflex", 0o373; "/udieresis", 0o374; "/ugrave", 0o371; "/underscore", 0o137; "/v", 0o166; "/w", 0o167; "/x", 0o170; "/y", 0o171; "/yacute", 0o375; "/ydieresis", 0o377; "/yen", 0o245; "/z", 0o172; "/zcaron", 0o236; "/zero", 0o060] (* Standard encoding *) let name_to_standard = ["/A", 0o101; "/AE", 0o341; "/B", 0o102; "/C", 0o103; "/D", 0o104; "/E", 0o105; "/F", 0o106; "/G", 0o107; "/H", 0o110; "/I", 0o111; "/J", 0o112; "/K", 0o113; "/L", 0o114; "/Lslash", 0o350; "/M", 0o115; "/N", 0o116; "/O", 0o117; "/OE", 0o352; "/Oslash", 0o351; "/P", 0o120; "/Q", 0o121; "/R", 0o122; "/S", 0o123; "/T", 0o124; "/U", 0o125; "/V", 0o126; "/W", 0o127; "/X", 0o130; "/Y", 0o131; "/Z", 0o132; "/a", 0o141; "/acute", 0o302; "/ae", 0o361; "/ampersand", 0o046; "/asciicircum", 0o136; "/asciitilde", 0o176; "/asterisk", 0o052; "/at", 0o100; "/b", 0o142; "/backslash", 0o134; "/bar", 0o174; "/braceleft", 0o173; "/braceright", 0o175; "/bracketleft", 0o133; "/bracketright", 0o135; "/breve", 0o306; "/bullet", 0o267; "/c", 0o143; "/caron", 0o317; "/cedilla", 0o313; "/cent", 0o242; "/circumflex", 0o303; "/colon", 0o072; "/comma", 0o054; "/currency", 0o250; "/d", 0o144; "/dagger", 0o262; "/daggerdbl", 0o263; "/dieresis", 0o310; "/dollar", 0o044; "/dotaccent", 0o307; "/dottlessi", 0o365; "/e", 0o145; "/eight", 0o070; "/ellipsis", 0o274; "/emdash", 0o320; "/endash", 0o261; "/equal", 0o075; "/exclam", 0o041; "/exclamdown", 0o241; "/f", 0o146; "/fi", 0o256; "/five", 0o065; "/fl", 0o257; "/florin", 0o246; "/four", 0o064; "/fraction", 0o244; "/g", 0o147; "/germandbls", 0o373; "/grave", 0o301; "/greater", 0o076; "/guillemotleft", 0o253; "/guillemotright", 0o273; "/guilsinglleft", 0o254; "/guilsinglright", 0o255; "/h", 0o150; "/hungarumlaut", 0o315; "/hyphen", 0o055; "/i", 0o151; "/j", 0o152; "/k", 0o153; "/l", 0o154; "/less", 0o074; "/lslash", 0o370; "/m", 0o155; "/macron", 0o305; "/n", 0o156; "/nine", 0o071; "/numbersign", 0o043; "/o", 0o157; "/oe", 0o372; "/ogonek", 0o316; "/one", 0o061; "/ordfeminine", 0o343; "/ordmasculine", 0o353; "/oslash", 0o361; "/p", 0o160; "/paragraph", 0o266; "/parenleft", 0o050; "/parenright", 0o051; "/percent", 0o045; "/period", 0o056; "/periodcentered", 0o264; "/perthousand", 0o275; "/plus", 0o053; "/q", 0o161; "/question", 0o077; "/questiondown", 0o277; "/quotedbl", 0o042; "/quotedblbase", 0o271; "/quotedblleft", 0o252; "/quotedblright", 0o272; "/quoteleft", 0o140; "/quoteright", 0o047; "/quotesinglbase", 0o270; "/quotesingle", 0o251; "/r", 0o162; "/ring", 0o312; "/s", 0o163; "/section", 0o247; "/semicolon", 0o073; "/seven", 0o067; "/six", 0o066; "/slash", 0o057; "/space", 0o040; "/sterling", 0o243; "/t", 0o164; "/three", 0o063; "/tilde", 0o304; "/two", 0o062; "/u", 0o165; "/underscore", 0o137; "/v", 0o166; "/w", 0o167; "/x", 0o170; "/y", 0o171; "/yen", 0o245; "/z", 0o172; "/zero", 0o060] (* Mac Roman Encoding *) let name_to_macroman = ["/A", 0o101; "/AE", 0o256; "/Aacute", 0o347; "/Acircumflex", 0o345; "/Adieresis", 0o200; "/Agrave", 0o313; "/Aring", 0o201; "/Atilde", 0o314; "/B", 0o102; "/C", 0o103; "/Ccedilla", 0o202; "/D", 0o104; "/E", 0o105; "/Eacute", 0o203; "/Ecircumflex", 0o346; "/Edieresis", 0o350; "/Egrave", 0o351; "/F", 0o106; "/G", 0o107; "/H", 0o110; "/I", 0o111; "/Iacute", 0o352; "/Icircumflex", 0o353; "/Idieresis", 0o354; "/Igrave", 0o355; "/J", 0o112; "/K", 0o113; "/L", 0o114; "/M", 0o115; "/N", 0o116; "/Ntilde", 0o204; "/O", 0o117; "/OE", 0o316; "/Oacute", 0o356; "/Ocircumflex", 0o357; "/Odieresis", 0o205; "/Ograve", 0o361; "/Oslash", 0o257; "/Otilde", 0o315; "/P", 0o120; "/Q", 0o121; "/R", 0o122; "/S", 0o123; "/T", 0o124; "/U", 0o125; "/Uacute", 0o362; "/Ucircumflex", 0o363; "/Udieresis", 0o206; "/Ugrave", 0o364; "/V", 0o126; "/W", 0o127; "/X", 0o130; "/Y", 0o131; "/Ydieresis", 0o331; "/Z", 0o132; "/a", 0o141; "/aacute", 0o207; "/acircumflex", 0o211; "/acute", 0o253; "/adieresis", 0o212; "/ae", 0o276; "/agrave", 0o210; "/ampersand", 0o046; "/aring", 0o214; "/asciicircum", 0o136; "/asciitilde", 0o176; "/asterisk", 0o052; "/at", 0o100; "/atilde", 0o213; "/b", 0o142; "/backslash", 0o134; "/bar", 0o174; "/braceleft", 0o173; "/braceright", 0o175; "/bracketleft", 0o133; "/bracketright", 0o135; "/breve", 0o371; "/bullet", 0o245; "/c", 0o143; "/caron", 0o377; "/ccedilla", 0o215; "/cedilla", 0o374; "/cent", 0o242; "/circumflex", 0o366; "/colon", 0o072; "/comma", 0o054; "/copyright", 0o251; "/currency", 0o333; "/d", 0o144; "/dagger", 0o240; "/daggerdbl", 0o340; "/degree", 0o241; "/dieresis", 0o254; "/divide", 0o326; "/dollar", 0o044; "/dotaccent", 0o372; "/dotlessi", 0o365; "/e", 0o145; "/eacute", 0o216; "/ecircumflex", 0o220; "/edieresis", 0o221; "/egrave", 0o217; "/eight", 0o070; "/ellipsis", 0o311; "/emdash", 0o321; "/endash", 0o320; "/equal", 0o075; "/exclam", 0o041; "/exclamdown", 0o301; "/f", 0o146; "/fi", 0o336; "/five", 0o065; "/fl", 0o337; "/florin", 0o304; "/four", 0o064; "/fraction", 0o332; "/g", 0o147; "/germandbls", 0o247; "/grave", 0o140; "/greater", 0o076; "/guillemotleft", 0o307; "/guillemotright", 0o310; "/guilsinglleft", 0o334; "/guilsinglright", 0o335; "/h", 0o150; "/hungrumlaut", 0o375; "/hyphen", 0o055; "/i", 0o151; "/iacute", 0o222; "/icircumflex", 0o224; "/idieresis", 0o225; "/igrave", 0o223; "/j", 0o152; "/k", 0o153; "/l", 0o154; "/less", 0o074; "/logicalnot", 0o302; "/m", 0o155; "/macron", 0o370; "/mu", 0o265; "/n", 0o156; "/nine", 0o071; "/ntilde", 0o226; "/numbersign", 0o043; "/o", 0o157; "/oacute", 0o227; "/ocircumflex", 0o231; "/odieresis", 0o232; "/oe", 0o317; "/ogonek", 0o376; "/one", 0o061; "/ordfeminine", 0o273; "/ordmasculine", 0o274; "/oslash", 0o277; "/otilde", 0o233; "/p", 0o160; "/paragraph", 0o246; "/parenleft", 0o050; "/parenright", 0o051; "/percent", 0o045; "/period", 0o056; "/periodcentered", 0o341; "/perthousand", 0o344; "/plus", 0o053; "/plusminus", 0o261; "/q", 0o161; "/question", 0o077; "/questiondown", 0o300; "/quotedbl", 0o042; "/quotedblbase", 0o343; "/quotedblleft", 0o322; "/quotedblright", 0o323; "/quoteleft", 0o324; "/quoteright", 0o325; "/quotesinglbase", 0o342; "/quotesingle", 0o047; "/r", 0o162; "/registered", 0o250; "/ring", 0o373; "/s", 0o163; "/section", 0o244; "/semicolon", 0o073; "/seven", 0o067; "/six", 0o066; "/slash", 0o057; "/space", 0o040; "/sterling", 0o243; "/t", 0o164; "/three", 0o063; "/tilde", 0o367; "/trademark", 0o252; "/two", 0o062; "/u", 0o165; "/uacute", 0o234; "/ucircumflex", 0o236; "/udieresis", 0o237; "/ugrave", 0o235; "/underscore", 0o137; "/v", 0o166; "/w", 0o167; "/x", 0o170; "/y", 0o171; "/ydieresis", 0o330; "/yen", 0o264; "/z", 0o172; "/zero", 0o060; (*"/space", 0o312*)] (*FIXME: see below*) (* Win Ansi Encoding *) let name_to_win = ["/A", 0o101; "/AE", 0o306; "/Aacute", 0o301; "/Acircumflex", 0o302; "/Adieresis", 0o304; "/Agrave", 0o300; "/Aring", 0o305; "/Atilde", 0o303; "/B", 0o102; "/C", 0o103; "/Ccedilla", 0o307; "/D", 0o104; "/E", 0o105; "/Eacute", 0o311; "/Ecircumflex", 0o312; "/Edieresis", 0o313; "/Egrave", 0o310; "/Eth", 0o320; "/Euro", 0o200; "/F", 0o106; "/G", 0o107; "/H", 0o110; "/I", 0o111; "/Iacute", 0o315; "/Icircumflex", 0o316; "/Idieresis", 0o317; "/Igrave", 0o314; "/J", 0o112; "/K", 0o113; "/L", 0o114; "/M", 0o115; "/N", 0o116; "/Ntilde", 0o321; "/O", 0o117; "/OE", 0o214; "/Oacute", 0o323; "/Ocircumflex", 0o324; "/Odieresis", 0o326; "/Ograve", 0o322; "/Oslash", 0o330; "/Otilde", 0o325; "/P", 0o120; "/Q", 0o121; "/R", 0o122; "/S", 0o123; "/Scaron", 0o212; "/T", 0o124; "/Thorn", 0o336; "/U", 0o125; "/Uacute", 0o332; "/Ucircumflex", 0o333; "/Udieresis", 0o334; "/Ugrave", 0o331; "/V", 0o126; "/W", 0o127; "/X", 0o130; "/Y", 0o131; "/Yacute", 0o335; "/Ydieresis", 0o237; "/Z", 0o132; "/Zcaron", 0o216; "/a", 0o141; "/aacute", 0o341; "/acircumflex", 0o342; "/acute", 0o264; "/adieresis", 0o344; "/ae", 0o346; "/agrave", 0o340; "/ampersand", 0o046; "/aring", 0o345; "/asciicircum", 0o136; "/asciitilde", 0o176; "/asterisk", 0o052; "/at", 0o100; "/atilde", 0o343; "/b", 0o142; "/backslash", 0o134; "/bar", 0o174; "/braceleft", 0o173; "/braceright", 0o175; "/bracketleft", 0o133; "/bracketright", 0o135; "/brokenbar", 0o246; "/bullet", 0o225; "/c", 0o143; "/ccedilla", 0o347; "/cedilla", 0o270; "/cent", 0o242; "/circumflex", 0o210; "/colon", 0o072; "/comma", 0o054; "/copyright", 0o251; "/currency", 0o244; "/d", 0o144; "/dagger", 0o206; "/daggerdbl", 0o207; "/degree", 0o260; "/dieresis", 0o250; "/divide", 0o367; "/dollar",0o044; "/e", 0o145; "/eacute", 0o351; "/ecircumflex", 0o352; "/edieresis", 0o353; "/egrave", 0o350; "/eight", 0o070; "/ellipsis", 0o205; "/emdash", 0o227; "/endash", 0o226; "/equal", 0o075; "/eth", 0o360; "/exclam", 0o041; "/exclamdown", 0o241; "/f", 0o146; "/five", 0o065; "/florin", 0o203; "/four", 0o064; "/g", 0o147; "/germandbls", 0o337; "/grave", 0o140; "/greater", 0o076; "/guillemotleft", 0o253; "/guillemotright", 0o273; "/guilsinglleft", 0o213; "/guilsinglright", 0o233; "/h", 0o150; "/hyphen", 0o055; "/i", 0o151; "/iacute", 0o355; "/icircumflex", 0o356; "/idieresis", 0o357; "/igrave", 0o354; "/j", 0o152; "/k", 0o153; "/l", 0o154; "/less", 0o074; "/logicalnot", 0o254; "/m", 0o155; "/macron", 0o257; "/mu", 0o265; "/multiply", 0o327; "/n", 0o156; "/nine", 0o071; "/ntilde", 0o361; "/numbersign", 0o043; "/o", 0o157; "/oacute", 0o363; "/ocircumflex", 0o364; "/odieresis", 0o366; "/oe", 0o234; "/ograve", 0o362; "/one", 0o061; "/onehalf", 0o275; "/onequarter", 0o274; "/onesuperior", 0o271; "/ordfeminine", 0o252; "/ordmasculine", 0o272; "/oslash", 0o370; "/otilde", 0o365; "/p", 0o160; "/paragraph", 0o266; "/parenleft", 0o050; "/parenright", 0o051; "/percent", 0o045; "/period", 0o056; "/periodcentered", 0o267; "/perthousand", 0o211; "/plus", 0o053; "/plusminus", 0o261; "/q", 0o161; "/question", 0o077; "/questiondown", 0o277; "/quotedbl", 0o042; "/quotedblbase", 0o204; "/quotedblleft", 0o223; "/quotedblright", 0o224; "/quoteleft", 0o221; "/quoteright", 0o222; "/quotesinglbase", 0o202; "/quotesingle", 0o047; "/r", 0o162; "/registered", 0o256; "/s", 0o163; "/scaron", 0o232; "/section", 0o247; "/semicolon", 0o073; "/seven", 0o067; "/six", 0o066; "/slash", 0o057; "/space", 0o040; "/sterling", 0o243; "/t", 0o164; "/thorn", 0o376; "/three", 0o063; "/threequarters", 0o276; "/threesuperior", 0o263; "/tilde", 0o230; "/trademark", 0o231; "/two", 0o062; "/twosuperior", 0o262; "/u", 0o165; "/uacute", 0o372; "/ucircumflex", 0o373; "/udieresis", 0o374; "/ugrave", 0o371; "/underscore", 0o137; "/v", 0o166; "/w", 0o167; "/x", 0o170; "/y", 0o171; "/yacute", 0o375; "/ydieresis", 0o377; "/yen", 0o245; "/z", 0o172; "/zcaron", 0o236; "/zero", 0o060;(* "/space", 0o240; "/hyphen", 0o255*)] (*FIXME: need these rules back in, but only in the reverse.. To make 1-to-1?*) (* Mac Expert Encoding *) let name_to_macexpert = ["/AEsmall", 0o276; "/Aacutesmall", 0o207; "/Acircumflexsmall", 0o211; "/Acutesmall", 0o047; "/Adieresissmall", 0o212; "/Agravesmall", 0o210; "/Aringsmall", 0o214; "/Asmall", 0o141; "/Atildesmall", 0o213; "/Brevesmall", 0o363; "/Bsmall", 0o142; "/Caronsmall", 0o256; "/Ccedillasmall", 0o215; "/Cedillasmall", 0o311; "/Circumflexsmall", 0o136; "/Csmall", 0o143; "/Dieresissmall", 0o254; "/Dotaccentsmall", 0o372; "/Dsmall", 0o144; "/Eacutesmall", 0o216; "/Ecircumflexsmall", 0o220; "/Edieresissmall", 0o221; "/Egravesmall", 0o217; "/Esmall", 0o145; "/Ethsmall", 0o104; "/Fsmall", 0o146; "/Gravesmall", 0o140; "/Gsmall", 0o147; "/Hsmall", 0o150; "/Hungarumlautsmall", 0o042; "/Iacutesmall", 0o222; "/Icircumflexsmall", 0o224; "/Idieresissmall", 0o225; "/Igravesmall", 0o223; "/Ismall", 0o151; "/Jsmall", 0o152; "/Ksmall", 0o153; "/Lslashsmall", 0o302; "/Lsmall", 0o154; "/Macronsmall", 0o364; "/Msmall", 0o155; "/Nsmall", 0o156; "/Ntildesmall", 0o226; "/OEsmall", 0o317; "/Oacutesmall", 0o227; "/Ocircumflexsmall", 0o231; "/Odieresissmall", 0o232; "/Ogoneksmall", 0o362; "/Ogravesmall", 0o230; "/Oslashsmall", 0o277; "/Osmall", 0o157; "/Otildesmall", 0o233; "/Psmall", 0o160; "/Qsmall", 0o161; "/Ringsmall", 0o373; "/Rsmall", 0o162; "/Scaronsmall", 0o247; "/Ssmall", 0o163; "/Thornsmall", 0o271; "/Tildesmall", 0o176; "/Tsmall", 0o164; "/Uacutesmall", 0o234; "/Ucircumflexsmall", 0o236; "/Udieresissmall", 0o237; "/Ugravesmall", 0o235; "/Usmall", 0o165; "/Vsmall", 0o166; "/Wsmall", 0o167; "/Xsmall", 0o170; "/Yacutesmall", 0o264; "/Ydieresissmall", 0o330; "/Ysmall", 0o171; "/Zcaronsmall", 0o275; "/Zsmall", 0o172; "/ampersandsmall", 0o046; "/asuperior", 0o201; "/bsuperior", 0o365; "/centinferior", 0o251; "/centoldstyle", 0o043; "/centsuperior", 0o202; "/colon", 0o072; "/colonmonetary", 0o173; "/comma", 0o054; "/commainferior", 0o262; "/commasuperior", 0o370; "/dollarinferior", 0o266; "/dollaroldstyle", 0o044; "/dsuperior", 0o353; "/eightinferior", 0o245; "/eightoldstyle", 0o070; "/eightsuperior", 0o241; "/esuperior", 0o344; "/exclamdownsmall", 0o326; "/exclamsmall", 0o041; "/ff", 0o126; "/ffi", 0o131; "/ffl", 0o132; "/fi", 0o127; "/figuredash", 0o320; "/fiveeighths", 0o114; "/fiveinferior", 0o260; "/fiveoldstyle", 0o065; "/fivesuperior", 0o336; "/fl", 0o130; "/fourinferior", 0o242; "/fouroldstyle", 0o064; "/foursuperior", 0o335; "/fraction", 0o057; "/hyphen", 0o055; "/hypheninferior", 0o137; "/hyphensuperior", 0o137; "/isuperior", 0o351; "/lsuperior", 0o361; "/msuperior", 0o367; "/nineinferior", 0o273; "/nineoldstyle", 0o071; "/ninesuperior", 0o341; "/nsuperior", 0o366; "/onedotenleader", 0o053; "/oneeighth", 0o112; "/onefitted", 0o174; "/onehalf", 0o110; "/oneinferior", 0o301; "/oneoldstyle", 0o061; "/onequarter", 0o107; "/onesuperior", 0o332; "/onethird", 0o116; "/osuperior", 0o257; "/parenleftinferior", 0o133; "/parenleftsuperior", 0o050; "/parenrightinferior", 0o135; "/parenrightsuperior", 0o051; "/period", 0o056; "/periodinferior", 0o263; "/periodsuperior", 0o371; "/questiondownsmall", 0o300; "/questionsmall", 0o077; "/rsuperior", 0o345; "/rupiah", 0o175; "/semicolon", 0o073; "/seveneighths", 0o115; "/seveninferior", 0o246; "/sevenoldstyle", 0o067; "/sevensuperior", 0o340; "/sixinferior", 0o244; "/sixoldstyle", 0o066; "/sixsuperior", 0o337; "/space", 0o040; "/ssuperior", 0o352; "/threeeighths", 0o113; "/threeinferior", 0o243; "/threeoldstyle", 0o063; "/threequarters", 0o111; "/threequartersemdash", 0o075; "/threesuperior", 0o334; "/tsuperior", 0o346; "/twodotenleader", 0o052; "/twoinferior", 0o252; "/twooldstyle", 0o062; "/twosuperior", 0o333; "/twothirds", 0o117; "/zeroinferior", 0o274; "/zerooldstyle", 0o060; "/zerosuperior", 0o342] (* Symbol Encoding *) let name_to_symbol = ["/Alpha", 0o101; "/Beta", 0o102; "/Chi", 0o103; "/Delta", 0o104; "/Epsilon", 0o105; "/Eta", 0o110; "/Euro", 0o240; "/Gamma", 0o107; "/Ifraktur", 0o301; "/Iota", 0o111; "/Kappa", 0o113; "/Lambda", 0o114; "/Mu", 0o115; "/Nu", 0o116; "/Omega", 0o127; "/Omicron", 0o117; "/Phi", 0o106; "/Pi", 0o120; "/Psi", 0o131; "/Rfraktur", 0o302; "/Rho", 0o122; "/Sigma", 0o123; "/Tau", 0o124; "/Theta", 0o121; "/Upsilon", 0o125; "/Upsilon1", 0o241; "/Xi", 0o130; "/Zeta", 0o132; "/aleph", 0o300; "/alpha", 0o141; "/ampersand", 0o046; "/angle", 0o320; "/angleleft", 0o341; "/angleright", 0o361; "/approxequal", 0o273; "/arrowboth", 0o253; "/arrowdblboth", 0o333; "/arrowdbldown", 0o337; "/arrowdblleft", 0o334; "/arrowdblright", 0o336; "/arrowhorizex", 0o276; "/arrowleft", 0o254; "/arrowright", 0o256; "/arrowup", 0o255; "/arrowvertex", 0o275; "/asteriskmath", 0o052; "/bar", 0o174; "/beta", 0o142; "/braceleft", 0o173; "/braceright", 0o175; "/bracelefttp", 0o354; "/braceleftmid", 0o355; "/braceleftbt", 0o376; "/bracerighttp", 0o374; "/bracerightmid", 0o375; "/bracerightbt", 0o376; "/braceex", 0o357; "/bracketleft", 0o133; "/bracketright", 0o135; "/bracketlefttp", 0o351; "/bracketleftex", 0o352; "/bracketleftbt", 0o353; "/bracketrighttp", 0o371; "/brackerrightex", 0o372; "/bracketrightbt", 0o373; "/bullet", 0o267; "/carriagereturn", 0o277; "/chi", 0o143; "/circlemultiply", 0o304; "/circleplus", 0o305; "/club", 0o247; "/colon", 0o072; "/comma", 0o054; "/congruent", 0o100; "/copyrightsans", 0o343; "/copyrightserif", 0o323; "/degree", 0o260; "/delta", 0o144; "/diamond", 0o250; "/divide", 0o270; "/dotmath", 0o327; "/eight", 0o070; "/element", 0o316; "/ellipsis", 0o274; "/emptyset", 0o306; "/epsilon", 0o145; "/equal", 0o075; "/equivalence", 0o272; "/eta", 0o150; "/exclam", 0o041; "/existential", 0o044; "/five", 0o065; "/florin", 0o246; "/four", 0o064; "/fraction", 0o244; "/gamma", 0o147; "/gradient", 0o321; "/greater", 0o076; "/greaterequal", 0o263; "/heart", 0o251; "/infinity", 0o245; "/integral", 0o362; "/integraltp", 0o363; "/integralex", 0o364; "/integralbt", 0o365; "/intersection", 0o307; "/iota", 0o151; "/kappa", 0o153; "/lambda", 0o154; "/less", 0o074; "/lessequal", 0o243; "/logicaland", 0o331; "/logicalnot", 0o330; "/logicalor", 0o332; "/lozenge", 0o340; "/minus", 0o055; "/minute", 0o242; "/mu", 0o155; "/multiply", 0o264; "/nine", 0o071; "/notelement", 0o317; "/notequal", 0o271; "/notsubset", 0o313; "/nu", 0o156; "/numbersign", 0o043; "/omega", 0o167; "/omega1", 0o166; "/omicron", 0o157; "/one", 0o061; "/parenleft", 0o050; "/parenright", 0o051; "/parenlefttp", 0o346; "/parenleftex", 0o347; "/parenleftbt", 0o350; "/parenrighttp", 0o366; "/parenrightex", 0o367; "/parenrightbt", 0o370; "/partialdiff", 0o266; "/percent", 0o045; "/period", 0o056; "/perpendicular", 0o136; "/phi", 0o146; "/phi1", 0o152; "/pi", 0o160; "/plus", 0o153; "/plusminus", 0o261; "/product", 0o325; "/propersubset", 0o314; "/propersuperset", 0o311; "/proportional", 0o265; "/psi", 0o171; "/question", 0o077; "/radical", 0o326; "/radicalex", 0o140; "/reflexsubset", 0o315; "/reflexsuperset", 0o312; "/registersans", 0o342; "/registerserif", 0o322; "/rho", 0o162; "/second", 0o262; "/semicolon", 0o073; "/seven", 0o067; "/sigma", 0o163; "/sigma1", 0o126; "/similar", 0o176; "/six", 0o066; "/slash", 0o157; "/space", 0o040; "/spade", 0o252; "/suchthat", 0o047; "/summation", 0o345; "/tau", 0o164; "/therefore", 0o134; "/theta", 0o161; "/theta1", 0o112; "/three", 0o063; "/trademarksans", 0o344; "/trademarkserif", 0o324; "/two", 0o062; "/underscore", 0o137; "/union", 0o310; "/universal", 0o042; "/upsilon", 0o165; "/weierstrass", 0o303; "/xi", 0o303; "/zero", 0o060; "/zeta", 0o172] (* 6. Dingbats encoding *) let name_to_dingbats = ["/space", 0o040; "/a1", 0o041; "/a2", 0o042; "/a202", 0o043; "/a3", 0o044; "/a4", 0o045; "/a5", 0o046; "/a119", 0o047; "/a118", 0o050; "/a117", 0o051; "/a11", 0o052; "/a12", 0o053; "/a13", 0o054; "/a14", 0o055; "/a15", 0o056; "/a16", 0o057; "/a105", 0o060; "/a17", 0o061; "/a18", 0o062; "/a19", 0o063; "/a20", 0o064; "/a21", 0o065; "/a22", 0o066; "/a23", 0o067; "/a24", 0o070; "/a25", 0o071; "/a26", 0o072; "/a27", 0o073; "/a28", 0o074; "/a6", 0o075; "/a7", 0o076; "/a8", 0o077; "/a9", 0o100; "/a10", 0o101; "/a29", 0o102; "/a30", 0o103; "/a31", 0o104; "/a32", 0o105; "/a33", 0o106; "/a34", 0o107; "/a35", 0o110; "/a36", 0o111; "/a37", 0o112; "/a38", 0o113; "/a39", 0o114; "/a40", 0o115; "/a41", 0o116; "/a42", 0o117; "/a43", 0o120; "/a44", 0o121; "/a45", 0o122; "/a46", 0o123; "/a47", 0o124; "/a48", 0o125; "/a49", 0o126; "/a50", 0o127; "/a51", 0o130; "/a52", 0o131; "/a53", 0o132; "/a54", 0o133; "/a55", 0o134; "/a56", 0o135; "/a57", 0o136; "/a58", 0o137; "/a59", 0o140; "/a60", 0o141; "/a61", 0o142; "/a62", 0o143; "/a63", 0o144; "/a64", 0o145; "/a65", 0o146; "/a66", 0o147; "/a67", 0o150; "/a68", 0o151; "/a69", 0o152; "/a70", 0o153; "/a71", 0o154; "/a72", 0o155; "/a73", 0o156; "/a74", 0o157; "/a203", 0o160; "/a75", 0o161; "/a204", 0o162; "/a76", 0o163; "/a77", 0o164; "/a78", 0o165; "/a79", 0o166; "/a81", 0o167; "/a82", 0o170; "/a83", 0o171; "/a84", 0o172; "/a97", 0o173; "/a98", 0o174; "/a99", 0o175; "/a100", 0o176; "/a101", 0o241; "/a102", 0o242; "/a103", 0o243; "/a104", 0o244; "/a106", 0o245; "/a107", 0o246; "/a108", 0o247; "/a112", 0o250; "/a111", 0o251; "/a110", 0o252; "/a109", 0o253; "/a120", 0o254; "/a121", 0o255; "/a122", 0o256; "/a123", 0o257; "/a124", 0o260; "/a125", 0o261; "/a126", 0o262; "/a127", 0o263; "/a128", 0o264; "/a129", 0o265; "/a130", 0o266; "/a131", 0o267; "/a132", 0o270; "/a133", 0o271; "/a134", 0o272; "/a135", 0o273; "/a136", 0o274; "/a137", 0o275; "/a138", 0o276; "/a139", 0o277; "/a140", 0o300; "/a141", 0o301; "/a142", 0o302; "/a143", 0o303; "/a144", 0o304; "/a145", 0o305; "/a146", 0o306; "/a147", 0o307; "/a148", 0o310; "/a149", 0o311; "/a150", 0o312; "/a151", 0o313; "/a152", 0o314; "/a153", 0O315; "/a154", 0o316; "/a155", 0o317; "/a156", 0o320; "/a157", 0o321; "/a158", 0o322; "/a159", 0o323; "/a160", 0o324; "/a161", 0o325; "/a163", 0o326; "/a164", 0o327; "/a196", 0o330; "/a165", 0o331; "/a192", 0o332; "/a166", 0o333; "/a167", 0o334; "/a168", 0o335; "/a169", 0o336; "/a170", 0o337; "/a171", 0o340; "/a172", 0o341; "/a173", 0o342; "/a162", 0o343; "/a174", 0o344; "/a175", 0o345; "/a176", 0o346; "/a177", 0o347; "/a178", 0o350; "/a179", 0o351; "/a193", 0o352; "/a180", 0o353; "/a199", 0o354; "/a181", 0o355; "/a200", 0o356; "/a182", 0o357; "/a201", 0o361; "/a183", 0o362; "/a184", 0o363; "/a197", 0o364; "/a185", 0o365; "/a194", 0o366; "/a198", 0o367; "/a186", 0o370; "/a195", 0o371; "/a187", 0o372; "/a188", 0o373; "/a189", 0o374; "/a190", 0o375; "/a191", 0o376] (* Unicode equivalents for some of the PDF ZapfDingbats Encoding (Heuristic!). *) let dingbatmap_arr = [|"/a100", [0x275E]; "/a101", [0x2761]; "/a102", [0x2762]; "/a103", [0x2763]; "/a104", [0x2764]; "/a105", [0x2710]; "/a106", [0x2765]; "/a107", [0x2766]; "/a108", [0x2767]; "/a109", [0x2660]; "/a10", [0x2721]; "/a110", [0x2665]; "/a111", [0x2666]; "/a112", [0x2663]; "/a117", [0x2709]; "/a118", [0x2708]; "/a119", [0x2707]; "/a11", [0x261B]; "/a120", [0x2460]; "/a121", [0x2461]; "/a122", [0x2462]; "/a123", [0x2463]; "/a124", [0x2464]; "/a125", [0x2465]; "/a126", [0x2466]; "/a127", [0x2467]; "/a128", [0x2468]; "/a129", [0x2469]; "/a12", [0x261E]; "/a130", [0x2776]; "/a131", [0x2777]; "/a132", [0x2778]; "/a133", [0x2779]; "/a134", [0x277A]; "/a135", [0x277B]; "/a136", [0x277C]; "/a137", [0x277D]; "/a138", [0x277E]; "/a139", [0x277F]; "/a13", [0x270C]; "/a140", [0x2780]; "/a141", [0x2781]; "/a142", [0x2782]; "/a143", [0x2783]; "/a144", [0x2784]; "/a145", [0x2785]; "/a146", [0x2786]; "/a147", [0x2787]; "/a148", [0x2788]; "/a149", [0x2789]; "/a14", [0x270D]; "/a150", [0x278A]; "/a151", [0x278B]; "/a152", [0x278C]; "/a153", [0x278D]; "/a154", [0x278E]; "/a155", [0x278F]; "/a156", [0x2790]; "/a157", [0x2791]; "/a158", [0x2792]; "/a159", [0x2793]; "/a15", [0x270E]; "/a160", [0x2794]; "/a161", [0x2192]; "/a162", [0x27A3]; "/a163", [0x2194]; "/a164", [0x2195]; "/a165", [0x2799]; "/a166", [0x279B]; "/a167", [0x279C]; "/a168", [0x279D]; "/a169", [0x279E]; "/a16", [0x270F]; "/a170", [0x279F]; "/a171", [0x27A0]; "/a172", [0x27A1]; "/a173", [0x27A2]; "/a174", [0x27A4]; "/a175", [0x27A5]; "/a176", [0x27A6]; "/a177", [0x27A7]; "/a178", [0x27A8]; "/a179", [0x27A9]; "/a17", [0x2711]; "/a180", [0x27AB]; "/a181", [0x27AD]; "/a182", [0x27AF]; "/a183", [0x27B2]; "/a184", [0x27B3]; "/a185", [0x27B5]; "/a186", [0x27B8]; "/a187", [0x27BA]; "/a188", [0x27BB]; "/a189", [0x27BC]; "/a18", [0x2712]; "/a190", [0x27BD]; "/a191", [0x27BE]; "/a192", [0x279A]; "/a193", [0x27AA]; "/a194", [0x27B6]; "/a195", [0x27B9]; "/a196", [0x2798]; "/a197", [0x27B4]; "/a198", [0x27B7]; "/a199", [0x27AC]; "/a19", [0x2713]; "/a1", [0x2701]; "/a200", [0x27AE]; "/a201", [0x27B1]; "/a202", [0x2703]; "/a203", [0x2750]; "/a204", [0x2752]; "/a205", [0x276E]; "/a206", [0x2770]; "/a20", [0x2714]; "/a21", [0x2715]; "/a22", [0x2716]; "/a23", [0x2717]; "/a24", [0x2718]; "/a25", [0x2719]; "/a26", [0x271A]; "/a27", [0x271B]; "/a28", [0x271C]; "/a29", [0x2722]; "/a2", [0x2702]; "/a30", [0x2723]; "/a31", [0x2724]; "/a32", [0x2725]; "/a33", [0x2726]; "/a34", [0x2727]; "/a35", [0x2605]; "/a36", [0x2729]; "/a37", [0x272A]; "/a38", [0x272B]; "/a39", [0x272C]; "/a3", [0x2704]; "/a40", [0x272D]; "/a41", [0x272E]; "/a42", [0x272F]; "/a43", [0x2730]; "/a44", [0x2731]; "/a45", [0x2732]; "/a46", [0x2733]; "/a47", [0x2734]; "/a48", [0x2735]; "/a49", [0x2736]; "/a4", [0x260E]; "/a50", [0x2737]; "/a51", [0x2738]; "/a52", [0x2739]; "/a53", [0x273A]; "/a54", [0x273B]; "/a55", [0x273C]; "/a56", [0x273D]; "/a57", [0x273E]; "/a58", [0x273F]; "/a59", [0x2740]; "/a5", [0x2706]; "/a60", [0x2741]; "/a61", [0x2742]; "/a62", [0x2743]; "/a63", [0x2744]; "/a64", [0x2745]; "/a65", [0x2746]; "/a66", [0x2747]; "/a67", [0x2748]; "/a68", [0x2749]; "/a69", [0x274A]; "/a6", [0x271D]; "/a70", [0x274B]; "/a71", [0x25CF]; "/a72", [0x274D]; "/a73", [0x25A0]; "/a74", [0x274F]; "/a75", [0x2751]; "/a76", [0x25B2]; "/a77", [0x25BC]; "/a78", [0x25C6]; "/a79", [0x2756]; "/a7", [0x271E]; "/a81", [0x25D7]; "/a82", [0x2758]; "/a83", [0x2759]; "/a84", [0x275A]; "/a85", [0x276F]; "/a86", [0x2771]; "/a87", [0x2772]; "/a88", [0x2773]; "/a89", [0x2768]; "/a8", [0x271F]; "/a90", [0x2769]; "/a91", [0x276C]; "/a92", [0x276D]; "/a93", [0x276A]; "/a94", [0x276B]; "/a95", [0x2774]; "/a96", [0x2775]; "/a97", [0x275B]; "/a98", [0x275C]; "/a99", [0x275D]; "/a9", [0x2720]|] let dingbatmap = Array.to_list dingbatmap_arr (* Ditto truetype. Heuristic! *) let truetypemap_arr = [|"/G20", [0x0020]; "/G21", [0x0021]; "/G22", [0x0022]; "/G23", [0x0023]; "/G24", [0x0024]; "/G25", [0x0025]; "/G26", [0x0026]; "/G27", [0x0027]; "/G28", [0x0028]; "/G29", [0x0029]; "/G2a", [0x002A]; "/G2b", [0x002B]; "/G2c", [0x002C]; "/G2d", [0x002D]; "/G2e", [0x002E]; "/G2f", [0x002F]; "/G30", [0x0030]; "/G31", [0x0031]; "/G32", [0x0032]; "/G33", [0x0033]; "/G34", [0x0034]; "/G35", [0x0035]; "/G36", [0x0036]; "/G37", [0x0037]; "/G38", [0x0038]; "/G39", [0x0039]; "/G3a", [0x003A]; "/G3b", [0x003B]; "/G3c", [0x003C]; "/G3d", [0x003D]; "/G3e", [0x003E]; "/G3f", [0x003F]; "/G40", [0x0040]; "/G41", [0x0041]; "/G42", [0x0042]; "/G43", [0x0043]; "/G44", [0x0044]; "/G45", [0x0045]; "/G46", [0x0046]; "/G47", [0x0047]; "/G48", [0x0048]; "/G49", [0x0049]; "/G4a", [0x004A]; "/G4b", [0x004B]; "/G4c", [0x004C]; "/G4d", [0x004D]; "/G4e", [0x004E]; "/G4f", [0x004F]; "/G50", [0x0050]; "/G51", [0x0051]; "/G52", [0x0052]; "/G53", [0x0053]; "/G54", [0x0054]; "/G55", [0x0055]; "/G56", [0x0056]; "/G57", [0x0057]; "/G58", [0x0058]; "/G59", [0x0059]; "/G5a", [0x005A]; "/G5b", [0x005B]; "/G5c", [0x005C]; "/G5d", [0x005D]; "/G5e", [0x005E]; "/G5f", [0x005F]; "/G60", [0x0060]; "/G61", [0x0061]; "/G62", [0x0062]; "/G63", [0x0063]; "/G64", [0x0064]; "/G65", [0x0065]; "/G66", [0x0066]; "/G67", [0x0067]; "/G68", [0x0068]; "/G69", [0x0069]; "/G6a", [0x006A]; "/G6b", [0x006B]; "/G6c", [0x006C]; "/G6d", [0x006D]; "/G6e", [0x006E]; "/G6f", [0x006F]; "/G70", [0x0070]; "/G71", [0x0071]; "/G72", [0x0072]; "/G73", [0x0073]; "/G74", [0x0074]; "/G75", [0x0075]; "/G76", [0x0076]; "/G77", [0x0077]; "/G78", [0x0078]; "/G79", [0x0079]; "/G7a", [0x007A]; "/G7b", [0x007B]; "/G7c", [0x007C]; "/G7d", [0x007D]; "/G7e", [0x007E]; "/Ga0", [0x00A0]; "/Ga1", [0x00A1]; "/Ga2", [0x00A2]; "/Ga3", [0x00A3]; "/Ga4", [0x00A4]; "/Ga5", [0x00A5]; "/Ga6", [0x00A6]; "/Ga7", [0x00A7]; "/Ga8", [0x00A8]; "/Ga9", [0x00A9]; "/Gaa", [0x00AA]; "/Gab", [0x00AB]; "/Gac", [0x00AC]; "/Gad", [0x00AD]; "/Gae", [0x00AE]; "/Gaf", [0x00AF]; "/Gb0", [0x00B0]; "/Gb1", [0x00B1]; "/Gb2", [0x00B2]; "/Gb3", [0x00B3]; "/Gb4", [0x00B4]; "/Gb5", [0x00B5]; "/Gb6", [0x00B6]; "/Gb7", [0x00B7]; "/Gb8", [0x00B8]; "/Gb9", [0x00B9]; "/Gba", [0x00BA]; "/Gbb", [0x00BB]; "/Gbc", [0x00BC]; "/Gbd", [0x00BD]; "/Gbe", [0x00BE]; "/Gbf", [0x00BF]; "/Gc0", [0x00C0]; "/Gc1", [0x00C1]; "/Gc2", [0x00C2]; "/Gc3", [0x00C3]; "/Gc4", [0x00C4]; "/Gc5", [0x00C5]; "/Gc6", [0x00C6]; "/Gc7", [0x00C7]; "/Gc8", [0x00C8]; "/Gc9", [0x00C9]; "/Gca", [0x00CA]; "/Gcb", [0x00CB]; "/Gcc", [0x00CC]; "/Gcd", [0x00CD]; "/Gce", [0x00CE]; "/Gcf", [0x00CF]; "/Gd0", [0x00D0]; "/Gd1", [0x00D1]; "/Gd2", [0x00D2]; "/Gd3", [0x00D3]; "/Gd4", [0x00D4]; "/Gd5", [0x00D5]; "/Gd6", [0x00D6]; "/Gd7", [0x00D7]; "/Gd8", [0x00D8]; "/Gd9", [0x00D9]; "/Gda", [0x00DA]; "/Gdb", [0x00DB]; "/Gdc", [0x00DC]; "/Gdd", [0x00DD]; "/Gde", [0x00DE]; "/Gdf", [0x00DF]; "/Ge0", [0x00E0]; "/Ge1", [0x00E1]; "/Ge2", [0x00E2]; "/Ge3", [0x00E3]; "/Ge4", [0x00E4]; "/Ge5", [0x00E5]; "/Ge6", [0x00E6]; "/Ge7", [0x00E7]; "/Ge8", [0x00E8]; "/Ge9", [0x00E9]; "/Gea", [0x00EA]; "/Geb", [0x00EB]; "/Gec", [0x00EC]; "/Ged", [0x00ED]; "/Gee", [0x00EE]; "/Gef", [0x00EF]; "/Gf0", [0x00F0]; "/Gf1", [0x00F1]; "/Gf2", [0x00F2]; "/Gf3", [0x00F3]; "/Gf4", [0x00F4]; "/Gf5", [0x00F5]; "/Gf6", [0x00F6]; "/Gf7", [0x00F7]; "/Gf8", [0x00F8]; "/Gf9", [0x00F9]; "/Gfa", [0x00FA]; "/Gfb", [0x00FB]; "/Gfc", [0x00FC]; "/Gfd", [0x00FD]; "/Gfe", [0x00FE]; "/Gff", [0x00FF]; "/G82", [0x201A]; "/G83", [0x0192]; "/G84", [0x201E]; "/G85", [0x2026]; "/G86", [0x2020]; "/G87", [0x2021]; "/G88", [0x02C6]; "/G89", [0x2030]; "/G8a", [0x0160]; "/G8b", [0x2039]; "/G8c", [0x0152]; "/G91", [0x2018]; "/G92", [0x2019]; "/G93", [0x201C]; "/G94", [0x201D]; "/G95", [0x2022]; "/G96", [0x2013]; "/G97", [0x2014]; "/G98", [0x02DC]; "/G99", [0x2122]; "/G9a", [0x0161]; "/G9b", [0x203A]; "/G9c", [0x0153]; "/G9f", [0x0178]; "/G2A", [0x002A]; "/G2B", [0x002B]; "/G2C", [0x002C]; "/G2D", [0x002D]; "/G2E", [0x002E]; "/G2F", [0x002F]; "/G3A", [0x003A]; "/G3B", [0x003B]; "/G3C", [0x003C]; "/G3D", [0x003D]; "/G3E", [0x003E]; "/G3F", [0x003F]; "/G4A", [0x004A]; "/G4B", [0x004B]; "/G4C", [0x004C]; "/G4D", [0x004D]; "/G4E", [0x004E]; "/G4F", [0x004F]; "/G5A", [0x005A]; "/G5B", [0x005B]; "/G5C", [0x005C]; "/G5D", [0x005D]; "/G5E", [0x005E]; "/G5F", [0x005F]; "/G6A", [0x006A]; "/G6B", [0x006B]; "/G6C", [0x006C]; "/G6D", [0x002D]; "/G6E", [0x006E]; "/G6F", [0x006F]; "/G7A", [0x007A]; "/G7B", [0x007B]; "/G7C", [0x007C]; "/G7D", [0x007D]; "/G7E", [0x007E]; "/G8A", [0x008A]; "/G8B", [0x008B]; "/G8C", [0x008C]; "/G9A", [0x009A]; "/G9B", [0x009B]; "/G9C", [0x009C]; "/GA0", [0x00A0]; "/GA1", [0x00A1]; "/GA2", [0x00A2]; "/GA3", [0x00A3]; "/GA4", [0x00A4]; "/GA5", [0x00A5]; "/GA6", [0x00A6]; "/GA7", [0x00A7]; "/GA8", [0x00A8]; "/GA9", [0x00A9]; "/GAA", [0x00AA]; "/GAB", [0x00AB]; "/GAC", [0x00AC]; "/GAD", [0x00AD]; "/GAE", [0x00AE]; "/GAF", [0x00AF]; "/GB0", [0x00B0]; "/GB1", [0x00B1]; "/GB2", [0x00B2]; "/GB3", [0x00B3]; "/GB4", [0x00B4]; "/GB5", [0x00B5]; "/GA6", [0x00B6]; "/GB7", [0x00B7]; "/GB8", [0x00B8]; "/GB9", [0x00B9]; "/GBA", [0x00BA]; "/GBB", [0x00BB]; "/GBC", [0x00BC]; "/GBD", [0x00BD]; "/GBE", [0x00BE]; "/GBF", [0x00BF]; "/GC0", [0x00C0]; "/GC1", [0x00C1]; "/GC2", [0x00C2]; "/GC3", [0x00C3]; "/GC4", [0x00C4]; "/GC5", [0x00C5]; "/GC6", [0x00C6]; "/GC7", [0x00C7]; "/GC8", [0x00C8]; "/GC9", [0x00C9]; "/GCA", [0x00CA]; "/GCB", [0x00CB]; "/GCC", [0x00CC]; "/GCD", [0x00CD]; "/GCE", [0x00CE]; "/GCF", [0x00CF]; "/GD0", [0x00D0]; "/GD1", [0x00D1]; "/GD2", [0x00D2]; "/GD3", [0x00D3]; "/GD4", [0x00D4]; "/GD5", [0x00D5]; "/GD6", [0x00D6]; "/GD7", [0x00D7]; "/GD8", [0x00D8]; "/GD9", [0x00D9]; "/GDA", [0x00DA]; "/GDB", [0x00DB]; "/GDC", [0x00DC]; "/GDD", [0x00DD]; "/GDE", [0x00DE]; "/GDF", [0x00DF]; "/GE0", [0x00E0]; "/GE1", [0x00E1]; "/GE2", [0x00E2]; "/GE3", [0x00E3]; "/GE4", [0x00E4]; "/GE5", [0x00E5]; "/GE6", [0x00E6]; "/GE7", [0x00E7]; "/GE8", [0x00E8]; "/GE9", [0x00E9]; "/GEA", [0x00EA]; "/GEB", [0x00EB]; "/GEC", [0x00EC]; "/GED", [0x00ED]; "/GEE", [0x00EE]; "/GEF", [0x00EF]; "/GF0", [0x00F0]; "/GF1", [0x00F1]; "/GF2", [0x00F2]; "/GF3", [0x00F3]; "/GF4", [0x00F4]; "/GF5", [0x00F5]; "/GF6", [0x00F6]; "/GF7", [0x00F7]; "/GF8", [0x00F8]; "/GF9", [0x00F9]; "/GFA", [0x00FA]; "/GFB", [0x00FB]; "/GFC", [0x00FC]; "/GFD", [0x00FD]; "/GFE", [0x00FE]; "/GFF", [0x00FF]|] let truetypemap = Array.to_list truetypemap_arr (* The reverse glyph map is not a 1-1 mapping. So we need special version of hashtable_of_dictionary which a) prefers glyphs with alphabetic names over those earlier in the map which have numeric names b) Doesn't overwrite any entry already there, preserving any intelligence which might be in the ordering of the glyph map *) let revglyph_hashtable_of_dictionary pairs = let contains_digit s = mem true (map isdigit (explode s)) in let table = Hashtbl.create (length pairs) in iter (fun (k, v) -> try if contains_digit (Hashtbl.find table k) && not (contains_digit v) then Hashtbl.replace table k v with Not_found -> Hashtbl.add table k v) pairs; table let glyph_hashes = memoize (fun () -> hashtable_of_dictionary (glyphmap () @ dingbatmap @ truetypemap)) let reverse_glyph_hashes = memoize (fun () -> revglyph_hashtable_of_dictionary (map (fun (a, b) -> (b, a)) (glyphmap ()))) let name_to_pdf_hashes = hashtable_of_dictionary name_to_pdf let reverse_name_to_pdf_hashes = hashtable_of_dictionary (map (fun (a, b) -> (b, a)) name_to_pdf) camlpdf-2.8.1/pdfimage.ml000066400000000000000000000533501477056064700152640ustar00rootroot00000000000000(* Images *) open Pdfutil open Pdfio type pixel_layout = | BPP1 | BPP8 | BPP24 | BPP48 type t = | JPEG of bytes * float list option | JPEG2000 of bytes * float list option | JBIG2 of bytes * float list option * int option | Raw of int * int * pixel_layout * bytes (* Decodes an image in-place, given an array of floats. Assumes that output of Decode fits into same number of bits as input of Decode. FIXME: When might this not be true? *) (* Invert the bits in a bytes *) let invert_bits s = for x = 0 to bytes_size s - 1 do bset s x (bget s x lxor 255) done let decode fs bpc image = (*i Printf.printf "decode, %i floats, BPC %i\n" (Array.length fs) bpc; i*) match Array.length fs with | 0 -> () | l when odd l -> raise (Pdf.PDFError "Bad /Decode") | l -> (* Check to see if it's the identity transform. If so, do nothing. *) let ident = ref true in for x = 0 to Array.length fs / 2 - 1 do if fs.(x * 2) <> 0. || fs.(x * 2 + 1) <> 1. then clear ident done; (*i Printf.printf "ident: %b\n" !ident; i*) if not !ident then let interpolate dmin dmax x = int_of_float (dmin +. (float x *. (dmax -. dmin) /. (2.0 ** float bpc -. 1.))) in let functions = Array.init (l / 2) (function i -> interpolate (fs.(i * 2)) (fs.(i * 2 + 1))) in match bpc with | 1 -> (* For now, just recognise [1 0] *) invert_bits image | 2 -> (*iflprint "DECODE: 2 bit\n"; i*)() | 4 -> (*iflprint "DECODE: 4 bit\n"; i*)() | 8 -> (*i flprint "DECODE: 8 bit\n"; print_floats fs; i*) for p = 0 to bytes_size image - 1 do bset image p ((functions.(p mod (l / 2))) (bget image p)) done | 16 -> (*i flprint "16 bit"; i*) () | _ -> raise (Pdf.PDFError "Bad /Decode") let decode_defaults pdf resources entry image = match entry with | None -> begin match Pdf.lookup_direct pdf "/ColorSpace" image with | None -> None | Some cspace -> match Pdfspace.read_colourspace pdf resources cspace with | Pdfspace.DeviceGray | Pdfspace.CalGray (_, _, _) | Pdfspace.Separation (_, _, _) -> Some (Pdf.Array [Pdf.Real 0.; Pdf.Real 1.]) | Pdfspace.DeviceRGB | Pdfspace.CalRGB (_, _, _, _) -> Some (Pdf.Array [Pdf.Real 0.; Pdf.Real 1.; Pdf.Real 0.; Pdf.Real 1.;Pdf.Real 0.; Pdf.Real 1.]) | Pdfspace.DeviceCMYK -> Some (Pdf.Array [Pdf.Real 0.; Pdf.Real 1.; Pdf.Real 0.; Pdf.Real 1.;Pdf.Real 0.; Pdf.Real 1.; Pdf.Real 0.; Pdf.Real 1.]) | Pdfspace.Lab (_, _, range) -> Some (Pdf.Array ([Pdf.Real 0.; Pdf.Real 1.] @ map (function n -> Pdf.Real n) (Array.to_list range))) | Pdfspace.ICCBased {Pdfspace.icc_range = range} -> (*i flprint "Making default from ICCBased colour space\n"; i*) Some (Pdf.Array (map (function n -> Pdf.Real n) (Array.to_list range))) | Pdfspace.Indexed (_, _) -> (*i flprint "Making default from Indexed colour space\n"; i*) (*i let bpc = match Pdf.lookup_direct_orelse pdf "/BitsPerComponent" "/BPC" image with | Some (Pdf.Integer n) -> n | _ -> 0 in i*) (* Commented out because we don't use it yet... *) (* For now, just make identity. FIXME: How should decode / indexed work - do it in the actual extraction routine? *) Some (Pdf.Array [Pdf.Real 0.; Pdf.Real 1.]) (*i let n = 2.0 ** float bpc -. 1.0 in Some (Pdf.Array [Pdf.Real 0.; Pdf.Real n]) i*) | Pdfspace.Pattern -> None | Pdfspace.PatternWithBaseColourspace _ -> None (* FIXME: Check this *) | Pdfspace.DeviceN (arr, _, _, _) -> Some (Pdf.Array (flatten (many [Pdf.Real 0.; Pdf.Real 1.] (Array.length arr)))) end | x -> match Pdf.lookup_direct pdf "/ColorSpace" image with | None -> x (* Because image masks don't have a colourspace *) | Some cspace -> match Pdfspace.read_colourspace pdf resources cspace with (* Again. A bodge. Need to sort out indexed decoding properly. *) | Pdfspace.Indexed (_, _) -> None | _ -> x (* Decode until it is either plain or a type of decoding we can't deal with natively. *) let rec decode_to_image pdf = function | Pdf.Stream {contents = d, s} as stream -> begin match Pdf.lookup_direct pdf "/Filter" d with | None | Some (Pdf.Array []) | Some (Pdf.Name ("/DCTDecode" | "/DCT" | "/JBIG2Decode" | "/JPXDecode")) | Some (Pdf.Array [Pdf.Name ("/DCTDecode" | "/DCT" | "/JBIG2Decode" | "/JPXDecode")]) -> () | _ -> Pdfcodec.decode_pdfstream_onestage pdf stream; decode_to_image pdf stream end | _ -> raise (Pdf.PDFError "decode_to_image: bad stream") (* Basic CMYK to RGB conversion *) let rgb_of_cmyk c m y k = let c = float c in let m = float m in let y = float y in let k = float k in let r = 255. -. fmin 255. ((c /. 255.) *. (255. -. k) +. k) in let g = 255. -. fmin 255. ((m /. 255.) *. (255. -. k) +. k) in let b = 255. -. fmin 255. ((y /. 255.) *. (255. -. k) +. k) in toint r, toint g, toint b let read_cmyk_8bpp_as_rgb24 width height data = let data' = mkbytes (width * height * 3) in for p = 0 to width * height - 1 do let c = bget data (p * 4) in let m = bget data (p * 4 + 1) in let y = bget data (p * 4 + 2) in let k = bget data (p * 4 + 3) in let r, g, b = rgb_of_cmyk c m y k in bset data' (p * 3) r; bset data' (p * 3 + 1) g; bset data' (p * 3 + 2) b done; data' let read_gray_8bpp_as_rgb24 width height data = let data' = mkbytes (width * height * 3) in for pout = 0 to width * height - 1 do bset data' (pout * 3) (bget data pout); bset data' (pout * 3 + 1) (bget data pout); bset data' (pout * 3 + 2) (bget data pout); done; data' (* Input is 1bpp, rows padded to bytes. *) let read_1bpp_as_rgb24 width height s = let s' = mkbytes (width * height * 3) in let s_bits = Pdfio.bitbytes_of_input (Pdfio.input_of_bytes s) in let pout = ref 0 in for row = 0 to height - 1 do let bits_to_do = ref width in while !bits_to_do > 0 do let bit = if Pdfio.getbit s_bits then 255 else 0 in bset s' !pout bit; bset s' (!pout + 1) bit; bset s' (!pout + 2) bit; decr bits_to_do; pout += 3 done; Pdfio.align s_bits done; s' (* 4bpp, rows padded to bytes. *) let read_4bpp_gray_as_rgb24 width height s = let s' = mkbytes (width * height * 3) in let s_bits = Pdfio.bitbytes_of_input (Pdfio.input_of_bytes s) in let pout = ref 0 in for row = 0 to height - 1 do let pix_to_do = ref width in while !pix_to_do > 0 do let a = if Pdfio.getbit s_bits then 1 else 0 in let b = if Pdfio.getbit s_bits then 1 else 0 in let c = if Pdfio.getbit s_bits then 1 else 0 in let d = if Pdfio.getbit s_bits then 1 else 0 in let col = (a * 8 + b * 4 + c * 2 + d) * (16 + 1) in bset s' !pout col; bset s' (!pout + 1) col; bset s' (!pout + 2) col; decr pix_to_do; pout += 3 done; Pdfio.align s_bits done; s' let read_8bpp_indexed_as_rgb24 table width height s = let s' = mkbytes (width * height * 3) in for x = 0 to width * height - 1 do match Hashtbl.find table (bget s x) with | [r; g; b] -> bset s' (x * 3) r; bset s' (x * 3 + 1) g; bset s' (x * 3 + 2) b | _ -> raise (Pdf.PDFError "read_8bpp_indexed_as_rgb24") done; s' (* Clamp a value to 0.0...1.0 *) let clamp10 f = if f > 1.0 then 1.0 else if f < 0.0 then 0.0 else f (* LAB colour space support *) let xyz_of_lab l' a' b' xw yw zw = let g x = if x >= 6. /. 29. then x *. x *. x else (108. /. 841.) *. (x -. 4. /. 29.) in let l = (l' +. 16.) /. 116. +. a' /. 500. in let m = (l' +. 16.) /. 116. in let n = (l' +. 16.) /. 116. -. b' /. 200. in clamp10 (xw *. g l), clamp10 (yw *. g m), clamp10 (zw *. g n) (* For x, y, z on 0..1 calculate r, g, b on 0..1 *) let rgb_of_xyz x y z = clamp10 (2.5623 *. x +. -.1.1661 *. y +. -.0.3962 *. z), clamp10 (-.1.0215 *. x +. 1.9778 *. y +. 0.0437 *. z), clamp10 (0.0752 *. x +. -.0.2562 *. y +. 1.1810 *. z) (* Assume indexed /Range of -127...128. FIXME *) let convert_lab_to_rgb width height (xw, yw, zw) q rs s = for p = 0 to width * height - 1 do let l = bget s (p * 3) - 127 in let a = bget s (p * 3 + 1) - 127 in let b = bget s (p * 3 + 2) - 127 in (*i Printf.printf "xw yw zw = %f, %f, %f\n" xw yw zw; Printf.printf "l a b = %i, %i, %i\n" l a b; i*) let l' = float l /. 255. in let a' = float a /. 255. in let b' = float b /. 255. in (*i Printf.printf "l' a' b' = %f, %f, %f\n" l' a' b'; i*) let x, y, z = xyz_of_lab l' a' b' xw yw zw in (*i Printf.printf "x y z = %f, %f, %f\n" x y z; i*) let r, g, b = rgb_of_xyz x y z in (*i Printf.printf "r g b = %f, %f, %f\n" r g b; i*) let r' = toint (r *. 255.) in let g' = toint (g *. 255.) in let b' = toint (b *. 255.) in (*i Printf.printf "r', g', b' = %i, %i, %i\n" r' g' b'; i*) bset s (p * 3) r'; bset s (p * 3 + 1) g'; bset s (p * 3 + 2) b' done let read_8bpp_lab_indexed_as_rgb24 table width height p q rs data = let s = read_8bpp_indexed_as_rgb24 table width height data in convert_lab_to_rgb width height p q rs s; s let read_8bpp_cmyk_indexed_as_rgb24 table width height s = let s' = mkbytes (width * height * 3) in for x = 0 to width * height - 1 do match Hashtbl.find table (bget s x) with | [c; m; y; k] -> let r, g, b = rgb_of_cmyk c m y k in bset s' (x * 3) r; bset s' (x * 3 + 1) g; bset s' (x * 3 + 2) b | _ -> raise (Pdf.PDFError "read_8bpp_indexed_as_rgb24") done; s' let read_4bpp_indexed_as_rgb24 table width height s = let s' = mkbytes (width * height * 3) in let posin = ref 0 in let posout = ref 0 in for row = 0 to height - 1 do for byte = 0 to (width + 1) / 2 - 1 do let p1 = bget s !posin lsr 4 in let p2 = bget s !posin land 15 in begin match Hashtbl.find table p1 with | [r1; g1; b1] -> bset s' !posout r1; incr posout; bset s' !posout g1; incr posout; bset s' !posout b1; incr posout; | _ -> raise (Pdf.PDFError "read_4bpp_indexed_as_rgb24") end; begin if not (odd width && byte = (width + 1) / 2 - 1) then match Hashtbl.find table p2 with | [r2; g2; b2] -> bset s' !posout r2; incr posout; bset s' !posout g2; incr posout; bset s' !posout b2; incr posout; | _ -> raise (Pdf.PDFError "read_4bpp_indexed_as_rgb24") end; incr posin done done; s' let read_4bpp_cmyk_indexed_as_rgb24 table width height s = let s' = mkbytes (width * height * 3) in let posin = ref 0 in let posout = ref 0 in for row = 0 to height - 1 do for byte = 0 to (width + 1) / 2 - 1 do let p1 = bget s !posin lsr 4 in let p2 = bget s !posin land 15 in begin match Hashtbl.find table p1 with | [c; m; y; k] -> let r1, g1, b1 = rgb_of_cmyk c m y k in bset s' !posout r1; incr posout; bset s' !posout g1; incr posout; bset s' !posout b1; incr posout; | _ -> raise (Pdf.PDFError "read_4bpp_cmyk_indexed_as_rgb24") end; begin if not (odd width && byte = (width + 1) / 2 - 1) then match Hashtbl.find table p2 with | [c; m; y; k] -> let r2, g2, b2 = rgb_of_cmyk c m y k in bset s' !posout r2; incr posout; bset s' !posout g2; incr posout; bset s' !posout b2; incr posout; | _ -> raise (Pdf.PDFError "read_4bpp_cmyk_indexed_as_rgb24") end; incr posin done done; s' (* Separation, CMYK alternate, tint transform function. *) let read_separation_cmyk_as_rgb24 f width height s = let s' = mkbytes (width * height * 3) in for p = 0 to width * height - 1 do let v = bget s p in try match Pdffun.eval_function f [float v /. 255.] with | [c; y; m; k] -> let c = toint (c *. 255.) and m = toint (m *. 255.) and y = toint (y *. 255.) and k = toint (k *. 255.) in let r, g, b = rgb_of_cmyk c m y k in bset s' (p * 3) r; bset s' (p * 3 + 1) g; bset s' (p * 3 + 2) b; | _ -> raise (Pdf.PDFError "Bad tint transform function") with Pdffun.BadFunctionEvaluation s -> raise (Pdf.PDFError ("Bad tint transform function " ^ s)) done; s' let rec read_raw_image size colspace bpc pdf resources width height dict data = match size, colspace, bpc with | size, (Pdfspace.DeviceRGB | Pdfspace.CalRGB _), Some (Pdf.Integer 8) when size >= width * height * 3 -> Raw (width, height, BPP24, data) | size, Pdfspace.DeviceCMYK, Some (Pdf.Integer 8) when size >= width * height * 4 -> Raw (width, height, BPP24, read_cmyk_8bpp_as_rgb24 width height data) | size, (Pdfspace.DeviceGray | Pdfspace.CalGray _), Some (Pdf.Integer 8) when size >= width * height -> Raw (width, height, BPP24, read_gray_8bpp_as_rgb24 width height data) | size, _, Some (Pdf.Integer 1) when size >= width * height / 8 -> Raw (width, height, BPP24, read_1bpp_as_rgb24 width height data) | size, Pdfspace.DeviceGray, Some (Pdf.Integer 4) when size >= width * height / 2 -> Raw (width, height, BPP24, read_4bpp_gray_as_rgb24 width height data) | size, Pdfspace.Indexed ((Pdfspace.DeviceRGB | Pdfspace.CalRGB _), table), Some (Pdf.Integer 8) | size, Pdfspace.Indexed ((Pdfspace.DeviceN (_, (Pdfspace.DeviceRGB | Pdfspace.CalRGB _ | Pdfspace.ICCBased {Pdfspace.icc_alternate = (Pdfspace.DeviceRGB | Pdfspace.CalRGB _)}), _, _) | Pdfspace.ICCBased {Pdfspace.icc_alternate = (Pdfspace.DeviceRGB | Pdfspace.CalRGB _)}) , table), Some (Pdf.Integer 8) when size >= width * height -> Raw (width, height, BPP24, read_8bpp_indexed_as_rgb24 table width height data) | size, Pdfspace.Indexed (Pdfspace.DeviceCMYK, table), Some (Pdf.Integer 8) when size >= width * height -> Raw (width, height, BPP24, read_8bpp_cmyk_indexed_as_rgb24 table width height data) | size, Pdfspace.Indexed ((Pdfspace.DeviceRGB | Pdfspace.CalRGB _), table), Some (Pdf.Integer 4) | size, Pdfspace.Indexed (Pdfspace.ICCBased {Pdfspace.icc_alternate = (Pdfspace.DeviceRGB | Pdfspace.CalRGB _)}, table), Some (Pdf.Integer 4) when size >= width * height / 2 -> Raw (width, height, BPP24, read_4bpp_indexed_as_rgb24 table width height data) | size, Pdfspace.Indexed ((Pdfspace.DeviceCMYK), table), Some (Pdf.Integer 4) | size, Pdfspace.Indexed (Pdfspace.ICCBased {Pdfspace.icc_alternate = (Pdfspace.DeviceCMYK)}, table), Some (Pdf.Integer 4) when size >= width * height / 2 -> Raw (width, height, BPP24, read_4bpp_cmyk_indexed_as_rgb24 table width height data) | size, Pdfspace.Indexed (Pdfspace.Lab (p, q, rs), table), Some (Pdf.Integer 8) when size >= width * height / 2 -> Raw (width, height, BPP24, read_8bpp_lab_indexed_as_rgb24 table width height p q rs data) | size, Pdfspace.Separation (_, Pdfspace.DeviceCMYK, fn), Some (Pdf.Integer 8) when size >= width * height -> Raw (width, height, BPP24, read_separation_cmyk_as_rgb24 fn width height data) | size, Pdfspace.ICCBased {Pdfspace.icc_alternate = cs}, _ -> read_raw_image size cs bpc pdf resources width height dict data | size, cs, bpc -> (*i Printf.printf "NO IMAGE:\n size:%i\n cspace\n%s\n bpc\n%s\n width %i\n height %i\n" size (Pdfspace.string_of_colourspace cs) (match bpc with None -> "NONE" | Some bpc -> Pdfwrite.string_of_pdf bpc) width height; flush stdout; i*) raise (Pdf.PDFError "No image\n") let colspace pdf dict resources = (* If an image mask, it's /DeviceGray, effectively *) match Pdf.lookup_direct_orelse pdf "/ImageMask" "/IM" dict with | Some (Pdf.Boolean true) -> Pdfspace.DeviceGray | _ -> let colspace = Pdf.lookup_direct_orelse pdf "/ColorSpace" "/CS" dict in let space = match Pdf.lookup_direct pdf "/ColorSpace" resources, colspace with | Some (Pdf.Dictionary _ as d), Some (Pdf.Name c) -> begin match Pdf.lookup_direct pdf c d with | Some colspace -> colspace | _ -> (Pdf.Name c) end | _ -> match colspace with | Some c -> c | _ -> raise (Pdf.PDFError "Pdf image: no colourspace") in Pdfspace.read_colourspace pdf resources space let bpc pdf dict = match Pdf.lookup_direct_orelse pdf "/BitsPerComponent" "/BPC" dict with | Some bpc -> Some bpc | None -> match Pdf.lookup_direct pdf "/ImageMask" dict with | Some (Pdf.Boolean true) -> Some (Pdf.Integer 1) | _ -> None let get_raw_image pdf resources width height dict data = try let size = bytes_size data in let colspace = colspace pdf dict resources in let bpc = bpc pdf dict in (*i flprint ("IMAGE SPACE:\n" ^ Pdfspace.string_of_colourspace colspace ^ * "\n"); i*) read_raw_image size colspace bpc pdf resources width height dict data with e -> (*i Pdf.log (Printf.sprintf ((Pdfwrite.string_of_pdf (Pdf.direct pdf dict)))); i*) raise e let get_image_24bpp pdf resources stream = (*i flprint "\n"; print_image pdf resources (Pdf.direct pdf stream); flprint "\n"; i*) let stream = Pdf.direct pdf stream in let streamdict, data = Pdf.getstream stream; match stream with | Pdf.Stream {contents = (s, Pdf.Got d)} -> s, d | _ -> assert false (*r [Pdf.getstream] would have failed *) in let width = match (Pdf.lookup_direct_orelse pdf "/Width" "/W" streamdict) with | Some (Pdf.Integer x) -> x | _ -> raise (Pdf.PDFError "Malformed /Image width") in let height = match (Pdf.lookup_direct_orelse pdf "/Height" "/H" streamdict) with | Some (Pdf.Integer x) -> x | _ -> raise (Pdf.PDFError "Malformed /Image height") in let bpc = match Pdf.lookup_direct_orelse pdf "/BitsPerComponent" "/BPC" streamdict with | Some (Pdf.Integer n) -> n | _ -> 0 in decode_to_image pdf stream; match stream with | Pdf.Stream {contents = (Pdf.Dictionary d) as dict, Pdf.Got s} -> let get_decode () = let decode_entry = Pdf.lookup_direct_orelse pdf "/Decode" "/D" dict in let decode_entry = decode_defaults pdf resources decode_entry dict in match decode_entry with | Some (Pdf.Array nums) -> Some (map (function (Pdf.Real n) -> n | _ -> 0.) nums) | _ -> None in begin match Pdf.lookup_direct_orelse pdf "/Filter" "/F" dict with | None | Some (Pdf.Array []) -> let raw = get_raw_image pdf resources width height dict s in let decode_entry = Pdf.lookup_direct_orelse pdf "/Decode" "/D" dict in (* Printf.printf "Decode entry before decode_defaults %s\n" ((function None -> "None" | Some x -> (Pdfwrite.string_of_pdf x)) decode_entry); i*) let decode_entry = decode_defaults pdf resources decode_entry dict in (*i Printf.printf "Decode entry after decode_defaults %s\n" ((function None -> "None" | Some x -> (Pdfwrite.string_of_pdf x)) decode_entry); i*) let floats = match decode_entry with | Some (Pdf.Array elts) -> Array.of_list (map (Pdf.getnum pdf) elts) | None -> [||] | _ -> raise (Pdf.PDFError "Bad /Decode") in begin match raw with | Raw (_, _, _, data) -> if floats <> [||] then decode floats bpc data; | _ -> () end; raw | Some (Pdf.Name ("/DCTDecode" | "/DCT")) | Some (Pdf.Array [Pdf.Name ("/DCTDecode" | "/DCT")]) -> JPEG (s, get_decode ()) | Some (Pdf.Name "/JBIG2Decode") | Some (Pdf.Array [Pdf.Name "/JBIG2Decode"]) -> let globals = match lookup "/DecodeParms" d with | Some (Pdf.Dictionary d) -> begin match lookup "/JBIG2Globals" d with | Some (Pdf.Indirect i) -> Some i | _ -> None end | _ -> None in JBIG2 (s, get_decode (), globals) | Some (Pdf.Name "/JPXDecode") | Some (Pdf.Array [Pdf.Name "/JPXDecode"]) -> JPEG2000 (s, get_decode ()) | _ -> raise (Pdf.PDFError "decode_to_image") end | _ -> assert false camlpdf-2.8.1/pdfimage.mli000066400000000000000000000017361477056064700154360ustar00rootroot00000000000000(** Extract Images *) type pixel_layout = | BPP1 (* Black and white *) | BPP8 (* Greyscale *) | BPP24 (* Colour *) | BPP48 (* 48 bit colour *) type t = | JPEG of Pdfio.bytes * float list option | JPEG2000 of Pdfio.bytes * float list option | JBIG2 of Pdfio.bytes * float list option * int option | Raw of int * int * pixel_layout * Pdfio.bytes (** Given a pdf document, resources dictionary and a stream representing an image, return a triple : width, height, and a stream of (width * height * 3) bytes RGBRGB etc. In all instances, if JPEG or JPEG2000 or JBIG2 is the compression method, data is returned still encoded. *) val get_image_24bpp : Pdf.t -> Pdf.pdfobject -> Pdf.pdfobject -> t (** Given a PDF, an image and a /Resources dictionary, return the colourspace of the image *) val colspace : Pdf.t -> Pdf.pdfobject -> Pdf.pdfobject -> Pdfspace.t (** Given a PDF and an image, return any /BPC entry *) val bpc : Pdf.t -> Pdf.pdfobject -> Pdf.pdfobject option camlpdf-2.8.1/pdfio.ml000066400000000000000000000471721477056064700146160ustar00rootroot00000000000000(* General Input and Output *) open Pdfutil (* On 64 bit platforms, bigarray isn't used since max_string is big. If * this is set, we use bigarray always, for testing... *) let test_bigarray = false (* We used to have a type called "bytes" before OCaml did. In order not to break client code using e.g. Pdfio.bytes, we keep the name but expose an alias caml_bytes for the built-in type. *) type caml_bytes = bytes (* External type for big streams of bytes passed to C*) type rawbytes = (int, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t (* But for speed, we use strings of length < Sys.max_string_length *) type bytes = | Long of rawbytes | Short of caml_bytes let bigarray_unsafe_get = Bigarray.Array1.unsafe_get let bigarray_unsafe_set = Bigarray.Array1.unsafe_set (* Extract the raw bytes, without necessarily copying *) let raw_of_bytes = function | Short b -> let l = Bigarray.Array1.create Bigarray.int8_unsigned Bigarray.c_layout (Bytes.length b) in for x = 0 to Bytes.length b - 1 do bigarray_unsafe_set l x (int_of_char (Bytes.unsafe_get b x)) done; l | Long b -> b (* Build a bytes from raw data, without copying *) let bytes_of_raw b = Long b (* Make a stream of a given size. *) let mkbytes l = if l <= (if test_bigarray then max_int else Sys.max_string_length) then Short (Bytes.create l) else Long (Bigarray.Array1.create Bigarray.int8_unsigned Bigarray.c_layout l) (* Find the size of a stream. *) let bytes_size = function | Short s -> Bytes.length s | Long b -> Bigarray.Array1.dim b let bset s n v = match s with | Short s -> Bytes.set s n (Char.unsafe_chr v) | Long s -> Bigarray.Array1.set s n v let bset_unsafe s n v = match s with | Short s -> Bytes.unsafe_set s n (Char.unsafe_chr v) | Long s -> bigarray_unsafe_set s n v let bget s n = match s with | Short s -> int_of_char (Bytes.get s n) | Long s -> Bigarray.Array1.get s n let bget_unsafe s n = match s with | Short s -> int_of_char (Bytes.unsafe_get s n) | Long s -> bigarray_unsafe_get s n (* For lexing / parsing byte streams, keep the position. Starts at zero. *) type stream = {mutable pos : int; data : bytes ref} (* Fill a stream with a value. *) let fillbytes v s = for x = 0 to bytes_size s - 1 do bset_unsafe s x v done let print_bytes s = if bytes_size s > 0 then for x = 0 to bytes_size s - 1 do Printf.printf "%i " (bget s x) done (* Make a bytes from a string, with no terminator. *) let bytes_of_string s = let l = String.length s in let stream = mkbytes l in if l > 0 then for k = 0 to l - 1 do bset_unsafe stream k (int_of_char (String.unsafe_get s k)) done; stream let bytes_of_caml_bytes s = let l = Bytes.length s in let stream = mkbytes l in if l > 0 then for k = 0 to l - 1 do bset_unsafe stream k (int_of_char (Bytes.unsafe_get s k)) done; stream (* Make a byte stream from an integer list. *) let bytes_of_list l = let length = length l in if length = 0 then mkbytes 0 else let s = mkbytes length in let l = ref l in for pos = 0 to length - 1 do bset_unsafe s pos (hd !l); l := tl !l done; s (* Convert a character list to a stream. *) let bytes_of_charlist cs = let length = length cs in if length = 0 then mkbytes 0 else let s = mkbytes length in let cs = ref cs in for pos = 0 to length - 1 do bset_unsafe s pos (int_of_char (hd !cs)); cs := tl !cs done; s let bytes_of_arraylist l = let totalsize = sum (map Array.length l) in let output = mkbytes totalsize in let pos = ref 0 in iter (fun a -> for x = 0 to Array.length a - 1 do bset_unsafe output !pos (Array.unsafe_get a x); incr pos done) l; output let string_of_bytes s = let l = bytes_size s in let buf = Buffer.create l in for x = 0 to l - 1 do Buffer.add_char buf (Char.unsafe_chr (bget_unsafe s x)) done; Buffer.contents buf let bytes_of_int_array a = let s = mkbytes (Array.length a) in for i = 0 to bytes_size s - 1 do bset_unsafe s i (Array.unsafe_get a i) done; s let int_array_of_bytes s = let a = Array.make (bytes_size s) 0 in for i = 0 to Array.length a - 1 do Array.unsafe_set a i (bget_unsafe s i) done; a (* Copy a stream. *) let copybytes s = let l = bytes_size s in let s' = mkbytes l in if l > 0 then for k = 0 to l - 1 do bset_unsafe s' k (bget_unsafe s k) done; s' let int_array_of_string s = Array.init (String.length s) (fun i -> int_of_char (String.unsafe_get s i)) let string_of_int_arrays arrays = let len = sum (map Array.length arrays) in let buf = Buffer.create len in iter (Array.iter (fun v -> Buffer.add_char buf (Char.unsafe_chr v))) arrays; Buffer.contents buf let string_of_int_array a = string_of_int_arrays [a] let bytes_selfmap f s = let l = bytes_size s in for k = 0 to l - 1 do bset_unsafe s k (f (bget_unsafe s k)) done let charlist_of_bytes s = let l = ref [] in for x = bytes_size s - 1 downto 0 do l =| Char.unsafe_chr (bget_unsafe s x) done; !l (* Position in a file *) type pos = int (* End_of_file without exceptions or Some / None *) let no_more = -1 (* A general type for input functions. This allows paramaterization over channels, strings, bigarrays etc. *) type input = {pos_in : unit -> pos; seek_in : pos -> unit; input_char : unit -> char option; input_byte : unit -> int; in_channel_length : pos; set_offset : pos -> unit; caml_channel : in_channel option; source : string} (* A general type for output functions, allowing parameterisation as above. *) type output = {pos_out : unit -> pos; seek_out : pos -> unit; output_char : char -> unit; output_byte : int -> unit; output_string : string -> unit; out_caml_channel : out_channel option; out_channel_length : unit -> pos} (* Create input functions from a channel. *) let input_of_channel ?(source = "channel") ch = let offset = ref 0 in {pos_in = (fun () -> pos_in ch - !offset); seek_in = (fun x -> seek_in ch (x + !offset)); input_char = (fun () -> try Some (input_char ch) with End_of_file -> None); input_byte = (fun () -> try input_byte ch with End_of_file -> no_more); in_channel_length = in_channel_length ch; set_offset = (fun o -> if !offset = 0 then offset := o); caml_channel = Some ch; source = source} (* Create input functions from a. *) let input_of_stream ?(source = "bytes") s = let offset = ref 0 in let ssize = bytes_size !(s.data) in let input_int () = let r = if s.pos > ssize - 1 then no_more else bget_unsafe !(s.data) s.pos in s.pos <- s.pos + 1; r in {pos_in = (fun () -> s.pos - !offset); seek_in = (fun p -> s.pos <- p + !offset); input_char = (fun () -> match input_int () with x when x = no_more -> None | s -> Some (Char.unsafe_chr s)); input_byte = input_int; in_channel_length = ssize; set_offset = (fun o -> if !offset = 0 then offset := o); caml_channel = None; source = source} (* Create input functions from a Pdfio.bytes *) let input_of_bytes ?(source = "bytes") b = input_of_stream ~source {pos = 0; data = ref b} (* Create input functions from a string *) let input_of_string ?(source = "string") s = let pos = ref 0 in let input_char () = if !pos < 0 then failwith "string input_char: attempt to be before beginning" else if !pos > String.length s - 1 then begin pos := !pos + 1; None end else begin pos := !pos + 1; Some (String.unsafe_get s (!pos - 1)) end in {pos_in = (fun () -> !pos); seek_in = (fun p -> if p < 0 then failwith "string seek_in: seek before beginning"; pos := p); input_char = (fun () -> input_char ()); input_byte = (fun () -> if !pos < 0 then failwith "string input_byte: attempt to be before beginning" else if !pos > String.length s - 1 then begin pos := !pos + 1; no_more end else begin pos := !pos + 1; int_of_char (String.unsafe_get s (!pos - 1)) end); in_channel_length = String.length s; set_offset = (fun _ -> ()); caml_channel = None; source = source} (* Output functions over channels *) let output_of_channel ch = {pos_out = (fun () -> pos_out ch); seek_out = seek_out ch; output_char = (fun c -> output_byte ch (int_of_char c)); output_byte = output_byte ch; output_string = output_string ch; out_caml_channel = Some ch; out_channel_length = (fun () -> out_channel_length ch)} (* Output functions over streams. If data is written past the end of a stream, we extend the stream to that point plus one-third of that (new) size. Note that this has an implication upon mixing reading and writing: the stream will have junk in the extended section and will be longer than that which has been written. *) let output_of_bytes s = let highest_written = ref 0 in let output_int i = if s.pos > bytes_size !(s.data) - 1 then let newstream = mkbytes (max 1 (s.pos * 2)) in for x = 0 to bytes_size !(s.data) - 1 do bset_unsafe newstream x (bget_unsafe !(s.data) x) done; bset_unsafe newstream s.pos i; highest_written := max !highest_written s.pos; s.pos <- s.pos + 1; s.data := newstream else begin highest_written := max !highest_written s.pos; bset_unsafe !(s.data) s.pos i; s.pos <- s.pos + 1 end in {pos_out = (fun () -> s.pos); seek_out = (fun p -> s.pos <- p); output_char = (fun c -> output_int (int_of_char c)); output_string = String.iter (function c -> output_int (int_of_char c)); output_byte = output_int; out_caml_channel = None; out_channel_length = (fun () -> !highest_written + 1)} let input_output_of_bytes l = let data = ref (mkbytes l) in (output_of_bytes {data = data; pos = 0}, data) let extract_bytes_from_input_output o data = let len = o.pos_out () in let b = mkbytes len in for x = 0 to len - 1 do bset_unsafe b x (bget_unsafe !data x) done; b (* Nudge forward one character. *) let nudge i = ignore (i.input_byte ()) (* Read one character behind the current position, and reposition ourselves on that character. *) let read_char_back i = let pos = i.pos_in () in i.seek_in (pos - 1); let chr = i.input_char () in i.seek_in (pos - 1); chr (* Go back one character in a file. *) let rewind i = i.seek_in (i.pos_in () - 1) (* Read a character, leaving the position unchanged. *) let peek_char i = let r = i.input_char () in rewind i; r (* Read a byte, leaving the position unchanged. *) let peek_byte i = let r = i.input_byte () in rewind i; r (* Make a bytes of an input channel. *) let bytes_of_input_channel ch = let fi = input_of_channel ch in let size = fi.in_channel_length in let s = mkbytes size in for x = 1 to size do match fi.input_byte () with | b when b = no_more -> failwith "channel length inconsistent" | b -> bset_unsafe s (x - 1) b done; s (* Save a bytes to a channel. *) let bytes_to_output_channel ch data = match data with | Short caml_bytes -> output_string ch (Obj.magic caml_bytes : string) | Long _ as data -> for x = 1 to bytes_size data do output_byte ch (bget_unsafe data (x - 1)) done (* Like Stdlib.read_line *) let b = Buffer.create 256 let read_line i = Buffer.clear b; (* Raise EndOfInput if at end *) begin match i.input_byte () with | x when x = no_more -> raise End_of_file | _ -> () end; rewind i; (* Read characters whilst <> newline or until end of input *) let rec read_chars () = match i.input_byte () with | x when x = no_more -> Buffer.contents b | x when Char.unsafe_chr x = '\n' -> Buffer.add_char b '\n'; Buffer.contents b | x -> Buffer.add_char b (Char.unsafe_chr x); read_chars () in read_chars () (* Read all the lines in an input *) let read_lines i = let ls = ref [] in try while true do ls := read_line i::!ls done; [] with End_of_file -> rev !ls let setinit i s o l = if l = 0 then () else let max = bytes_size s - 1 and last = o + 1 - 1 in if o > max || o < 0 || last < 0 || last > max then raise (Failure "setinit") else match s with | Short s -> begin match i.caml_channel with | None -> for x = o to o + l - 1 do Bytes.unsafe_set s x (Char.unsafe_chr (i.input_byte ())) done | Some ch -> really_input ch s o l end | Long s -> for x = o to o + l - 1 do bigarray_unsafe_set s x (i.input_byte ()) done let setinit_string i s o l = if l = 0 then () else let max = Bytes.length s - 1 and last = o + 1 - 1 in if o > max || o < 0 || last < 0 || last > max then raise (Failure "setinit_string") else match i.caml_channel with | Some ch -> really_input ch s o l | None -> for x = o to o + l - 1 do Bytes.unsafe_set s x (Char.unsafe_chr (i.input_byte ())) done let bytes_of_input i o l = i.seek_in o; let s = Bytes.create l in setinit_string i s 0 l; if l <= Sys.max_string_length then Short s else bytes_of_caml_bytes s let string_of_input i = string_of_bytes (bytes_of_input i 0 i.in_channel_length) let getinit i s o l = if l = 0 then () else let max = bytes_size s - 1 and last = o + 1 - 1 in if o > max || o < 0 || last < 0 || last > max then raise (Failure "getinit") else match s with | Short s -> begin match i.out_caml_channel with | None -> for x = o to o + l - 1 do i.output_byte (int_of_char (Bytes.unsafe_get s x)) done | Some ch -> output ch s o l end | Long s -> for x = o to o + l - 1 do i.output_byte (bigarray_unsafe_get s x) done (* The type of bit (MSB first) streams. *) type bitstream = {input : input; (* The input from which bits are taken. It is advanced a byte at a time *) mutable currbyte : int; (* Current byte value from input *) mutable bit : int; (* Mask for getting the next bit (128, 64,... 2, 1 or 0 = none left) *) mutable bitsread : int (* A count of the number of bits read since inception. Debug use only *)} (* A bitstream position is a byte (the position in the base input of the CURRENT byte) together with the mask value (128 down to 0) *) type bitstream_position = int * int * int * int let bitstream_pos b = (b.input.pos_in (), b.currbyte, b.bit, b.bitsread) let bitstream_seek b (pos, currbyte, bit, bitsread) = b.input.seek_in pos; b.currbyte <- currbyte; b.bit <- bit; b.bitsread <- bitsread (* Make a bitstream from an input. *) let bitbytes_of_input i = {currbyte = 0; bit = 0; bitsread = 0; input = i} (* Get a single bit *) let rec getbit b = if b.bit = 0 then begin b.currbyte <- begin match b.input.input_byte () with | x when x = no_more -> raise End_of_file | x -> x end; b.bit <- 128; getbit b end else let r = b.currbyte land b.bit > 0 in b.bitsread <- b.bitsread + 1; b.bit <- b.bit / 2; r (* Get a bit as an integer, set = 1, unset = 0 *) let getbitint i = if getbit i then 1 else 0 (* Get n bits at once *) let rec getbitsint i n = if n < 0 then assert false else if n = 0 then 0 else let rest = getbitsint i (n - 1) lsl 1 in getbitint i lor rest (* Align on a byte boundary. *) let align b = if b.bit > 0 then b.bitsread <- (b.bitsread / 8 + 1) * 8; b.bit <- 0 (* Further speed possibilities - if byte-aligned and bitstoget >=8 read whole bytes in.. *) (* Get n (up to 32) bits from b, returned as an int32, taken highest bit first. Getting 0 bits gets the value 0. *) let getval_32 b n = if n < 0 then raise (Invalid_argument "Pdfio.getval_32 - n < 0") else if n = 0 then 0l else let r = ref Int32.zero in for x = n - 1 downto 0 do r := Int32.logor !r (Int32.shift_left (i32ofi (getbitint b)) x) done; !r let getval_31 b n = if n < 0 then raise (Invalid_argument "Pdfio.getval_31 - n < 0") else if n = 0 then 0 else let r = ref 0 in for x = n - 1 downto 0 do r := !r lor (getbitint b lsl x) done; !r (* Writing MSB-first bit streams *) (* FIXME: This is excessively complicated and probably inefficient - we should be able to do the appending and so on by other means? *) (* The type: A current byte, the position in the byte (0 = nothing in it, 7 = almost full), and the list (in reverse order) of full bytes so far *) type bitstream_write = {mutable wcurrbyte : int; mutable wbit : int; mutable bytes : int list} let make_write_bitstream () = {wcurrbyte = 0; wbit = 0; bytes = []} let copy_write_bitstream b = let b' = make_write_bitstream () in b'.wcurrbyte <- b.wcurrbyte; b'.wbit <- b.wbit; b'.bytes <- b.bytes; b' (* Put a single bit into bitstream b*) let putbit b bit = assert (bit = 0 || bit = 1); match b.wbit with | 7 -> b.bytes <- (b.wcurrbyte lor bit) :: b.bytes; b.wbit <- 0; b.wcurrbyte <- 0 | _ -> b.wbit <- b.wbit + 1; b.wcurrbyte <- b.wcurrbyte lor (bit lsl (8 - b.wbit)) let putbool b bit = putbit b (if bit then 1 else 0) (* Put a multi-bit value n of bits bs (given as an int32) into bitstream b. *) let rec putval b bs n = if bs < 0 || bs > 32 then raise (Invalid_argument "putval"); match bs with | 0 -> () | _ -> let bit = if land32 n (i32ofi (1 lsl (bs - 1))) > 0l then 1 else 0 in putbit b bit; putval b (bs - 1) n (* Align on a byte boundary, writing zeroes. *) let align_write b = if b.wbit > 0 then for x = 1 to 8 - b.wbit do putbit b 0 done (* Get the output out. *) let bytes_of_write_bitstream b = align_write b; bytes_of_list (rev b.bytes) (* Return a list of booleans, representing (in order) the bits *) let bits_of_write_bitstream b = let numbits = length b.bytes * 8 + b.wbit and bytes : bytes = bytes_of_write_bitstream b and bits = ref [] in let bitstream = bitbytes_of_input (input_of_bytes bytes) in for x = 1 to numbits do bits =| getbit bitstream done; rev !bits (* Same, but from a list *) let join_write_bitstreams ss = let c = make_write_bitstream () in iter (putbool c) (flatten (map bits_of_write_bitstream ss)); c (* Append b to a. Inputs unaltered. *) let write_bitstream_append a b = join_write_bitstreams [a; b] (* Same, but align at the join. *) let write_bitstream_append_aligned a b = let c = copy_write_bitstream a in align_write c; write_bitstream_append c b (* Print the next five characters, to the extent that they exist. *) let debug_next_char i = try let a = unopt (i.input_char ()) in Pdfe.log (Printf.sprintf "%C = %i\n" a (int_of_char a)) with _ -> () let debug_next_n_chars n i = for x = 1 to n do debug_next_char i done; Pdfe.log "\n"; for x = 1 to n do rewind i done camlpdf-2.8.1/pdfio.mli000066400000000000000000000214011477056064700147520ustar00rootroot00000000000000(** Generic Input/Ouput from/to channels, strings, files etc. *) (* {2 Types} *) (** An input. - Calling [pos_in ()] will give the current position (i.e the index of the next byte to be read) in the range zero to the length of the channel minus one. - [seek_in x] moves to a given position. - [input_char ()] returns None if end of input, or the next byte of the input as a character. - [input_byte ()] returns the next byte as an integer, or [Pdfio.no_more] in case of end of input. - [in_channel_length] is the length of the channel. - [set_offset] shifts the channel so positions run from offset to channel_length + offset - 1 instead of 0 to channel_length - 1. - [caml_channel] is the underlying OCaml channel (if any) of the input. - [source] is a string used to inficate the original source of the data, for debugging purposes. *) type input = {pos_in : unit -> int; seek_in : int -> unit; input_char : unit -> char option; input_byte : unit -> int; in_channel_length : int; set_offset : int -> unit; caml_channel : in_channel option; source : string} (** An output. - Calling [pos_out ()] gives the position of the next byte to be written - [seek_out x] moves to a a given position in the output - [output_char] writes a given character as the next byte - [output_byte] writes an integer between 0 and 255 as the next byte - [output_string] writes a string as a sequence of bytes - [out_caml_channel] holds the OCaml channel this output is based on, if any - [out_channel_length ()] gives the current length of the output channel *) type output = {pos_out : unit -> int; seek_out : int -> unit; output_char : char -> unit; output_byte : int -> unit; output_string : string -> unit; out_caml_channel : out_channel option; out_channel_length : unit -> int} (** A distinguished byte value indicating "no more input" *) val no_more : int (** An alias to OCaml built-in [bytes] type. *) type caml_bytes = bytes (** The type of fast to access but possibly very large arrays of bytes. *) type bytes (** {2 Building inputs} *) (** Make an input from an OCaml input channel. *) val input_of_channel : ?source:string -> in_channel -> input (** Make an input from a bytes. *) val input_of_bytes : ?source:string -> bytes -> input (** Make an input from a string. *) val input_of_string : ?source:string -> string -> input (** {2 Building outputs} *) (** Make an output from an OCaml channel *) val output_of_channel : out_channel -> output (** {2 Building an input-output} *) (** An input-output in this context is an output of a bytes, whose content can be extracted to another bytes having been written. For example, one might use a write bitstream (see below), and then extract the result into a [bytes] *) (** Build an input-ouput, with an initial buffer size. *) val input_output_of_bytes : int -> output * bytes ref (** Extract the contents of an input-output in bytes *) val extract_bytes_from_input_output : output -> bytes ref -> bytes (** {2 Compound operations on inputs} *) (** Move forward one byte *) val nudge : input -> unit (** Move backward one byte *) val rewind : input -> unit (** Look at the next character without advancing the pointer. *) val peek_char : input -> char option (** Look at the next byte without advancing the pointer. Returns [Pdfio.no_more] for end of file. *) val peek_byte : input -> int (** Read the previous character (if there is one), moving the pointer back one. *) val read_char_back : input -> char option (** Read a line from an input in the manner of [Stdlib.read_line]. *) val read_line : input -> string (** Read all the lines in an input, in the manner of [Stdlib.read_line]. *) val read_lines : input -> string list (** {2 Bytes } *) (**/**) type rawbytes = (int, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t (* JS forces us to expose this *) val raw_of_bytes : bytes -> rawbytes val bytes_of_raw : rawbytes -> bytes (**/**) (** Make bytes from a given size. Contents not initialized. *) val mkbytes : (int -> bytes) (** Size of bytes. *) val bytes_size : bytes -> int (** Fill bytes with a value *) val fillbytes : int -> bytes -> unit (** Print bytes to standard output. Format undefined: for debug only. *) val print_bytes : bytes -> unit (** Get the value at a position in a bytes *) val bget : bytes -> int -> int (** Like [bget], but with no range checking *) val bget_unsafe : bytes -> int -> int (** [getinit f s o l] calls f on each s within o...l - 1 *) val getinit : output -> bytes -> int -> int -> unit (** [bset s n v] sets the value n at position v in bytes *) val bset : bytes -> int -> int -> unit (** Like [bset] but with no range checking *) val bset_unsafe : bytes -> int -> int -> unit (** [setinit i s o l] sets s o...o + l - 1 from the input *) val setinit : input -> bytes -> int -> int -> unit (** [setinit_string i s o l] sets s o...o + l - 1 from the input *) val setinit_string : input -> caml_bytes -> int -> int -> unit (** [bytes_of_input i o l] gives a [bytes] with s o...o + l - 1 from the input *) val bytes_of_input : input -> int -> int -> bytes (** [string_of_input i] gives a [string] with the contents of [i] *) val string_of_input : input -> string (** Make bytes from a string. *) val bytes_of_string : string -> bytes (** Make bytes from ocaml bytes. *) val bytes_of_caml_bytes : caml_bytes -> bytes (** Make bytes from a list of integers, each between 0 and 255. *) val bytes_of_list : int list -> bytes (** Make bytes from a character list. *) val bytes_of_charlist : char list -> bytes (** Make bytes from a list of integer arrays. *) val bytes_of_arraylist : int array list -> bytes (** Make bytes from an integer array *) val bytes_of_int_array : int array -> bytes (** An integer array of bytes from bytes *) val int_array_of_bytes : bytes -> int array (** Integer array from a string *) val int_array_of_string : string -> int array (** A string from a list of integer arrays *) val string_of_int_arrays : int array list -> string (** A string from a single int array *) val string_of_int_array : int array -> string (** Map bytes onto itself using a function on each byte *) val bytes_selfmap : (int -> int) -> bytes -> unit (** Make a string from a bytes. Fails if array is longer than [String.max_length]. *) val string_of_bytes : bytes -> string (** Make a character list from a bytes *) val charlist_of_bytes : bytes -> char list (** Copy bytes. *) val copybytes : bytes -> bytes (** Write a bytes to an output channel *) val bytes_to_output_channel : out_channel -> bytes -> unit (** Extract a bytes from an input or output. *) val bytes_of_input_channel : in_channel -> bytes (** {2 Bit streams for reading} *) (** The type of most-significant-bit-first bitstreams over inputs. *) type bitstream = {input : input; (* The input from which bits are taken. It is advanced a byte at a time *) mutable currbyte : int; (* Current byte value from input *) mutable bit : int; (* Mask for getting the next bit (128, 64,... 2, 1 or 0 = none left) *) mutable bitsread : int (* A count of the number of bits read since inception. Debug use only *)} (** Make a bitstream from an input. *) val bitbytes_of_input : input -> bitstream (** The type of a position within a bitstream *) type bitstream_position (** Get the current position. It's abstract, so can't be manipulated, but it can be used to return to a previous point *) val bitstream_pos : bitstream -> bitstream_position (** Seek to a position within a bitstream *) val bitstream_seek : bitstream -> bitstream_position -> unit (** Get a bit *) val getbit : bitstream -> bool (** Get a bit, but as an integer, 0 or 1. *) val getbitint : bitstream -> int (** Align the bitstream on a byte boundary *) val align : bitstream -> unit (** Get up to 32 bits as a 32 bit value *) val getval_32 : bitstream -> int -> int32 (** Get up to 31 bits as a native integer *) val getval_31 : bitstream -> int -> int (** {2 Bit streams for writing} *) (** The type of most-significant-bit-first bitstreams for writing over outputs. *) type bitstream_write (** Return a new write bistream. *) val make_write_bitstream : unit -> bitstream_write (** Put a single bit, 0 or 1. *) val putbit : bitstream_write -> int -> unit (** Put a multi-bit value (given as an [int32]) containing the given number of useful bits into a bitstream *) val putval : bitstream_write -> int -> int32 -> unit (** Byte-align. *) val align_write : bitstream_write -> unit (** Append two write bitstreams, aligning at boundary *) val write_bitstream_append_aligned : bitstream_write -> bitstream_write -> bitstream_write (** Build bytes from a write bitstream, padding the with zero-valued bits. *) val bytes_of_write_bitstream : bitstream_write -> bytes (** {2 Debug } *) (** Debug the next [n] chars to standard output and then rewind back *) val debug_next_n_chars : int -> input -> unit camlpdf-2.8.1/pdfjpeg.ml000066400000000000000000000015401477056064700151210ustar00rootroot00000000000000(* JPEG images *) open Pdfutil open Pdfio (* This function is used by the inline image code to return the JPEG data without decoding it, placing the stream pointer at the byte following the data. This is done by searching for the two-byte sequence &FF, &D9 (the end of image marker). This sequence cannot occur in the entropy-encoded image data because the encoder always puts a &00 after any &FF. *) let get_jpeg_data i = let s, data = input_output_of_bytes 4096 in let fin = ref false and last = ref 0 in while not !fin do match i.input_byte () with | x when x = no_more -> raise (Failure "Could not read JPEG data - end of stream") | 0xD9 -> if !last = 0xFF then set fin else last := 0xD9; s.output_byte 0xD9 | n -> last := n; s.output_byte n done; extract_bytes_from_input_output s data camlpdf-2.8.1/pdfjpeg.mli000066400000000000000000000003431477056064700152720ustar00rootroot00000000000000(** PDF JPEG support *) (** Return the JPEG data starting at the current position in the [Pdfio.input], leaving the input ready to read the first byte following the JPEG data. *) val get_jpeg_data : Pdfio.input -> Pdfio.bytes camlpdf-2.8.1/pdfmarks.ml000066400000000000000000000256221477056064700153200ustar00rootroot00000000000000(* PDF Bookmarks *) open Pdfutil type t = {level : int; text : string; target : Pdfdest.t; isopen : bool; colour : float * float * float; flags : int} let string_of_bookmark m = Printf.sprintf "%i %s %s %b\n" m.level m.text (Pdfwrite.string_of_pdf (Pdfdest.pdfobject_of_destination m.target)) m.isopen let remove_bookmarks pdf = match Pdf.lookup_direct pdf "/Root" pdf.Pdf.trailerdict with | None -> raise (Pdf.PDFError "remove_boomarks: Bad PDF: no root") | Some catalog -> let catalog' = Pdf.remove_dict_entry catalog "/Outlines" in let newcatalognum = Pdf.addobj pdf catalog' in {pdf with Pdf.root = newcatalognum; Pdf.trailerdict = Pdf.add_dict_entry pdf.Pdf.trailerdict "/Root" (Pdf.Indirect newcatalognum)} type ntree = Br of int * Pdf.pdfobject * ntree list * bool (* bool is will_be_open *) (*let rec print_tree (Br (i, obj, ls, isopen)) = Printf.printf "Br (%i, %s, %b\n" i (Pdfwrite.string_of_pdf obj) isopen; iter print_tree ls; flprint ")\n"*) let fresh source pdf = incr source; pdf.Pdf.objects.Pdf.maxobjnum + !source (* True if there are any open nodes in the tree *) let rec any_open_nodes = function | [] -> false | (Br (_, _, ls, o))::r -> o || any_open_nodes ls || any_open_nodes r (* Total visible nodes in a tree *) let rec total_visible = function | [] -> 0 | (Br (_, _, ls, o))::r -> 1 + (if o then total_visible ls else 0) + total_visible r (* Flatten a tree and produce a root object for it. Return a list of (num, pdfobject) pairs with the root first. *) let flatten_tree source pdf = function | [] -> let n = fresh source pdf in [(n, Pdf.Dictionary [])], n | tree -> let root_objnum = fresh source pdf in (* Add /Parent links to root *) let tree = let add_root_parent (Br (i, dict, children, isopen)) = Br (i, Pdf.add_dict_entry dict "/Parent" (Pdf.Indirect root_objnum), children, isopen) in map add_root_parent tree in let rec really_flatten = function Br (i, pdfobject, children, isopen) -> (i, pdfobject) :: flatten (map really_flatten children) in let all_but_top = flatten (map really_flatten tree) in let top, topnum = (* Make top level from objects at first level of tree *) let Br (first, _, _, _), Br (last, _, _, _) = extremes tree in let count = if any_open_nodes tree then ["/Count", (Pdf.Integer (total_visible tree))] else [] in (root_objnum, Pdf.Dictionary ([("/First", Pdf.Indirect first); ("/Last", Pdf.Indirect last)] @ count)), root_objnum in top::all_but_top, topnum (* Add negative /Count entries to an ntree *) let rec add_counts l = map add_count l and add_count (Br (i, obj, ls, isopen)) = let newobj = if ls = [] then obj else if isopen then (* Calculate sum of the number of visible descendent items *) Pdf.add_dict_entry obj "/Count" (Pdf.Integer (total_visible ls)) else (* Negative - abs value is number of descendants which would be visible *) Pdf.add_dict_entry obj "/Count" (Pdf.Integer (~-(total_visible ls))) in Br (i, newobj, add_counts ls, isopen) (* Add /Parent entries to an ntree *) let rec add_parent parent (Br (i, obj, children, isopen)) = let obj' = match parent with | None -> obj | Some parent_num -> Pdf.add_dict_entry obj "/Parent" (Pdf.Indirect parent_num) in Br (i, obj', map (add_parent (Some i)) children, isopen) (* Add /First and /Last entries to an ntree *) let rec add_firstlast (Br (i, obj, children, isopen)) = match children with | [] -> (Br (i, obj, children, isopen)) | c -> match extremes c with Br (i', _, _, _), Br (i'', _, _, _) -> let obj = Pdf.add_dict_entry obj "/First" (Pdf.Indirect i') in let obj = Pdf.add_dict_entry obj "/Last" (Pdf.Indirect i'') in (Br (i, obj, map add_firstlast children, isopen)) (* Add /Next and /Prev entries to an ntree *) let rec add_next (Br (i, obj, children, isopen)) = match children with | [] -> Br (i, obj, children, isopen) | [_] -> Br (i, obj, map add_next children, isopen) | c::cs -> let numbers = map (fun (Br (i, _, _, _)) -> i) cs in let children' = (map2 (fun (Br (i, obj, children, isopen)) nextnum -> Br (i, Pdf.add_dict_entry obj "/Next" (Pdf.Indirect nextnum), children, isopen)) (all_but_last (c::cs)) numbers) @ [last cs] in Br (i, obj, map add_next children', isopen) let rec add_prev (Br (i, obj, children, isopen)) = match children with | [] -> Br (i, obj, children, isopen) | [_] -> Br (i, obj, map add_prev children, isopen) | c::cs -> let numbers = map (fun (Br (i, _, _, _)) -> i) (all_but_last (c::cs)) in let children' = c:: map2 (fun (Br (i, obj, children, isopen)) prevnum -> Br (i, Pdf.add_dict_entry obj "/Prev" (Pdf.Indirect prevnum), children, isopen)) cs numbers in Br (i, obj, map add_prev children', isopen) (* Make a node from a given title, destination page number in a given PDF ond open flag. *) let node_of_line pdf title target colour flags = Pdf.Dictionary (("/Title", Pdf.String title):: let dest = Pdfdest.pdfobject_of_destination target in if dest = Pdf.Null then [] else (match target with Pdfdest.Action a -> [("/A", a)] | _ -> [("/Dest", dest)]) @ (match colour with (0., 0., 0.) -> [] | (r, g, b) -> [("/C", Pdf.Array [Pdf.Real r; Pdf.Real g; Pdf.Real b])]) @ (match flags with 0 -> [] | _ -> [("/F", Pdf.Integer flags)])) (* Make an ntree list from a list of parsed bookmark lines. *) let rec make_outline_ntree source pdf = function | [] -> [] | h::t -> let lower, rest = cleavewhile (fun {level = n'} -> n' > h.level) t in (*Printf.printf "make_outline_ntree: %s\n" h.text;*) let node = node_of_line pdf h.text h.target h.colour h.flags in Br (fresh source pdf, node, make_outline_ntree source pdf lower, h.isopen) ::make_outline_ntree source pdf rest (* Add bookmarks. *) let add_bookmarks parsed pdf = if parsed = [] then remove_bookmarks pdf else let source = ref 0 in let tree = make_outline_ntree source pdf parsed in (* Build the (object number, bookmark tree object) pairs. *) let pairs, tree_root_num = let tree = map add_firstlast tree in let tree = match add_next (add_prev (Br (0, Pdf.Null, tree, false))) with Br (_, _, children, _) -> children in let tree = add_counts (map (add_parent None) tree) in flatten_tree source pdf tree in (* Add the objects to the pdf *) iter (function x -> ignore (Pdf.addobj_given_num pdf x)) pairs; (* Replace the /Outlines entry in the document catalog. *) match Pdf.lookup_direct pdf "/Root" pdf.Pdf.trailerdict with | None -> raise (Pdf.PDFError "Bad PDF: no root") | Some catalog -> let catalog' = Pdf.add_dict_entry catalog "/Outlines" (Pdf.Indirect tree_root_num) in let newcatalognum = Pdf.addobj pdf catalog' in {pdf with Pdf.root = newcatalognum; Pdf.trailerdict = Pdf.add_dict_entry pdf.Pdf.trailerdict "/Root" (Pdf.Indirect newcatalognum)} (* Read bookmarks *) let rec traverse_outlines_lb ~preserve_actions indent_lb pdf outlines output = match Pdf.lookup_direct pdf "/First" outlines with | None -> () | Some first -> do_until_no_next_lb ~preserve_actions indent_lb pdf first output and do_until_no_next_lb ~preserve_actions indent_lb pdf outline output = let title = match Pdf.lookup_direct pdf "/Title" outline with | Some (Pdf.String s) -> s | _ -> Pdfe.log "/Title not a string or not present in document outline entry. Using the empty string.\n"; "" in begin let page = match Pdf.lookup_direct pdf "/Dest" outline with | Some (Pdf.String stringdest) when preserve_actions -> Pdfdest.NamedDestination stringdest | Some dest -> Pdfdest.read_destination ~shallow:preserve_actions pdf dest | None -> match Pdf.lookup_direct pdf "/A" outline with | None -> Pdfdest.NullDestination | Some action -> if preserve_actions then (* 05/03/2024: Only preserve if there is a name or byte string. If it's a direct destination, don't preserve. *) match Pdf.lookup_direct pdf "/D" action with | Some ((Pdf.Array _) as dest) -> Pdfdest.read_destination ~shallow:preserve_actions pdf dest | _ -> Pdfdest.Action (Pdf.direct pdf action) else match Pdf.lookup_direct pdf "/D" action with | None -> Pdfdest.Action (Pdf.direct pdf action) | Some dest -> Pdfdest.read_destination ~shallow:preserve_actions pdf dest in let opn = match Pdf.lookup_direct pdf "/Count" outline with | Some (Pdf.Integer i) when i > 0 -> true | _ -> false in let colour = try begin match Pdf.lookup_direct pdf "/C" outline with | Some (Pdf.Array [a; b; c]) -> (Pdf.getnum pdf a, Pdf.getnum pdf b, Pdf.getnum pdf c) | _ -> (0., 0., 0.) end with _ -> (0., 0., 0.) in let flags = match Pdf.lookup_direct pdf "/F" outline with | Some (Pdf.Integer i) -> i | _ -> 0 in output {level = !indent_lb; text = title; target = page; isopen = opn; colour; flags} end; incr indent_lb; traverse_outlines_lb ~preserve_actions indent_lb pdf outline output; if !indent_lb > 0 then decr indent_lb; begin match Pdf.lookup_direct pdf "/Next" outline with | None -> () | Some outline -> do_until_no_next_lb ~preserve_actions indent_lb pdf outline output end let read_bookmarks ~preserve_actions pdf = match Pdf.lookup_direct pdf "/Root" pdf.Pdf.trailerdict with | None -> raise (Pdf.PDFError "read_bookmarks - Bad PDF: no root") | Some catalog -> match Pdf.lookup_direct pdf "/Outlines" catalog with | None -> [] | Some outlines -> let out = ref [] in let output = (function b -> out := b::!out) in traverse_outlines_lb ~preserve_actions (ref 0) pdf outlines output; rev !out let transform_bookmark pdf tr m = {m with target = Pdfdest.transform_destination pdf tr m.target} camlpdf-2.8.1/pdfmarks.mli000066400000000000000000000015051477056064700154630ustar00rootroot00000000000000(** Bookmarks *) (** The type of bookmarks. *) type t = {level : int; text : string; target : Pdfdest.t; isopen : bool; colour : float * float * float; flags : int} (** Debug string from a bookmark. *) val string_of_bookmark : t -> string (** Read the bookmarks from a document. If [preserve_actions] is set, the [target] preserves actions rather than extracting the resultant rectangle. See discussion of [shallow] in [Pdfdest]. *) val read_bookmarks : preserve_actions:bool -> Pdf.t -> t list (** Remove the bookmarks from a document. *) val remove_bookmarks : Pdf.t -> Pdf.t (** Add bookmarks to a document, replacing any currently there. *) val add_bookmarks : t list -> Pdf.t -> Pdf.t (** Transform a bookmark's destination *) val transform_bookmark : Pdf.t -> Pdftransform.transform_matrix -> t -> t camlpdf-2.8.1/pdfmerge.ml000066400000000000000000000652431477056064700153050ustar00rootroot00000000000000open Pdfutil (* We read all the files, read their pages and concatenate them, dealing with clashing object numbers. We then build a new page tree, and build the output PDF document, with a new root and trailer dictionary. We then remove any unreferenced objects, and write to file. The [names] argument contains the initial filenames, so that a file referenced several times (and only loaded once, of course) is not inadvertantly renumbered to form several separate PDFs, which would increase output size. *) (* Equality on PDF streams *) let streameq pdf x y = let x = Pdf.lookup_obj pdf x and y = Pdf.lookup_obj pdf y in Pdf.getstream x; Pdf.getstream y; match x, y with | Pdf.Stream {contents = (dict, Pdf.Got (bytes))}, Pdf.Stream {contents = (dict', Pdf.Got (bytes'))} -> compare (dict, bytes) (dict', bytes') | _ -> raise (Pdf.PDFError "streameq") let remove_duplicate_fonts pdf = let streamobjs = ref [] in Pdf.objiter (fun objnum obj -> match obj with Pdf.Stream _ -> streamobjs := objnum::!streamobjs | _ -> ()) pdf; let toprocess = keep (fun x -> length x > 1) (collate (streameq pdf) (sort (streameq pdf) !streamobjs)) in let pdfr = ref pdf in iter (function [] -> assert false | h::t -> let changetable = Hashtbl.create 100 in iter (fun e -> Hashtbl.add changetable e h) t; pdfr := Pdf.renumber changetable !pdfr) toprocess; pdf.Pdf.root <- !pdfr.Pdf.root; pdf.Pdf.objects <- !pdfr.Pdf.objects; pdf.Pdf.trailerdict <- !pdfr.Pdf.trailerdict (*let debug_pagelabels ls = iter (Printf.printf "%s\n") (map Pdfpagelabels.string_of_pagelabel ls) let debug_collection_of_pagelabels = iter (fun ls -> debug_pagelabels ls; flprint "\n")*) (* Merging /Dests (Named destinations) in the catalog (PDF v1.1 style, rather * than in the PDF 1.3 style in the name tree). Since the new /Dests must be an * indirect reference, we add the new object to the pdf, returning the new pdf * and the reference. FIXME: merging a v1.1 file with a v1.2 file will result in both sets of dests, confusing the reader...*) let new_dests pdf pdfs = let dests = option_map (function pdf -> let catalog = Pdf.catalog_of_pdf pdf in match Pdf.lookup_direct pdf "/Dests" catalog with | Some (Pdf.Dictionary d) -> Some d | _ -> None) pdfs in if dests = [] then None else let new_dests = Pdf.Dictionary (flatten dests) in Some (Pdf.addobj pdf new_dests) (* Names distinguish PDFs which are actually the same. So we only use the first of each group of same ones. Then renumber them. and return. *) let merge_pdfs_renumber names pdfs = (* Can't use setify due to functional values in PDFs, so use a hash table *) let h = Hashtbl.create 20 in iter2 (Hashtbl.replace h) names pdfs; let first_names, first_pdfs = let ns = ref [] and ps = ref [] in Hashtbl.iter (fun name pdf -> ns := name::!ns; ps := pdf::!ps) h; (!ns, !ps) in let table = combine first_names (Pdf.renumber_pdfs first_pdfs) in map (function k -> lookup_failnull k table) names (* Merging entries in the Name Dictionary. [pdf] here is the new merged pdf, [pdfs] the original ones. *) let merge_namedicts pdf pdfs = let names = ["/Dests"; "/AP"; "/JavaScript"; "/Pages"; "/Templates"; "/IDS"; "/URLS"; "/EmbeddedFiles"; "/AlternatePresentations"; "/Renditions"] in let gettree name pdf = let catalog = Pdf.catalog_of_pdf pdf in match Pdf.lookup_direct pdf "/Names" catalog with | Some d -> Pdf.lookup_direct pdf name d | None -> None in (* Build a list of the lists of trees for each name *) let trees_in_each = map (fun name -> option_map (gettree name) pdfs) names in (* Combine with the names, and lose nulls *) let with_names = lose (function (_, []) -> true | _ -> false) (combine names trees_in_each) in let new_trees = map (fun (name, trees) -> name, Pdftree.merge_name_trees_no_clash pdf trees) with_names in (* Add all the trees as indirect references to the pdf *) let nums = ref [] in iter (function (_, obj) -> let num = Pdf.addobj pdf obj in nums =| num) new_trees; (* Build the new name dictionary *) let newdict = Pdf.Dictionary (map2 (fun (name, _) n -> name, Pdf.Indirect n) new_trees (rev !nums)) in (* Return the new pdf, and the new dictionary. *) Pdf.addobj pdf newdict (* Merge the bookmarks in the pdfs and ranges, adding to the new pdf. changes is oldpageobjnum, newpageobjnum pairs. *) let merge_bookmarks changes pdfs ranges pdf = (*Printf.printf "changes:\n"; iter (fun (a, b) -> Printf.printf "%i -> %i\n" a b) changes;*) try let dest_nametree = let catalog = Pdf.catalog_of_pdf pdf in let oldstyle = match Pdf.lookup_direct pdf "/Dests" catalog with | Some d -> Pdftree.read_name_tree pdf d | _ -> [] in let newstyle = match Pdf.lookup_direct pdf "/Names" catalog with | Some d -> begin match Pdf.lookup_direct pdf "/Dests" d with | Some d -> Pdftree.read_name_tree pdf d | _ -> [] end | _ -> [] in oldstyle @ newstyle in let process_mark oldnums changes mark = let rec pageobjectnumber_of_target t = let pagenumber_of_target_string s = (*Printf.printf "merge_bookmarks: found string %s in action\n" s;*) (* Look up in /Dest name tree. Then /D is the destionation. Read it and recurse. *) begin match lookup s dest_nametree with | Some dest -> begin match Pdf.lookup_direct pdf "/D" dest with | Some dest -> let r = pageobjectnumber_of_target (Pdfdest.read_destination pdf dest) in (*Printf.printf "Is new page object number %i\n" r;*) begin match lookup r (map (fun (x, y) -> (y, x)) changes) with | Some old -> (*Printf.printf "Which was old page obj number %i\n" old;*) old | None -> r end | None -> 0 end | None -> 0 end in match t with | Pdfdest.NullDestination -> 0 | Pdfdest.NamedDestination s -> pagenumber_of_target_string s | Pdfdest.StringDestination s -> pagenumber_of_target_string s | Pdfdest.Action a -> (* Look for a /GoTo and find the page number. If /S /GoTo then read /D destination string. By the time this is called; we have the new merged PDF name tree done, so this should all be correct. *) begin match Pdf.lookup_direct pdf "/S" a with | Some (Pdf.Name "/GoTo") -> begin match Pdf.lookup_direct pdf "/D" a with | Some (Pdf.String s) -> pagenumber_of_target_string s | _ -> 0 end | _ -> 0 end | Pdfdest.XYZ (t, _, _, _) | Pdfdest.Fit t | Pdfdest.FitH (t, _) | Pdfdest.FitV (t, _) | Pdfdest.FitR (t, _, _, _, _) | Pdfdest.FitB t | Pdfdest.FitBH (t, _) | Pdfdest.FitBV (t, _) -> match t with | Pdfdest.OtherDocPageNumber _ -> 0 | Pdfdest.PageObject i -> i in let objnum = pageobjectnumber_of_target mark.Pdfmarks.target in (*Printf.printf "Considering objnum %i for inclusion...\n" objnum;*) if mem objnum oldnums || mark.Pdfmarks.target = Pdfdest.NullDestination (* If this bookmark is to be included... *) then let change_target_destinationpage target n = let change_targetpage = function | Pdfdest.OtherDocPageNumber a -> Pdfdest.OtherDocPageNumber a | Pdfdest.PageObject _ -> Pdfdest.PageObject n in match target with | Pdfdest.Action a -> (* The target page has already been updated. *) Pdfdest.Action a | Pdfdest.NullDestination -> Pdfdest.NullDestination | Pdfdest.NamedDestination s -> Pdfdest.NamedDestination s | Pdfdest.StringDestination s -> Pdfdest.StringDestination s | Pdfdest.XYZ (t, a, b, c) -> Pdfdest.XYZ (change_targetpage t, a, b, c) | Pdfdest.Fit t -> Pdfdest.Fit (change_targetpage t) | Pdfdest.FitH (t, a) -> Pdfdest.FitH (change_targetpage t, a) | Pdfdest.FitV (t, a) -> Pdfdest.FitV (change_targetpage t, a) | Pdfdest.FitR (t, a, b, c, d) -> Pdfdest.FitR (change_targetpage t, a, b, c, d) | Pdfdest.FitB t -> Pdfdest.FitB (change_targetpage t) | Pdfdest.FitBH (t, a) -> Pdfdest.FitBH (change_targetpage t, a) | Pdfdest.FitBV (t, a) -> Pdfdest.FitBV (change_targetpage t, a) in Some {mark with Pdfmarks.target = if mark.Pdfmarks.target = Pdfdest.NullDestination then Pdfdest.NullDestination else change_target_destinationpage mark.Pdfmarks.target (lookup_failnull objnum changes)} else None in let bookmarks' = let oldnums = ref (fst (split changes)) and changes = ref changes in let call_process_mark marks range = let r = (* Pass just the oldnums / changes in question. This is a fix for when a single file is multiply included without renumbering for efficiency. *) option_map (process_mark (take !oldnums (length range)) (take !changes (length range))) marks in (* Remove (length range) things from the beginning of !oldnums / !changes. This allows the function to work properly when a single file is included unrenumbered multiple times due to being included twice or more in the merge! *) oldnums := drop !oldnums (length range); changes := drop !changes (length range); r in let markss = map (Pdfmarks.read_bookmarks ~preserve_actions:true) pdfs in (*iter (fun l -> Printf.printf "\n%i marks\n:" (length l); iter (fun m -> Printf.printf "%s\n" (Pdfmarks.string_of_bookmark m)) l) markss;*) flatten (map2 call_process_mark markss ranges) in Pdfmarks.add_bookmarks bookmarks' pdf with e -> Pdfe.log (Printf.sprintf "failure in merge_bookmarks %s\n" (Printexc.to_string e)); pdf (* This is a pre-processing step to deduplicate name trees. It presently only runs on destination name trees, because that's the only kind where we know how to find all uses of these names (can't just assume any identical string in a PDF is a name). In future, it will be expanded to the other name trees. This runs after merge_pdfs_renumber, so there can be no clashing of values. We can return the OCaml name tree structure safe in the knowledge that it can be written to the eventual merged PDF and the object numbers will be correct. FIXME: This is insufficient in one weird case: if a file has some or all pages multiply included, the names will not be disabiguated between the uses: e.g cpdf -merge a.pdf b.pdf a.pdf -o out.pdf links in the second a.pdf here would point to destinations in the first a.pdf. The workaround here is to simply rename the file so it appears to be two files before processing. *) let apply_namechanges_to_destination_nametree pdf changes = let changes = hashtable_of_dictionary changes in let rewrite_string s = try (*let r = *) Hashtbl.find changes s (*in Printf.printf "%s -> %s\n" s r; r*) with Not_found -> Pdfe.log ("apply_namechanges_to_destination_nametree: destination not found: " ^ s ^ "\n"); s in let rec rewrite_kids d = (*Printf.printf "rewrite_kids on dict %s\n" (Pdfwrite.string_of_pdf d);*) match Pdf.lookup_direct pdf "/Kids" d with | Some (Pdf.Array is) -> iter (function Pdf.Indirect i -> Pdf.addobj_given_num pdf (i, rewrite (Pdf.direct pdf (Pdf.Indirect i))) | _ -> ()) is; | _ -> () and rewrite dict = (*Printf.printf "rewrite_dict on %s\n" (Pdfwrite.string_of_pdf dict);*) (* 1. Update the names per the change, if a change is found. *) let dict = match Pdf.lookup_direct pdf "/Names" dict with | Some (Pdf.Array a) -> begin try let pairs = map (function (Pdf.String x, o) -> (Pdf.String (rewrite_string x), o) | x -> x) (pairs_of_list a) in let a' = flatten (map (fun (a, b) -> [a; b]) pairs) in Pdf.add_dict_entry dict "/Names" (Pdf.Array a') with Invalid_argument _ -> Pdfe.log "Warning: malformed /Names"; dict end | _ -> dict in let dict = match Pdf.lookup_direct pdf "/Limits" dict with | Some (Pdf.Array [Pdf.String a; Pdf.String b]) -> Pdf.add_dict_entry dict "/Limits" (Pdf.Array [Pdf.String (rewrite_string a); Pdf.String (rewrite_string b)]) | _ -> dict in rewrite_kids dict; dict in (* Find dest name tree root /Root -> /Names -> /Dests. *) let catalog = Pdf.catalog_of_pdf pdf in match Pdf.lookup_direct pdf "/Names" catalog with | Some (Pdf.Dictionary d) -> begin match lookup "/Dests" d with | Some (Pdf.Dictionary d) -> (* If direct, update it in place, and rewrite the kids *) rewrite_kids (Pdf.Dictionary d); let newdest = rewrite (Pdf.Dictionary d) in let newcatalog = Pdf.add_dict_entry catalog "/Dests" newdest in Pdf.addobj_given_num pdf (pdf.Pdf.root, newcatalog) | Some (Pdf.Indirect i) -> (* If indirect, just begin *) Pdf.addobj_given_num pdf (i, rewrite (Pdf.direct pdf (Pdf.Indirect i))) | _ -> () end | _ -> () let apply_namechanges_at_destination_callsites pdf changes allchanges = let changes = hashtable_of_dictionary changes in let allchanges = hashtable_of_dictionary (rev allchanges) in (* prefer first instance *) let rewrite_string s = try Hashtbl.find changes s with Not_found -> (* It may be an external link. Look up the (first) change for that *) try Hashtbl.find allchanges s with Not_found -> (*Pdfe.log ("warning: apply_namechanges_at_destination_callsite: destination not found: " ^ s ^ "\n");*) s in let rec f = function | Pdf.Dictionary d -> let d = Pdf.recurse_dict f d in (* Rewrite any /S /GoTo (/D) *) let d = begin match Pdf.lookup_direct pdf "/S" d with | Some (Pdf.Name "/GoTo") -> begin match Pdf.lookup_direct pdf "/D" d with | Some (Pdf.String s) -> Pdf.add_dict_entry d "/D" (Pdf.String (rewrite_string s)) | _ -> d end | _ -> d end; in (* Rewrite any /Dest *) begin match Pdf.lookup_direct pdf "/Dest" d with | Some (Pdf.String s) -> Pdf.add_dict_entry d "/Dest" (Pdf.String (rewrite_string s)) | _ -> d end | Pdf.Array a -> Pdf.recurse_array f a | x -> x in Pdf.objselfmap f pdf; (* Include trailerdict for /OpenAction *) pdf.Pdf.trailerdict <- f pdf.Pdf.trailerdict let mdebug = ref false let merge_pdfs_rename_name_trees names pdfs = (* Find unique PDFs, based on names arg. *) let cmp (a, _) (b, _) = compare a b in let pdfs = map snd (map hd (collate cmp (sort cmp (combine names pdfs)))) in if !mdebug then Printf.printf "merge_pdfs_rename_name_trees %i pdfs\n" (length pdfs); (* Find the /Dests nametree in each file. /Root -> /Names -> /Dests. *) let pdfs_and_nametrees = map (function pdf -> let catalog = Pdf.catalog_of_pdf pdf in match Pdf.lookup_direct pdf "/Names" catalog with | Some d -> begin match Pdf.lookup_direct pdf "/Dests" d with | Some (Pdf.Dictionary d) -> (pdf, Some (Pdf.Dictionary d)) | _ -> (pdf, None) end | _ -> (pdf, None)) pdfs in (* Read the list of names *) let names = map (function | (pdf, Some nametree) -> (pdf, map fst (Pdftree.read_name_tree pdf nametree)) | (pdf, None) -> (pdf, [])) pdfs_and_nametrees in (*if !mdebug then iter (fun (_, ns) -> iter (fun n -> Printf.printf "%s\n" n) ns; Printf.printf "\n") names;*) (* Calculate the changes e.g (pdf, "section", "section-f1") *) let num = ref ~-1 in let worked l = let ns = flatten (map (fun (pdf, ns) -> map snd ns) l) in length (setify ns) = length ns in let names = ref (map (fun (pdf, ns) -> (pdf, map (fun n -> (n, n)) ns)) names) in while not (worked !names) do num += 1; names := map2 (fun (pdf, ns) i -> (pdf, map (fun (n, _) -> (n, n ^ "-f" ^ string_of_int i)) ns)) !names (ilist !num (!num + length !names - 1)) done; if !mdebug then begin iter (fun (pdf, ns) -> Printf.printf "Changes for this PDF:\n"; iter (fun (nold, nnew) -> Printf.printf "%s %s \n" nold nnew) ns) !names; end; (* Apply the changes to the destination name tree in each file, in place *) iter (fun (pdf, changes) -> apply_namechanges_to_destination_nametree pdf changes) !names; (* Apply the changes to each PDFs annots entries and anywhere else Dests can be used, in place. *) let allchanges = flatten (map snd !names) in iter (fun (pdf, changes) -> apply_namechanges_at_destination_callsites pdf changes allchanges) !names (* Merge catalog items from the PDFs, taking the first instance of any one we * find. Items we know how to merge properly, like /Dests, /Names, /PageLabels, * /Outlines, will be overwritten, so we don't worry about them here. *) let catalog_items_from_original_documents pdfs = let catalog_entries = flatten (map (fun pdf -> match Pdf.catalog_of_pdf pdf with Pdf.Dictionary es -> es | _ -> failwith "catalog_items_from_original_documents") pdfs) in fold_right (fun (k, v) d -> add k v d) catalog_entries [] (* Optional Content Groups. We merge the /OCProperties entries like this: * a) append /OCGs entries * b) append /Configs entries, or leave absent if everywhere-absent. * c) combine /D dictionary by appending its subentries: * 1) /ON / /OFF arrays, merge or absent if everywhere-absent * 2) /Order ditto * 3) /RBGroups ditto * 4) Use first or any found /Locked /ListMode /AS /Intent /BaseState /Creator /Name *) let merge_entries pdf n maindict = flatten (option_map (fun dict -> match Pdf.lookup_direct pdf n dict with Some (Pdf.Array a) -> Some a | _ -> None) maindict) let merge_default_dictionaries pdf dics = let merge_empty_is_none n = match option_map (Pdf.lookup_direct pdf n) dics with | [] -> [] | l -> [(n, Pdf.Array (flatten (option_map (function Pdf.Array a -> Some a | _ -> None) l)))] in let merged_on = merge_empty_is_none "/ON" in let merged_off = merge_empty_is_none "/OFF" in let merged_order = merge_empty_is_none "/Order" in let merged_rbgroups = merge_empty_is_none "/RBGroups" in let simple_copies = let keys = ["/Locked"; "/ListMode"; "/AS"; "/Intent"; "/BaseState"; "/Creator"; "/Name"] in let find_first_item key = match option_map (Pdf.lookup_direct pdf key) dics with | [] -> [] | h::_ -> [(key, h)] in flatten (map find_first_item keys) in (*Printf.printf "merged_on length %i\n" (length merged_on); Printf.printf "merged_off length %i\n" (length merged_off); Printf.printf "merged_order length %i\n" (length merged_order); Printf.printf "merged_rbgroups length %i\n" (length merged_rbgroups); Printf.printf "simple_copies length %i\n" (length simple_copies);*) merged_on @ merged_off @ merged_order @ merged_rbgroups @ simple_copies let merge_optional_content_groups pdf pdfs = let ocp_dicts = option_map (fun pdf -> Pdf.lookup_direct pdf "/OCProperties" (Pdf.catalog_of_pdf pdf)) pdfs in if ocp_dicts = [] then None else let merged_ocg_arrays = merge_entries pdf "/OCGs" ocp_dicts in let merged_config_arrays = merge_entries pdf "/Configs" ocp_dicts in let merged_default_dictionary = merge_default_dictionaries pdf (option_map (Pdf.lookup_direct pdf "/D") ocp_dicts) in let new_ocproperties = Pdf.Dictionary ([("/OCGs", Pdf.Array merged_ocg_arrays); ("/D", Pdf.Dictionary merged_default_dictionary)] @ if merged_config_arrays = [] then [] else [("/Configs", Pdf.Array merged_config_arrays)]) in Some (Pdf.addobj pdf new_ocproperties) (* Look up any acroforms and merge their fields entries, retaining any other entries from any found. This is very basic, and we need to see more example files to know what to do properly. *) let merge_acroforms pdf pdfs = let form_dicts = option_map (fun pdf -> Pdf.lookup_direct pdf "/AcroForm" (Pdf.catalog_of_pdf pdf)) pdfs in if form_dicts = [] then None else let merged_field_arrays = flatten (map (fun d -> match Pdf.lookup_direct pdf "/Fields" d with Some (Pdf.Array a) -> a | _ -> []) form_dicts) in let merged_nonfield_items = fold_left (fun d (k, v) -> Pdf.add_dict_entry d k v) (Pdf.Dictionary []) (flatten (map (function (Pdf.Dictionary d) -> d | _ -> []) form_dicts)) in let new_dict = Pdf.add_dict_entry merged_nonfield_items "/Fields" (Pdf.Array merged_field_arrays) in Some (Pdf.addobj pdf new_dict) let max_version_number pdfs = if pdfs = [] then raise (Invalid_argument "max_version_number") else hd (sort compare (map (fun p -> (p.Pdf.major, p.Pdf.minor)) pdfs)) let merge_pdfs retain_numbering do_remove_duplicate_fonts ?(process_struct_trees=true) ?(add_toplevel_document=false) names pdfs ranges = if process_struct_trees && length (setify names) < length names then Pdfe.log "Warning: multiply-included files will not merge structure trees properly.\n"; if process_struct_trees then iter2 Pdfst.trim_structure_tree pdfs ranges; if process_struct_trees then Pdfst.renumber_parent_trees pdfs; let pdfs = merge_pdfs_renumber names pdfs in merge_pdfs_rename_name_trees names pdfs; let major', minor' = max_version_number pdfs in let pagelists = map Pdfpage.pages_of_pagetree pdfs in let pdf = Pdf.empty () in let select_pages range pagelist = let pages = ref [] in iter (fun n -> pages =| select n pagelist) range; rev !pages in let pages = flatten (map2 select_pages ranges pagelists) in iter (Pdf.objiter (fun k v -> ignore (Pdf.addobj_given_num pdf (k, v)))) pdfs; let pdf, pagetree_num = Pdfpage.add_pagetree pages pdf in let page_labels = if retain_numbering then Pdfpagelabels.merge_pagelabels pdfs ranges else [] in let dests = new_dests pdf pdfs in let namedict = merge_namedicts pdf pdfs in let extra_catalog_entries = let with_names = (add "/Names" (Pdf.Indirect namedict) (catalog_items_from_original_documents pdfs)) in match dests with None -> with_names | Some dests -> add "/Dests" (Pdf.Indirect dests) with_names in (* Merge Optional content groups *) let extra_catalog_entries = match merge_optional_content_groups pdf pdfs with None -> extra_catalog_entries | Some ocgpropnum -> add "/OCProperties" (Pdf.Indirect ocgpropnum) extra_catalog_entries | exception e -> Pdfe.log (Printf.sprintf "Warning: failed to merge OCGs (%s)\n" (Printexc.to_string e)); extra_catalog_entries in let extra_catalog_entries = match merge_acroforms pdf pdfs with | None -> extra_catalog_entries | Some acroformnum -> add "/AcroForm" (Pdf.Indirect acroformnum) extra_catalog_entries | exception e -> Pdfe.log (Printf.sprintf "Warning: failed to merge Acroforms (%s)\n" (Printexc.to_string e)); extra_catalog_entries in let extra_catalog_entries = if not process_struct_trees then extra_catalog_entries else match Pdfst.merge_structure_trees ~add_toplevel_document pdf pdfs with | None -> extra_catalog_entries | exception e -> Pdfe.log (Printf.sprintf "Warning: failed to merge structure tree roots (%s)\n" (Printexc.to_string e)); extra_catalog_entries | Some structheirnum -> add "/StructTreeRoot" (Pdf.Indirect structheirnum) extra_catalog_entries in let extra_catalog_entries = remove "/OpenAction" extra_catalog_entries in let infodict = Pdf.lookup_direct (hd pdfs) "/Info" (hd pdfs).Pdf.trailerdict in let pdf = match infodict with | None -> pdf | Some infodict -> {pdf with Pdf.trailerdict = Pdf.Dictionary ["/Info", Pdf.Indirect (Pdf.addobj pdf infodict)]} in let pdf = Pdfpage.add_root pagetree_num extra_catalog_entries pdf in (* To sort out annotations etc. *) let old_page_numbers = let select_page_numbers range pageobjnums = let pages = ref [] in iter (fun n -> pages =| select n pageobjnums) range; rev !pages in flatten (map2 select_page_numbers ranges (map Pdf.page_reference_numbers pdfs)) in let new_page_numbers = Pdf.page_reference_numbers pdf in let changes = combine old_page_numbers new_page_numbers in Pdf.objselfmap (Pdf.renumber_object_parsed pdf (hashtable_of_dictionary changes)) pdf; let pdf = {pdf with Pdf.major = major'; Pdf.minor = minor'} in let pdf = merge_bookmarks changes pdfs ranges pdf in Pdfpagelabels.write pdf page_labels; if do_remove_duplicate_fonts then remove_duplicate_fonts pdf; Pdf.change_id pdf ""; pdf camlpdf-2.8.1/pdfmerge.mli000066400000000000000000000021751477056064700154510ustar00rootroot00000000000000(** Merge PDF files *) (** Merge PDF files. [merge_pdfs retain_numbering remove_duplicate_fonts ?process_struct_trees ?add_toplevel_document names pdfs ranges] will merge the given PDFs. if [retain_numbering] is true, page labels are retained. If [remove_duplicate_fonts] is true, duplicate fonts are detected and coalesced. If [process_struct_trees] is true (default false), structure trees are trimmed and merged. If [add_toplevel_document] is also true (default false) a PDF/UA-2-style top level /Document structure tree entry is added. [names] is a list of strings the same length as the list of PDFs. Equal names imply equal PDFs (for efficiency). [ranges] is a list of page ranges. A page range is a list of pages to select, in order. For example [[1]] or [[2; 2; 2; 5; 6; 7]]. *) val merge_pdfs : bool -> bool -> ?process_struct_trees:bool -> ?add_toplevel_document:bool -> string list -> Pdf.t list -> int list list -> Pdf.t (** Remove duplicate fonts from a PDF. For example, if it was created by merging several documents from the same source. *) val remove_duplicate_fonts : Pdf.t -> unit camlpdf-2.8.1/pdfocg.ml000066400000000000000000000142031477056064700147440ustar00rootroot00000000000000(* Pdf Optional Content Groups *) open Pdfutil type ocgusage (* Nothing for now; expand later *) type ocg = {ocg_name : string; ocg_intent : string list; ocg_usage : ocgusage option} type ocgstate = OCG_ON | OCG_OFF | OCG_Unchanged type ocglistmode = OCG_AllPages | OCG_VisiblePages type ocgappdict = AppDict (* Nothing for now; expand later *) type ocgconfig = {ocgconfig_name : string option; ocgconfig_creator : string option; ocgconfig_basestate : ocgstate; ocgconfig_on : int list option; ocgconfig_off : int list option; ocgconfig_intent: string list; ocgconfig_usage_application_dictionaries: ocgappdict list option; ocgconfig_order : int tree option; ocgconfig_listmode : ocglistmode; ocgconfig_rbgroups : int list list; ocgconfig_locked : int list} type ocgproperties = {ocgs : (int * ocg) list; ocg_default_config : ocgconfig; ocg_configs : ocgconfig list} let read_ocgappdict pdf appdict = AppDict (* Read an OCG from a file, if there is one. None represents a non-existent /OCProperties, rather than an error. *) let read_config pdf config = let ocgconfig_name = match Pdf.lookup_direct pdf "/Name" config with | Some (Pdf.String s) -> Some s | _ -> None and ocgconfig_creator = match Pdf.lookup_direct pdf "/Creator" config with | Some (Pdf.String s) -> Some s | _ -> None and ocgconfig_basestate = match Pdf.lookup_direct pdf "/BaseState" config with | Some (Pdf.Name "/ON") -> OCG_ON | Some (Pdf.Name "/OFF") -> OCG_OFF | Some (Pdf.Name "/Unchanged") -> OCG_Unchanged | _ -> OCG_ON and ocgconfig_on = match Pdf.lookup_direct pdf "/ON" config with | Some (Pdf.Array indirects) -> Some (map (function Pdf.Indirect n -> n | _ -> 0) indirects) | _ -> None and ocgconfig_off = match Pdf.lookup_direct pdf "/OFF" config with | Some (Pdf.Array indirects) -> Some (map (function Pdf.Indirect n -> n | _ -> 0) indirects) | _ -> None and ocgconfig_intent = match Pdf.lookup_direct pdf "/Intent" config with | Some (Pdf.Name n) -> [n] | Some (Pdf.Array a) -> (map (function x -> match Pdf.direct pdf x with | Pdf.Name n -> n | _ -> "") a) | _ -> ["/View"] and ocgconfig_usage_application_dictionaries = match Pdf.lookup_direct pdf "/AS" config with | Some (Pdf.Array appdicts) -> Some (map (read_ocgappdict pdf) appdicts) | _ -> None and ocgconfig_order = None (* FIXME *) and ocgconfig_listmode = match Pdf.lookup_direct pdf "/ListMode" config with | Some (Pdf.Name "/VisiblePages") -> OCG_VisiblePages | _ -> OCG_AllPages and ocgconfig_rbgroups = [] (* FIXME *) and ocgconfig_locked = match Pdf.lookup_direct pdf "/Locked" config with | Some (Pdf.Array a) -> (map (function x -> match Pdf.direct pdf x with | Pdf.Indirect n -> n | _ -> 0) a) | _ -> [] in {ocgconfig_name = ocgconfig_name; ocgconfig_creator = ocgconfig_creator; ocgconfig_basestate = ocgconfig_basestate; ocgconfig_on = ocgconfig_on; ocgconfig_off = ocgconfig_off; ocgconfig_intent = ocgconfig_intent; ocgconfig_usage_application_dictionaries = ocgconfig_usage_application_dictionaries; ocgconfig_order = ocgconfig_order; ocgconfig_listmode = ocgconfig_listmode; ocgconfig_rbgroups = ocgconfig_rbgroups; ocgconfig_locked = ocgconfig_locked} let read_ocg_usage pdf usage = None (* FIXME *) let read_individual_ocg pdf ocg = let ocg_name = match Pdf.lookup_direct pdf "/Name" ocg with | Some (Pdf.String s) -> s | _ -> raise (Pdf.PDFError "No /Name in optional content group") and ocg_intent = match Pdf.lookup_direct pdf "/Intent" ocg with | Some (Pdf.Name n) -> [n] | Some (Pdf.Array a) -> option_map (function Pdf.Name n -> Some n | _ -> None) (map (Pdf.direct pdf) a) | _ -> ["/View"] and ocg_usage = match Pdf.lookup_direct pdf "/Usage" ocg with | None -> None | Some usage -> read_ocg_usage pdf usage in {ocg_name = ocg_name; ocg_intent = ocg_intent; ocg_usage = ocg_usage} let read_ocg pdf = match Pdf.lookup_direct pdf "/Root" pdf.Pdf.trailerdict with | None -> raise (Pdf.PDFError "No /Root") | Some r -> match Pdf.lookup_direct pdf "/OCProperties" r with | None -> None | Some ocproperties -> let ocgs = match Pdf.lookup_direct pdf "/OCGs" ocproperties with | Some (Pdf.Array indirects) -> combine (map (function Pdf.Indirect n -> n | _ -> 0) indirects) (map (read_individual_ocg pdf) indirects) | _ -> [] and ocg_default_config = match Pdf.lookup_direct pdf "/D" ocproperties with | None -> raise (Pdf.PDFError "No default config in /OCProperties") | Some config -> read_config pdf config and ocg_configs = match Pdf.lookup_direct pdf "/Configs" ocproperties with | Some (Pdf.Array configs) -> map (read_config pdf) configs | _ -> [] in Some {ocgs = ocgs; ocg_default_config = ocg_default_config; ocg_configs = ocg_configs} let write_ocg pdf ocgprops = () (* Use things called by write_ocg to get the pdf objects, then can use Pdfwrite.string_of_pdf to do the work *) let print_ocg (num, ocg) = Printf.printf "OCG %i\n" num; Printf.printf "Name %s\n" ocg.ocg_name; Printf.printf "Intent(s)"; iter (Printf.printf "%s ") ocg.ocg_intent; Printf.printf "\n" let print_ocg_config config = begin match config.ocgconfig_name with | None -> Printf.printf "No config name\n" | Some n -> Printf.printf "Config Name: %s\n" n end let print_document_ocg pdf = match read_ocg pdf with | None -> flprint "There are no optional content groups in this document\n" | Some ocgs -> Printf.printf "There are %i OCGs, and %i additional configs\n" (length ocgs.ocgs) (length ocgs.ocg_configs); flprint "OCGs\n-------------\n"; iter print_ocg ocgs.ocgs; flprint "OCG Configs\n------------\n"; iter print_ocg_config ocgs.ocg_configs camlpdf-2.8.1/pdfocg.mli000066400000000000000000000023121477056064700151130ustar00rootroot00000000000000(** Optional Content Groups. *) open Pdfutil type ocgusage (* Nothing for now; expand later *) type ocg = {ocg_name : string; ocg_intent : string list; ocg_usage : ocgusage option} type ocgstate = OCG_ON | OCG_OFF | OCG_Unchanged type ocglistmode = OCG_AllPages | OCG_VisiblePages type ocgappdict (* Nothing for now; expand later *) type ocgconfig = {ocgconfig_name : string option; ocgconfig_creator : string option; ocgconfig_basestate : ocgstate; ocgconfig_on : int list option; ocgconfig_off : int list option; ocgconfig_intent: string list; ocgconfig_usage_application_dictionaries: ocgappdict list option; ocgconfig_order : int tree option; ocgconfig_listmode : ocglistmode; ocgconfig_rbgroups : int list list; ocgconfig_locked : int list} type ocgproperties = {ocgs : (int * ocg) list; ocg_default_config : ocgconfig; ocg_configs : ocgconfig list} (** Read optional content data. *) val read_ocg : Pdf.t -> ocgproperties option (** Write optional content data. *) val write_ocg : Pdf.t -> ocgproperties -> unit (** Print information about the document's Optional Content Groups to Standard Output. For debug only. *) val print_document_ocg : Pdf.t -> unit camlpdf-2.8.1/pdfops.ml000066400000000000000000001135631477056064700150060ustar00rootroot00000000000000open Pdfutil open Pdfio let debug = ref false let write_comments = ref false (* Graphics operators. *) type t = | Op_w of float (* Set line width *) | Op_J of int (* Set line cap *) | Op_j of int (* Set line join *) | Op_M of float (* Set mitre limit *) | Op_d of float list * float (* Set dash pattern (dash, phase) *) | Op_ri of string (* Set rendering intent. *) | Op_i of int (* Set flatness. *) | Op_gs of string (* Set graphics state from dictionary *) | Op_q (* Save graphics state to stack *) | Op_Q (* Restore graphics state from stack *) | Op_cm of Pdftransform.transform_matrix (*r Modify CTM by concatenation *) | Op_m of float * float (* Begin a new subpath *) | Op_l of float * float (* Append a straight segment *) | Op_c of float * float * float * float * float * float (* Cubic bezier *) | Op_v of float * float * float * float (* Similar. *) | Op_y of float * float * float * float (* Similar. *) | Op_h (* Close subpath *) | Op_re of float * float * float * float (* Append rectangle *) | Op_S (* Stroke a path *) | Op_s (* Close and stroke path *) | Op_f (* Fill path, non-zero *) | Op_F (* Same. *) | Op_f' (* f* operator. Fill path, even-odd. *) | Op_B (* Fill and stroke path, non-zero *) | Op_B' (* B* operator. Fill and stroke path, even-odd *) | Op_b (* Close fill and stroke, non-zero *) | Op_b' (* b* operator. Close fill and stroke, even-odd *) | Op_n (* Path no-op *) | Op_W (* Clipping path, even-odd *) | Op_W' (* Clipping path, non-zero *) | Op_BT (* Begin a text object *) | Op_ET (* End a text object *) | Op_Tc of float (* Set character spacing *) | Op_Tw of float (* Set word spacing *) | Op_Tz of float (* Set horizontal scaling *) | Op_TL of float (* Set leading *) | Op_Tf of string * float (* Set font size *) | Op_Tr of int (* Set text rendering mode *) | Op_Ts of float (* Set text rise *) | Op_Td of float * float (* Move to next line *) | Op_TD of float * float (* Ditto, but set leading *) | Op_Tm of Pdftransform.transform_matrix (* Set text and line matrices *) | Op_T' (* T* operator. Move text to the next line *) | Op_Tj of string (* Show text string *) | Op_TJ of Pdf.pdfobject (* Show many text strings *) | Op_' of string (* Move to next line and show text *) | Op_'' of float * float * string (* Ditto, extra parameters *) | Op_d0 of float * float (* Set glpyh width info *) | Op_d1 of float * float * float * float * float * float (* Similar *) | Op_CS of string (* Set colour space. *) | Op_cs of string (* Same for nonstroking operations *) | Op_SC of float list (* Set colour in current colour space. *) | Op_sc of float list (* Same for nonstroking operations *) | Op_SCN of float list (* Set colour in current colour space. *) | Op_scn of float list (* Same for nonstroking operations *) | Op_SCNName of string * float list (* A named Op_SCN *) | Op_scnName of string * float list (* Same for Op_scn *) | Op_G of float (* set gray *) | Op_g of float (* set gray nonstroking *) | Op_RG of float * float * float (* Set stroking colour *) | Op_rg of float * float * float (* Set painting colour *) | Op_K of float * float * float * float (* Set CMYK stroking *) | Op_k of float * float * float * float (* Set CMYK nonstroking *) | Op_sh of string (* Shading pattern *) | InlineImage of (Pdf.pdfobject * Pdf.pdfobject option * bytes) (* Inline image dictionary, previous decodeparams if any, data *) | Op_Do of string (* Introduce an XObject *) | Op_MP of string (* Marked content point *) | Op_DP of string * Pdf.pdfobject (* same with property list *) | Op_BMC of string (* begin marked content sequence *) | Op_BDC of string * Pdf.pdfobject (* same with property list *) | Op_EMC (* end of marked content sequence *) | Op_BX (* Start compatibility mode *) | Op_EX (* End compatibility mode *) | Op_Unknown of string (* Unknown operand / operator sequence *) | Op_Comment of string (* Comments are silently ignored when reading, but can be written for debug. *) type lexeme = | Op of string | Obj of Pdfgenlex.t | PdfObj of Pdf.pdfobject | LexInlineImage of (Pdf.pdfobject * Pdf.pdfobject option * bytes) | LexComment of string (* Lexing *) let lexemes_of_op f = function | Op_w w -> f (Obj (Pdfgenlex.LexReal w)); f (Op "w") | Op_J j -> f (Obj (Pdfgenlex.LexInt j)); f (Op "J") | Op_j j -> f (Obj (Pdfgenlex.LexInt j)); f (Op "j") | Op_M m -> f (Obj (Pdfgenlex.LexReal m)); f (Op "M") | Op_d (fl, y) -> f (Obj Pdfgenlex.LexLeftSquare); iter (fun x -> f (Obj (Pdfgenlex.LexReal x))) fl; f (Obj Pdfgenlex.LexRightSquare); f (Obj (Pdfgenlex.LexReal y)); f (Op "d") | Op_ri s -> f (Obj (Pdfgenlex.LexName s)); f (Op "ri") | Op_i i -> f (Obj (Pdfgenlex.LexInt i)); f (Op "i") | Op_gs s -> f (Obj (Pdfgenlex.LexName s)); f (Op "gs") | Op_q -> f (Op "q") | Op_Q -> f (Op "Q") | Op_cm t -> f (Obj (Pdfgenlex.LexReal t.Pdftransform.a)); f (Obj (Pdfgenlex.LexReal t.Pdftransform.b)); f (Obj (Pdfgenlex.LexReal t.Pdftransform.c)); f (Obj (Pdfgenlex.LexReal t.Pdftransform.d)); f (Obj (Pdfgenlex.LexReal t.Pdftransform.e)); f (Obj (Pdfgenlex.LexReal t.Pdftransform.f)); f (Op "cm") | Op_m (a, b) -> f (Obj (Pdfgenlex.LexReal a)); f (Obj (Pdfgenlex.LexReal b)); f (Op "m") | Op_l (a, b) -> f (Obj (Pdfgenlex.LexReal a)); f (Obj (Pdfgenlex.LexReal b)); f (Op "l") | Op_c (a, b, c, d, e, k) -> f (Obj (Pdfgenlex.LexReal a)); f (Obj (Pdfgenlex.LexReal b)); f (Obj (Pdfgenlex.LexReal c)); f (Obj (Pdfgenlex.LexReal d)); f (Obj (Pdfgenlex.LexReal e)); f (Obj (Pdfgenlex.LexReal k)); f (Op "c"); | Op_v (a, b, c, d) -> f (Obj (Pdfgenlex.LexReal a)); f (Obj (Pdfgenlex.LexReal b)); f (Obj (Pdfgenlex.LexReal c)); f (Obj (Pdfgenlex.LexReal d)); f (Op "v") | Op_y (a, b, c, d) -> f (Obj (Pdfgenlex.LexReal a)); f (Obj (Pdfgenlex.LexReal b)); f (Obj (Pdfgenlex.LexReal c)); f (Obj (Pdfgenlex.LexReal d)); f (Op "y") | Op_h -> f (Op "h") | Op_re (a, b, c, d) -> f (Obj (Pdfgenlex.LexReal a)); f (Obj (Pdfgenlex.LexReal b)); f (Obj (Pdfgenlex.LexReal c)); f (Obj (Pdfgenlex.LexReal d)); f (Op "re") | Op_S -> f (Op "S") | Op_s -> f (Op "s") | Op_f -> f (Op "f") | Op_F -> f (Op "F") | Op_f' -> f (Op "f*") | Op_B -> f (Op "B") | Op_B' -> f (Op "B*") | Op_b -> f (Op "b") | Op_b' -> f (Op "b*") | Op_n -> f (Op "n") | Op_W -> f (Op "W") | Op_W' -> f (Op "W*") | Op_BT -> f (Op "BT") | Op_ET -> f (Op "ET") | Op_Tc c -> f (Obj (Pdfgenlex.LexReal c)); f (Op "Tc") | Op_Tw w -> f (Obj (Pdfgenlex.LexReal w)); f (Op "Tw") | Op_Tz z -> f (Obj (Pdfgenlex.LexReal z)); f (Op "Tz") | Op_TL l -> f (Obj (Pdfgenlex.LexReal l)); f (Op "TL") | Op_Tf (k, s) -> f (Obj (Pdfgenlex.LexName k)); f (Obj (Pdfgenlex.LexReal s)); f (Op "Tf") | Op_Tr i -> f (Obj (Pdfgenlex.LexInt i)); f (Op "Tr") | Op_Ts k -> f (Obj (Pdfgenlex.LexReal k)); f (Op "Ts") | Op_Td (k, k') -> f (Obj (Pdfgenlex.LexReal k)); f (Obj (Pdfgenlex.LexReal k')); f (Op "Td") | Op_TD (k, k') -> f (Obj (Pdfgenlex.LexReal k)); f (Obj (Pdfgenlex.LexReal k')); f (Op "TD") | Op_Tm t -> f (Obj (Pdfgenlex.LexReal t.Pdftransform.a)); f (Obj (Pdfgenlex.LexReal t.Pdftransform.b)); f (Obj (Pdfgenlex.LexReal t.Pdftransform.c)); f (Obj (Pdfgenlex.LexReal t.Pdftransform.d)); f (Obj (Pdfgenlex.LexReal t.Pdftransform.e)); f (Obj (Pdfgenlex.LexReal t.Pdftransform.f)); f (Op "Tm") | Op_T' -> f (Op "T*") | Op_Tj s -> f (Obj (Pdfgenlex.LexString s)); f (Op "Tj") | Op_TJ pdfobject -> f (PdfObj pdfobject); f (Op "TJ") | Op_' s -> f (Obj (Pdfgenlex.LexString s)); f (Op "'") | Op_'' (k, k', s) -> f (Obj (Pdfgenlex.LexReal k)); f (Obj (Pdfgenlex.LexReal k')); f (Obj (Pdfgenlex.LexString s)); f (Op "\"") | Op_d0 (k, k') -> f (Obj (Pdfgenlex.LexReal k)); f (Obj (Pdfgenlex.LexReal k')); f (Op "d0") | Op_d1 (a, b, c, d, e, k) -> f (Obj (Pdfgenlex.LexReal a)); f (Obj (Pdfgenlex.LexReal b)); f (Obj (Pdfgenlex.LexReal c)); f (Obj (Pdfgenlex.LexReal d)); f (Obj (Pdfgenlex.LexReal e)); f (Obj (Pdfgenlex.LexReal k)); f (Op "d1") | Op_CS s -> f (Obj (Pdfgenlex.LexName s)); f (Op "CS") | Op_cs s -> f (Obj (Pdfgenlex.LexName s)); f (Op "cs") | Op_SC fs -> iter (fun x -> f (Obj (Pdfgenlex.LexReal x))) fs; f (Op "SC") | Op_sc fs -> iter (fun x -> f (Obj (Pdfgenlex.LexReal x))) fs; f (Op "sc") | Op_SCN fs -> iter (fun x -> f (Obj (Pdfgenlex.LexReal x))) fs; f (Op "SCN") | Op_scn fs -> iter (fun x -> f (Obj (Pdfgenlex.LexReal x))) fs; f (Op "scn") | Op_SCNName (s, fs) -> iter (fun x -> f (Obj (Pdfgenlex.LexReal x))) fs; f (Obj (Pdfgenlex.LexName s)); f (Op "SCN") | Op_scnName (s, fs) -> iter (fun x -> f (Obj (Pdfgenlex.LexReal x))) fs; f (Obj (Pdfgenlex.LexName s)); f (Op "scn") | Op_G k -> f (Obj (Pdfgenlex.LexReal k)); f (Op "G") | Op_g k -> f (Obj (Pdfgenlex.LexReal k)); f (Op "g") | Op_RG (r, g, b) -> f (Obj (Pdfgenlex.LexReal r)); f (Obj (Pdfgenlex.LexReal g)); f (Obj (Pdfgenlex.LexReal b)); f (Op "RG") | Op_rg (r, g, b) -> f (Obj (Pdfgenlex.LexReal r)); f (Obj (Pdfgenlex.LexReal g)); f (Obj (Pdfgenlex.LexReal b)); f (Op "rg") | Op_K (c, m, y, k) -> f (Obj (Pdfgenlex.LexReal c)); f (Obj (Pdfgenlex.LexReal m)); f (Obj (Pdfgenlex.LexReal y)); f (Obj (Pdfgenlex.LexReal k)); f (Op "K") | Op_k (c, m, y, k) -> f (Obj (Pdfgenlex.LexReal c)); f (Obj (Pdfgenlex.LexReal m)); f (Obj (Pdfgenlex.LexReal y)); f (Obj (Pdfgenlex.LexReal k)); f (Op "k") | Op_sh s -> f (Obj (Pdfgenlex.LexName s)); f (Op "sh") | InlineImage (dict, dp, data) -> f (LexInlineImage (dict, dp, data)) | Op_Do s -> f (Obj (Pdfgenlex.LexName s)); f (Op "Do") | Op_MP s -> f (Obj (Pdfgenlex.LexName s)); f (Op "MP") | Op_DP (s, obj) -> f (Obj (Pdfgenlex.LexName s)); f (PdfObj obj); f (Op "DP") | Op_BMC s -> f (Obj (Pdfgenlex.LexName s)); f (Op "BMC") | Op_BDC (s, obj) -> f (Obj (Pdfgenlex.LexName s)); f (PdfObj obj); f (Op "BDC") | Op_EMC -> f (Op "EMC") | Op_BX -> f (Op "BX") | Op_EX -> f (Op "EX") | Op_Unknown _ -> () | Op_Comment s -> f (Obj (Pdfgenlex.LexComment s)) let lexemes_of_ops ops = let ls = ref [] in iter (lexemes_of_op (fun x -> ls := x::!ls)) ops; rev !ls let lexemelists_of_ops (ops : t list) = map (fun op -> let ls = ref [] in lexemes_of_op (fun x -> ls := x::!ls) op; rev !ls) ops (* Find a string representing some lexemes *) let rec filterspecial = function | [] -> false | Pdf.Name ("/ASCIIHexDecode" | "/ASCII85Decode" | "/AHx" | "/A85")::_ -> true | _::t -> filterspecial t let b = Buffer.create 256 let string_of_lexeme = function | LexComment s -> "" | Obj o -> Pdfread.string_of_lexeme o | Op op -> op | PdfObj obj -> Pdfwrite.string_of_pdf obj | LexInlineImage (dict, dp, data) -> (* Compress if no compression *) let dict, data = match Pdf.lookup_direct_orelse (Pdf.empty ()) "/F" "/Filter" dict with | None | Some (Pdf.Array []) -> (* Was there previously a predictor? *) let dict, data = match dp with | _ -> dict, data (* 13/10/2024: This is failing, removed until fixed: https://github.com/coherentgraphics/cpdf-binaries/issues/90 *) (*| Some d -> let colours = match Pdf.lookup_direct (Pdf.empty ()) "/Colors" d with Some (Pdf.Integer x) -> x | _ -> 1 in let bpc = match Pdf.lookup_direct_orelse (Pdf.empty ()) "/BPC" "/BitsPerComponent" d with Some (Pdf.Integer x) -> x | _ -> 8 in let columns = match Pdf.lookup_direct (Pdf.empty ()) "/Columns" d with Some (Pdf.Integer x) -> x | _ -> 1 in match colours, bpc with | 3, 8 -> let data = Pdfcodec.encode_predictor 11 colours bpc columns data in let dict = Pdf.add_dict_entry dict "/DP" (Pdf.Dictionary [("/Colors", Pdf.Integer colours); ("/Columns", Pdf.Integer columns); ("/Predictor", Pdf.Integer 11)]) in dict, data | _, _ -> dict, data*) in Pdf.add_dict_entry dict "/F" (Pdf.Name "/Fl"), Pdfcodec.encode_flate data | _ -> dict, data in let dict = Pdf.add_dict_entry dict "/L" (Pdf.Integer (bytes_size data)) in let dict_string = Pdfwrite.string_of_pdf dict in let dict_string' = (* Remove the dictionary markers. *) implode (rev (drop' 2 (rev (drop' 2 (explode dict_string))))) in let space = let filters = match Pdf.lookup_direct_orelse (Pdf.empty ()) "/F" "/Filter" dict with | Some (Pdf.Array filters) -> filters | Some (Pdf.Name f) -> [Pdf.Name f] | _ -> [] in if filterspecial filters then "" else " " in Buffer.clear b; iter (Buffer.add_string b) ["BI\n"; dict_string'; " ID"; space; string_of_bytes data; "\nEI\n"]; Buffer.contents b let b = Buffer.create 30 let string_of_lexemes lexemes = Buffer.clear b; iter (fun l -> let str = string_of_lexeme l in (* Add a space character if neither the current last character in the * buffer nor the first character of the new string is a delimiter *) if Buffer.length b > 0 && not (Pdf.is_delimiter (Buffer.nth b (Buffer.length b - 1))) && String.length str > 0 && not (Pdf.is_delimiter str.[0]) then Buffer.add_char b ' '; Buffer.add_string b str) lexemes; Buffer.contents b (* Make a string of an operation, for debug purposes only. *) let string_of_ops ops = string_of_lexemes (lexemes_of_ops ops) let string_of_op op = string_of_ops [op] exception LexingEnd (* Lex a name. *) let lex_name i = nudge i; Obj (Pdfgenlex.LexName ("/" ^ Pdfread.getuntil_white_or_delimiter_string i)) (* This is raised when we can't deal with some content. This should only happen in the case of a malformed operator stream, not on any legitimate content. *) exception Couldn'tHandleContent let nocontent i = Pdfe.log "Failed to understand content on page\n"; if !Pdfread.read_debug then begin Pdfio.debug_next_n_chars 20 i; flprint "\n" end; raise Couldn'tHandleContent (* Lex a number *) let lex_number i = match Pdfread.lex_number i with | Pdfgenlex.LexReal r -> Obj (Pdfgenlex.LexReal r) | Pdfgenlex.LexInt i -> Obj (Pdfgenlex.LexReal (float_of_int i)) | _ -> nocontent i (* Lex and parse a dictionary to a Pdf.pdfobject. This constitutes a single lexeme in terms of this module. *) let get_dictionary i = PdfObj (snd (Pdfread.parse (Pdfread.lex_dictionary false i))) (* Given a colourspace and the number of bits per component, give the number of bytes per pixel in the stored image data. *) let rec components pdf resources t = match t with | Pdf.Name ("/CalGray" | "/DeviceGray" | "/G") -> 1 | Pdf.Name ("/CalRGB" | "/DeviceRGB" | "/RGB") -> 3 | Pdf.Name ("/CalCMYK" | "/DeviceCMYK" | "/CMYK") -> 4 | Pdf.Name "/Pattern" -> raise (Pdf.PDFError "Can't use /Pattern here") | Pdf.Name space -> begin match Pdf.lookup_direct pdf "/ColorSpace" resources with | Some csdict -> begin match Pdf.lookup_direct pdf space csdict with | Some space' -> components pdf resources space' | None -> raise (Pdf.PDFError "ColorSpace not found") end | None -> raise (Pdf.PDFError "ColorSpace dict not found") end | Pdf.Array [Pdf.Name "/Lab"; _] -> 3 | Pdf.Array [Pdf.Name "/ICCBased"; iccstream] -> begin match Pdf.lookup_direct pdf "/N" iccstream with | Some (Pdf.Integer n) -> n | _ -> raise (Pdf.PDFError "Bad iccstream") end | Pdf.Array (Pdf.Name "/DeviceN"::Pdf.Array items::_) -> (* 4th July 2017. Changed from looking at alternate to counting items. *) length items | Pdf.Array [Pdf.Name "/Separation"; _; _; _] | Pdf.Array (Pdf.Name ("/Indexed" | "/I")::_::_) -> 1 | Pdf.Array [Pdf.Name "/CalRGB"; _] -> 3 | Pdf.Array [Pdf.Name "/CalCMYK"; _] -> 4 | Pdf.Array [Pdf.Name "/CalGray"; _] -> 1 | Pdf.Array [Pdf.Name "/Pattern"; alternate] -> components pdf resources (Pdf.direct pdf alternate) | cs -> Pdfe.log (Printf.sprintf "%s\n" (Pdfwrite.string_of_pdf cs)); raise (Pdf.PDFError "Unknown colourspace") (* Lex an inline image. We read the dictionary, and then the stream. *) let lex_inline_image pdf resources i = if !debug then Pdfe.log (Printf.sprintf "lex_inline_image at %i\n" (i.pos_in ())); try let dict = let lexemes = Pdfread.lex_dictionary true i in snd (Pdfread.parse ([Pdfgenlex.LexLeftDict] @ lexemes @ [Pdfgenlex.LexRightDict])) in if !debug then Pdfe.log (Printf.sprintf "dict was %s\n" (Pdfwrite.string_of_pdf dict)); (* Read ID token *) Pdfread.dropwhite i; let c = char_of_int (i.input_byte ()) in let c' = char_of_int (i.input_byte ()) in match c, c' with | 'I', 'D' -> (* Skip a byte if not ASCII85 / ASCIIHex as one of the filters. *) let toskip = let filters = match Pdf.lookup_direct_orelse pdf "/F" "/Filter" dict with | Some (Pdf.Array filters) -> filters | Some (Pdf.Name f) -> [Pdf.Name f] | _ -> [] in not (filterspecial filters) in if toskip then ignore (i.input_byte ()); if !debug then Pdfe.log "**got ID header, skipped possble byte"; let bytes = let bpc = match Pdf.lookup_direct_orelse pdf "/BPC" "/BitsPerComponent" dict with | Some (Pdf.Integer bpc) -> bpc | _ -> Pdfe.log "no BPC\n"; nocontent i in let cspace = match Pdf.lookup_direct_orelse pdf "/CS" "/ColorSpace" dict with | Some (Pdf.Name ("/DeviceGray" | "/DeviceRGB" | "/DeviceCMYK") as n) -> n | Some (Pdf.Name ("/G" | "/RGB" | "/CMYK") as n) -> n | Some ((Pdf.Array _) as n) -> n | Some (Pdf.Name cspace) -> if !debug then Pdfe.log (Printf.sprintf "resources is %s\n" (Pdfwrite.string_of_pdf resources)); begin match Pdf.lookup_direct pdf "/ColorSpace" resources with | Some (Pdf.Dictionary _ as d) -> begin match Pdf.lookup_direct pdf cspace d with | Some c -> c | _ -> Pdfe.log "no colourspace A\n"; nocontent i end | _ -> Pdfe.log "no colourspace B\n"; nocontent i end | None -> (* Could it be an image mask? *) begin match Pdf.lookup_direct_orelse pdf "/IM" "/ImageMask" dict with | Some (Pdf.Boolean true) -> Pdf.Name "/DeviceGray" | _ -> Pdfe.log "no colourspace C\n"; nocontent i end | _ -> Pdfe.log "no colourspace D\n"; nocontent i in let width = match Pdf.lookup_direct_orelse pdf "/W" "/Width" dict with | Some (Pdf.Integer w) -> w | _ -> Pdfe.log "no or malformed /W"; nocontent i in let height = match Pdf.lookup_direct_orelse pdf "/H" "/Height" dict with | Some (Pdf.Integer h) -> h | _ -> Pdfe.log "no or malformed /H"; nocontent i in let bitwidth = components pdf resources cspace * bpc * width in let bytewidth = if bitwidth mod 8 = 0 then bitwidth / 8 else bitwidth / 8 + 1 in bytewidth * height in let data = match Pdf.lookup_direct_orelse (Pdf.empty ()) "/F" "/Filter" dict with | None | Some (Pdf.Array []) -> begin try let data = mkbytes bytes in if bytes > 0 then for x = 0 to bytes_size data - 1 do bset_unsafe data x (i.input_byte ()); done; data with | e -> Pdfe.log (Printexc.to_string e); raise e end | Some (Pdf.Name ("/DCT" | "/DCTDecode") | Pdf.Array [Pdf.Name ("/DCT" | "/DCTDecode")]) -> (* FIXME. The case of DCT combined with another one is possible e.g ["/DCT"; "/A85"]. Need to re-work. But have not seen an example yet. *) begin try Pdfjpeg.get_jpeg_data i with e -> Pdfe.log (Printf.sprintf "Couldn't read inline image JPEG data %s\n" (Printexc.to_string e)); raise e end | Some _ -> try match Pdfcodec.decode_from_input i dict with | None -> Pdfe.log "decode_from_input failed\n"; nocontent i | Some data -> data with | Pdfcodec.DecodeNotSupported d -> Pdfe.log (Printf.sprintf "Content DecodeNotSupported: %s\n" d); nocontent i | Pdfcodec.Couldn'tDecodeStream r -> raise (Pdf.PDFError ("Inline image, bad data: " ^ r)) | e -> raise e in (* Read EI token *) Pdfread.dropwhite i; let c = char_of_int (i.input_byte ()) in let c' = char_of_int (i.input_byte ()) in if c <> 'E' || c' <> 'I' then begin Pdfe.log (Printf.sprintf "warning: bad end to inline image %C, %C\n" c c'); (* We try to find "EI" anyway, in case there is just some junk. This is basic - if the junk contains E....I somewhere in it, the procedure will fail. *) Pdfread.ignoreuntil true (( = ) 'E') i; Pdfread.ignoreuntil true (( = ) 'I') i; Pdfio.nudge i; Pdfread.dropwhite i; (* 29/03/2023: Previous, worse implementation here: *) (*Pdfread.ignoreuntil true (fun x -> Pdf.is_not_whitespace x && x <> 'E' && x <> 'I') i;*) end; (* Remove filter, predictor, if it wasn't JPEG. *) let dict' = match Pdf.lookup_direct_orelse (Pdf.empty ()) "/F" "/Filter" dict with (* FIXME as above *) | Some (Pdf.Name ("/DCT" | "/DCTDecode") | Pdf.Array [Pdf.Name ("/DCT" | "/DCTDecode")]) -> dict | _ -> fold_left Pdf.remove_dict_entry dict ["/Filter"; "/F"; "/DecodeParms"; "/DP"] in let dp = Pdf.lookup_direct_orelse (Pdf.empty ()) "/DP" "/DecodeParms" dict in dict', dp, data | _ -> Pdfe.log "Did not recognise beginning of inline image ID\n"; nocontent i with e -> Pdfe.log (Printf.sprintf "inline image reading failed: %s\n" (Printexc.to_string e)); nocontent i (* Lex a keyword. *) let lex_keyword pdf resources i = match Pdfread.getuntil_white_or_delimiter_string i with | "true" -> Obj (Pdfgenlex.LexBool true) | "false" -> Obj (Pdfgenlex.LexBool false) | "BI" -> LexInlineImage (lex_inline_image pdf resources i) | "ID" | "EI" -> nocontent i (* lex_inline_image should consume these *) | "" -> nocontent i | opstring -> Op opstring (* Lex a string. *) let lex_string i = match Pdfread.lex_string i with | Pdfgenlex.LexString str -> Obj (Pdfgenlex.LexString str) | _ -> nocontent i (* Lex a hexadecimal string. *) let lex_hexstring i = match Pdfread.lex_hexstring i with | Pdfgenlex.LexString str -> Obj (Pdfgenlex.LexString str) | _ -> nocontent i (* Lex one token *) let lex_next pdf resources i = try Pdfread.dropwhite i; match peek_byte i with | x when x = Pdfio.no_more -> raise LexingEnd | chr -> match char_of_int chr with | '/' -> lex_name i | '+' | '-' | '.' | '0'..'9' -> lex_number i | 'A'..'Z' | 'a'..'z' | '\'' | '\"' -> lex_keyword pdf resources i | '(' -> lex_string i | '[' -> nudge i; Obj (Pdfgenlex.LexLeftSquare) | ']' -> nudge i; Obj (Pdfgenlex.LexRightSquare) | '<' -> begin match nudge i; let c = unopt (peek_char i) in rewind i; c with | '<' -> get_dictionary i | _ -> lex_hexstring i end | '%' -> ignore (Pdfread.lex_comment i); LexComment "" | _ -> raise (Pdf.PDFError "Lexing failure in content stream") with | Pdf.PDFError r -> raise (Pdf.PDFError ("Pdfpages.lex_next => " ^ r)) | Failure _ (*"unopt"*) | End_of_file -> raise LexingEnd | Couldn'tHandleContent -> raise (Pdf.PDFError "Malformed page content") (*let print_lexeme = function | Obj p -> Pdfread.print_lexeme p | Op s -> print_string s; print_newline () | PdfObj p -> print_string "PDF OBJECT\n" | LexInlineImage _ -> print_string "INLINE IMAGE\n" | LexComment -> print_string "COMMENT\n"*) (* Lex a graphics stream *) let lex_stream pdf resources i = let lexemes = ref [] in try while true do match lex_next pdf resources i with | LexComment _ -> () | lexeme -> lexemes := lexeme::!lexemes done; [] with LexingEnd -> rev !lexemes (* Split the lexemes into sections (zero or more operands followed by an operator) and parse each. Section is reversed. *) let split s = let rec split_inner prev = function | (Op _ | LexInlineImage _) as f::r -> f::prev, r | [] -> prev, [] | x::r -> split_inner (x::prev) r in split_inner [] s (* Parse a single operator and its operands, provided as a lexeme list. The string from which these lexemes were extracted is provided so that Op_Unknown instances can be generated. The compatibility level is also provided, and may be updated. *) let parse_operator compatibility = function | Op "W"::r -> Op_W, r | Op "W*"::r -> Op_W', r | Op "q"::r -> Op_q, r | Op "Q"::r -> Op_Q, r | Op "h"::r -> Op_h, r | Op "n"::r -> Op_n, r | Op "f*"::r -> Op_f', r | Op "f"::r -> Op_f, r | Op "F"::r -> Op_F, r | Op "BT"::r -> Op_BT, r | Op "ET"::r -> Op_ET, r | Op "B"::r -> Op_B, r | Op "B*"::r -> Op_B', r | Op "b"::r -> Op_b, r | Op "b*"::r -> Op_b', r | Op "S"::r -> Op_S, r | Op "s"::r -> Op_s, r | Op "T*"::r -> Op_T', r | Op "BX"::r -> incr compatibility; Op_BX, r | Op "EX"::r -> decr compatibility; Op_EX, r | Obj (Pdfgenlex.LexReal tx)::Obj (Pdfgenlex.LexReal ty)::Op "Td"::r -> Op_Td (tx, ty), r | Obj (Pdfgenlex.LexReal tx)::Obj (Pdfgenlex.LexReal ty)::Op "TD"::r -> Op_TD (tx, ty), r | Obj (Pdfgenlex.LexReal width)::Op "w"::r -> Op_w width, r | Obj (Pdfgenlex.LexReal cap)::Op "J"::r -> Op_J (int_of_float cap), r | Obj (Pdfgenlex.LexReal join)::Op "j"::r -> Op_j (int_of_float join), r | Obj (Pdfgenlex.LexReal x)::Obj (Pdfgenlex.LexReal y)::Op "m"::r -> Op_m (x, y), r | Obj (Pdfgenlex.LexReal x)::Obj (Pdfgenlex.LexReal y)::Op "l"::r -> Op_l (x, y), r | Obj (Pdfgenlex.LexReal leading)::Op "TL"::r -> Op_TL leading, r | Obj (Pdfgenlex.LexName n)::Obj (Pdfgenlex.LexReal s)::Op "Tf"::r -> Op_Tf (n, s), r | Obj (Pdfgenlex.LexString s)::Op "Tj"::r -> Op_Tj s, r | Obj (Pdfgenlex.LexReal r):: Obj (Pdfgenlex.LexReal g):: Obj (Pdfgenlex.LexReal b)::Op "RG"::rest -> Op_RG (r, g, b), rest | Obj (Pdfgenlex.LexReal r):: Obj (Pdfgenlex.LexReal g):: Obj (Pdfgenlex.LexReal b)::Op "rg"::rest -> Op_rg (r, g, b), rest | Obj (Pdfgenlex.LexReal g)::Op "G"::r -> Op_G g, r | Obj (Pdfgenlex.LexReal g)::Op "g"::r -> Op_g g, r | Obj (Pdfgenlex.LexReal c)::Obj (Pdfgenlex.LexReal m):: Obj (Pdfgenlex.LexReal y)::Obj (Pdfgenlex.LexReal k):: Op "k"::r -> Op_k (c, m, y, k), r | Obj (Pdfgenlex.LexReal c)::Obj (Pdfgenlex.LexReal m):: Obj (Pdfgenlex.LexReal y)::Obj (Pdfgenlex.LexReal k):: Op "K"::r -> Op_K (c, m, y, k), r | Obj (Pdfgenlex.LexReal a)::Obj (Pdfgenlex.LexReal b):: Obj (Pdfgenlex.LexReal c)::Obj (Pdfgenlex.LexReal d):: Obj (Pdfgenlex.LexReal e)::Obj (Pdfgenlex.LexReal f):: Op "cm"::r -> Op_cm {Pdftransform.a = a; Pdftransform.b = b; Pdftransform.c = c; Pdftransform.d = d; Pdftransform.e = e; Pdftransform.f = f}, r | Obj (Pdfgenlex.LexReal a)::Obj (Pdfgenlex.LexReal b):: Obj (Pdfgenlex.LexReal c)::Obj (Pdfgenlex.LexReal d):: Obj (Pdfgenlex.LexReal e)::Obj (Pdfgenlex.LexReal f)::Op "Tm"::r -> Op_Tm {Pdftransform.a = a; Pdftransform.b = b; Pdftransform.c = c; Pdftransform.d = d; Pdftransform.e = e; Pdftransform.f = f}, r | Obj (Pdfgenlex.LexName n)::Op "MP"::r -> Op_MP n, r | Obj (Pdfgenlex.LexName n)::PdfObj p::Op "DP"::r -> Op_DP (n, p), r | Obj (Pdfgenlex.LexName n)::Obj o::Op "DP"::r -> let p = snd (Pdfread.parse [o]) in Op_DP (n, p), r | Obj (Pdfgenlex.LexName n)::Op "BMC"::r -> Op_BMC n, r | Obj (Pdfgenlex.LexName n)::PdfObj p::Op "BDC"::r -> Op_BDC (n, p), r | Obj (Pdfgenlex.LexName n)::Obj o::Op "BDC"::r -> let p = snd (Pdfread.parse [o]) in Op_BDC (n, p), r | Op "EMC"::r -> Op_EMC, r | Obj (Pdfgenlex.LexName n)::Op "gs"::r -> Op_gs n, r | Obj (Pdfgenlex.LexName n)::Op "Do"::r -> Op_Do n, r | Obj (Pdfgenlex.LexName n)::Op "CS"::r -> Op_CS n, r | Obj (Pdfgenlex.LexName n)::Op "cs"::r -> Op_cs n, r | Obj (Pdfgenlex.LexReal x1)::Obj (Pdfgenlex.LexReal y1):: Obj (Pdfgenlex.LexReal x2)::Obj (Pdfgenlex.LexReal y2):: Obj (Pdfgenlex.LexReal x3)::Obj (Pdfgenlex.LexReal y3):: Op "c"::r -> Op_c (x1, y1, x2, y2, x3, y3), r | Obj (Pdfgenlex.LexReal x2)::Obj (Pdfgenlex.LexReal y2):: Obj (Pdfgenlex.LexReal x3)::Obj (Pdfgenlex.LexReal y3):: Op "v"::r -> Op_v (x2, y2, x3, y3), r | Obj (Pdfgenlex.LexReal x1)::Obj (Pdfgenlex.LexReal y1):: Obj (Pdfgenlex.LexReal x3)::Obj (Pdfgenlex.LexReal y3):: Op "y"::r -> Op_y (x1, y1, x3, y3), r | Obj (Pdfgenlex.LexReal x)::Obj (Pdfgenlex.LexReal y):: Obj (Pdfgenlex.LexReal w)::Obj (Pdfgenlex.LexReal h):: Op "re"::r -> Op_re (x, y, w, h), r | Obj (Pdfgenlex.LexName n)::Op "ri"::r -> Op_ri n, r | Obj (Pdfgenlex.LexReal i)::Op "i"::r -> Op_i (int_of_float i), r | Obj (Pdfgenlex.LexReal m)::Op "M"::r -> Op_M m, r | Obj (Pdfgenlex.LexString s)::Op "\'"::r -> Op_' s, r | Obj (Pdfgenlex.LexReal aw):: Obj (Pdfgenlex.LexReal ac):: Obj (Pdfgenlex.LexString s)::Op "\""::r -> Op_'' (aw, ac, s), r | Obj (Pdfgenlex.LexReal wx)::Obj (Pdfgenlex.LexReal wy)::Op "d0"::r -> Op_d0 (wx, wy), r | Obj (Pdfgenlex.LexReal wx)::Obj (Pdfgenlex.LexReal wy):: Obj (Pdfgenlex.LexReal llx)::Obj (Pdfgenlex.LexReal lly):: Obj (Pdfgenlex.LexReal urx)::Obj (Pdfgenlex.LexReal ury)::Op "d1"::r -> Op_d1 (wx, wy, llx, lly, urx, ury), r | Obj (Pdfgenlex.LexName n)::Op "sh"::r -> Op_sh n, r | Obj (Pdfgenlex.LexReal tc)::Op "Tc"::r -> Op_Tc tc, r | Obj (Pdfgenlex.LexReal tw)::Op "Tw"::r -> Op_Tw tw, r | Obj (Pdfgenlex.LexReal tz)::Op "Tz"::r -> Op_Tz tz, r | Obj (Pdfgenlex.LexReal tr)::Op "Tr"::r -> Op_Tr (toint tr), r | Obj (Pdfgenlex.LexReal ts)::Op "Ts"::r -> Op_Ts ts, r | LexInlineImage d::r -> InlineImage d, r | ls -> let ls, more = split ls in (* More complicated things are parsed by reversing the lexemes so we may inspect the operator. *) let r = let reals_of_real_lexemes errtext lexemes = let real_of_real_lexeme errtext = function | Obj (Pdfgenlex.LexReal n) -> n | _ -> raise (Pdf.PDFError errtext) in (* Adobe Distiller 5.0.5 produces bad Op_scn *) try rev_map (real_of_real_lexeme errtext) lexemes with _ -> [0.;0.;0.;] in match ls with | Op "sc"::nums -> Op_sc (reals_of_real_lexemes "Malformed 'sc'" nums) | Op "SC"::nums -> Op_SC (reals_of_real_lexemes "Malformed 'SC'" nums) | Op "scn"::Obj (Pdfgenlex.LexName n)::rest -> Op_scnName (n, reals_of_real_lexemes "scn" rest) | Op "SCN"::Obj (Pdfgenlex.LexName n)::rest -> Op_SCNName (n, reals_of_real_lexemes "SCN" rest) | Op "scn"::nums -> Op_scn (reals_of_real_lexemes "Malformed 'scn'" nums) | Op "SCN"::nums -> Op_SCN (reals_of_real_lexemes "Malformed 'SCN'" nums) | Op "d":: Obj (Pdfgenlex.LexReal phase):: Obj Pdfgenlex.LexRightSquare::r -> begin match rev r with | Obj Pdfgenlex.LexLeftSquare::t -> let reals = map (function | (Obj (Pdfgenlex.LexReal i)) -> i | _ -> raise (Pdf.PDFError "malformed 'd' op")) t in Op_d (reals, phase) | _ -> raise (Pdf.PDFError "malformed 'd' op") end | Op "TJ"::Obj Pdfgenlex.LexRightSquare::r -> begin match rev r with | Obj Pdfgenlex.LexLeftSquare::t -> let elements = option_map (function | (Obj (Pdfgenlex.LexReal i)) -> Some (Pdf.Real i) | (Obj (Pdfgenlex.LexString s)) -> Some (Pdf.String s) | e -> Pdfe.log "Warning: malformed TJ element; skipping\n"; None) t in Op_TJ (Pdf.Array elements) | _ -> raise (Pdf.PDFError "malformed TJ op") end | Op _::_ as l -> Pdfe.log (Printf.sprintf "Empty or malformed graphics operation %s.\n" (string_of_lexemes (rev l))); Op_Unknown (string_of_lexemes (rev l)) | l -> Pdfe.log (Printf.sprintf "Empty or malformed graphics operation %s.\n" (string_of_lexemes (rev l))); Op_Unknown (string_of_lexemes (rev l)) in r, more let rec parse_lexemes compatibility ls ops = match ls with | [] -> rev ops | _ -> let op, remaining = parse_operator compatibility ls in parse_lexemes compatibility remaining (op::ops) (* Parse, given a list of streams. The contents of a single PDF page can be split over several streams, which must be concatenated at the lexeme level. *) (* Concatenate bytess, padding with whitespace *) let concat_bytess ss = let total_length = sum (map bytes_size ss) in let s' = mkbytes (total_length + length ss) in let p = ref 0 in iter (fun s -> for x = 0 to bytes_size s - 1 do bset_unsafe s' !p (bget s x); incr p done; bset_unsafe s' !p (int_of_char ' '); incr p) ss; s' let parse_single_stream pdf resources stream = let i = input_of_bytes stream in let lexemes = lex_stream pdf resources i in parse_lexemes (ref 0) lexemes [] let parse_stream pdf resources streams = let stream = match streams with [s] -> s | _ -> concat_bytess streams in parse_single_stream pdf resources stream (* Parse the operators in a list of streams. *) let parse_operators pdf resources streams = let rawstreams = map (fun c -> let c = Pdf.direct pdf c in Pdfcodec.decode_pdfstream pdf c; Pdf.bigarray_of_stream c) streams in parse_stream pdf resources rawstreams (* Flattening *) let whitespace = ref " " let always_add_whitespace = ref false (* Give a bigarray representing a list of graphics operators. *) let stream_of_lexemes (oplists : lexeme list list) = let strings = map string_of_lexemes oplists in (* Insert whitespace if the neither the last character of a string nor the * first character of the next is a delimiter *) let rec addspaces prev = function [] -> rev prev | [x] -> addspaces (x::prev) [] | x::y::r -> if (String.length x > 0 && Pdf.is_delimiter x.[String.length x - 1] || String.length y > 0 && Pdf.is_delimiter y.[0]) && not !always_add_whitespace then addspaces (x::prev) (y::r) else addspaces (!whitespace::x::prev) (y::r) in let strings = addspaces [] strings in let total_length = let l = ref 0 in iter (fun s -> l := !l + String.length s) strings; !l in let s = mkbytes total_length in let strings = ref strings in let pos = ref 0 in while !strings <> [] do let str = hd !strings in let l = String.length str in if l > 0 then for n = 0 to l - 1 do bset_unsafe s !pos (int_of_char str.[n]); incr pos done; strings := tl !strings done; s (*let print_stream s = if bytes_size s > 0 then for x = 0 to bytes_size s - 1 do Printf.printf "%c" (char_of_int (bget s x)) done; print_newline ()*) (* Make a stream from a list of operators. *) let stream_of_ops ops = let data = stream_of_lexemes (lexemelists_of_ops ops) in Pdf.Stream (ref (Pdf.Dictionary [("/Length", Pdf.Integer (bytes_size data))], Pdf.Got data)) let begin_artifact = Op_BMC "/Artifact" let end_artifact = Op_EMC camlpdf-2.8.1/pdfops.mli000066400000000000000000000073051477056064700151530ustar00rootroot00000000000000(** Parsing PDF Graphics Streams *) (** A flat representation of the PDF graphics stream operators. Where the operator contains the asterisk character (not allowable in OCaml syntax), a prime is substituted. *) type t = | Op_w of float | Op_J of int | Op_j of int | Op_M of float | Op_d of float list * float | Op_ri of string | Op_i of int | Op_gs of string | Op_q | Op_Q | Op_cm of Pdftransform.transform_matrix | Op_m of float * float | Op_l of float * float | Op_c of float * float * float * float * float * float | Op_v of float * float * float * float | Op_y of float * float * float * float | Op_h | Op_re of float * float * float * float | Op_S | Op_s | Op_f | Op_F | Op_f' | Op_B | Op_B' | Op_b | Op_b' | Op_n | Op_W | Op_W' | Op_BT | Op_ET | Op_Tc of float | Op_Tw of float | Op_Tz of float | Op_TL of float | Op_Tf of string * float | Op_Tr of int | Op_Ts of float | Op_Td of float * float | Op_TD of float * float | Op_Tm of Pdftransform.transform_matrix | Op_T' | Op_Tj of string | Op_TJ of Pdf.pdfobject | Op_' of string | Op_'' of float * float * string | Op_d0 of float * float | Op_d1 of float * float * float * float * float * float | Op_CS of string | Op_cs of string | Op_SC of float list | Op_sc of float list | Op_SCN of float list | Op_scn of float list | Op_SCNName of string * float list | Op_scnName of string * float list | Op_G of float | Op_g of float | Op_RG of float * float * float | Op_rg of float * float * float | Op_K of float * float * float * float | Op_k of float * float * float * float | Op_sh of string | InlineImage of (Pdf.pdfobject * Pdf.pdfobject option * Pdfio.bytes) | Op_Do of string | Op_MP of string | Op_DP of string * Pdf.pdfobject | Op_BMC of string | Op_BDC of string * Pdf.pdfobject | Op_EMC | Op_BX | Op_EX | Op_Unknown of string | Op_Comment of string (** Parse a single byte streams to an operator list given a document and resource dictionary. *) val parse_single_stream : Pdf.t -> Pdf.pdfobject -> Pdfio.bytes -> t list (** Parse a list of byte streams to an operator list given a document and resource dictionary. *) val parse_stream : Pdf.t -> Pdf.pdfobject -> Pdfio.bytes list -> t list (** Concatenate a list of bytes, padding with whitespace between. *) val concat_bytess : Pdfio.bytes list -> Pdfio.bytes (** Given a pdf document, resource dictionary and list of streams representing the graphics content (PDF allows a single page's graphics content to be split over several streams), return a list of operators. Raises PDFError on bad content. *) val parse_operators : Pdf.t -> Pdf.pdfobject -> Pdf.pdfobject list -> t list (** Flatten a list of operators to an uncompressed PDF stream. *) val stream_of_ops : t list -> Pdf.pdfobject (** Make a string of a single operator (for debug purposes). *) val string_of_op : t -> string (** Same as [string_of_op], but of several operators (for debug purposes). *) val string_of_ops : t list -> string (** Given a pdf, a resources dictionary and a colourspace dictionary, give the number of bytes per pixel in the stored image data. *) val components : Pdf.t -> Pdf.pdfobject -> Pdf.pdfobject -> int (** When this reference is set, some debug information is printed to Standard Output. *) val debug : bool ref (** Whitespace between operators *) val whitespace : string ref (** Add whitespace even where not lexically-required. *) val always_add_whitespace : bool ref (** If set, comments will be written. *) val write_comments : bool ref (** The operation which begins an artifact in PDF/UA *) val begin_artifact : t (** The operation which ends an artifact in PDF/UA *) val end_artifact : t camlpdf-2.8.1/pdfpage.ml000066400000000000000000001662411477056064700151220ustar00rootroot00000000000000open Pdfutil (* The type of the four rotations of pages. This defines how a viewing application (e.g Acrobat) displays the page. *) type rotation = | Rotate0 | Rotate90 | Rotate180 | Rotate270 (* A type representing a page. content is the list of objects containing the graphical content stream (see the Pdfops module), mediabox the page size, resources the page's resource dictionary, rotate its rotation and rest any other entries to reside in the page dictionary. *) type t = {content : Pdf.pdfobject list; mediabox : Pdf.pdfobject; resources : Pdf.pdfobject; rotate : rotation; rest : Pdf.pdfobject} (* A dictionary of the other entries in the page dictionary. *) (* Make a PDF rectangle from a Paper.papersize. *) let rectangle_of_paper paper = let u = Pdfpaper.unit paper in let w = Pdfunits.points (Pdfpaper.width paper) u in let h = Pdfunits.points (Pdfpaper.height paper) u in Pdf.Array [Pdf.Real 0.; Pdf.Real 0.; Pdf.Real w; Pdf.Real h] (* Create a page with empty content, media box from the given paper size, empty resources, zero rotation and no extra dictionary entries. *) let custompage rectangle = {content = []; mediabox = rectangle; resources = Pdf.Dictionary []; rotate = Rotate0; rest = Pdf.Dictionary []} let blankpage papersize = custompage (rectangle_of_paper papersize) (* Utility function to convert from rotation to integers. *) let int_of_rotation = function | Rotate0 -> 0 | Rotate90 -> 90 | Rotate180 -> 180 | Rotate270 -> 270 (* The reverse. raises [Pdf.PDFError] if its input modulo 360 is not 0, 90, 180, 270, -90, -180 or -270. *) let rotation_of_int i = match i mod 360 with | 0 -> Rotate0 | 90 | -270 -> Rotate90 | 180 | -180 -> Rotate180 | 270 | -90 -> Rotate270 | _ -> raise (Pdf.PDFError "Bad /Rotate") (* Extracting the page tree *) let rec remove_dict_entries e = function | (("/Resources" | "/Contents" | "/MediaBox" | "/Rotate" | "/Parent" | "/Type"), v)::t -> remove_dict_entries e t | h::t -> remove_dict_entries (h::e) t | [] -> e (* Given a page tree, find the first page resources, contents and mediabox. The resources and mediabox may be inherited from any node above in the page tree. *) (* Some files erroneously miss out a mediabox, expecting the reader to inherit it not from the page tree node above, but from the previous page. Most PDF readers can do this, and GhostScript can too. So we adopt this behaviour in the case of a missing mediabox. These readers also use US Letter Portrait as the default in case of no mediabox being present at all. *) let last_mediabox_seen = ref (Pdf.Array [Pdf.Integer 0; Pdf.Integer 0; Pdf.Integer 612; Pdf.Integer 792]) let rec find_pages pages pdf resources mediabox rotate = match pages with Pdf.Null -> [] | _ -> match Pdf.lookup_direct pdf "/Type" pages with | Some (Pdf.Name "/Pages") | None -> begin match Pdf.lookup_fail "No /Kids in page tree" pdf "/Kids" pages with | Pdf.Array kids -> let kids = map (function | Pdf.Indirect k -> (try Pdf.lookup_obj pdf k with Not_found -> raise (Pdf.PDFError "missing kid\n")) | Pdf.Dictionary d -> Pdf.Dictionary d (* malformed but we allow *) | _ -> raise (Pdf.PDFError "malformed kid\n")) kids in let resources = match Pdf.lookup_direct pdf "/Resources" pages with | Some x -> Some x | None -> resources in let mediabox = match Pdf.lookup_direct pdf "/MediaBox" pages with | Some x -> Some x | None -> mediabox in let rotate = match Pdf.lookup_direct pdf "/Rotate" pages with | Some (Pdf.Integer r) -> rotation_of_int r | _ -> rotate in flatten (map (fun k -> find_pages k pdf resources mediabox rotate) kids) | _ -> raise (Pdf.PDFError "Malformed /Kids in page tree node") end | Some _ -> let resources = match Pdf.lookup_direct pdf "/Resources" pages with | Some x -> Some x | None -> resources in let mediabox = match Pdf.lookup_direct pdf "/MediaBox" pages with | Some x -> Some x | None -> mediabox in let contents = (* 28th March 2016. We modify this to always create an array of one indirect if just a single contents stream, rather than following through to the actual object. Other code can then preserve the sharing. *) begin match pages with Pdf.Dictionary d -> begin match lookup "/Contents" d with Some (Pdf.Indirect i) -> (* A single content stream, or indirect to array *) begin match Pdf.lookup_obj pdf i with | Pdf.Array a -> Some (Pdf.Array a) | _ -> Some (Pdf.Array [Pdf.Indirect i]) end | _ -> (* An array of indirects. Just return it *) Pdf.lookup_direct pdf "/Contents" pages end | _ -> raise (Pdf.PDFError "Pages not a dictionary") end in let rotate = match Pdf.lookup_direct pdf "/Rotate" pages with | Some (Pdf.Integer r) -> rotation_of_int r | _ -> rotate in [{resources = (match resources with | Some r -> r | None -> Pdf.Dictionary []); content = (* 15th Feb 2012. We now preserve indirect references in /Contents to preserve sharing, at least on operations which don't modify the /Contents. *) (match contents with | None -> [] | Some (Pdf.Array cs) -> option_map (function x -> match Pdf.direct pdf x with | Pdf.Stream _ -> Some x | x -> Pdfe.log "Page /Contents not a stream: ignoring.\n"; None) cs; | Some pdfobject -> begin match Pdf.direct pdf pdfobject with | Pdf.Stream _ -> [pdfobject] | _ -> Pdfe.log "Page /Contents not a stream: ignoring.\n"; [] end); mediabox = (match mediabox with | Some m -> last_mediabox_seen := m; m | None -> Pdfe.log "Warning: missing mediabox. Using most recently seen.\n"; !last_mediabox_seen); rotate = rotate; rest = (match pages with | Pdf.Dictionary d -> Pdf.Dictionary (remove_dict_entries [] d) | _ -> raise (Pdf.PDFError "Bad /Pages")) }] (* Given a pdf, return a list of (resources, contents, mediabox) triples. *) let pages_of_pagetree pdf = let document_catalog = try Pdf.lookup_obj pdf pdf.Pdf.root with Not_found -> raise (Pdf.PDFError "/Root entry is incorrect") in let pages = Pdf.lookup_fail "No or malformed /Pages" pdf "/Pages" document_catalog in find_pages pages pdf None None Rotate0 let rec find_pages_quick pages pdf = match pages with Pdf.Null -> 0 | _ -> match Pdf.lookup_direct pdf "/Type" pages with | Some (Pdf.Name "/Pages") | None -> begin match Pdf.lookup_fail "No /Kids in page tree" pdf "/Kids" pages with | Pdf.Array kids -> let kids = map (function | Pdf.Indirect k -> (try Pdf.lookup_obj pdf k with Not_found -> raise (Pdf.PDFError "missing kid\n")) | Pdf.Dictionary d -> Pdf.Dictionary d (* malformed, but we allow *) | x -> raise (Pdf.PDFError "malformed kid\n")) kids in sum (map (fun k -> find_pages_quick k pdf) kids) | _ -> raise (Pdf.PDFError "Malformed /Kids in page tree node") end | Some _ -> 1 let pages_of_pagetree_quick pdf = let document_catalog = try Pdf.lookup_obj pdf pdf.Pdf.root with Not_found -> raise (Pdf.PDFError "/Root entry is incorrect") in let pages = Pdf.lookup_fail "No or malformed /Pages" pdf "/Pages" document_catalog in find_pages_quick pages pdf let endpage pdf = pages_of_pagetree_quick pdf let endpage_fast pdf = let document_catalog = try Pdf.lookup_obj pdf pdf.Pdf.root with Not_found -> raise (Pdf.PDFError "/Root entry is incorrect") in let pages = Pdf.lookup_fail "No or malformed /Pages" pdf "/Pages" document_catalog in match Pdf.lookup_direct pdf "/Count" pages with | Some (Pdf.Integer i) -> i | _ -> 0 let _ = Pdfread.endpage := endpage; Pdfst.endpage := endpage (* Make a collection of pages capable of being merged -- in other words rename their resources so as not to clash. *) let source k = let k = ref k in (fun () -> incr k; !k) let freshname source = "/r" ^ string_of_int (source ()) let resource_keys = ["/Font"; "/ExtGState"; "/ColorSpace"; "/Pattern"; "/Shading"; "/XObject"; "/Properties"] let make_changes pdf pages = let src = source 0 in let entries_of_page entry pageseq page = let entries = match Pdf.lookup_direct pdf entry page.resources with | Some (Pdf.Dictionary es) -> es | _ -> [] in map (fun (k, v) -> entry, pageseq, k, freshname src) entries in let pagenums = ilist 1 (length pages) in let entries name = map2 (entries_of_page name) pagenums pages in let entries = flatten <| flatten (map entries resource_keys) in let table = Hashtbl.create 1000 in iter (fun (entry, pageseq, k, name) -> Hashtbl.add table (entry, pageseq, k) name) entries; table let change_operator pdf lookup lookup_option seqnum = function | Pdfops.Op_Tf (f, s) -> Pdfops.Op_Tf (lookup "/Font" seqnum f, s) | Pdfops.Op_gs n -> Pdfops.Op_gs (lookup "/ExtGState" seqnum n) | Pdfops.Op_CS n -> begin match lookup_option "/ColorSpace" seqnum n with | Some x -> Pdfops.Op_CS x | None -> Pdfops.Op_CS n end | Pdfops.Op_cs n -> begin match lookup_option "/ColorSpace" seqnum n with | Some x -> Pdfops.Op_cs x | None -> Pdfops.Op_cs n end | Pdfops.Op_SCNName (s, ns) -> Pdfops.Op_SCNName (lookup "/Pattern" seqnum s, ns) | Pdfops.Op_scnName (s, ns) -> Pdfops.Op_scnName (lookup "/Pattern" seqnum s, ns) | Pdfops.Op_sh s -> Pdfops.Op_sh (lookup "/Shading" seqnum s) | Pdfops.Op_Do x -> Pdfops.Op_Do (lookup "/XObject" seqnum x) | Pdfops.Op_DP (n, Pdf.Name p) -> Pdfops.Op_DP (n, Pdf.Name (lookup "/Properties" seqnum p)) | Pdfops.Op_BDC (n, Pdf.Name p) -> begin match lookup_option "/Properties" seqnum p with | Some x -> Pdfops.Op_BDC (n, Pdf.Name x) | None -> Pdfe.log "Warning: Missing Op_BDC /Properties entry\n"; Pdfops.Op_BDC (n, Pdf.Name p) end | Pdfops.InlineImage (dict, dp, bytes) -> (* Replace any indirect "/CS" or "/ColorSpace" with a new "/CS" *) let dict' = match Pdf.lookup_direct_orelse pdf "/CS" "/ColorSpace" dict with | Some (Pdf.Name "/DeviceGray") | Some (Pdf.Name "/DeviceRGB") | Some (Pdf.Name "/DeviceCMYK") | Some (Pdf.Name "/G") | Some (Pdf.Name "/RGB") | Some (Pdf.Name "/CMYK") -> dict | Some (Pdf.Name n) -> Pdf.add_dict_entry (Pdf.remove_dict_entry (Pdf.remove_dict_entry dict "/ColorSpace") "/CS") "/CS" (Pdf.Name (lookup "/ColorSpace" seqnum n)) | _ -> dict in Pdfops.InlineImage (dict', dp, bytes) | x -> x (* Only for use with twoup now. FIXME: Can blow up shared content streams. Needs a cunning new method to preserve sharing. *) let renumber_pages pdf pages = match pages with | [] -> [] | pages -> let changes = make_changes pdf pages in let lookup_option dictname page oldkey = tryfind changes (dictname, page, oldkey) and lookup dictname page oldkey = try Hashtbl.find changes (dictname, page, oldkey) with Not_found -> raise (Pdf.PDFError "Pdfdoc.renumber_pages: Bad key") in let change_content seqnum resources content = let operators = Pdfops.parse_operators pdf resources content in let operators' = map (change_operator pdf lookup lookup_option seqnum) operators in [Pdfops.stream_of_ops operators'] in let change_resources seqnum resources = let newdict name = match Pdf.lookup_direct pdf name resources with | Some (Pdf.Dictionary fonts) -> Pdf.Dictionary (map (fun (k, v) -> lookup name seqnum k, v) fonts) | _ -> Pdf.Dictionary [] in let newdicts = map newdict resource_keys in let resources = ref resources in iter2 (fun k v -> resources := Pdf.add_dict_entry !resources k v) resource_keys newdicts; !resources in let process_page seqnum page = {page with content = change_content seqnum page.resources page.content; resources = change_resources seqnum page.resources} in map2 process_page (indx pages) pages (* New code for better page trees *) (* Each branch contains a list of pages to go at that branch, and pointers to two more page tree nodes. Each leaf contains just a page list. Page lists must be non-null. Leaves and branches also hold a parent pointer, and the object number of that leaf or branch. *) type ptree = | Lf of t list * int * int | Br of t list * ptree * ptree * int * int (* Split a list into three parts, the middle being of fixed, given, length n, and the left and right roughly equal in size, but at least of length one. *) let split3 n l = let len = length l in if n > len - 2 then raise (Invalid_argument "split3") else let leftlen = (len - n) / 2 in let left, rest = cleave l leftlen in let middle, right = cleave rest n in left, middle, right (* Build the pages *) let rec pagetree objnumsource pages parent = if length pages < 10 then Lf (pages, parent, objnumsource ()) else let left, this, right = split3 5 pages in let this_num = objnumsource () in let left_tree = pagetree objnumsource left this_num in let right_tree = pagetree objnumsource right this_num in Br (this, left_tree, right_tree, parent, this_num) (*let pagetree_flat objnumsource pages parent = Lf (pages, parent, objnumsource ())*) (* Version for pdf_of_pages where we are using the same object numbers *) type ptree_objnumbers = | OLf of int list * int * int (* object numbers, parent, object number of this leaf *) | OBr of int list * ptree_objnumbers * ptree_objnumbers * int * int (* object numbers, left, right, parent, object number of this branch *) (*let rec print_ptree = function | OLf (is, parent, objnumleaf) -> Printf.printf "OLf with object numbers "; print_ints is; Printf.printf " parent %i and this leaf object number is %i\n" parent objnumleaf | OBr (is, l, r, p, thisobjnumbranch) -> Printf.printf "OBt with object numbers "; print_ints is; Printf.printf " parent %i, this object number is %i\n" p thisobjnumbranch; Printf.printf "***LEFTS\n"; print_ptree l; Printf.printf "***RIGHTS\n"; print_ptree r*) let rec pagetree_with_objnumbers toplevel old_pagetree_root_num objnumsource objnumbers parent = if length objnumbers < 10 then OLf (objnumbers, parent, if toplevel then old_pagetree_root_num else objnumsource ()) else let left, this, right = split3 5 objnumbers and this_num = if toplevel then old_pagetree_root_num else objnumsource () in let left_tree = pagetree_with_objnumbers false old_pagetree_root_num objnumsource left this_num and right_tree = pagetree_with_objnumbers false old_pagetree_root_num objnumsource right this_num in OBr (this, left_tree, right_tree, parent, this_num) (* Make a page. Returns, objectnumber, page pdfobject, extra objects to be added. *) let mkpage getobjnum parent page = (*Printf.printf "mkpage with parent %i\n" parent;*) let content, extras = match page.content with | [] -> [], [] (*r Null Contents not allowed. *) | cs -> let indirects, objects = split (map (function | Pdf.Indirect i -> Pdf.Indirect i, None | c -> let i = getobjnum () in Pdf.Indirect i, Some (i, c)) cs) in [("/Contents", Pdf.Array indirects)], losenones objects in let page = Pdf.Dictionary ([("/Type", Pdf.Name "/Page"); ("/Parent", Pdf.Indirect parent); ("/Resources", page.resources); ("/MediaBox", page.mediabox)] @ (let i = int_of_rotation page.rotate in if i = 0 then [] else [("/Rotate", Pdf.Integer i)]) @ (match page.rest with | Pdf.Dictionary d -> d | _ -> raise (Pdf.PDFError "mkpage")) @ content) in getobjnum (), page, extras (* Build a list of objnum, pdfobject pairs from the ptree. The pages in the ptree are just missing their parent entries, so we add those. *) let rec objects_of_ptree getobjnum extras = function | Lf (pages, parent, this) -> let page_objects = map (fun (o, p, x) -> extras =@ x; (o, p)) (map (mkpage getobjnum this) pages) in let page_tree_node = let pdfobject = let parent_entry = if parent = 0 then [] else ["/Parent", Pdf.Indirect parent] in Pdf.Dictionary (["/Type", Pdf.Name "/Pages"; "/Kids", Pdf.Array ( map (fun x -> Pdf.Indirect x) (fst <| split page_objects)); "/Count", Pdf.Integer (length pages)] @ parent_entry) in this, pdfobject in page_tree_node::page_objects | Br (pages, left, right, parent, this) -> let objs_left = objects_of_ptree getobjnum extras left in let objs_right = objects_of_ptree getobjnum extras right in let left_num = match objs_left with | (n, _)::_ -> n | [] -> assert false in let right_num = match objs_right with | (n, _)::_ -> n | [] -> assert false in let count_left = match objs_left with | (_, Pdf.Dictionary d)::_ -> begin match lookup "/Count" d with | Some (Pdf.Integer i) -> i | _ -> assert false end | _ -> assert false in let count_right = match objs_right with | (_, Pdf.Dictionary d)::_ -> begin match lookup "/Count" d with | Some (Pdf.Integer i) -> i | _ -> assert false end | _ -> assert false in let this_objects = let page_objects = map (fun (o, p, x) -> extras =@ x; (o, p)) (map (mkpage getobjnum this) pages) in let page_tree_node = let pdfobject = let parent_entry = if parent = 0 then [] else ["/Parent", Pdf.Indirect parent] in let kids = fst <| split page_objects in Pdf.Dictionary (["/Type", Pdf.Name "/Pages"; "/Kids", Pdf.Array (map (fun x -> Pdf.Indirect x) ([left_num] @ kids @ [right_num])); "/Count", Pdf.Integer (count_left + count_right + length kids)] @ parent_entry) in this, pdfobject in page_tree_node::page_objects in this_objects @ objs_left @ objs_right (* Take a list of pages and a PDF. Build a page tree in the PDF, returning the new pdf and the object number assigned to the top page node. All references to objects not forming part of the tree nodes themselves are left unchanged. *) let add_pagetree pages pdf = let extras = ref [] in let getobjnum = source pdf.Pdf.objects.Pdf.maxobjnum in let ptree = pagetree getobjnum pages 0 in let objects = objects_of_ptree getobjnum extras ptree in let topnode = match hd objects with (n, _) -> n in iter (fun x -> ignore (Pdf.addobj_given_num pdf x)) (objects @ !extras); pdf, topnode (* Add a root entry, replacing the Type and Pages entry, and any entries in extras. Preserves any entries in any existing root (e.g Metadata pointer). *) let add_root pageroot extras pdf = let existing_entries = try match Pdf.lookup_obj pdf pdf.Pdf.root with | Pdf.Dictionary d -> d | _ -> [] with _ -> [] in let root = Pdf.Dictionary (fold_right (* Right so that /Type, /Pages overwrite *) (fun (k, v) d -> add k v d) ([("/Type", Pdf.Name "/Catalog"); ("/Pages", Pdf.Indirect pageroot)] @ existing_entries) extras) in let rootnum = Pdf.addobj pdf root in let trailerdict' = match pdf.Pdf.trailerdict with | Pdf.Dictionary d -> Pdf.Dictionary (add "/Root" (Pdf.Indirect rootnum) d) | _ -> raise (Pdf.PDFError "add_root: bad trailer dictionary") in {pdf with Pdf.root = rootnum; Pdf.trailerdict = trailerdict'} (* Make sure to supply refnums to speed it up, if you already have them from a * previous call to Pdf.page_reference_numbers *) let rec pagenumber_of_target ?fastrefnums pdf = function | Pdfdest.NullDestination -> 0 | Pdfdest.NamedDestination _ -> 0 | Pdfdest.StringDestination _ -> 0 | Pdfdest.Action a -> begin match Pdf.lookup_direct pdf "/S" a, Pdf.lookup_direct pdf "/D" a with | Some (Pdf.Name "/GoTo"), Some dest -> pagenumber_of_target ?fastrefnums pdf (Pdfdest.read_destination pdf dest) | _ -> 0 end | Pdfdest.XYZ (t, _, _, _) | Pdfdest.Fit t | Pdfdest.FitH (t, _) | Pdfdest.FitV (t, _) | Pdfdest.FitR (t, _, _, _, _) | Pdfdest.FitB t | Pdfdest.FitBH (t, _) | Pdfdest.FitBV (t, _) -> match t with | Pdfdest.OtherDocPageNumber i -> i + 1 (* If it's really a Pdfdest.OtherDocPageNumber, you must process this yourself before. *) | Pdfdest.PageObject i -> match fastrefnums with | Some table -> begin try Hashtbl.find table i with Not_found -> 0 end | None -> match position_1 i (Pdf.page_reference_numbers pdf) with | Some n -> n | None -> 0 (* Return a new PDF containing everything the old one does, but with new pages. Other objects (e.g destinations in the document outline) may point to the individual page objects, so we must renumber these. We can only do this if the number of pages are the same. We do this [if change_references is true]. If the new and old page lists are of different lengths, change_references must be false, or you must supply the changes (expressed as (from, to) 1-based serial number pairs). The matrices optional argument, only relevant when change_references is true and the number of pages has not changed, gives a list of (page number, matrix) pairs which indicate that the page has been transformed. We can then rewrite bookmark destinations to reflect the transformed destination positions. We also rewrite annotation destinations after the same fashion. *) let change_pages_find_matrix dest mattable refnumstable = match dest with | Pdfdest.XYZ (tp, _, _, _) | Pdfdest.FitH (tp, _) | Pdfdest.FitV (tp, _) | Pdfdest.FitR (tp, _, _, _, _) | Pdfdest.FitBH (tp, _) | Pdfdest.FitBV (tp, _) -> begin match tp with Pdfdest.PageObject i -> begin try let pagenumber = Hashtbl.find refnumstable i in Hashtbl.find mattable pagenumber with _ -> (*Pdfe.log (Printf.sprintf "page not found for bookmark or annotation dest:%s\n" (Pdfwrite.string_of_pdf (Pdfdest.pdfobject_of_destination dest)));*) Pdftransform.i_matrix end | _ -> Pdftransform.i_matrix end | _ -> Pdftransform.i_matrix (* For each bookmark, find the page its target is on, look up the appropriate matrix, and transform it. Works only for destinations. /GoTo actions are rewritten globally, separately. *) let change_pages_process_bookmarks mattable refnumstable pdf = (*List.iter (fun (p, m) -> Printf.printf "chppb: %i = %s\n" p (Pdftransform.string_of_matrix m)) matpairs;*) let bookmarks = map (fun m -> let tr = change_pages_find_matrix m.Pdfmarks.target mattable refnumstable in if tr <> Pdftransform.i_matrix then Pdfmarks.transform_bookmark pdf tr m else m) (Pdfmarks.read_bookmarks ~preserve_actions:true pdf) in Pdfmarks.add_bookmarks bookmarks pdf let rewrite_dest pdf mattable refnumstable dest = let parsed_dest = Pdfdest.read_destination pdf dest in let tr = change_pages_find_matrix parsed_dest mattable refnumstable in (*Printf.printf "tr is %s\n" (Pdftransform.string_of_matrix tr);*) if tr <> Pdftransform.i_matrix then let transformed = Pdfdest.transform_destination pdf tr parsed_dest in let new_dest = Pdfdest.pdfobject_of_destination transformed in Some (Pdf.addobj pdf new_dest) else None let rewrite_action pdf mattable refnumstable action = begin match Pdf.lookup_direct pdf "/S" action with | Some (Pdf.Name "/GoTo") -> begin match Pdf.lookup_direct pdf "/D" action with | Some dest -> begin match rewrite_dest pdf mattable refnumstable dest with | Some objnum -> Some (Pdf.add_dict_entry action "/D" (Pdf.Indirect objnum)) | None -> None end | _ -> None end | _ -> None end (* For each page, find its annotations. For each, transform its annotations *) let change_pages_process_annotations mattable refnumstable pdf = iter2 (fun page pnum -> (*Pdfe.log (Printf.sprintf "Page %i...\n" pnum);*) match Pdf.lookup_direct pdf "/Annots" page.rest with | Some (Pdf.Array annots) -> iter (fun annotobj -> match annotobj with Pdf.Indirect i -> let annot = Pdf.lookup_obj pdf i in (* Find its destination, if it has one. Either in /Dest or /A *) begin match Pdf.lookup_direct pdf "/Subtype" annot with | Some (Pdf.Name "/Link") -> begin match Pdf.lookup_direct pdf "/Dest" annot with | Some dest -> begin match rewrite_dest pdf mattable refnumstable dest with | Some objnum -> let new_annot = Pdf.add_dict_entry annot "/Dest" (Pdf.Indirect objnum) in Pdf.addobj_given_num pdf (i, new_annot) | None -> () end | _ -> begin match Pdf.lookup_direct pdf "/A" annot with | Some (Pdf.Dictionary _ as action) -> begin match rewrite_action pdf mattable refnumstable action with | Some action -> let new_annot = Pdf.add_dict_entry annot "/A" action in Pdf.addobj_given_num pdf (i, new_annot) | _ -> () end | _ -> () end end | _ -> () end | _ -> Pdfe.log "change_pages_process_annotations: annotation direct\n") annots | None -> () | _ -> Pdfe.log "change_pages_process_annotations: /Annots not an array\n") (pages_of_pagetree pdf) (indx (pages_of_pagetree pdf)) (* Process the /OpenAction if its destination or action points to a page which has been scaled. *) (* Trailer --/Root--> Catalog dict --/OpenAction--> (array = dest || dict == action). No name option. *) let rewrite_openaction pdf action = let catalog = Pdf.catalog_of_pdf pdf in let catalog = Pdf.add_dict_entry catalog "/OpenAction" action in Pdf.addobj_given_num pdf (pdf.Pdf.root, catalog) let change_pages_process_openaction mattable refnumstable pdf = match Pdf.lookup_direct pdf "/OpenAction" (Pdf.catalog_of_pdf pdf) with | Some (Pdf.Array dest) -> begin match rewrite_dest pdf mattable refnumstable (Pdf.Array dest) with | Some new_dest_objnum -> rewrite_openaction pdf (Pdf.Indirect new_dest_objnum) | None -> () end | Some (Pdf.Dictionary action) -> begin match rewrite_action pdf mattable refnumstable (Pdf.Dictionary action) with | Some action -> rewrite_openaction pdf action | _ -> () end | _ -> () let change_pages ?matrices ?changes change_references basepdf pages' = let pdf = Pdf.empty () in Pdf.objiter (fun k v -> ignore (Pdf.addobj_given_num pdf (k, v))) basepdf; pdf.Pdf.objects.Pdf.object_stream_ids <- Hashtbl.copy basepdf.Pdf.objects.Pdf.object_stream_ids; (* Preserve objstms 11/12/2021 *) let old_page_numbers = Pdf.page_reference_numbers basepdf in let pdf, pagetree_num = add_pagetree pages' pdf in let pdf = {pdf with Pdf.major = basepdf.Pdf.major; Pdf.minor = basepdf.Pdf.minor; Pdf.trailerdict = basepdf.Pdf.trailerdict; Pdf.saved_encryption = basepdf.Pdf.saved_encryption} in let existing_root_entries = try match Pdf.lookup_obj basepdf basepdf.Pdf.root with | Pdf.Dictionary d -> d | _ -> [] with _ -> [] in let pdf = add_root pagetree_num existing_root_entries pdf in let new_page_numbers = Pdf.page_reference_numbers pdf in if not change_references then pdf else let changes = match changes with None -> if length old_page_numbers = length new_page_numbers then combine old_page_numbers new_page_numbers else begin Pdfe.log "change_pages: No change supplied, and lengths differ\n"; [] end | Some cs -> (* Turn the 1-based serial numbers into page reference numbers *) try map (fun (x, y) -> List.nth old_page_numbers (x - 1), List.nth new_page_numbers (y - 1)) cs with _ -> raise (Pdf.PDFError "change_pages: bad serial number") in Pdf.objselfmap (Pdf.renumber_object_parsed pdf (hashtable_of_dictionary changes)) pdf; match matrices with None -> pdf | Some matpairs -> let refnums = Pdf.page_reference_numbers pdf in let mattable = hashtable_of_dictionary matpairs in let refnumstable = hashtable_of_dictionary (combine refnums (indx refnums)) in let pdf = if length old_page_numbers = length new_page_numbers then change_pages_process_bookmarks mattable refnumstable pdf else begin Pdfe.log "Pdfpage.change_pages: non-null matrices when lengths differ\n"; pdf end in begin try change_pages_process_annotations mattable refnumstable pdf with e -> Pdfe.log (Printf.sprintf "failure in change_pages_process_annotations: %s\n" (Printexc.to_string e)) end; begin try change_pages_process_openaction mattable refnumstable pdf with e -> Pdfe.log (Printf.sprintf "failure in change_pages_process_openaction: %s\n" (Printexc.to_string e)) end; pdf (* Return a pdf with a subset of pages, but nothing else changed - exactly the same page object numbers, so bookmarks etc still work. Also sorts out bookmarks so only those in the range are kept. *) (* Find a page indirect from the page tree of a document, given a page number. *) let page_object_number pdf destpage = try Some (select destpage (Pdf.page_reference_numbers pdf)) with (* The page might not exist in the output *) Invalid_argument _ (*"select"*) -> None let target_of_pagenumber pdf i = match page_object_number pdf i with | None -> Pdfdest.NullDestination | Some p -> Pdfdest.Fit (Pdfdest.PageObject p) (* Build a pagetree using existing object numbers of exisiting pages, adding any intermediate nodes to the pdf *) let buildnode kids parent count = Pdf.Dictionary ([("/Type", Pdf.Name "/Pages"); ("/Kids", Pdf.Array (map (function i -> Pdf.Indirect i) kids)); ("/Count", Pdf.Integer count)] @ (if parent = 0 then [] else [("/Parent", Pdf.Indirect parent)])) let objnumfrom = function | OLf (_, _, o) -> o | OBr (_, _, _, _, o) -> o let rec countof = function | OLf (os, _, _) -> length os | OBr (os, l, r, _, _) -> countof l + countof r + length os let rec objects_of_ptree_objnumbers pdf = function | OLf (objnumbers, parent, objnumofthisleaf) as node -> Pdf.addobj_given_num pdf (objnumofthisleaf, buildnode objnumbers parent (countof node)) | OBr (objnumbers, left, right, parent, objnumofthisbranch) as node -> Pdf.addobj_given_num pdf (objnumofthisbranch, buildnode ([objnumfrom left] @ objnumbers @ [objnumfrom right]) parent (countof node)); objects_of_ptree_objnumbers pdf left; objects_of_ptree_objnumbers pdf right let pdf_of_pages_build_pagetree thetree objnumbers pdf = match thetree with | OLf (objnumbers, parent, _) as node -> (* Just a leaf. Don't add it, just build the node *) buildnode objnumbers parent (countof node) | OBr (objnumbers, left, right, parent, _) as node -> (* A branch. Return the top level built node, and call main function on left, right *) objects_of_ptree_objnumbers pdf left; objects_of_ptree_objnumbers pdf right; buildnode ([objnumfrom left] @ objnumbers @ [objnumfrom right]) parent (countof node) (* pdf_of_pages, if it has duplicates in the range, will produce duplicate items in the page tree, pointing to the same page object. This is bad for two reasons: a) Adobe Reader is broken and crashes in this case b) In any event, duplicate references make further document changes confusing for most programs. So, we duplicate the actual page objects, and do the minimal renumbering. *) (* Given a number n, of a page node, copy it to a new object, and rewrite all but the first instance in the page tree to that new number. *) exception RewriteDone (* Rewrite first instance of an indirect in an array of such. *) let rec rewrite_first_kid m n = function [] -> [] | Pdf.Indirect x::t when x = m -> Pdf.Indirect n :: t | h::t -> h :: rewrite_first_kid m n t (* Rewrite first instance of m if any, in obj to n at objnum. Raise Rewrite if we did it. *) let rewrite_first_indirect pdf objnum obj m n = match Pdf.lookup_direct pdf "/Kids" obj with Some (Pdf.Array kids) -> if mem (Pdf.Indirect m) kids then let newobj = Pdf.add_dict_entry obj "/Kids" (Pdf.Array (rewrite_first_kid m n kids)) in Pdf.addobj_given_num pdf (objnum, newobj); raise RewriteDone | _ -> failwith "rewrite_first_indirect" (* Those page tree nodes which are not pages *) let page_tree_nodes_not_pages pdf = let objs = ref [] in Pdf.objiter (fun objnum o -> match o with Pdf.Dictionary d when lookup "/Type" d = Some (Pdf.Name "/Pages") -> objs := (objnum, o) :: !objs | _ -> ()) pdf; !objs let rewrite_page_tree_first pdf m = let n = Pdf.addobj pdf (Pdf.lookup_obj pdf m) and nodes = page_tree_nodes_not_pages pdf in try iter (fun (objnum, obj) -> rewrite_first_indirect pdf objnum obj m n) nodes with RewriteDone -> () | _ -> raise (Pdf.PDFError "rewrite_page_tree_first: malformed page tree") (* Run this strategy repeatedly, until there are no duplicate page objects *) let rec fixup_duplicate_pages pdf = let pagerefs = Pdf.page_reference_numbers pdf in let groups = keep (fun x -> length x > 1) (collate compare (sort compare pagerefs)) in match groups with (h::_)::_ -> rewrite_page_tree_first pdf h; fixup_duplicate_pages pdf | _ -> () (* When there are duplicate pages, even once de-duplicated by * fixup_duplicate_pages, we can end up with incorrect /Parent links. This * procedure rewrites them. *) let rec fixup_parents_inner pdf parent_objnum objnum = (*Printf.printf "fixup_parents_inner %i %i\n" parent_objnum objnum;*) let obj = Pdf.lookup_obj pdf objnum in begin match Pdf.indirect_number pdf "/Parent" obj with Some _ -> Pdf.addobj_given_num pdf (objnum, (Pdf.add_dict_entry obj "/Parent" (Pdf.Indirect parent_objnum))) | _ -> () end; begin match Pdf.lookup_direct pdf "/Kids" obj with Some (Pdf.Array kids) -> iter (function Pdf.Indirect x -> fixup_parents_inner pdf objnum x | _ -> ()) kids | _ -> () end let fixup_parents pdf = let root = Pdf.lookup_obj pdf pdf.Pdf.root in match Pdf.indirect_number pdf "/Pages" root with Some pagetreeroot -> fixup_parents_inner pdf 0 pagetreeroot | _ -> raise (Pdf.PDFError "fixup_parents: no page tree root") (* Page-nulling will have left us with a /Dests tree with some destinations pointing to null pages. This can be a problem when pulling apart and re-assembling a single file, where we want destintations to match back up upon merging - the null one might get chosen instead. So we rewrite the /Dests name tree, removing any name which now points to a nulled page. Hopefully a missing name is treated by viewers no worse than a name which points to a missing page. *) (* FIXME /Dests could alternatively be in directly in document catalog, in very old PDFs. *) (* FIXME Dictionary instead of array in /Dests entry *) let was_nulled pdf (_, d) = match Pdf.direct pdf d with | Pdf.Array (Pdf.Indirect i::_) -> begin match Pdf.lookup_obj pdf i with | Pdf.Null | exception Not_found -> true | _ -> false end | _ -> false let fixup_destinations pdf = match Pdf.lookup_chain pdf pdf.Pdf.trailerdict ["/Root"; "/Names"; "/Dests"] with | Some t -> let tree = Pdftree.read_name_tree pdf t in let tree' = lose (was_nulled pdf) tree in let tree'obj = Pdftree.build_name_tree false pdf tree' in Pdf.replace_chain pdf ["/Root"; "/Names"; "/Dests"] tree'obj | None -> () (* For all pages in objnumbers, make sure they have no inherited attribues. *) let replace_inherit pdf objnumbers = iter (function objnum -> let replace_inherit objnum entry = let obj = Pdf.lookup_obj pdf objnum in (* Find the first parent entry we can which has the correct attribute. *) let rec find_attribute obj = (* Only replace if not there! *) match Pdf.lookup_direct pdf entry obj with | Some _ -> None | _ -> match Pdf.lookup_direct pdf "/Parent" obj with | Some (Pdf.Dictionary parent) -> (* Does this one have the attribute? If yes, return, if no carry on looking... Don't use a direct lookup, because we want to retain the indirect reference to resources, for example. *) begin match lookup entry parent with | Some pdfobj -> Some pdfobj | None -> find_attribute (Pdf.Dictionary parent) end | _ -> None (* Got to top, couldn't find anything *) in match find_attribute obj with | None -> () | Some replacement_attr -> (* Replace the attribute with replacement_attr, updating the page object in place. *) Pdf.addobj_given_num pdf (objnum, Pdf.add_dict_entry obj entry replacement_attr) in replace_inherit objnum "/MediaBox"; replace_inherit objnum "/CropBox"; replace_inherit objnum "/Rotate"; replace_inherit objnum "/Resources") objnumbers let pdf_of_pages ?(retain_numbering = false) ?(process_struct_tree = false) basepdf range = let page_labels = if length (Pdfpagelabels.read basepdf) = 0 then [] else if retain_numbering then Pdfpagelabels.merge_pagelabels [basepdf] [range] else [] and marks = let refnums = Pdf.page_reference_numbers basepdf in let fastrefnums = hashtable_of_dictionary (combine refnums (indx refnums)) in let table = hashset_of_list range in let firstindex = ref ~-1 in let firstindexlevel = ref ~-1 in let index = ref ~-1 in let marks = Pdfmarks.read_bookmarks ~preserve_actions:true basepdf in let r = option_map (function m -> index += 1; if Hashtbl.mem table (pagenumber_of_target ~fastrefnums basepdf m.Pdfmarks.target) then begin (*Printf.printf "Keeping index %i: %s\n" !index m.Pdfmarks.text;*) if !firstindex = -1 then begin firstindex := !index; firstindexlevel := m.Pdfmarks.level end; Some m end else None) marks in (*Printf.printf "Index of first saved bookmark: %i, at level %i\n" !firstindex !firstindexlevel;*) (* Find the last bookmark at firstindexlevel - 1, firstindexlevel -2 .... 0 and add them as prefixes *) firstindexlevel -= 1; let got = ref [] in for n = !firstindex downto 0 do let mark = List.nth marks n in (*Printf.printf "n = %i: %s\n" n mark.Pdfmarks.text;*) if !firstindexlevel > -1 then if mark.Pdfmarks.level = !firstindexlevel then begin (*Printf.printf "got a mark at level %i\n" !firstindexlevel;*) got := mark::!got; firstindexlevel -= 1 end done; !got @ r in let pdf = Pdf.empty () in Pdf.objiter (fun k v -> ignore (Pdf.addobj_given_num pdf (k, v))) basepdf; let page_numbers = Pdf.page_reference_numbers basepdf in let pdf = {pdf with Pdf.major = basepdf.Pdf.major; Pdf.minor = basepdf.Pdf.minor; Pdf.root = basepdf.Pdf.root; (* So structure tree trimmer can run *) Pdf.was_linearized = basepdf.Pdf.was_linearized; Pdf.trailerdict = basepdf.Pdf.trailerdict; Pdf.saved_encryption = basepdf.Pdf.saved_encryption} in (*Printf.eprintf "----BEFORE trim_structure_tree\n"; Pdfwrite.debug_whole_pdf pdf; *) if process_struct_tree then Pdfst.trim_structure_tree pdf range; (*Printf.eprintf "----AFTER trim_structure_tree\n"; Pdfwrite.debug_whole_pdf pdf; *) let existing_root_entries = try match Pdf.lookup_obj basepdf basepdf.Pdf.root with | Pdf.Dictionary d -> d | _ -> [] with _ -> [] in let objnumbers = map (function i -> select i page_numbers) range in let old_pagetree_root_num = match Pdf.lookup_direct basepdf "/Root" pdf.Pdf.trailerdict with | Some (Pdf.Dictionary d) -> begin match lookup "/Pages" d with | Some (Pdf.Indirect i) -> i | _ -> raise (Pdf.PDFError "pdf_of_pages") end | _ -> raise (Pdf.PDFError "pdf_of_pages") in (* 1. Look through all the page objects to be included, and replicate inheritable entries from their parent nodes, since they may fail to exist, leaving pages without Media boxes or resources! Inheritable entries are /MediaBox /CropBox /Rotate /Resources *) replace_inherit pdf objnumbers; let thetree = pagetree_with_objnumbers true old_pagetree_root_num (source pdf.Pdf.objects.Pdf.maxobjnum) objnumbers 0 in (* 2. Kill the old page tree, excepting pages which will appear in the new PDF. It will link, via /Parent entries etc, to the new page tree. To do this, we remove all objects with /Type /Page or /Type /Pages. The other places that null can appear, in destinations and so on, are ok, we think. *) Pdf.objiter (fun i o -> match o with | Pdf.Dictionary d -> begin match lookup "/Type" d with | Some (Pdf.Name ("/Pages")) -> Pdf.removeobj pdf i | Some (Pdf.Name ("/Page")) -> if not (mem i objnumbers) then Pdf.removeobj pdf i | _ -> () end | _ -> ()) pdf; (* Now, add the new page tree, with root at the same object number, and finish *) let new_pagetree = pdf_of_pages_build_pagetree thetree objnumbers pdf in Pdf.addobj_given_num pdf (old_pagetree_root_num, new_pagetree); let pdf = add_root old_pagetree_root_num existing_root_entries pdf in Pdfpagelabels.write pdf page_labels; let pdf = Pdfmarks.add_bookmarks marks pdf in fixup_duplicate_pages pdf; fixup_parents pdf; fixup_destinations pdf; pdf let prepend_operators pdf ops ?(fast=false) page = if fast then {page with content = Pdfops.stream_of_ops ops :: page.content} else let old_ops = Pdfops.parse_operators pdf page.resources page.content in {page with content = [Pdfops.stream_of_ops (ops @ old_ops)]} (* Add stack operators to a content stream to ensure it is composeable. *) let protect ops = let qs = length (keep (eq Pdfops.Op_q) ops) and bigqs = length (keep (eq Pdfops.Op_Q) ops) in let deficit = if qs > bigqs then qs - bigqs else 0 in if deficit <> 0 then Pdfe.log (Printf.sprintf "Q Deficit was nonzero. Fixing. %i\n" deficit); many Pdfops.Op_Q deficit (* We check for q/Q mismatches in existing section. *) let postpend_operators pdf ops ?(fast=false) page = if fast then {page with content = page.content @ [Pdfops.stream_of_ops ([Pdfops.Op_q] @ ops @ [Pdfops.Op_Q])]} else let existing_ops = Pdfops.parse_operators pdf page.resources page.content in if existing_ops = [] then {page with content = [Pdfops.stream_of_ops ops]} (* avoid protecting the empty contents *) else let protected = protect existing_ops in let beforeops = [Pdfops.Op_q] in let afterops = protected @ [Pdfops.Op_Q] @ ops in {page with content = [Pdfops.stream_of_ops (beforeops @ existing_ops @ afterops)]} (* Source of possible prefix strings. String is always copied. *) let next_string s = if s = "" then "a" else if s.[0] = 'z' then "a" ^ s else String.mapi (fun i c -> if i = 0 then char_of_int (int_of_char c + 1) else c) s (* True if one string [p] is a prefix of another [n] *) let is_prefix p n = String.length p <= String.length n && String.sub n 0 (String.length p) = p (* a) List every name used in a /Resources in a /Type /Page or /Type /Pages (without the leading "/" b) Find the shortest lower-case alphabetic string which is not a prefix of any of these strings. This prefix can be added to the other PDF's names, and will never clash with any of these. *) let names_used pdf = let names = ref [] in let unslash x = if x = "" then "" else String.sub x 1 (String.length x - 1) in Pdf.objiter (fun n obj -> match obj with Pdf.Dictionary d | Pdf.Stream {contents = (Pdf.Dictionary d, _)} -> begin match lookup "/Type" d with Some (Pdf.Name ("/Page" | "/Pages")) -> begin match Pdf.lookup_direct pdf "/Resources" obj with Some resources -> iter (fun key -> match Pdf.lookup_direct pdf key resources with Some (Pdf.Dictionary d) -> iter (fun (k, _) -> names := unslash k::!names) d | _ -> ()) resource_keys | _ -> () end | _ -> () end | _ -> () ) pdf; setify !names let shortest names = let rec loop prefix = if List.exists (is_prefix prefix) names then loop (next_string prefix) else prefix in loop "a" let shortest_unused_prefix pdf = shortest (names_used pdf) let addp p n = if n = "" then raise (Pdf.PDFError "addp: blank name") else "/" ^ p ^ String.sub n 1 (String.length n - 1) let direct_cs_names = ["/DeviceGray"; "/DeviceRGB"; "/DeviceCMYK"; "/Pattern"] let direct_cs_names_inline = ["/DeviceGray"; "/DeviceRGB"; "/DeviceCMYK"; "/G"; "/RGB"; "/CMYK"] let prefix_operator pdf p = function | Pdfops.Op_Tf (f, s) -> Pdfops.Op_Tf (addp p f, s) | Pdfops.Op_gs n -> Pdfops.Op_gs (addp p n) | Pdfops.Op_CS n -> Pdfops.Op_CS (if mem n direct_cs_names then n else addp p n) | Pdfops.Op_cs n -> Pdfops.Op_cs (if mem n direct_cs_names then n else addp p n) | Pdfops.Op_SCNName (s, ns) -> Pdfops.Op_SCNName (addp p s, ns) | Pdfops.Op_scnName (s, ns) -> Pdfops.Op_scnName (addp p s, ns) | Pdfops.Op_sh s -> Pdfops.Op_sh (addp p s) | Pdfops.Op_Do x -> Pdfops.Op_Do (addp p x) | Pdfops.Op_DP (n, Pdf.Name x) -> Pdfops.Op_DP (n, Pdf.Name (addp p x)) | Pdfops.Op_BDC (n, Pdf.Name x) -> Pdfops.Op_BDC (n, Pdf.Name (addp p x)) | Pdfops.InlineImage (dict, dp, bytes) -> (* Replace any indirect "/CS" or "/ColorSpace" with a new "/CS" *) let dict' = match Pdf.lookup_direct_orelse pdf "/CS" "/ColorSpace" dict with | Some (Pdf.Name n) when mem n direct_cs_names_inline -> dict | Some (Pdf.Name n) -> Pdf.add_dict_entry (Pdf.remove_dict_entry (Pdf.remove_dict_entry dict "/ColorSpace") "/CS") "/CS" (Pdf.Name (addp p n)) | _ -> dict in Pdfops.InlineImage (dict', dp, bytes) | x -> x let change_resources pdf prefix resources = let newdict name = match Pdf.lookup_direct pdf name resources with | Some (Pdf.Dictionary dict) -> Pdf.Dictionary (map (fun (k, v) -> addp prefix k, v) dict) | _ -> Pdf.Dictionary [] in let newdicts = map newdict resource_keys in let resources = ref resources in iter2 (fun k v -> resources := Pdf.add_dict_entry !resources k v) resource_keys newdicts; !resources (* For each object in the PDF with /Type /Page or /Type /Pages: a) Add the prefix to any name in /Resources b) Add the prefix to any name used in any content streams, keeping track of the streams we have processed to preserve sharing *) let add_prefix pdf prefix = let fixed_streams = Hashtbl.create 100 in let fix_stream resources i = match i with Pdf.Indirect i -> if not (Hashtbl.mem fixed_streams i) then let operators = Pdfops.parse_operators pdf resources [Pdf.Indirect i] in let operators' = map (prefix_operator pdf prefix) operators in begin match Pdf.lookup_obj pdf i with Pdf.Stream ({contents = (dict, stream)} as s) -> begin match Pdfops.stream_of_ops operators' with Pdf.Stream {contents = ncontents} -> s := ncontents | _ -> failwith "add_prefix: bad stream" end | _ -> failwith "add_prefix: bad stream 2" end; Hashtbl.add fixed_streams i () | _ -> failwith "add_prefix: not indirect" in Pdf.objselfmap (fun obj -> match obj with Pdf.Dictionary dict as d -> begin match Pdf.lookup_direct pdf "/Type" d with Some (Pdf.Name ("/Page" | "/Pages")) -> let resources, resources' = begin match Pdf.lookup_direct pdf "/Resources" obj with Some resources -> Some resources, Some (change_resources pdf prefix resources) | _ -> None, None end in begin match lookup "/Contents" dict with Some (Pdf.Indirect i) -> fix_stream (if resources = None then Pdf.Dictionary [] else unopt resources) (Pdf.Indirect i) | Some (Pdf.Array a) -> (* May be Non-ISO, and not parse properly individually! If so, detect, and Exit *) begin match if length a > 1 then (* Can't be broken when just a single entry *) iter (function c -> let c = Pdf.direct pdf c in Pdfcodec.decode_pdfstream pdf c; let s = Pdf.bigarray_of_stream c in let resources = match resources with Some r -> r | _ -> Pdf.Dictionary [] in ignore (Pdfops.parse_single_stream pdf resources s)) a with | () -> iter (fix_stream (if resources = None then Pdf.Dictionary [] else unopt resources)) a | exception _ -> Pdfe.log "add_prefix: non-ISO PDF detected streams detected. Fixing...\n"; raise Exit end; | _ -> () end; begin match resources' with Some x -> Pdf.add_dict_entry d "/Resources" x | None -> d end | _ -> obj end | _ -> obj) pdf let merge_content_streams pdf = Pdf.objselfmap (fun obj -> match obj with Pdf.Dictionary dict as d -> begin match Pdf.lookup_direct pdf "/Type" d with Some (Pdf.Name ("/Page" | "/Pages")) -> begin match lookup "/Contents" dict with | Some (Pdf.Indirect _ | Pdf.Array [_]) -> obj | Some (Pdf.Array a) -> let a = map (Pdf.direct pdf) a in iter (Pdfcodec.decode_pdfstream pdf) a; let bigarrays = map Pdf.bigarray_of_stream a in let merged = Pdfops.concat_bytess bigarrays in let stream = Pdf.Stream {contents = (Pdf.Dictionary ["/Length", Pdf.Integer (Pdfio.bytes_size merged)], Pdf.Got merged)} in let i = Pdf.addobj pdf stream in Pdf.add_dict_entry d "/Contents" (Pdf.Indirect i) | _ -> obj end | _ -> obj end | _ -> obj) pdf (* If a non-ISO PDF with content streams which don't end on lexical boundaries is provided, we must merge them. But we don't want to unless we have to, because it destroys sharing. *) let add_prefix pdf prefix = try add_prefix pdf prefix with Exit -> merge_content_streams pdf; add_prefix pdf prefix (* For uses of process_pages which don't need to deal with matrices, this function transforms into one which returns the identity matrix *) let ppstub f n p = (f n p, n, Pdftransform.i_matrix) let process_xobject f pdf resources i = let xobj = Pdf.lookup_obj pdf i in match Pdf.lookup_direct pdf "/Subtype" xobj with | None -> raise (Pdf.PDFError "No /Subtype in Xobject") | Some (Pdf.Name "/Form") -> Pdf.getstream xobj; begin match xobj with | Pdf.Stream ({contents = Pdf.Dictionary dict, Pdf.Got bytes} as rf) -> begin match f pdf resources [Pdf.Stream rf] with | [Pdf.Stream {contents = (Pdf.Dictionary dict', data)}] -> let dict' = Pdf.remove_dict_entry (Pdf.Dictionary (mergedict dict dict')) "/Filter" in rf := (dict', data) | _ -> assert false end | _ -> assert false (* getstream would have complained already *) end | Some _ -> () let process_xobjects pdf page f = match Pdf.lookup_direct pdf "/XObject" page.resources with | Some (Pdf.Dictionary elts) -> iter (fun (k, v) -> match v with | Pdf.Indirect i -> process_xobject f pdf page.resources i | _ -> raise (Pdf.PDFError "process_xobject")) elts | _ -> () (* Union two resource dictionaries from the same PDF. *) let combine_pdf_resources pdf a b = let a_entries = match a with | Pdf.Dictionary entries -> entries | _ -> [] in let b_entries = match b with | Pdf.Dictionary entries -> entries | _ -> [] in let resource_keys = ["/Font"; "/ExtGState"; "/ColorSpace"; "/Pattern"; "/Shading"; "/XObject"; "/Properties"] in let combine_entries key = let a_entries = match Pdf.lookup_direct pdf key a with | Some (Pdf.Dictionary d) -> d | _ -> [] in let b_entries = match Pdf.lookup_direct pdf key b with | Some (Pdf.Dictionary d) -> d | _ -> [] in if a_entries = [] && b_entries = [] then None else Some (key, Pdf.Dictionary (a_entries @ b_entries)) in let unknown_keys_a = lose (fun (k, _) -> mem k resource_keys) a_entries in let unknown_keys_b = lose (fun (k, _) -> mem k resource_keys) b_entries in let combined_known_entries = option_map combine_entries resource_keys in fold_left (fun dict (k, v) -> Pdf.add_dict_entry dict k v) (Pdf.Dictionary []) (unknown_keys_a @ unknown_keys_b @ combined_known_entries) let minimum_valid_pdf () = let pdf_pages = [blankpage Pdfpaper.a4] in let pdf, pageroot = add_pagetree pdf_pages (Pdf.empty ()) in add_root pageroot [] pdf camlpdf-2.8.1/pdfpage.mli000066400000000000000000000133131477056064700152620ustar00rootroot00000000000000(** Page-level functionality *) (** {2 Page rotations} *) (** The type of the four rotations of pages. This defines how a viewing application (e.g Acrobat) displays the page. *) type rotation = Rotate0 | Rotate90 | Rotate180 | Rotate270 (** Utility function to convert from rotation to integers. *) val int_of_rotation : rotation -> int (** The reverse. raises [Pdf.PDFError] if its input modulo 360 is not 0, 90, 180 or 270. *) val rotation_of_int : int -> rotation (** {2 Pages} *) (** A type representing a page. [content] is the list of objects containing the graphical content stream (see the [Pdfpages] module), [mediabox] the page size, [resources] the page's resource dictionary, [rotate] its rotation and [rest] any other entries to reside in the page dictionary. *) type t = {content : Pdf.pdfobject list; mediabox : Pdf.pdfobject; resources : Pdf.pdfobject; rotate : rotation; rest : Pdf.pdfobject} (** Create a page with empty content, media box from the given paper size, empty resources, zero rotation and no extra dictionary entries. *) val blankpage : Pdfpaper.t -> t (** The same, but given a page size rectangle. *) val custompage : Pdf.pdfobject -> t (** Extract the page tree from a PDF document and parse it to a list of page objects. Owing to the [rest] entry in the [page] type, no information is lost. *) val pages_of_pagetree : Pdf.t -> t list (** Build a page tree from a list of pages and install it in the given PDF document. The resultant document and the number of the new page root object are returned. If the document already contains a page root, it is overwritten but is not garbage collected. *) val add_pagetree : t list -> Pdf.t -> Pdf.t * int (** Given the page root number (for instance that returned by [add_pagetree]), any specific extra dictionary entries and a PDF document, build a document root. Returns the new document. If a root exists, it is overwritten but is not garbage collected. *) val add_root : int -> (string * Pdf.pdfobject) list -> Pdf.t -> Pdf.t (** Number of pages in a document, faster than reading the pages and counting. *) val endpage : Pdf.t -> int (** Number of pages in a document, simply believing top level /Count *) val endpage_fast : Pdf.t -> int (** Find a page indirect from the page tree of a document, given a page number. *) val page_object_number : Pdf.t -> int -> int option (** {2 Compound operations} *) (** Rename the resources within a number of page resource dictionaries and contents, so as to allow them to be merged without name clashes. *) val renumber_pages : Pdf.t -> t list -> t list (** Change the pages in a document for some new ones. If the boolean is true and the number of pages in the old and new documents are equal (or ~changes, a list of (from, to) page nummber changes, is provided), references to the old pages from outside the page tree (for instance in destinations or bookmarks) are renumbered. This ensures bookmarks are preserved correctly. A list of (page number, matrix) pairs may also be supplied if the boolean is true and the number of old and new pages are equal. This allows transformed pages (e.g scaled) to have their bookmark destionations pointed at correctly. *) val change_pages : ?matrices:(int * Pdftransform.transform_matrix) list -> ?changes:((int * int) list) -> bool -> Pdf.t -> t list -> Pdf.t (** Return a pdf with a subset of pages, but nothing else changed - exactly the same page object numbers, so bookmarks etc still work. Also modifies bookmarks so only those in the range are kept, and other ancillary structures. If [retain_numbering] is true, page numbers are kept from the original. If [process_struct_tree] is true, the structure tree is trimmed. *) val pdf_of_pages : ?retain_numbering:bool -> ?process_struct_tree:bool -> Pdf.t -> int list -> Pdf.t (** {2 Miscellaneous} *) (** Make a PDF rectangle from a Paper.papersize. *) val rectangle_of_paper : Pdfpaper.t -> Pdf.pdfobject (** Find the shortest lower-case alphabetic string which is not a prefix of any name in /Resources. This prefix can be added to the other PDF's names, and will never clash with any of these. *) val shortest_unused_prefix : Pdf.t -> string (** For every page in the PDF, add the prefix to any name in /Resources and add the prefix to any name used in any content streams. *) val add_prefix : Pdf.t -> string -> unit (** Calling [protect pdf] add stack operators to a pre-ISO content stream to ensure it is composeable. *) val protect : Pdfops.t list -> Pdfops.t list (** Add operators to the beginning of a page. If [fast] is set (default false), don't check for mismatched stack operators. *) val prepend_operators : Pdf.t -> Pdfops.t list -> ?fast:bool -> t -> t (** Add operators to the end of a page. If [fast] is set (default false), don't check for mismatched stack operators. *) val postpend_operators : Pdf.t -> Pdfops.t list -> ?fast:bool -> t -> t (** Return a page number given a destination. Supply [fastrefnums] from a previous call to [Pdf.page_reference_numbers] to speed things up. *) val pagenumber_of_target : ?fastrefnums:(int, int) Hashtbl.t -> Pdf.t -> Pdfdest.t -> int (** Build a basic [Fit] destintation from a page number of a PDF. *) val target_of_pagenumber : Pdf.t -> int -> Pdfdest.t (** Generate a PDF file with a single A4 page. Unlike [Pdf.empty] it is a fully valid PDF. *) val minimum_valid_pdf : unit -> Pdf.t (**/**) val process_xobjects : Pdf.t -> t -> (Pdf.t -> Pdf.pdfobject -> Pdf.pdfobject list -> Pdf.pdfobject list) -> unit val combine_pdf_resources : Pdf.t -> Pdf.pdfobject -> Pdf.pdfobject -> Pdf.pdfobject val ppstub : ('a -> 'b -> 'c) -> 'a -> 'b -> 'c * 'a * Pdftransform.transform_matrix val replace_inherit : Pdf.t -> int list -> unit camlpdf-2.8.1/pdfpagelabels.ml000066400000000000000000000155521477056064700163030ustar00rootroot00000000000000(* Page Labels. 1-based. All functions assume input lists of page labels are well-formed. *) open Pdfutil type labelstyle = | DecimalArabic | UppercaseRoman | LowercaseRoman | UppercaseLetters | LowercaseLetters | NoLabelPrefixOnly type t = {labelstyle : labelstyle; labelprefix : string option; startpage : int; startvalue : int} let string_of_labelstyle = function | DecimalArabic -> "DecimalArabic" | UppercaseRoman -> "UppercaseRoman" | LowercaseRoman -> "LowercaseRoman" | UppercaseLetters -> "UppercaseLetters" | LowercaseLetters -> "LowercaseLetters" | NoLabelPrefixOnly -> "NoLabelPrefixOnly" let string_of_pagelabel l = (Printf.sprintf "labelstyle: %s\n" (string_of_labelstyle l.labelstyle)) ^ (Printf.sprintf "labelprefix: %s\n" (match l.labelprefix with None -> "None" | Some s -> s)) ^ (Printf.sprintf "startpage: %i\n" l.startpage) ^ (Printf.sprintf "startvalue: %s\n" (string_of_int l.startvalue)) let label_of_range pdf (startpage, thing) = let startpage = match startpage with | Pdf.Integer i -> i + 1 | _ -> Pdfe.log "Bad Number Tree\n"; 1 and labelstyle = match Pdf.lookup_direct pdf "/S" thing with | Some (Pdf.Name "/D") -> DecimalArabic | Some (Pdf.Name "/R") -> UppercaseRoman | Some (Pdf.Name "/r") -> LowercaseRoman | Some (Pdf.Name "/A") -> UppercaseLetters | Some (Pdf.Name "/a") -> LowercaseLetters | _ -> NoLabelPrefixOnly and labelprefix = match Pdf.lookup_direct pdf "/P" thing with | Some (Pdf.String s) -> Some s | _ -> None and startvalue = match Pdf.lookup_direct pdf "/St" thing with | Some (Pdf.Integer i) -> i | _ -> 1 in {labelstyle = labelstyle; labelprefix = labelprefix; startpage = startpage; startvalue = startvalue} let read pdf = match Pdf.lookup_direct pdf "/PageLabels" (Pdf.lookup_obj pdf pdf.Pdf.root) with | None -> [] | Some labeltree -> let labelranges = Pdf.contents_of_nametree pdf labeltree in map (label_of_range pdf) labelranges (** Add a label, rearranging existing labels. *) let add_label endpage ls l e = let beforeorduringorequal, after = List.partition (function x -> x.startpage <= e) ls in let beforeorduring = lose (function x -> x.startpage = l.startpage) beforeorduringorequal in let replica = match after with | _ when e = endpage -> [] | x::_ when x.startpage = e + 1 -> [] | _ -> match beforeorduringorequal with [] -> [] | _ -> let lst = last beforeorduringorequal in [{lst with startpage = e + 1; startvalue = e + 1 + (lst.startvalue - lst.startpage)}] and before = lose (function x -> x.startpage > l.startpage && x.startpage <= e) beforeorduring in before @ [l] @ replica @ after let basic = {labelstyle = DecimalArabic; labelprefix = None; startpage = 1; startvalue = 1} (** Make a complete set, so that each page has a number *) let complete = function | [] -> [basic] | x::xs when x.startpage > 1 -> basic::x::xs | ls -> ls let letter_string n = implode (many (char_of_int ((n - 1) mod 26 + 65)) (((n - 1) / 26) + 1)) (* Make a page label string *) let string_of_pagenumber n = function | NoLabelPrefixOnly -> "" | DecimalArabic -> string_of_int n | UppercaseRoman -> roman_upper n | LowercaseRoman -> roman_lower n | UppercaseLetters -> letter_string n | LowercaseLetters -> String.lowercase_ascii (letter_string n) let pagelabeltext_of_single n l = let realnumber = n - (l.startpage - l.startvalue) in begin match l.labelprefix with None -> "" | Some s -> s end ^ string_of_pagenumber realnumber l.labelstyle let rec pagelabeltext_of_pagenumber n = function | [] -> raise Not_found | [x] -> pagelabeltext_of_single n x | x::y::_ when n < y.startpage -> pagelabeltext_of_single n x | _::r -> pagelabeltext_of_pagenumber n r (* Just make a page label for a single one *) let pagelabel_of_single n l = let realnumber = n - (l.startpage - l.startvalue) in {l with startpage = realnumber; startvalue = realnumber} let rec pagelabel_of_pagenumber n = function | [] -> raise Not_found | [x] -> pagelabel_of_single n x | x::y::_ when n < y.startpage -> pagelabel_of_single n x | _::r -> pagelabel_of_pagenumber n r let rec coalesce prev = function | [] -> rev prev | [x] -> rev (x::prev) | x::y::r when x.labelstyle = y.labelstyle && x.labelprefix = y.labelprefix && y.startpage - y.startvalue = x.startpage - x.startvalue -> coalesce prev (x::r) | x::r -> coalesce (x::prev) r let coalesce ls = coalesce [] ls (* Merging page labels. Requires that pdfs, ranges non-empty and same length. *) let merge_pagelabels pdfs ranges = let completed = map complete (map read pdfs) in let new_labels = map2 (fun labels range -> map (fun p -> pagelabel_of_pagenumber p labels) range) completed ranges in let change_labels ls = map2 (fun l sp -> {l with startpage = sp}) ls (indx (flatten ranges)) in coalesce (change_labels (flatten new_labels)) let remove pdf = let root = Pdf.lookup_obj pdf pdf.Pdf.root in let rootnum = Pdf.addobj pdf (Pdf.remove_dict_entry root "/PageLabels") in pdf.Pdf.root <- rootnum; pdf.Pdf.trailerdict <- Pdf.add_dict_entry pdf.Pdf.trailerdict "/Root" (Pdf.Indirect rootnum) (* For now, just a flat number tree. Doesn't check ranges are well-formed (i.e contiguous / nonoverlapping) *) let write pdf labels = if labels = [] then remove pdf else let arr = flatten (map (function label -> [Pdf.Integer (label.startpage - 1); Pdf.Dictionary ((match label.labelstyle with | NoLabelPrefixOnly -> [] | DecimalArabic -> [("/S", Pdf.Name "/D")] | UppercaseRoman -> [("/S", Pdf.Name "/R")] | LowercaseRoman -> [("/S", Pdf.Name "/r")] | UppercaseLetters -> [("/S", Pdf.Name "/A")] | LowercaseLetters -> [("/S", Pdf.Name "/a")]) @ (match label.labelprefix with | None -> [] | Some p -> [("/P", Pdf.String p)]) @ (match label.startvalue with | 1 -> [] | s -> [("/St", Pdf.Integer s)]))]) labels) in let root = Pdf.lookup_obj pdf pdf.Pdf.root in let rootnum = Pdf.addobj pdf (Pdf.add_dict_entry root "/PageLabels" (Pdf.Dictionary ["/Nums", Pdf.Array arr])) in pdf.Pdf.root <- rootnum; pdf.Pdf.trailerdict <- Pdf.add_dict_entry pdf.Pdf.trailerdict "/Root" (Pdf.Indirect rootnum) camlpdf-2.8.1/pdfpagelabels.mli000066400000000000000000000044521477056064700164510ustar00rootroot00000000000000(** Page Labels *) (** The type for page labels. The page labels of a document, if well-formed, are a list of [t]s where the [startpage] values are in increasing numerical order. The numerical page number for the page range is [startvalue]. The default labelstyle is [DecimalArabic]. The default [labelprefix] is the empty string. For example, a document might have five pages of introduction with roman numerals, followed by the rest of the pages in decimal arabic, numbered from one: {labelstyle = LowercaseRoman; labelprefix = ""; startpage = 1; startvalue = 1} {labelstyle = DecimalArabic; labelprefix = ""; startpage = 6; startvalue = 1} For more details, see ISO 32000 12.4.2, but note that in our implementation, pages are 1-based not 0-based, just like PDF page numbers. *) type labelstyle = | DecimalArabic | UppercaseRoman | LowercaseRoman | UppercaseLetters | LowercaseLetters | NoLabelPrefixOnly type t = {labelstyle : labelstyle; labelprefix : string option; startpage : int; startvalue : int} (** String of label style e.g DecimalArabic *) val string_of_labelstyle : labelstyle -> string (** Debug string of page label *) val string_of_pagelabel : t -> string (** Read the page labels from a document *) val read : Pdf.t -> t list (** Return a list where every page has a label - pages which don't are given arabic page numbers *) val complete : t list -> t list (** Single label representing a given page. Raises [Not_found] if no label. *) val pagelabel_of_pagenumber : int -> t list -> t (** Return the text for a page label. Raises [Not_found] if no label. *) val pagelabeltext_of_pagenumber : int -> t list -> string (** Add a range starting at pagelabel.startpage, ending at the integer page given. The first integer argument is the number of pages in the PDF. *) val add_label : int -> t list -> t -> int -> t list (** Optimise page labels, removing any which are not required. *) val coalesce : t list -> t list (** Merge some page labels for some PDFs and page ranges. *) val merge_pagelabels : Pdf.t list -> int list list -> t list (** Write page labels to a document, replacing any there. Any existing page labels are removed. *) val write : Pdf.t -> t list -> unit (** Remove all page labels. Equivalent to an empty list given to [write]. *) val remove : Pdf.t -> unit camlpdf-2.8.1/pdfpaper.ml000066400000000000000000000017431477056064700153100ustar00rootroot00000000000000(* Type for paper sizes --- unit, width, height. *) type t = Paper of (Pdfunits.t * float * float) let make u w h = Paper (u, w, h) let unit (Paper (u, _, _)) = u let width (Paper (_, w, _)) = w let height (Paper (_, _, h)) = h (* Make a paper size landscape *) let landscape (Paper (u, w, h)) = Paper (u, h, w) (* European `A' sizes. *) let a0 = Paper (Pdfunits.Millimetre, 841., 1189.) let a1 = Paper (Pdfunits.Millimetre, 594., 841.) let a2 = Paper (Pdfunits.Millimetre, 420., 594.) let a3 = Paper (Pdfunits.Millimetre, 297., 420.) let a4 = Paper (Pdfunits.Millimetre, 210., 297.) let a5 = Paper (Pdfunits.Millimetre, 148., 210.) let a6 = Paper (Pdfunits.Millimetre, 105., 148.) let a7 = Paper (Pdfunits.Millimetre, 74., 105.) let a8 = Paper (Pdfunits.Millimetre, 52., 74.) let a9 = Paper (Pdfunits.Millimetre, 37., 52.) let a10 = Paper (Pdfunits.Millimetre, 26., 37.) (* US Imperial sizes. *) let usletter = Paper (Pdfunits.Inch, 8.5, 11.) let uslegal = Paper (Pdfunits.Inch, 8.5, 14.) camlpdf-2.8.1/pdfpaper.mli000066400000000000000000000013561477056064700154610ustar00rootroot00000000000000(** Media Sizes *) (** A paper size consists of its unit, width and height. *) type t (** Make a paper size given its unit, width and height. *) val make : Pdfunits.t -> float -> float -> t (** Project the unit from a paper size *) val unit : t -> Pdfunits.t (** Project the width from a paper size. *) val width : t -> float (** Project the height from a paper size. *) val height : t -> float (** Flip a paper size between landscape and portrait, swapping its dimensions. *) val landscape : t -> t val a0 : t val a1 : t val a2 : t val a3 : t val a4 : t val a5 : t val a6 : t val a7 : t val a8 : t val a9 : t val a10 : t (** ISO A series paper sizes, portrait. *) val usletter : t val uslegal : t (** United States paper sizes. portrait. *) camlpdf-2.8.1/pdfread.ml000066400000000000000000002217611477056064700151200ustar00rootroot00000000000000(* This module can read PDF files into the format given by the [Pdf] module *) open Pdfutil open Pdfio open Pdfgenlex let read_debug = ref false let error_on_malformed = ref false let debug_always_treat_malformed = ref false (* Predicate on newline characters (carriage return and linefeed). *) let is_newline = function | '\010' | '\013' -> true | _ -> false let b = Buffer.create 30 let input_line i = Buffer.clear b; let goteol = ref false and finished = ref false in while not !finished do match i.input_byte () with | x when x = Pdfio.no_more -> set finished | x -> let c = Char.unsafe_chr x in if is_newline c then set goteol else if !goteol then (rewind i; set finished) else Buffer.add_char b c done; Buffer.contents b (* Read back until a predicate is fulfilled. *) let rec read_back_until p i = if (notpred p) (match read_char_back i with Some x -> x | None -> raise End_of_file) then read_back_until p i (* Go back one line. In other words, find the second EOL character group seeking back in the file, and seek to the character after it. A blank line after a line with a single EOL character will be treated as being part of that EOL. *) let backline i = read_back_until is_newline i; read_back_until (notpred is_newline) i; read_back_until is_newline i; nudge i (* Read the major and minor version numbers *) let get8chars i = let c1 = i.input_char () in let c2 = i.input_char () in let c3 = i.input_char () in let c4 = i.input_char () in let c5 = i.input_char () in let c6 = i.input_char () in let c7 = i.input_char () in let c8 = i.input_char () in try map unopt [c1; c2; c3; c4; c5; c6; c7; c8] with _ -> [] let rec read_header_inner pos i = try if pos > 1024 then raise End_of_file else i.Pdfio.seek_in pos; match get8chars i with | '%'::'P'::'D'::'F'::'-'::major::'.'::minor -> let minorchars = takewhile isdigit minor in if minorchars = [] then raise (Pdf.PDFError (Pdf.input_pdferror i "Malformed PDF header")) else begin if !read_debug then Pdfe.log (Printf.sprintf "setting offset to %i\n" pos); i.set_offset pos; int_of_string (string_of_char major), int_of_string (implode minorchars) end | _ -> read_header_inner (pos + 1) i with End_of_file | Failure _ (*"int_of_string"*) -> (2, 0) let read_header = read_header_inner 0 (* Find the EOF marker, and move position to its first character. We allow 1024 bytes from end-of-file for compatibility with Acrobat. *) let find_eof i = let fail () = raise (Pdf.PDFError (Pdf.input_pdferror i "Could not find EOF marker")) in let pos = ref (i.in_channel_length - 4) in try let notfound = ref true in let tries = ref !pos in (* unlike Acrobat, we check whole file *) while !notfound do pos := !pos - 1; i.seek_in !pos; if !tries < 0 then fail () else decr tries; let a = i.input_byte () in let b = i.input_byte () in let c = i.input_byte () in let d = i.input_byte () in let e = i.input_byte () in if a = int_of_char '%' && b = int_of_char '%' && c = int_of_char 'E' && d = int_of_char 'O' && e = int_of_char 'F' then clear notfound done; i.seek_in !pos; with _ -> fail () (* String of lexeme. *) let string_of_lexeme = function | LexNull -> "null" | LexBool b -> Pdfwrite.string_of_pdf (Pdf.Boolean b) | LexInt i -> Pdfwrite.string_of_pdf (Pdf.Integer i) | LexReal f -> Pdfwrite.string_of_pdf (Pdf.Real f) | LexString s -> Pdfwrite.string_of_pdf (Pdf.String s) | LexName s -> s | LexLeftSquare -> "[" | LexRightSquare -> "]" | LexLeftDict -> "<<" | LexRightDict -> ">>" | LexStream _ -> "LexStream" | LexEndStream -> "EndStream" | LexObj -> "obj" | LexEndObj -> "endobj" | LexR -> "R" | LexComment s -> "\n%" ^ s ^ "\n" | StopLexing -> "StopLexing" | LexNone -> "LexNone" let print_lexeme l = Printf.printf "%s " (string_of_lexeme l) (* Predicate on whitespace and delimiters. *) let is_whitespace_or_delimiter c = Pdf.is_whitespace c || Pdf.is_delimiter c (* Return the list of characters between and including the current position and before the next character satisfying a given predicate, leaving the position at the character following the last one returned. Can raise [EndOfInput]. If [eoi] is true, end of input is considered a delimiter, and the characters up to it are returned if it is reached. *) let getuntil eoi f i = let rec getuntil_inner r eoi f i = match i.input_byte () with | x when x = Pdfio.no_more -> if eoi then rev r else raise End_of_file | x -> let chr = char_of_int x in if f chr then (rewind i; rev r) else getuntil_inner (chr::r) eoi f i in getuntil_inner [] eoi f i let b = Buffer.create 30 let getuntil_string eoi f i = let rec getuntil_inner_string b eoi f i = match i.input_byte () with | x when x = Pdfio.no_more -> if eoi then Buffer.contents b else raise End_of_file | x -> let chr = char_of_int x in if f chr then (rewind i; Buffer.contents b) else getuntil_inner_string (Buffer.add_char b chr; b) eoi f i in Buffer.clear b; getuntil_inner_string b eoi f i (* The same, but don't return anything. *) let rec ignoreuntil eoi f i = match i.input_byte () with | x when x = Pdfio.no_more -> if eoi then () else raise End_of_file | x -> if f (Char.unsafe_chr x) then rewind i else ignoreuntil eoi f i (* Ignore until the next whitespace *) let ignoreuntilwhite = ignoreuntil true Pdf.is_whitespace (* Position on the next non-whitespace character. *) let dropwhite i = ignoreuntil true Pdf.is_not_whitespace i (* The same, but stop at array, dictionary endings etc. *) let getuntil_white_or_delimiter = getuntil true is_whitespace_or_delimiter let getuntil_white_or_delimiter_string = getuntil_string true is_whitespace_or_delimiter (* Lexing *) (* Each of the following functions lexes a particular object, leaving the channel position at the character after the end of the lexeme. Upon entry, the file position is on the first character of the potential lexeme. *) (* Lex a bool. *) let lex_bool i = match getuntil_white_or_delimiter i with | ['t'; 'r'; 'u'; 'e'] -> LexBool true | ['f'; 'a'; 'l'; 's'; 'e'] -> LexBool false | _ -> LexNone (* Lex an int or float. See PDF manual for details of policy. *) let lex_number i = let pos = i.pos_in () in try match Pdfgenlex.lex_single i with | Pdfgenlex.LexInt i -> LexInt i | Pdfgenlex.LexReal f -> LexReal f | _ -> LexNone with | Failure x when x = "hd" -> LexNone | Pdf.PDFError _ (* can't cope with floats with leading point. *) | Failure _ (*"int_of_string"*) -> LexReal (float_of_string (i.seek_in pos; (getuntil_white_or_delimiter_string i))) (* [float_of_string] never fails. *) (* Lex a name. *) let b = Buffer.create 30 let lex_name i = Buffer.clear b; nudge i; Buffer.add_char b '/'; let fini = ref false in while not !fini do match i.input_byte () with | x when x = Pdfio.no_more -> set fini | x -> let c = Char.unsafe_chr x in if is_whitespace_or_delimiter c then begin rewind i; set fini end else if c = '#' then begin let a = i.input_byte () in let a2 = i.input_byte () in if a <> Pdfio.no_more && a2 <> Pdfio.no_more then Buffer.add_char b (char_of_int (int_of_string ("0x" ^ string_of_char (char_of_int a) ^ string_of_char (char_of_int a2)))) end else Buffer.add_char b c done; LexName (Buffer.contents b) (* Lex a comment. We throw away everything from here until a new line. In the case of a CRLF, only the CR is consumed, but the LF will be consumed before the next token is read anyway, so this is fine. *) let lex_comment i = ignoreuntil false is_newline i; LexComment "" (* Lex a string. A string is between parenthesis. Unbalanced parenthesis in the string must be escaped, but balanced ones need not be. We convert escaped characters to the characters themselves. A newline sequence following a backslash represents a newline. The string is returned without its enclosing parameters. *) (* PDF strings can contain characters as a backslash followed by up to three octal characters. If there are fewer than three, the next character in the file cannot be a digit (The format is ambiguous as to whether this means an octal digit --- we play safe and allow non-octal digits). This replaces these sequences of characters by a single character as used by OCaml in its native strings. Beware malformed strings. For instance, Reader accepts ((\\(ISA)) *) (* Build a character from a list of octal digits. *) let mkchar l = try char_of_int (int_of_string ("0o" ^ implode l)) with _ -> raise (Pdf.PDFError ("mkchar")) let str = Buffer.create 16 (* Main function. *) let lex_string i = try Buffer.clear str; let paren = ref 1 in let c = char_of_int (i.input_byte ()) in assert (c = '('); while !paren > 0 do let c = char_of_int (i.input_byte ()) in match c with | '(' -> incr paren; Buffer.add_char str c; | ')' -> decr paren; if !paren > 0 then Buffer.add_char str c; | '\\' -> let c' = char_of_int (i.input_byte ()) in (match c' with | 'n' -> Buffer.add_char str '\n' | 'r' -> Buffer.add_char str '\r' | 't' -> Buffer.add_char str '\t' | 'b' -> Buffer.add_char str '\b' | 'f' -> Buffer.add_char str '\012' | '\r' -> if char_of_int (i.input_byte ()) <> '\n' then rewind i | '\n' -> () | x when x >= '0' && x <= '7' -> (* Replace octal character sequences with the real character. *) let o2 = char_of_int (i.input_byte ()) in (match o2 with | y when y >= '0' && y <= '7' -> let o3 = char_of_int (i.input_byte ()) in (match o3 with | z when z >= '0' && z <= '7' -> Buffer.add_char str (mkchar [c'; o2; o3]) | _ -> rewind i; Buffer.add_char str (mkchar [c'; o2])) | _ -> rewind i; Buffer.add_char str (mkchar [c'])) | _ -> (* including ['('], [')'], ['\\'], and all the others *) Buffer.add_char str c' ) | _ -> Buffer.add_char str c done; LexString (Buffer.contents str) with | Failure _ (*"unopt"*) -> raise (Pdf.PDFError (Pdf.input_pdferror i "lex_string failure")) (* Lex a hexadecimal string. *) let lex_hexstring i = let mkchar a b = try char_of_int (int_of_string ("0x" ^ implode [a; b])) with _ -> raise (Pdf.PDFError (Pdf.input_pdferror i "Lexing Hexstring")) in let str = Buffer.create 16 in try let _ = i.input_byte () (*r skip start marker *) in let finished = ref false in let addchar = Buffer.add_char str in let rec input_next_char () = let x = i.input_byte () in if x = -1 then raise End_of_file else let c = char_of_int x in if Pdf.is_whitespace c then input_next_char () else c in while not !finished do let c = input_next_char () in let c' = input_next_char () in match c, c' with | '>', _ -> rewind i; set finished | a, '>' -> addchar (mkchar a '0'); set finished | a, b -> addchar (mkchar a b) done; LexString (Buffer.contents str) with | End_of_file -> LexString (Buffer.contents str) | Failure _ (*"unopt"*) -> raise (Pdf.PDFError (Pdf.input_pdferror i "lex_hexstring")) (* Lex a keyword. *) let lex_keyword i = match Pdfgenlex.lex_single i with | Pdfgenlex.LexName "obj" -> LexObj | Pdfgenlex.LexName "endobj" -> LexEndObj | Pdfgenlex.LexName "R" -> LexR | Pdfgenlex.LexName "null" -> LexNull | Pdfgenlex.LexName "endstream" -> LexEndStream | Pdfgenlex.LexName x -> (* Some malformed files have endobj run together with the next object number *) begin match explode x with | 'e'::'n'::'d'::'o'::'b'::'j'::l -> iter (fun _ -> rewind i) l; LexEndObj | _ -> LexNone end | l -> Pdfe.log (Printf.sprintf "failed to lex keyword: %s\n" (Pdfgenlex.string_of_token l)); LexNone (* Read some chars from a file. Leaves position as-is, except in the case of reaching past the end of a file, in which case an exception is raised. *) let read_chunk n i = try let orig_pos = i.pos_in () in let s = String.init n (fun _ -> unopt (i.input_char ())) in i.seek_in orig_pos; s with _ -> raise (Failure "read_chunk") (* Lex a stream, given its length (previously extracted by parsing the stream dictionary). If [opt] is [true] the stream is actually read, if [false] a [ToGet] tuple is created. The channel is positioned on the first character of the stream keyword. *) let is_malformed i = try match read_chunk 9 i with | "endstream" -> false | _ -> match read_chunk 10 i with | "\nendstream" | "\rendstream" -> false | _ -> match read_chunk 11 i with | "\r\nendstream" -> false | x -> true with _ -> true (* Beyond end of file - so, read_chunk would have failed... *) let skip_stream_beginning i = ignoreuntilwhite i; (* consume the 'stream' keyword *) (* Ignore any white other than CR or LF. For malformed files which don't have * CR or LF immediately following stream keyword. *) ignoreuntil true (function ' ' | '\000' | '\012' | '\009' -> false | _ -> true) i; (* Skip either CRLF or LF. (See PDF specification for why). *) match char_of_int (i.input_byte ()) with | '\013' -> begin match char_of_int (i.input_byte ()) with | '\010' -> () (* It was CRLF *) | _ -> rewind i (* No padding, happens to be CR *) end | '\010' -> () (* Just LF *) | _ -> rewind i (* No padding. *) (* Return position of first character for endstream sequence, or last character of file if none exists. *) let rec find_endstream i = let rec match_chunk s n i = n = String.length s || match i.input_char () with | None -> false | Some c when c = s.[n] -> match_chunk s (n + 1) i | Some _ -> false in let match_chunk s i = let pos = i.pos_in () in let r = match_chunk s 0 i in i.seek_in pos; r in if match_chunk "endstream" i || match_chunk "\nendstream" i || match_chunk "\r\nendstream" i || match_chunk "\rendstream" i then i.pos_in () else (if i.pos_in () = i.in_channel_length then i.pos_in () else (nudge i; find_endstream i)) let lex_malformed_stream_data i = try skip_stream_beginning i; let curr = i.pos_in () in let pos = find_endstream i in (* returns first char of endstream *) i.seek_in curr; let arr = mkbytes (pos - curr) in for x = 0 to bytes_size arr - 1 do bset_unsafe arr x (i.input_byte ()) done; LexStream (Pdf.Got arr) with e -> raise (Pdf.PDFError ("Bad read malformed stream - " ^ Printexc.to_string e)) let lex_stream_data i l opt = let original_pos = i.pos_in () in try skip_stream_beginning i; let pos = i.pos_in () in if opt then let arr = mkbytes l in if l > 0 then setinit i arr 0 l; i.seek_in (pos + l); if is_malformed i then (i.seek_in original_pos; lex_malformed_stream_data i) else (i.seek_in (pos + l); LexStream (Pdf.Got arr)) else begin i.seek_in (pos + l); if is_malformed i then (i.seek_in original_pos; lex_malformed_stream_data i) else (i.seek_in (pos + l); LexStream (Pdf.ToGet (Pdf.toget i pos l))) end with _ -> raise (Pdf.PDFError (Pdf.input_pdferror i "lex_stream_data")) (* Lex a stream. This involves parsing the stream dictionary to get the length. [i] is at the start of the stream data, suitable for input to [lex_stream_data]. We extract the dictionary by going through [previous_lexemes], the reverse-order list of the lexemes already read. *) let lex_stream i p previous_lexemes lexobj opt = let fail () = raise (Pdf.PDFError (Pdf.input_pdferror i "Failure lexing stream dict")) in let dictlexemes = takewhile_reverse (function LexObj -> false | _ -> true) previous_lexemes in match p dictlexemes with | _, Pdf.Dictionary a -> let pos = i.pos_in () in let rec findlength = function | Pdf.Integer l -> Some l | Pdf.Indirect k -> findlength (snd (p (lexobj k))) | _ -> None in begin match lookup "/Length" a with | None -> lex_malformed_stream_data i | Some v -> try match findlength v with | None -> lex_malformed_stream_data i | Some l -> lex_stream_data i l opt with _ -> (* When reading malformed files, /Length could be indirect, and therefore not available. Treat as if it were available, but incorrect. *) i.seek_in pos; lex_malformed_stream_data i end | _ -> fail () (* Find the next lexeme in the channel and return it. The latest-first lexeme list [previous_lexemes] contains all things thus-far lexed. [dictlevel] is a number representing the dictionary and/or array nesting level. If [endonstream] is true, lexing ends upon encountering a [LexStream] lexeme. *) let lex_next dictlevel arraylevel endonstream i previous_lexemes p opt lexobj = try dropwhite i; let raw = i.input_byte () in if raw = Pdfio.no_more then StopLexing else let chr1 = Char.unsafe_chr raw in rewind i; match chr1 with | '%' -> lex_comment i | 't' | 'f' -> lex_bool i | '/' -> lex_name i | x when (x >= '0' && x <= '9') || x = '+' || x = '-' || x = '.' -> lex_number i | '[' -> nudge i; incr arraylevel; LexLeftSquare | ']' -> nudge i; decr arraylevel; LexRightSquare | '(' -> lex_string i | '<' -> let _ = char_of_int (i.input_byte ()) in let chr2 = char_of_int (i.input_byte ()) in rewind i; rewind i; begin match chr2 with | '<' -> nudge i; nudge i; incr dictlevel; LexLeftDict | _ -> lex_hexstring i end | '>' -> let _ = i.input_byte () in let chr2 = char_of_int (i.input_byte ()) in rewind i; rewind i; begin match chr2 with | '>' -> nudge i; nudge i; decr dictlevel; LexRightDict | c -> LexNone end | 'R' -> nudge i; LexR | 's' -> (* Disambiguate "startxref" and "stream" on the third character. *) let _ = i.input_byte () in let _ = i.input_byte () in let chr3 = char_of_int (i.input_byte ()) in rewind i; rewind i; rewind i; begin match chr3 with | 'a' -> StopLexing (* startxref *) | _ -> (* stream *) if endonstream then StopLexing else lex_stream i p previous_lexemes lexobj opt end | x when x >= 'a' && x <= 'z' -> lex_keyword i | 'I' -> StopLexing (* We've hit an ID marker in an inline image *) | c -> (*Pdfe.log (Printf.sprintf "lexnone with character %C\n" c);*) LexNone with e -> Pdfe.log (Printf.sprintf "Recovering from Lex error: %s\n" (Printexc.to_string e)); StopLexing (* Lex just a dictionary, consuming only the tokens to the end of it. This is used in the [PDFPages] module to read dictionaries in graphics streams. *) let lex_dictionary minus_one i = let rec lex_dictionary_getlexemes i lexemes dictlevel arraylevel = let lex_dictionary_next i dictlevel arraylevel = let dummyparse = fun _ -> 0, Pdf.Null in let dummylexobj = fun _ -> [] in (*Printf.eprintf "lex_dictionary_next: dictlevel = %i\n" !dictlevel;*) let r = lex_next dictlevel arraylevel false i [] dummyparse false dummylexobj in (*Printf.eprintf "Read lexeme %S\n" (string_of_lexeme r); Printf.eprintf "after lex_dictionary_next: dictlevel = %i\n" !dictlevel;*) r in match lex_dictionary_next i dictlevel arraylevel with | LexRightDict when !dictlevel = (if minus_one then -1 else 0) && !arraylevel = 0 -> rev (LexRightDict::lexemes) | StopLexing -> rev lexemes | LexNone -> raise (Pdf.PDFError (Pdf.input_pdferror i "Could not read dictionary")) | a -> lex_dictionary_getlexemes i (a::lexemes) dictlevel arraylevel in lex_dictionary_getlexemes i [] (ref 0) (ref 0) (* Calculate a list of lexemes from input [i], using parser [p] to lex streams. Can raise [PDFError]. *) let lex_object_at oneonly i opt p lexobj = let dictlevel = ref 0 in let arraylevel = ref 0 in let rec lex_object_at i lexemes = let lexeme = lex_next dictlevel arraylevel false i lexemes p opt lexobj in match lexeme with | LexEndObj -> rev (lexeme::lexemes) | StopLexing -> rev lexemes | LexComment _ -> lex_object_at i (lexeme::lexemes) | LexRightSquare | LexRightDict -> if oneonly && !dictlevel = 0 && !arraylevel = 0 then begin let pos = i.pos_in () in match lex_next dictlevel arraylevel false i (lexeme::lexemes) p opt lexobj with | LexStream s -> begin match lex_next dictlevel arraylevel false i (LexStream s::lexeme::lexemes) p opt lexobj with | LexEndStream -> begin match lex_next dictlevel arraylevel false i (LexEndStream::LexStream s::lexeme::lexemes) p opt lexobj with | LexEndObj -> rev (LexEndObj::LexEndStream::LexStream s::lexeme::lexemes) | _ -> rev (LexEndObj::LexEndStream::LexStream s::lexeme::lexemes) end | _ -> rev (LexEndObj::LexEndStream::LexStream s::lexeme::lexemes) end | _ -> i.seek_in pos; rev (lexeme::lexemes) end else lex_object_at i (lexeme::lexemes) | LexNone -> raise (Pdf.PDFError (Pdf.input_pdferror i "Could not read object")) | LexInt i1 -> (* Check for the case of "x y obj", which in the case of oneonly should be returned as the one object. If i is followed by something other than an integer and 'obj', we must rewind and just return the integer *) if oneonly && !dictlevel = 0 && !arraylevel = 0 then let pos = i.pos_in () in begin match lex_next dictlevel arraylevel false i lexemes p opt lexobj with | LexInt i2 -> begin match lex_next dictlevel arraylevel false i lexemes p opt lexobj with | LexObj -> lex_object_at i (LexObj::LexInt i2::LexInt i1::lexemes) | _ -> i.seek_in pos; rev (LexInt i1::lexemes) end | _ -> i.seek_in pos; rev (LexInt i1::lexemes) end else lex_object_at i (LexInt i1::lexemes) | a -> (* If oneonly, then can return if not in an array or dictionary and if this lexeme was an atom. *) let isatom = function | LexBool _ | LexReal _ | LexString _ | LexName _ | LexNull -> true | _ -> false in if oneonly && isatom a && !dictlevel = 0 && !arraylevel = 0 then rev (a::lexemes) else lex_object_at i (a::lexemes) in lex_object_at i [] (* Type of sanitized cross-reference entries. They are either plain offsets, or an object stream an index into it. *) type xref = | XRefPlain of int * int (* offset, generation. *) | XRefStream of int * int (* object number of stream, index. *) (*let string_of_xref = function | XRefPlain (p, i) -> Printf.sprintf "XRefPlain (%i, %i)" p i | XRefStream (o, i) -> Printf.sprintf "XrefStream %i, index %i" o i*) let xrefs_table_create () = Hashtbl.create 1001 let xrefs_table_add_if_not_present table k v = try ignore (Hashtbl.find table k) with Not_found -> Hashtbl.add table k v let xrefs_table_find table k = try Some (Hashtbl.find table k) with Not_found -> None let xrefs_table_iter = Hashtbl.iter (* [p] is the parser. Since this will be called from within functions it also calls, we must store and retrieve the current file position on entry and exit. *) let rec lex_object i xrefs p opt n = let current_pos = i.pos_in () in let xref = match xrefs_table_find xrefs n with | Some x -> x | None -> raise (Pdf.PDFError (Pdf.input_pdferror i "Object not in xref table")) in match xref with | XRefStream (objstm, index) -> assert false (*r lex object only used on XRefPlain entries *) | XRefPlain (o, _) -> i.seek_in o; let result = lex_object_at false i opt p (lex_object i xrefs p opt) in i.seek_in current_pos; result (* Parsing proceeds as a series of operations over lists of lexemes or parsed objects. Parsing ends when the list is a singleton and its element is an well-formed object. *) type partial_parse_element = | Lexeme of Pdfgenlex.t | Parsed of Pdf.pdfobject (*let print_parseme = function | Parsed p -> flprint "PARSED:"; print_string (Pdfwrite.string_of_pdf p); flprint "\n" | Lexeme l -> flprint "LEXEME:"; print_lexeme l; flprint "\n"*) (* Parse stage one. *) let parse_R ts = let rec parse_R_inner r = function | [] -> rev r | LexInt o::LexInt _::LexR::rest -> parse_R_inner (Parsed (Pdf.Indirect o)::r) rest | LexComment _::t -> parse_R_inner r t | LexNull::t -> parse_R_inner (Parsed Pdf.Null::r) t | LexBool b::t -> parse_R_inner (Parsed (Pdf.Boolean b)::r) t | LexInt i::t -> parse_R_inner (Parsed (Pdf.Integer i)::r) t | LexReal f::t -> parse_R_inner (Parsed (Pdf.Real f)::r) t | LexString s::t -> parse_R_inner (Parsed (Pdf.String s)::r) t | LexName n::t -> parse_R_inner (Parsed (Pdf.Name n)::r) t | h::t -> parse_R_inner (Lexeme h::r) t in parse_R_inner [] ts let process_parse_dictionary elts = let rec mkpairs pairs = function | [] -> pairs | Parsed v::Parsed (Pdf.Name k)::t -> mkpairs ((k, v)::pairs) t | _ -> raise (Pdf.PDFError "parse_dictionary") in try Parsed (Pdf.Dictionary (mkpairs [] elts)) with Pdf.PDFError "parse_dictionary" -> Pdfe.log "Malformed file: odd length dictionary. Carrying on...\n"; Parsed (Pdf.Dictionary []) let process_parse_array elts = let arry = rev_map (function | Parsed x -> x | _ -> raise (Pdf.PDFError "parse_array")) elts in Parsed (Pdf.Array arry) (* Read everything to the close of the dictionary *) let rec parse_dictionary sofar = function | [] -> process_parse_dictionary sofar, [] | Lexeme LexLeftDict::t -> let dict, rest = parse_dictionary [] t in parse_dictionary (dict::sofar) rest | Lexeme LexLeftSquare::t -> let arr, rest = parse_array [] t in parse_dictionary (arr::sofar) rest | Lexeme LexRightDict::t -> process_parse_dictionary sofar, t | h::t -> parse_dictionary (h::sofar) t (* Read everything to the close of the array *) and parse_array sofar = function | [] -> process_parse_array sofar, [] | Lexeme LexLeftDict::t -> let dict, rest = parse_dictionary [] t in parse_array (dict::sofar) rest | Lexeme LexLeftSquare::t -> let arr, rest = parse_array [] t in parse_array (arr::sofar) rest | Lexeme LexRightSquare::t -> process_parse_array sofar, t | h::t -> parse_array (h::sofar) t (* Main function *) let rec parse_to_tree sofar = function | Lexeme LexLeftDict::t -> let dict, rest = parse_dictionary [] t in parse_to_tree (dict::sofar) rest | Lexeme LexLeftSquare::t -> let arr, rest = parse_array [] t in parse_to_tree (arr::sofar) rest | h::t -> parse_to_tree (h::sofar) t | [] -> rev sofar let parse_finish_read_stream o d obj s = (* Fix up length, if necessary *) let l = match s with Pdf.Got b -> bytes_size b | Pdf.ToGet t -> Pdf.length_of_toget t and lold = try begin match lookup_failnull "/Length" d with Pdf.Integer l -> l | _ -> -1 end with Not_found -> -1 in if lold <> l then (o, Pdf.Stream {contents = Pdf.add_dict_entry obj "/Length" (Pdf.Integer l), s}) else (o, Pdf.Stream {contents = obj, s}) let parse_finish ?(failure_is_ok = false) q = match q with | [Parsed (Pdf.Integer o); Parsed (Pdf.Integer _); Lexeme LexObj; Parsed obj; Lexeme LexEndObj] -> o, obj | Parsed (Pdf.Integer o):: Parsed (Pdf.Integer _):: Lexeme LexObj:: Parsed (Pdf.Dictionary d as obj):: Lexeme (LexStream s):: Lexeme LexEndStream::_ -> parse_finish_read_stream o d obj s | Parsed (Pdf.Dictionary d as obj):: Lexeme (LexStream s):: Lexeme LexEndStream::_ -> (* Malformed file: stream object in object stream! *) parse_finish_read_stream 0 d obj s | Parsed (Pdf.Integer o)::Parsed (Pdf.Integer _):: Lexeme LexObj::Parsed obj::_ -> o, obj | [Parsed d] -> 0, d | [Parsed (Pdf.Integer o); Parsed (Pdf.Integer _); Lexeme LexObj; Lexeme LexEndObj] -> o, Pdf.Null | l -> Pdfe.log "Unable to parse object:\n"; iter (function Parsed p -> Pdfe.log (Printf.sprintf "%S\n" (Pdfwrite.string_of_pdf p)) | Lexeme l -> Pdfe.log (Printf.sprintf "%S\n" (string_of_lexeme l))) l; raise (Pdf.PDFError "Could not extract object") (* Parse some lexemes *) let parse ?(failure_is_ok = false) lexemes = try parse_finish ~failure_is_ok:failure_is_ok (parse_to_tree [] (parse_R lexemes)) with Pdf.PDFError _ as e -> if failure_is_ok then (max_int, Pdf.Null) else raise e let parse_single_object s = snd (parse (lex_object_at true (Pdfio.input_of_string s) true (fun _ -> (0, Pdf.Null)) (fun _ -> []))) (* Given an object stream pdfobject and a list of object indexes to extract, return an [(int * Pdf.objectdata) list] representing those object number, lexeme pairs - assuming they exist! *) let lex_stream_object i xrefs parse opt obj indexes user_pw owner_pw partial_pdf gen = if !read_debug then begin Pdfe.log (Printf.sprintf "lexing object stream at %i\n" (i.Pdfio.pos_in ())); Pdfe.log (Printf.sprintf "lexing object stream %i\nTo find the indexes:\n" obj); iter (fun i -> Pdfe.log (Printf.sprintf "%i " i)) indexes; Pdfe.log "\n" end; let _, stmobj = parse (lex_object i xrefs parse opt obj) in match stmobj with | Pdf.Stream {contents = d, stream} -> let n = match Pdf.lookup_direct partial_pdf "/N" d with | Some (Pdf.Integer n) -> n | _ -> raise (Pdf.PDFError (Pdf.input_pdferror i "malformed /N")) in let first = match Pdf.lookup_direct partial_pdf "/First" d with | Some (Pdf.Integer n) -> n | _ -> raise (Pdf.PDFError (Pdf.input_pdferror i "malformed /First")) in (* Decrypt if necessary *) let stmobj = Pdfcrypt.decrypt_single_stream user_pw owner_pw partial_pdf obj gen stmobj in Pdfcodec.decode_pdfstream partial_pdf stmobj; begin match stmobj with | Pdf.Stream {contents = _, Pdf.Got raw} -> let i = input_of_bytes raw in begin try (* Read index. *) let rawnums = ref [] in for x = 1 to n * 2 do dropwhite i; rawnums =| match lex_number i with | LexInt i -> i | k -> raise (Pdf.PDFError (Pdf.input_pdferror i "objstm offset problem")) done; rawnums := rev !rawnums; (* Read each object *) let pairs = pairs_of_list !rawnums and objects = ref [] and index = ref 0 and indexes = ref (sort compare_i indexes) in iter (fun (objnum, offset) -> begin match !indexes with | [] -> () | x::xs when x <> !index -> () | _::xs -> indexes := xs; i.seek_in (offset + first); let lexemes = lex_object_at true i opt parse (lex_object i xrefs parse opt) in let obj = (ref (Pdf.ParsedAlreadyDecrypted (snd (parse lexemes))), 0) in objects =| (objnum, obj) end; incr index) pairs; Pdf.addobj_given_num partial_pdf (obj, Pdf.Null); !objects with End_of_file -> raise (Pdf.PDFError (Pdf.input_pdferror i "unexpected objstream end")) end | _ -> raise (Pdf.PDFError (Pdf.input_pdferror i "couldn't decode objstream")) end | stmobj -> raise (Pdf.PDFError (Pdf.input_pdferror i (Printf.sprintf "lex_stream_object: not a stream, but %s" (Pdfwrite.string_of_pdf stmobj)))) (* Cross-reference tables *) (* Read the cross-reference table. Supports the multiple sections created when a PDF file is incrementally modified. *) type xref_line = | Invalid | Section of int * int (* Start, length. *) | Valid of int * int (* byte offset, gen. *) | Free of int * int (* free entry. *) | InObjectStream of int * int (* Stream number, index. *) | StreamFree of int * int (* free entry in an object stream. *) | XRefNull (* is the null object. *) | Finished (* end of a table. *) (* Read and parse a single line of a cross-reference table. We use a long-winded match pattern on the characters of cross-reference lines because a byte offset can exceed the range for [Genlex.Int]. *) let rec read_xref_line i = let pos = i.pos_in () in dropwhite i; let line = input_line i in if line = "xref" || line = "xref " then read_xref_line i else let is09 x = x >= '0' && x <= '9' in (* Consider the usual case - no need to pull apart *) if String.length line >= 18 && is09 line.[0] && is09 line.[1] && is09 line.[2] && is09 line.[3] && is09 line.[4] && is09 line.[5] && is09 line.[6] && is09 line.[7] && is09 line.[8] && is09 line.[9] && is09 line.[11] && is09 line.[12] && is09 line.[13] && is09 line.[14] && is09 line.[15] then let p, i = int_of_string (String.sub line 0 10), int_of_string (String.sub line 11 5) in match line.[17] with | 'n' -> Valid (p, i) | 'f' -> Free (p, i) | _ -> Invalid else match explode line with | 't'::'r'::'a'::'i'::'l'::'e'::'r'::more -> (* Bad files may not put newlines after the trailer, so [input_line] may have taken too much, preventing us from reading the trailer dictionary, so we rewind. *) let leading_spaces = length (takewhile (eq ' ') (explode line)) in i.seek_in (pos + 7 + leading_spaces); Finished | '0'::'0'::'0'::'0'::'0'::'0'::'0'::'0'::'0'::'0':: ' '::_::_::_::_::_::' '::'n'::_ -> (* Consider 0000000000 _____ n as a free entry (malformed file workaround) *) Free (0, 0) | r -> (* Artworks produces bad PDF with lines like xref 1 5 *) match Pdfgenlex.lex (input_of_string line) with | [Pdfgenlex.LexName "xref"; Pdfgenlex.LexInt s; Pdfgenlex.LexInt l] | [Pdfgenlex.LexInt s; Pdfgenlex.LexInt l] -> Section (s, l) | _ -> Invalid (* Read the cross-reference table in [i] at the current position. Leaves [i] at the first character of the trailer dictionary. *) let read_xref i = let fail () = raise (Pdf.PDFError (Pdf.input_pdferror i "Could not read x-ref table")) in let xrefs = ref [] in let entries = ref 0 in begin try let finished = ref false in let objnumber = ref 0 in while not !finished do match read_xref_line i with | Invalid -> fail () | Valid (offset, gen) -> entries += 1; xrefs =| (!objnumber, XRefPlain (offset, gen)); incr objnumber | Finished -> set finished | Section (s, _) -> objnumber := s | Free _ -> entries +=1; incr objnumber | _ -> () (* Xref stream types won't have been generated. *) done with End_of_file | Sys_error _ | Failure _ (*"int_of_string"*) -> fail () end; !xrefs (* PDF 1.5 cross-reference stream support. [i] is the input. The tuple describes the lengths in bytes of each of the three fields. *) let read_xref_line_stream i w1 w2 w3 = try let read_field bytes = let rec read_field bytes mul = if bytes = 0 then 0 else match i.input_byte () with | x when x = Pdfio.no_more -> raise (Pdf.PDFError (Pdf.input_pdferror i "Bad xref stream")) | b -> b * mul + (read_field (bytes - 1) (mul / 256)) in if bytes = 0 then 0 else (* Empty entry *) read_field bytes (pow (bytes - 1) 256) in let f1 = read_field w1 in let f2 = read_field w2 in let f3 = read_field w3 in (*if !read_debug then Pdfe.log (Printf.sprintf "%i %i %i\n" f1 f2 f3);*) match f1 with | 0 -> StreamFree (f2, f3) | 1 -> Valid (f2, f3) | 2 -> InObjectStream (f2, f3) | n -> XRefNull with _ -> raise (Pdf.PDFError (Pdf.input_pdferror i "read_xref_line_stream")) (* The function to read a whole cross-reference stream, and return an [xref list]. Leaves [i] at the first character of the stream dictionary, which containes the trailer dictionary entries. *) let read_xref_stream i = let original_pos = i.pos_in () in let err = Pdf.PDFError (Pdf.input_pdferror i "Bad xref stream") in (* Read the next token, which is the object number *) let xrefstream_objectnumber = match lex_next (ref 0) (ref 0) false i [] (fun _ -> 0, Pdf.Null) false (fun _ -> []) with | LexInt i -> i | _ -> Pdfe.log "couldn't lex object number\n"; raise err in if !read_debug then Pdfe.log (Printf.sprintf "Object number of this xref stream is %i\n" xrefstream_objectnumber); (* Go back to the beginning *) i.seek_in original_pos; (* And proceed as before *) let rec lex_untilstream i ls = let lexobj = lex_object i (null_hash ()) parse false in match lex_next (ref 0) (ref 0) true i [] parse false lexobj with | StopLexing | LexNone -> rev ls (* LexNone stops loop on malformed *) | l -> lex_untilstream i (l::ls) in let stream, obj, gen = match try let lexobj = lex_object i (null_hash ()) parse true in let dictlex = lex_untilstream i [] in let obj = match hd dictlex with | LexInt i -> i | _ -> raise Not_found in let gen = match (hd (tl dictlex)) with | LexInt i -> i | _ -> raise Not_found in begin match lex_stream i parse (rev dictlex) lexobj true with | LexNone -> raise err | stream -> snd (parse (dictlex @ [stream] @ [LexEndStream; LexEndObj])), obj, gen end with _ -> raise (Pdf.PDFError (Pdf.input_pdferror i "Failure reading xref stream - malformed")) with | Pdf.Stream _ as stream, obj, gen -> stream, obj, gen | _ -> raise err in if !read_debug then (Pdfe.log "HAVE READ XREF STREAM DICT, NOW ACTUAL XREF STREAM DATA\n"; tt' ()); Pdfcodec.decode_pdfstream (Pdf.empty ()) stream; let w1, w2, w3 = match Pdf.lookup_direct (Pdf.empty ()) "/W" stream with | Some (Pdf.Array [Pdf.Integer w1; Pdf.Integer w2; Pdf.Integer w3]) when w1 >= 0 && w2 >= 0 && w3 >= 0 && w1 + w2 + w3 > 0 -> w1, w2, w3 | _ -> raise err in let i' = match stream with | Pdf.Stream {contents = _, Pdf.Got s} -> input_of_bytes s | _ -> raise err in let xrefs = ref [] in begin try if !read_debug then (Pdfe.log "About to start read_xref_stream\n"; tt' ()); while true do xrefs =| read_xref_line_stream i' w1 w2 w3 done with _ -> if !read_debug then (Pdfe.log "End of read_xref_stream\n"; tt' ()); () end; xrefs := rev !xrefs; if !read_debug then (Pdfe.log (Printf.sprintf "****** read %i raw Xref stream entries\n" (length !xrefs)); tt' ()); let starts_and_lens = match Pdf.lookup_direct (Pdf.empty ()) "/Index" stream with | Some (Pdf.Array elts) -> if odd (length elts) then raise (Pdf.PDFError (Pdf.input_pdferror i "Bad /Index")); map (function | (Pdf.Integer s, Pdf.Integer l) -> s, l | _ -> raise (Pdf.PDFError (Pdf.input_pdferror i "Bad /Index entry"))) (pairs_of_list elts) | Some _ -> raise (Pdf.PDFError (Pdf.input_pdferror i "Unknown /Index")) | None -> let size = match Pdf.lookup_direct (Pdf.empty ()) "/Size" stream with | Some (Pdf.Integer s) -> s | _ -> raise (Pdf.PDFError (Pdf.input_pdferror i "Missing /Size in xref dict")) in [0, size] in let xrefs' = ref [] in if !read_debug then Pdfe.log (Printf.sprintf "****** Begin iteration: %i\n" (length starts_and_lens)); iter (fun (start, len) -> let these_xrefs = try take !xrefs len with _ -> raise (Pdf.PDFError (Pdf.input_pdferror i "Bad xref stream\n")) in xrefs := drop !xrefs len; let objnumber = ref start in iter (fun x -> match x with | Valid (offset, gen) -> xrefs' =| (!objnumber, XRefPlain (offset, gen)); incr objnumber | InObjectStream (stream, index) -> xrefs' =| (!objnumber, XRefStream (stream, index)); incr objnumber | _ -> incr objnumber) these_xrefs) starts_and_lens; i.seek_in original_pos; if !read_debug then (Pdfe.log (Printf.sprintf "***READ_XREF_STREAM final result was %i xrefs\n" (length !xrefs')); tt' ()); rev !xrefs', xrefstream_objectnumber (* A suitable function for the Pdf module to use to lex and parse an object. Assumes [i] has been set to the correct position. [n] is the object number. *) let get_object i xrefs n = let lexemes = lex_object i xrefs parse false n in snd (parse lexemes) let is_linearized i = try ignore (read_header i); let lexemes = lex_dictionary false i in let _, parsed = parse ~failure_is_ok:true lexemes in match Pdf.lookup_direct (Pdf.empty ()) "/Linearized" parsed with | Some (Pdf.Integer _ | Pdf.Real _) -> true | _ -> false with _ -> false exception Revisions of int exception BadRevision let sanitize_trailerdict l trailerdict = add "/Size" (Pdf.Integer l) (remove "/W" (remove "/Type" (remove "/Index" (remove "/Prev" (remove "/XRefStm" (remove "/Filter" (remove "/DecodeParms" trailerdict))))))) (* FIXME: Further ideas for monster_squeezed.pdf - too many intermediate data structures here - should we split the xref table into two instead of splitting it into plain / stream ones on-the-fly all the time? Also, generally too many lists. *) (* Read a PDF from a channel. If [opt], streams are read immediately into memory. Revision: 1 = first revision, 2 = second revision etc. max_int = latest revision (default). If revision = -1, the file is not read, but instead the exception Revisions x is raised, giving the number of revisions. *) let read_pdf ?revision user_pw owner_pw opt i = if !read_debug then (Pdfe.log (Printf.sprintf "read_pdf, revision is %s\n" (match revision with None -> "None" | Some x -> string_of_int x)); tt' ()); begin match revision with Some x when x < 1 && x <> (-1) -> raise BadRevision | _ -> () end; let revisions = ref 1 in let current_revision = ref 0 in let was_linearized = is_linearized i in i.seek_in 0; if !read_debug then begin Pdfe.log (Printf.sprintf "Start of read_pdf\n"); Pdfe.log (Printf.sprintf "%s\n" i.Pdfio.source); Pdfe.log (Printf.sprintf "opt is "); Pdfe.log (Printf.sprintf "%b" opt); Pdfe.log (Printf.sprintf "\n") end; let postdeletes = ref [] in let object_stream_ids = null_hash () in let xrefs = xrefs_table_create () in let major, minor = read_header i in let objects_stream, objects_nonstream, root, trailerdict = let addref (n, x) = xrefs_table_add_if_not_present xrefs n x in let got_all_xref_sections = ref false in let trailerdict = ref [] in let xref = ref 0 in let first = ref true in (* This function builds a partial pdf of the plain objects whose references have currently been seen. *) let mkpartial nonstream_objects trailerdict = let objpairs = ref [] in (* 1. Build object number, offset pairs *) xrefs_table_iter (fun n x -> match x with | XRefPlain (offset, gen) -> objpairs =| (n, (ref Pdf.ToParse, gen)) | _ -> ()) xrefs; (* 2. Build the object map *) let objects = Pdf.objects_of_list (Some (get_object i xrefs)) (!objpairs @ nonstream_objects) in (* 3. Build the Pdf putting the trailerdict in *) {(Pdf.empty ()) with Pdf.objects = objects; Pdf.trailerdict = trailerdict} in (* Move to the first xref section. *) find_eof i; backline i; (* Drop any initial contents which is not a digit - may occur if there is legitimate whitespace of if the PDF is malformed such that it has the startxref keyword and the byte offset on the same line. *) ignoreuntil false isdigit i; begin match takewhile isdigit (getuntil_white_or_delimiter i) with | [] -> raise (Pdf.PDFError (Pdf.input_pdferror i "Could not find xref pointer")) | xrefchars -> xref := int_of_string (implode xrefchars); end; if !read_debug then (Pdfe.log (Printf.sprintf "Reading Cross-reference table\n"); tt' ()); while not !got_all_xref_sections do if !read_debug then Pdfe.log (Printf.sprintf "Reading xref section at %i\n" !xref); i.seek_in !xref; incr current_revision; (* Distinguish between xref table and xref stream. *) dropwhite i; (* Read cross-reference table *) let read_table skip = if !read_debug then Pdfe.log (Printf.sprintf "Reading table for revision %i, skip = %b\n" !current_revision skip); if peek_char i = Some 'x' then iter (if skip then (function _ -> ()) else addref) (read_xref i) else if not skip then let refs, objnumbertodelete = read_xref_stream i in (postdeletes := objnumbertodelete::!postdeletes; iter addref refs) in begin match revision with None -> read_table false | Some r when r <= !current_revision -> read_table false | _ -> if !read_debug then Pdfe.log (Printf.sprintf "Skipping revision %i\n" !current_revision); read_table true end; (* It is now assumed that [i] is at the start of the trailer dictionary. *) let trailerdict_current = let lexemes = lex_object_at true i opt parse (lex_object i xrefs parse opt) in match parse lexemes with | (_, Pdf.Dictionary d) | (_, Pdf.Stream {contents = Pdf.Dictionary d, _}) -> d | _ -> raise (Pdf.PDFError (Pdf.input_pdferror i "Malformed trailer")) in begin if !first then begin trailerdict := mergedict trailerdict_current !trailerdict; clear first end; (* Do we have a /XRefStm to follow? *) begin match lookup "/XRefStm" trailerdict_current with | Some (Pdf.Integer n) -> i.seek_in n; let read_table () = if !read_debug then Pdfe.log (Printf.sprintf "Reading table for revision stm %i\n" !current_revision); let refs, objnumbertodelete = read_xref_stream i in postdeletes := objnumbertodelete::!postdeletes; iter addref refs in begin match revision with None -> read_table () | Some r when r <= !current_revision -> read_table () | _ -> if !read_debug then Pdfe.log (Printf.sprintf "Skipping /XRefStm in revision %i\n" !current_revision) end; | _ -> () end; (* Is there another to do? *) match lookup "/Prev" trailerdict_current with | None -> set got_all_xref_sections | Some (Pdf.Integer n) -> revisions := !revisions + 1; xref := n | _ -> raise (Pdf.PDFError (Pdf.input_pdferror i "Malformed trailer")) end; done; if revision = Some (-1) then (* If there are exactly two "revisions", and the file is linearized, then we return 1, since there is only one real revision. If there are more than 2, we assume it has been incrementally updated, is not really "linearized" at all, and so we return !revisions - 1, (the original linearized part counting for two). Thus, one can never accidently read half the original linearized file. *) let real_revisions = if was_linearized then !revisions - 1 else !revisions in raise (Revisions real_revisions) else if !read_debug then (Pdfe.log (Printf.sprintf "*** READ %i XREF entries\n" (Hashtbl.length xrefs)); tt' ()); let root = match lookup "/Root" !trailerdict with | Some (Pdf.Indirect i) -> i | None -> raise (Pdf.PDFError (Pdf.input_pdferror i "No /Root entry")) | _ -> raise (Pdf.PDFError (Pdf.input_pdferror i "Malformed /Root entry")) in let getgen n = match xrefs_table_find xrefs n with | Some (XRefPlain (_, g)) -> g | Some (XRefStream _) -> 0 | None -> raise Not_found in if !read_debug then (Pdfe.log (Printf.sprintf "Reading non-stream objects\n"); tt' ()); let objects_nonstream = let objnumbers = ref [] in xrefs_table_iter (fun n x -> match x with | XRefPlain (offset, gen) -> objnumbers =| n | _ -> ()) xrefs; map (if opt then fun o -> let num, parsed = parse (lex_object i xrefs parse opt o) in num, (ref (Pdf.Parsed parsed), getgen o) else fun o -> o, (ref Pdf.ToParse, getgen o)) !objnumbers in if !read_debug then (Pdfe.log (Printf.sprintf "Reading stream objects\n"); tt' ()); let objects_stream = let streamones = let l = ref [] in Hashtbl.iter (fun k v -> match v with XRefStream (s, i) -> l =| (k, s, i) | _ -> ()) xrefs; !l in if !read_debug then (Pdfe.log "Made streamones\n"; tt' ()); (*Printf.printf "*** %i objects are in streams\n" (length streamones); iter (function (n, s, i) -> Printf.printf "STREAMONES: Obj %i, Stream %i, Index %i\n" n s i) streamones;*) iter (function (n, s, _) -> Hashtbl.add object_stream_ids n s) streamones; if !read_debug then (Pdfe.log "Added object_stream_ids\n"; tt' ()); if opt then begin let collated = let gt = Hashtbl.create 200 in let sst = Hashtbl.create 200 in List.iter (function (_, s, _) as x -> Hashtbl.add gt s x; Hashtbl.replace sst s 0) streamones; List.map (Hashtbl.find_all gt) (map fst (list_of_hashtbl sst)) in let inputs_to_lex_stream_object = map (fun l -> match hd l with (_, s, _) -> s, map (fun (_, _, i) -> i) l) collated in (* Read objects from object streams now *) let outputs_from_lex_stream_object = let partial = mkpartial objects_nonstream (Pdf.Dictionary !trailerdict) in map (function (s, is) -> let r = lex_stream_object i xrefs parse opt s is user_pw owner_pw partial (getgen s) in postdeletes := s::!postdeletes; r) inputs_to_lex_stream_object in flatten outputs_from_lex_stream_object end else let partial = mkpartial objects_nonstream (Pdf.Dictionary !trailerdict) in if !read_debug then (Pdfe.log "Made partial\n"; tt' ()); let readstream streamobjnumber indexes = lex_stream_object i xrefs parse opt streamobjnumber indexes user_pw owner_pw partial (getgen streamobjnumber) in let themap = let t = Hashtbl.create 200 in let groups = let gt = Hashtbl.create 200 in let sst = Hashtbl.create 200 in List.iter (function (_, s, _) as x -> Hashtbl.add gt s x; Hashtbl.replace sst s 0) streamones; List.map (Hashtbl.find_all gt) (map fst (list_of_hashtbl sst)) in if !read_debug then (Pdfe.log "Made groups\n"; tt' ()); iter (fun group -> let firsts = map (fun (n, _, _) -> n) group in let seconds = map (fun (_, _, i) -> i) group in iter (fun n -> Hashtbl.add t n seconds) firsts) groups; t in if !read_debug then (Pdfe.log "Made themap\n"; tt' ()); map (function (n, s, i) -> (n, (ref (Pdf.ToParseFromObjectStream (themap, s, i, readstream)), 0))) streamones in if !read_debug then begin Pdfe.log (Printf.sprintf "There were %i nonstream objects\n" (length objects_nonstream)); Pdfe.log (Printf.sprintf "There were %i stream objects\n" (length objects_stream)); Pdfe.log (Printf.sprintf "\n"); tt' (); end; objects_stream, objects_nonstream, root, trailerdict in if !read_debug then (Pdfe.log (Printf.sprintf "Finishing up...\n"); tt' ()); let objects = objects_stream @ objects_nonstream in (* Fix Size entry and remove Prev, XRefStm, Filter, Index, W, Type, and DecodeParms *) let trailerdict' = sanitize_trailerdict (length objects) !trailerdict in let pdf = {Pdf.major = major; Pdf.minor = minor; Pdf.objects = Pdf.objects_of_list (Some (get_object i xrefs)) objects; Pdf.root = root; Pdf.trailerdict = Pdf.Dictionary trailerdict'; Pdf.was_linearized = was_linearized; Pdf.saved_encryption = None} in if !read_debug then (Pdfe.log (Printf.sprintf "made final objects...\n"); tt' ()); (* Check for a /Version in the document catalog *) begin match Pdf.lookup_direct pdf "/Version" (Pdf.lookup_obj pdf root) with Some (Pdf.Name s) -> let major, minor = try read_header (Pdfio.input_of_string ("%PDF-" ^ String.sub s 1 (String.length s - 1))) with e -> Pdfe.log (Printf.sprintf "%s\n" (Printexc.to_string e)); (pdf.Pdf.major, pdf.Pdf.minor) in pdf.Pdf.major <- major; pdf.Pdf.minor <- minor | _ -> () end; (* Delete items in !postdeletes - these are any xref streams, and object streams (if finished with). This allows decryption to be performed without accidently trying to decrypt these streams - which would fail due to them not being of set lengths. *) iter (fun i -> (* Oct 2023 - check it's not been overwritten by a later revision of the file *) match Pdf.lookup_obj pdf i with | Pdf.Stream {contents = (Pdf.Dictionary d, _)} -> begin match lookup "/Type" d with | Some (Pdf.Name ("/XRef" | "/ObjStm")) -> Pdf.removeobj pdf i | _ -> () end | exception Not_found -> () | _ -> ()) !postdeletes; (* Add stream_object_ids *) pdf.Pdf.objects.Pdf.object_stream_ids <- object_stream_ids; (*if !read_debug then begin Pdfe.log (Printf.sprintf "Object stream IDs:\n"); Hashtbl.iter (fun o s -> Pdfe.log (Printf.sprintf "Object %i was in stream %i\n" o s)) object_stream_ids end;*) if !read_debug then begin Pdfe.log "Done reading PDF file.\n"; tt' (); match Pdf.lookup_direct pdf "/Encrypt" pdf.Pdf.trailerdict with | Some _ -> Pdfe.log "***File is encrypted\n" | _ -> () end; pdf (* Read the number of revisions of the document, by performing a dummy read. For example, if this function returns 3, then appropriate values to pass to ?revision in a subsequent call to read_pdf are 1, 2, and 3. The position of input after this runs is unspecified. On a malformed PDF, will raise whatever error [read_pdf] does. *) let revisions i = try ignore (read_pdf ~revision:(-1) None None false i); assert false with Revisions n -> n (* Malformed file reading. *) (* We read all trailerdicts in the file, preferring entries in later * dictionaries. *) let read_malformed_trailerdict i = try (* Move to just after the keyword trailer, if one still exists. Otherwise, file position ends up at the end of the file. *) while let currpos = i.pos_in () in try let l = input_line i in let r = not (l.[0] = 't' && l.[1] = 'r' && l.[2] = 'a' && l.[3] = 'i' && l.[4] = 'l' && l.[5] = 'e' && l.[6] = 'r') in (* In case of "trailer_<<..." i.e a missing newline, we backtrack until * just after the trailer keyword itself *) if String.length l > 7 && (l.[7] = '<' || l.[7] = ' ') then i.seek_in (currpos + 7); r with _ -> (* out of bounds from l.[n], End_of_file *) not (i.pos_in () = currpos || i.pos_in () >= i.in_channel_length) do () done; let lexemes = lex_object_at true i true parse (lex_object i (null_hash ()) parse true) in match parse lexemes with | (_, Pdf.Dictionary d) | (_, Pdf.Stream {contents = Pdf.Dictionary d, _}) -> remove "/Prev" d | _ -> raise (Pdf.PDFError (Pdf.input_pdferror i "Malformed or missing trailer")) with e -> raise (Pdf.PDFError (Printf.sprintf "File reconstructor: could not read trailer dictionary - %s" (Printexc.to_string e))) let read_malformed_trailerdicts i = i.seek_in 0; let trailerdicts = ref [] in while try let currpos = i.pos_in () in trailerdicts := read_malformed_trailerdict i::!trailerdicts; i.pos_in () > currpos with _ -> false do () done; !trailerdicts (* This function is used to skip non-whitespace junk between objects when reading malformed files. It looks for the first integer, not actually for the x y obj pattern itself. *) let rec advance_to_integer i = dropwhite i; let p = i.pos_in () in match lex_next (ref 0) (ref 0) false i [] parse true (fun _ -> []) with | StopLexing -> () | LexInt x -> i.seek_in p | l -> (* If no progress at all, bail out. *) if i.pos_in () > p then advance_to_integer i (* Read the actual objects, in order. *) let read_malformed_pdf_objects i = if !read_debug then flprint "read_debug is true\n"; let objs = ref [] in (* Can't just test i.pos_in () < i.in_channel_length because of set_offset! *) while let x = i.input_char () in rewind i; x <> None do let c = i.pos_in () in try if !read_debug then Pdfe.log (Printf.sprintf "read_malformed_pdf_object is reading an object at %i\n" c); let objnum, obj = parse ~failure_is_ok:true (lex_object_at true i true parse (lex_object i (null_hash ()) parse true)) in if !read_debug then Pdfe.log (Printf.sprintf "Got object %i ok\n" objnum); (*if !read_debug then Printf.printf "Got object %i, which is %s ok\n" objnum (Pdfwrite.string_of_pdf obj);*) if objnum > 0 && objnum < max_int then objs := add objnum obj !objs; advance_to_integer i; (* find next possible object *) if i.pos_in () = c then ignore (input_line i) (* no progress. *) with e -> if !read_debug then Pdfe.log "Couldn't get object, moving on\n"; (* 26/02/2024 advance only to any line beginning or ending with 'endobj'. Before, a runaway string read, for example, could advance too far, perhaps into the middle of a stream, then no more objects could be read. *) i.seek_in c; let fin = ref false in while not !fin do let l = String.trim (input_line i) in fin := starts_with "endobj" l || starts_with "jbodne" (implode (rev (explode l))) done done; !objs let read_malformed_pdf upw opw i = Pdfe.log (Printf.sprintf "Attempting to reconstruct the malformed pdf %s...\n" i.Pdfio.source); if !read_debug then flprint "Beginning of malformed PDF reconstruction\n"; let trailerdicts = read_malformed_trailerdicts i in if !read_debug then flprint "Finished reading malformed trailer dictionaries\n"; let major, minor = read_header i in if !read_debug then flprint "Finished reading malformed header\n"; i.Pdfio.seek_in 0; let objects = map (function (objnum, obj) -> (objnum, (ref (Pdf.Parsed obj), 0))) (read_malformed_pdf_objects i) in Pdfe.log (Printf.sprintf "Read %i objects\n" (length objects)); let trailerdict, root = if !read_debug then iter (fun td -> Pdfe.log (Printf.sprintf "trailerdict is %s\n" (Pdfwrite.string_of_pdf (Pdf.Dictionary td)))) trailerdicts; (* Select best trailerdict. Most recent one which has a dictionary as a root. *) let trailerdict = ref [] in let root = ref ~-1 in iter (fun td -> match lookup "/Root" td with | Some (Pdf.Indirect i) -> begin match lookup i objects with | Some (({contents = Pdf.Parsed (Pdf.Dictionary _)}, _)) -> trailerdict := td; root := i | _ -> () end | _ -> ()) (rev trailerdicts); if !root = ~-1 then raise (Pdf.PDFError (Pdf.input_pdferror i "Malformed /Root entry")); (!trailerdict, !root) in i.Pdfio.seek_in 0; (* Fix Size entry and remove Prev, XRefStm, Filter, Index, W, Type, and DecodeParms *) let trailerdict' = sanitize_trailerdict (length objects) trailerdict in let was_linearized = is_linearized i in Pdfe.log "Malformed PDF reconstruction succeeded!\n"; let pdf = {Pdf.major = major; Pdf.minor = minor; Pdf.root = root; Pdf.objects = Pdf.objects_of_list None objects; Pdf.trailerdict = Pdf.Dictionary trailerdict'; Pdf.was_linearized = was_linearized; Pdf.saved_encryption = None} in if !read_debug then Pdfwrite.debug_whole_pdf pdf; pdf let report_read_error i e e' = raise (Pdf.PDFError (Pdf.input_pdferror i (Printf.sprintf "Failed to read PDF - initial error was\n%s\n\n\ final error was \n%s\n\n" (Printexc.to_string e) (Printexc.to_string e')))) let endpage = ref (fun _ -> 0) let read_pdf revision upw opw opt i = let r = if !debug_always_treat_malformed then try read_malformed_pdf upw opw i with e -> report_read_error i e e else try let r = read_pdf ?revision upw opw opt i in (* Experiment: Try to read pagetree. Triggers malformed file read if can't. Helps with reading lots of files with malformed xref tables. Improvement: detect the malformed tables properly. *) ignore (!endpage r); r with | Pdf.PDFError s as e when String.length s >= 10 && String.sub s 0 10 = "Encryption" -> (* If it failed due to encryption not supported or user password not right, the error should be passed up - it's not a malformed file. *) raise e | BadRevision -> raise (Pdf.PDFError "Revision number too low when reading PDF") | e -> if !error_on_malformed then raise e else begin Pdfe.log (Printf.sprintf "Because of error %s, will read as malformed.\n" (Printexc.to_string e)); try read_malformed_pdf upw opw i with e' -> report_read_error i e e' end in if !read_debug then Pdfwrite.debug_whole_pdf r; r (* Read a PDF into memory, including its streams. *) let pdf_of_channel ?revision ?(source = "channel") upw opw ch = read_pdf revision upw opw true (input_of_channel ~source ch) (* Same, but delay reading of streams. *) let pdf_of_channel_lazy ?revision ?(source = "channel") upw opw ch = read_pdf revision upw opw false (input_of_channel ~source ch) (* Similarly for inputs. *) let pdf_of_input ?revision upw opw i = read_pdf revision upw opw true i (* And lazy on inputs. *) let pdf_of_input_lazy ?revision upw opw i = read_pdf revision upw opw false i (* Read a whole PDF file into memory. Closes file. *) let pdf_of_file ?revision upw opw f = try let fh = open_in_bin f in let pdf = pdf_of_channel ?revision ~source:f upw opw fh in close_in fh; pdf with | (Pdf.PDFError _) as e -> raise e | Sys_error str -> raise (Pdf.PDFError str) let what_encryption pdf = if Pdfcrypt.is_encrypted pdf then let crypt, _, _, _, _, _, _ = Pdfcrypt.get_encryption_values pdf in match crypt with | Pdfcryptprimitives.ARC4 (40, _) -> Some (Pdfwrite.PDF40bit) | Pdfcryptprimitives.ARC4 (128, _) -> Some (Pdfwrite.PDF128bit) | Pdfcryptprimitives.AESV2 | Pdfcryptprimitives.AESV3 _ -> let metadata = match Pdf.lookup_direct pdf "/Encrypt" pdf.Pdf.trailerdict with | Some encrypt_dict -> begin match Pdf.lookup_direct pdf "/EncryptMetadata" encrypt_dict with | Some (Pdf.Boolean false) -> false | _ -> true end | _ -> assert false in begin match crypt with | Pdfcryptprimitives.AESV2 -> Some (Pdfwrite.AES128bit metadata) | Pdfcryptprimitives.AESV3 false -> Some (Pdfwrite.AES256bit metadata) | Pdfcryptprimitives.AESV3 true -> Some (Pdfwrite.AES256bitISO metadata) | _ -> assert false end | _ -> None else None let permissions pdf = if Pdfcrypt.is_encrypted pdf then let _, _, _, p, _, _, _ = Pdfcrypt.get_encryption_values pdf in Pdfcrypt.banlist_of_p p else [] camlpdf-2.8.1/pdfread.mli000066400000000000000000000101571477056064700152640ustar00rootroot00000000000000(** Reading PDF Files *) (** Read a PDF from a [Pdfio.input], with an optional user password which, if absent, is assumed to be the empty string, and optional owner password. *) val pdf_of_input : ?revision:int -> string option -> string option -> Pdfio.input -> Pdf.t (** Same as [pdf_of_input], but delay loading of streams and parsing of objects (they will be loaded and parsed when needed). Useful if we only intend to do something simple, like read metadata. *) val pdf_of_input_lazy : ?revision:int -> string option -> string option -> Pdfio.input -> Pdf.t (** Same as [pdf_of_input], but from an OCaml channel. *) val pdf_of_channel : ?revision:int -> ?source:string -> string option -> string option -> in_channel -> Pdf.t (** As [pdf_of_channel], but delay loading of streams and parsing of objects like [pdf_of_input_lazy]. *) val pdf_of_channel_lazy : ?revision:int -> ?source:string -> string option -> string option -> in_channel -> Pdf.t (** Read a PDF from the given filename with optional user and owner passwords. *) val pdf_of_file : ?revision:int -> string option -> string option -> string -> Pdf.t (** {2 Configuration and debugging} *) (** If set, some debug output is produced. *) val read_debug : bool ref (** If set, a malformed PDF will cause an error, not an attempt to read using the malformed PDF reader. *) val error_on_malformed : bool ref (** If set, we always use the malformed PDF reader. For debug. *) val debug_always_treat_malformed : bool ref (** {2 Low level functions} *) (** Read the number of revisions of the document, by performing a dummy read. For example, if this function returns 3, then appropriate values to pass to [?revision] in a subsequent call to pdf_of_input are 1, 2, and 3. *) val revisions : Pdfio.input -> int (** Return encryption method in use *) val what_encryption : Pdf.t -> Pdfwrite.encryption_method option (** Return list of permissions *) val permissions : Pdf.t -> Pdfcrypt.permission list (** Given a filename, see if the file is linearized. *) val is_linearized : Pdfio.input -> bool (** Read a PDF header *) val read_header : Pdfio.input -> int * int (** Read characters until a PDF delimiter. *) val getuntil_white_or_delimiter : Pdfio.input -> char list (** Read characters until a PDF delimiter, returned as a string. *) val getuntil_white_or_delimiter_string : Pdfio.input -> string (** Read characters until a predicate is true. If the boolean is set, end of input is considered a delimiter. *) val getuntil : bool -> (char -> bool) -> Pdfio.input -> char list (** Throw away characters until a predicate is true. If the boolean is set, end of input is considered a delimiter. *) val ignoreuntil : bool -> (char -> bool) -> Pdfio.input -> unit (** Drop whitespace characters from an input. *) val dropwhite : Pdfio.input -> unit (** Lex a name, assuming there is one to lex. *) val lex_name : Pdfio.input -> Pdfgenlex.t (** Lex a number, assuming there is one to lex. *) val lex_number : Pdfio.input -> Pdfgenlex.t (** Lex a string, assuming there is one to lex. *) val lex_string : Pdfio.input -> Pdfgenlex.t (** Lex a hexadecimal string, assuming there is one to lex. *) val lex_hexstring : Pdfio.input -> Pdfgenlex.t (** Lex a comment, assuming there is one to lex. *) val lex_comment : Pdfio.input -> Pdfgenlex.t (** Lex a dictinonary, assuming there is one to lex. *) val lex_dictionary : bool -> Pdfio.input -> Pdfgenlex.t list (** Lex stream data of the given length. If the boolean is true, then actually read the data. If not, merely record the intention to. *) val lex_stream_data : Pdfio.input -> int -> bool -> Pdfgenlex.t (** Parse a PDF object. If [failure_is_ok] is set, a null object with high object number is returned, instead of an exception being raised. *) val parse : ?failure_is_ok:bool -> Pdfgenlex.t list -> int * Pdf.pdfobject (** Parse a single object. *) val parse_single_object : string -> Pdf.pdfobject (** String representation of a lexeme *) val string_of_lexeme : Pdfgenlex.t -> string (** Print a lexeme to Standard Output with a space after it, for debug. *) val print_lexeme : Pdfgenlex.t -> unit (**/**) val endpage : (Pdf.t -> int) ref camlpdf-2.8.1/pdfspace.ml000066400000000000000000000247601477056064700153000ustar00rootroot00000000000000(* PDF Colour space parsing *) open Pdfutil open Pdfio type point = float * float * float type iccbased = {icc_n : int; icc_alternate : t; icc_range : float array; icc_metadata : Pdf.pdfobject option; icc_stream : Pdf.pdfobject} (* Add CalCMYK - read as deviceCMYK *) and t = | DeviceGray | DeviceRGB | DeviceCMYK | CalGray of point * point * float (* White, Black, Gamma *) | CalRGB of point * point * float array * float array (* White, Black, Gamma, Matrix *) | Lab of point * point * float array (* White, Black, Range *) | ICCBased of iccbased | Indexed of t * (int, int list) Hashtbl.t (* Base colourspace, values *) | Pattern | PatternWithBaseColourspace of t | Separation of string * t * Pdffun.t | DeviceN of string array * t * Pdffun.t * Pdf.pdfobject let rec string_of_colourspace = function | DeviceGray -> "/DeviceGray" | DeviceRGB -> "/DeviceRGB" | DeviceCMYK -> "/DeviceCMYK" | CalGray (_, _, _) -> "/CalGray" | CalRGB (_, _, _, _) -> "/CalRGB" | Lab (_, _, _) -> "/Lab" | ICCBased {icc_alternate = a} -> "ICCBased (" ^ string_of_colourspace a ^ ")" | Indexed (a, _) -> "Indexed (" ^ string_of_colourspace a ^ ")" | Pattern -> "/Pattern" | PatternWithBaseColourspace a -> "PatternWithBaseColourspace (" ^ string_of_colourspace a ^ ")" | Separation (_, a, _) -> "Separation (" ^ string_of_colourspace a ^ ")" | DeviceN (_, a, _, _) -> "DeviceN (" ^ string_of_colourspace a ^ ")" let name_of_colourspace = function | Separation (x, _, _) -> Some x | _ -> None (* Read a tristimulus point. *) let read_point pdf d n = match Pdf.lookup_direct pdf n d with | Some (Pdf.Array [a; b; c]) -> Pdf.getnum pdf a, Pdf.getnum pdf b, Pdf.getnum pdf c | _ -> 0., 0., 0. let rec get_basic_table_colourspace c = match c with | Indexed (alt, _) (* FIXME Not actually checked the following two are correct *) | DeviceN (_, alt, _, _) | Separation (_, alt, _) | ICCBased {icc_alternate = alt} -> get_basic_table_colourspace alt | x -> x (* Read a colour space. Raises [Not_found] on error. *) let rec read_colourspace pdf resources = function | Pdf.Indirect i -> read_colourspace pdf resources (Pdf.direct pdf (Pdf.Indirect i)) | Pdf.Name ("/DeviceGray" | "/G") -> DeviceGray | Pdf.Name ("/DeviceRGB" | "/RGB") -> DeviceRGB | Pdf.Name ("/DeviceCMYK" | "/CMYK") -> DeviceCMYK | Pdf.Name "/Pattern" -> Pattern | Pdf.Array [Pdf.Name "/Pattern"; base_colspace] -> PatternWithBaseColourspace (read_colourspace pdf resources base_colspace) | Pdf.Array [onething] -> read_colourspace pdf resources onething (* [PDFTests/illus_effects.pdf] [[/Pattern]] *) | Pdf.Name space -> begin match Pdf.lookup_direct pdf "/ColorSpace" resources with | Some csdict -> begin match Pdf.lookup_direct pdf space csdict with | Some space' -> read_colourspace pdf resources space' | None -> raise Not_found end | None -> raise Not_found end | Pdf.Array [Pdf.Name "/CalGray"; dict] -> let whitepoint = read_point pdf dict "/WhitePoint" in let blackpoint = read_point pdf dict "/BlackPoint" in let gamma = match Pdf.lookup_direct pdf "/Gamma" dict with | Some n -> Pdf.getnum pdf n | None -> 1. in CalGray (whitepoint, blackpoint, gamma) | Pdf.Array [Pdf.Name "/CalRGB"; dict] -> let whitepoint = read_point pdf dict "/WhitePoint" in let blackpoint = read_point pdf dict "/BlackPoint" in let gamma = match Pdf.lookup_direct pdf "/Gamma" dict with | Some (Pdf.Array [a; b; c]) -> [|Pdf.getnum pdf a; Pdf.getnum pdf b; Pdf.getnum pdf c|] | _ -> [|1.; 1.; 1.|] in let matrix = match Pdf.lookup_direct pdf "/Matrix" dict with | Some (Pdf.Array [a; b; c; d; e; f; g; h; i]) -> [|Pdf.getnum pdf a; Pdf.getnum pdf b; Pdf.getnum pdf c; Pdf.getnum pdf d; Pdf.getnum pdf e; Pdf.getnum pdf f; Pdf.getnum pdf g; Pdf.getnum pdf h; Pdf.getnum pdf i|] | _ -> [|1.; 0.; 0.; 0.; 1.; 0.; 0.; 0.; 1.|] in CalRGB (whitepoint, blackpoint, gamma, matrix) | Pdf.Array [Pdf.Name "/Lab"; dict] -> let whitepoint = read_point pdf dict "/WhitePoint" in let blackpoint = read_point pdf dict "/BlackPoint" in let range = match Pdf.lookup_direct pdf "/Range" dict with | Some (Pdf.Array [a; b; c; d]) -> [|Pdf.getnum pdf a; Pdf.getnum pdf b; Pdf.getnum pdf c; Pdf.getnum pdf d|] | _ -> [|-.100.; 100.; -.100.; 100.|] in Lab (whitepoint, blackpoint, range) | Pdf.Array [Pdf.Name "/ICCBased"; stream] -> begin match Pdf.direct pdf stream with | Pdf.Stream {contents = (dict, _)} -> let n = match Pdf.lookup_direct pdf "/N" dict with | Some (Pdf.Integer n) -> if n = 1 || n = 3 || n = 4 then n else raise Not_found | _ -> raise Not_found in let alternate = match Pdf.lookup_direct pdf "/Alternate" dict with | Some cs -> read_colourspace pdf resources cs | _ -> match n with | 1 -> DeviceGray | 3 -> DeviceRGB | 4 -> DeviceCMYK | _ -> assert false in let range = match Pdf.lookup_direct pdf "/Range" dict with | Some (Pdf.Array elts) when length elts = 2 * n -> Array.of_list (map (Pdf.getnum pdf) elts) | _ -> Array.of_list (flatten (many [0.; 1.] n)) in let metadata = Pdf.lookup_direct pdf "/Metadata" dict in ICCBased {icc_n = n; icc_alternate = alternate; icc_range = range; icc_metadata = metadata; icc_stream = stream} | _ -> raise Not_found end | Pdf.Array [Pdf.Name ("/Indexed" | "/I"); bse; hival; lookup_data] -> let hival = match hival with | Pdf.Integer h -> h | _ -> raise (Pdf.PDFError "Bad /Hival") in let bse = read_colourspace pdf resources bse in let mktable_rgb data = try let table = Hashtbl.create (hival + 1) in let i = Pdfio.input_of_bytes data in for x = 0 to hival do let r = i.input_byte () in let g = i.input_byte () in let b = i.input_byte () in Hashtbl.add table x [r; g; b] done; table with _ -> raise (Pdf.PDFError "Pdfspace: bad table") in let mktable_cmyk data = try let table = Hashtbl.create (hival + 1) in let i = Pdfio.input_of_bytes data in for x = 0 to hival do let c = i.input_byte () in let m = i.input_byte () in let y = i.input_byte () in let k = i.input_byte () in Hashtbl.add table x [c; m; y; k] done; table with _ -> raise (Pdf.PDFError "Pdfspace: bad table") in let table = begin match Pdf.direct pdf lookup_data with | (Pdf.Stream _) as stream -> Pdfcodec.decode_pdfstream pdf stream; begin match stream with | (Pdf.Stream {contents = (_, Pdf.Got data)}) -> begin match get_basic_table_colourspace bse with | DeviceCMYK -> mktable_cmyk data | DeviceRGB | CalRGB _ | Lab _ -> mktable_rgb data (* FIXME: We need to read all colourspaces here, except Pattern and Index, which aren't allowed. I think this just means grey - everything else is found through get_basic_table_colourspace. *) | Pattern | PatternWithBaseColourspace _ | Indexed (_, _) -> raise (Pdf.PDFError "Disallowed base colourspace in index colourspace") | _ -> raise (Pdf.PDFError "Unsupported base colourspace in index colourspace") end | _ -> raise (Pdf.PDFError "Indexed/Inconsistent") end | Pdf.String s -> let data = mkbytes (String.length s) in for x = 0 to bytes_size data - 1 do bset data x (int_of_char s.[x]) done; begin match get_basic_table_colourspace bse with | DeviceRGB | CalRGB _ | Lab _ -> mktable_rgb data (* FIXME: Same comment as above *) | DeviceCMYK -> mktable_cmyk data | Pattern | PatternWithBaseColourspace _ | Indexed (_, _) -> raise (Pdf.PDFError "Disallowed base colourspace in index colourspace") | _ -> raise (Pdf.PDFError "Unsupported base colourspace in index colourspace") end | _ -> raise (Pdf.PDFError ("PDFSpace: unknown indexed colourspace")) end in Indexed (bse, table) | Pdf.Array [Pdf.Name "/Separation"; Pdf.Name name; alternate; tint] -> let alt_space = read_colourspace pdf resources alternate in let tint_transform = Pdffun.parse_function pdf tint in Separation (name, alt_space, tint_transform) | Pdf.Array [Pdf.Name "/DeviceN"; Pdf.Array names; alternate; tint] -> let names = Array.of_list (map (function Pdf.Name s -> s | _ -> raise Not_found) names) in let alternate = read_colourspace pdf resources alternate in let tint = Pdffun.parse_function pdf tint in DeviceN (names, alternate, tint, Pdf.Dictionary []) | Pdf.Array [Pdf.Name "/DeviceN"; Pdf.Array names; alternate; tint; attributes] -> let names = Array.of_list (map (function Pdf.Name s -> s | _ -> raise Not_found) names) in let alternate = read_colourspace pdf resources alternate in let tint = Pdffun.parse_function pdf tint in DeviceN (names, alternate, tint, attributes) | _ -> raise Not_found (* Flatten a colourspace to pdf objects. Unfinished. *) let write_colourspace (pdf : Pdf.t) = function | DeviceGray -> Pdf.Name "/DeviceGray" | DeviceRGB -> Pdf.Name "/DeviceRGB" | DeviceCMYK -> Pdf.Name "/DeviceCMYK" | _ -> Pdfe.log "write_colourspace space not suppported\n"; Pdf.Null camlpdf-2.8.1/pdfspace.mli000066400000000000000000000023511477056064700154410ustar00rootroot00000000000000(** Colour Spaces *) (** A Tristimulus Point *) type point = float * float * float (** ICC Based Colour Spaces *) type iccbased = {icc_n : int; icc_alternate : t; icc_range : float array; icc_metadata : Pdf.pdfobject option; icc_stream : Pdf.pdfobject} (** Colour spaces *) and t = | DeviceGray | DeviceRGB | DeviceCMYK | CalGray of point * point * float (* White, Black, Gamma *) | CalRGB of point * point * float array * float array (* White, Black, Gamma, Matrix *) | Lab of point * point * float array (* White, Black, Range *) | ICCBased of iccbased | Indexed of t * (int, int list) Hashtbl.t (* Base colourspace, lookup table *) | Pattern | PatternWithBaseColourspace of t | Separation of string * t * Pdffun.t | DeviceN of string array * t * Pdffun.t * Pdf.pdfobject (** Produce a debug string *) val string_of_colourspace : t -> string (** Read the name of a colour, if it has one. *) val name_of_colourspace : t -> string option (** Read a colourspace from a PDF given a document, page resources dictionary and the colourspace object *) val read_colourspace : Pdf.t -> Pdf.pdfobject -> Pdf.pdfobject -> t (** Write a colourspace to a PDF, returning it. *) val write_colourspace : Pdf.t -> t -> Pdf.pdfobject camlpdf-2.8.1/pdfst.ml000066400000000000000000000331351477056064700146270ustar00rootroot00000000000000(** Operations on structure trees. *) open Pdfutil (* NB. This is very tightly integrated into pdfmerge.ml/pdfpage.ml with all sorts of phase-order intricacies. Beware. *) (* Future structure tree merging/trimming work: o Stamping with -stamp-on, -stamp-under, -combine-pages needs to renumber MCIDs on each page in some way. o What should we do with IDTree, RoleMap, ClassMap, Namespaces? Simple mechanisms work for all known examples, but known examples are few. o Do we need to resurrect nulling of references to deleted annots when trimming, for example, so they don't accidentally get included due to being referenced from the parent tree? This is not a correctness issue, but a space one. *) (* Recursion between modules *) let endpage = ref (fun _ -> 0) (* Remove any structure tree node (and therefore its children) which has a page number pointing to a page not to be included in the output. This should be a reasonable first approximation to the required behaviour. Pdfpage.pdf_of_pages immediately after making the copied PDF. *) let trim_structure_tree pdf range = let page_objnums_to_remove = let objnums = Pdf.page_reference_numbers pdf in map (fun x -> List.nth objnums (x - 1)) (setminus (ilist 1 (!endpage pdf)) range) in if page_objnums_to_remove = [] then () else (* Calculate initial deletions - any object with /Pg not in range. *) let del = ref [] in Pdf.objiter (fun n o -> match Pdf.direct pdf o with | Pdf.Dictionary d -> begin match List.assoc_opt "/Pg" d with | Some (Pdf.Indirect i) -> if mem i page_objnums_to_remove then del := n::!del | _ -> () end | _ -> ()) pdf; (* Any /K referencing these deleted objects is modifed to no longer reference it. *) let replaceobjs = ref [] in while !del <> [] || !replaceobjs <> [] do (*Printf.printf "Top of loop. %i to remove, %i to replace\n" (length (setify_large !del)) (length (setify_large !replaceobjs)); iter (fun x -> Printf.printf "Removing %s\n" (Pdfwrite.string_of_pdf (Pdf.lookup_obj pdf x))) (setify_large !del);*) iter (Pdf.removeobj pdf) (setify_large !del); del := []; (*iter (fun (x, y) -> Printf.printf "Replacing %s with\n %s\n" x y) (map (fun (n, r) -> (Pdfwrite.string_of_pdf (Pdf.lookup_obj pdf n), Pdfwrite.string_of_pdf r)) (setify_large !replaceobjs));*) iter (Pdf.addobj_given_num pdf) (setify_large !replaceobjs); replaceobjs := []; Pdf.objiter (fun n o -> let process objs = let survives = function | Pdf.Indirect i -> (* Must a) still exist in this file *) Pdf.lookup_obj pdf i <> Pdf.Null && (* b) not be an object reference dictionary or marked content reference dictionary referencing a /Pg which is to be deleted *) (* c) not be an object reference dictionary with a /Obj which is a deleted page *) begin match Pdf.indirect_number pdf "/Pg" (Pdf.Indirect i), Pdf.indirect_number pdf "/Obj" (Pdf.Indirect i) with | Some i, _ when mem i page_objnums_to_remove -> false | _, Some i when mem i page_objnums_to_remove -> false | _ -> true end | _ -> true in if List.for_all survives objs then None else Some (keep survives objs) in let process_indirect d is = begin match process is with | None -> () (* no change *) | Some [] -> (* empty not allowed - we must now delete this object *) del := n::!del | Some newlist -> (* update the value of /K and change the object in place *) begin match newlist with | [e] -> replaceobjs =| (n, Pdf.replace_dict_entry (Pdf.Dictionary d) "/K" e) | e::es -> replaceobjs =| (n, Pdf.replace_dict_entry (Pdf.Dictionary d) "/K" (Pdf.Array (e::es))) | _ -> assert false end end in match Pdf.direct pdf o with | Pdf.Dictionary d -> begin match List.assoc_opt "/K" d with | Some (Pdf.Integer _) -> () | Some (Pdf.Indirect i) -> process_indirect d [Pdf.Indirect i] | Some (Pdf.Array objs) -> process_indirect d objs | _ -> () (* /K can exist in transparency object, but is a boolean so ok. *) end | _ -> ()) pdf done (* Merge structure hierarchy / tagged PDF. Asterisked items will require further work when we find good examples. /IDTree name tree *merge /ParentTree number tree renumber and merge /ParentTreeNextKey integer remove /RoleMap dict *merge /ClassMap dict *merge /Namespaces array merge /PronunciationLexicon array concatenate /AF array concatenate /K structure tree merge trees *) let print_parent_tree = iter (fun (a, b) -> Printf.printf "%s -> %s\n" a (Pdfwrite.string_of_pdf b)) let renumber_parent_trees pdfs = if length pdfs = 1 then () else let parent_trees = map (fun pdf -> match Pdf.lookup_chain pdf pdf.Pdf.trailerdict ["/Root"; "/StructTreeRoot"; "/ParentTree"] with | Some t -> Pdftree.read_number_tree pdf t | None -> []) pdfs in (* iter2 (fun pt n -> Printf.printf "****************** PARENT TREE %i:\n" n; print_parent_tree pt) parent_trees (ilist 1 (length pdfs)); *) (* Calculate a renumbering mapping from (pdf number, parent tree number) to 0,1,2.... *) let num = ref 0 in let rs = Hashtbl.create 256 in iter2 (fun pt pdfn -> iter (fun (k, _) -> Hashtbl.add rs (pdfn, int_of_string k) !num; num += 1) pt) parent_trees (ilist 1 (length pdfs)); (* Process all /StructParent(s) dictionary entries to point to new /ParentTree entries. *) let replace_any_structparent n = function | ("/StructParent" | "/StructParents") as k, Pdf.Integer i -> begin match Hashtbl.find_opt rs (n, i) with | Some i' -> (k, Pdf.Integer i') | None -> (k, Pdf.Integer i) end | x -> x in let rec f n = function | Pdf.Dictionary d -> Pdf.recurse_dict (f n) (map (replace_any_structparent n) d) | Pdf.Array a -> Pdf.recurse_array (f n) a | Pdf.Stream {contents = (Pdf.Dictionary d, s)} -> Pdf.Stream {contents = (Pdf.recurse_dict (f n) (map (replace_any_structparent n) d), s)} | x -> x in iter2 (fun pdf n -> Pdf.objselfmap (f n) pdf) pdfs (ilist 1 (length pdfs)); (* Write the new parent tree to each file *) let renumbered_parent_trees = map2 (fun pt pdfnum -> map (fun (k, v) -> match Hashtbl.find_opt rs (pdfnum, int_of_string k) with Some k' -> (string_of_int k', v) | None -> assert false) pt) parent_trees (ilist 1 (length pdfs)) in (* iter2 (fun pt n -> Printf.printf "****************** FINAL PARENT TREE %i:\n" n; print_parent_tree pt) renumbered_parent_trees (ilist 1 (length pdfs)); *) iter2 (fun pdf renumbered -> match Pdf.lookup_chain pdf pdf.Pdf.trailerdict ["/Root"; "/StructTreeRoot"; "/ParentTree"] with | None -> () | Some t -> Pdf.replace_chain pdf ["/Root"; "/StructTreeRoot"; "/ParentTree"] (Pdftree.build_name_tree true pdf renumbered)) pdfs renumbered_parent_trees (*; (* Write the PDFs to file to check them *) iter2 (fun n pdf -> Pdfwrite.pdf_to_file pdf (string_of_int n ^ ".pdf")) (ilist 1 (length pdfs)) pdfs*) (* If add_toplevel_document is true, we add a PDF/UA-2 top-level /Document at the top of the structure tree. *) let merge_structure_trees ?(add_toplevel_document=false) pdf pdfs = let get_all struct_tree_roots pdf name = option_map (fun str -> Pdf.lookup_direct pdf name str) struct_tree_roots in let merge_dicts dicts = fold_left (fun d (k, v) -> Pdf.add_dict_entry d k v) (Pdf.Dictionary []) (flatten (setify (option_map (function | Pdf.Dictionary d -> Some d | _ -> Pdfe.log "merge_dicts: not a dict"; None) dicts))) in let merge_arrays arrays = Pdf.Array (flatten (setify (option_map (function | Pdf.Array a -> Some a | _ -> Pdfe.log "merge_array: not an array"; None) arrays))) in let mkarray = function | Pdf.Array a -> Pdf.Array a | x -> Pdf.Array [x] in let struct_tree_roots, struct_tree_objnums = split (option_map (fun pdf -> let catalog = Pdf.catalog_of_pdf pdf in match Pdf.lookup_direct pdf "/StructTreeRoot" catalog with | None -> None | Some str -> Some (str, match catalog with | Pdf.Dictionary d -> begin match lookup "/StructTreeRoot" d with Some (Pdf.Indirect i) -> i | _ -> 0 end | _ -> raise (Pdf.PDFError "merge_structure_hierarchy: bad catalog"))) pdfs) in match struct_tree_roots with | [] -> None | [x] -> Some (hd struct_tree_objnums) (* if only one, don't interfere, just preserve it. *) | _ -> let merged_idtree = Pdftree.merge_name_trees_no_clash pdf (get_all struct_tree_roots pdf "/IDTree") in let merged_parenttree = Pdftree.merge_number_trees_no_clash pdf (get_all struct_tree_roots pdf "/ParentTree") in let merged_rolemap = merge_dicts (get_all struct_tree_roots pdf "/RoleMap") in let merged_classmap = merge_dicts (get_all struct_tree_roots pdf "/ClassMap") in let merged_namespaces = merge_arrays (get_all struct_tree_roots pdf "/Namespaces") in let merged_pronunciation_lexicon = merge_arrays (get_all struct_tree_roots pdf "/PronunciationLexicon") in let merged_af = merge_arrays (get_all struct_tree_roots pdf "/AF") in let struct_tree_objnum = Pdf.addobj pdf Pdf.Null in let merged_k = (* 1. Get indirect references to each existing structure tree root object. They should be indirect, because /Ps will need to point up to them, but may not be - so if not indirect, keep direct. *) let existing_ks_of_struct_tree_roots_as_mostly_indirects = flatten (map (fun root -> match Pdf.lookup_immediate "/K" root with | Some (Pdf.Indirect i) -> [Pdf.Indirect i] | Some (Pdf.Array a) -> a | Some x -> [x] | None -> []) struct_tree_roots) in (* 2. Rewrite in-place each previous indirect struct tree root /K member to have a /P pointing up to the new struct tree root. *) mkarray (Pdf.Array (map (function | Pdf.Indirect i -> let d = Pdf.lookup_obj pdf i in Pdf.addobj_given_num pdf (i, Pdf.add_dict_entry d "/P" (Pdf.Indirect struct_tree_objnum)); Pdf.Indirect i | Pdf.Dictionary _ as d -> Pdf.add_dict_entry d "/P" (Pdf.Indirect struct_tree_objnum) | x -> x) existing_ks_of_struct_tree_roots_as_mostly_indirects)) in let optional n = function | Pdf.Dictionary [] -> [] | Pdf.Array [] -> [] | x -> [(n, Pdf.Indirect (Pdf.addobj pdf x))] in let standard_entries = ["/Type", Pdf.Name "/StructTreeRoot"] @ optional "/IDTree" merged_idtree @ optional "/ParentTree" merged_parenttree @ optional "/RoleMap" merged_rolemap @ optional "/ClassMap" merged_classmap @ optional "/PronunciationLexicon" merged_pronunciation_lexicon @ optional "/AF" merged_af in if add_toplevel_document then begin let merged_namespaces, pdf2_namespace_dictionary = let namespace_objnum = Pdf.addobj pdf (Pdf.Dictionary [("/NS", Pdf.String "http://iso.org/pdf2/ssn")]) in let merged_namespaces = match merged_namespaces with | Pdf.Array a -> Pdf.Array (Pdf.Indirect namespace_objnum::a) | x -> x in (merged_namespaces, namespace_objnum) in let top_level_objnum = Pdf.addobj pdf (Pdf.Dictionary [("/NS", Pdf.Indirect pdf2_namespace_dictionary); ("/S", Pdf.Name "/Document"); ("/P", Pdf.Indirect struct_tree_objnum); ("/K", merged_k)]) in let new_dict = Pdf.Dictionary (standard_entries @ optional "/Namespaces" merged_namespaces @ [("/K", Pdf.Indirect top_level_objnum)]) in Pdf.addobj_given_num pdf (struct_tree_objnum, new_dict); Some struct_tree_objnum end else begin let new_dict = Pdf.Dictionary (standard_entries @ optional "/Namespaces" merged_namespaces @ optional "/K" merged_k) in Pdf.addobj_given_num pdf (struct_tree_objnum, new_dict); Some struct_tree_objnum end camlpdf-2.8.1/pdfst.mli000066400000000000000000000013201477056064700147670ustar00rootroot00000000000000(** Structure trees *) (** Trim structure tree to remove parts marked as not in the page range given. *) val trim_structure_tree : Pdf.t -> int list -> unit (** Renumber parent trees in a list of PDFs so as not to clash when subsequently merged. *) val renumber_parent_trees : Pdf.t list -> unit (** Merge the structure tree given the part-merged PDF and list of original PDFs. Returns the object number of the new structure tree, if any. If ?add_toplevel_document is true (default false) a PDF/UA-2-style top-level /Document will be added to the structure tree. *) val merge_structure_trees : ?add_toplevel_document:bool -> Pdf.t -> Pdf.t list -> int option (**/**) val endpage : (Pdf.t -> int) ref camlpdf-2.8.1/pdfstandard14.ml000066400000000000000000000112651477056064700161460ustar00rootroot00000000000000(* The 14 Standard PDF Fonts (Widths and Kerns). *) open Pdfutil let read_afm afm = let decompressed = Pdfio.string_of_bytes (Pdfcodec.decode_flate (Pdfio.bytes_of_string afm)) in let headers, ws, ks, ws' = Pdfafm.read (Pdfio.input_of_string decompressed) in hashtable_of_dictionary headers, hashtable_of_dictionary ws, hashtable_of_dictionary (map (fun (c, c', k) -> (c, c'), k) ks), hashtable_of_dictionary ws' (* Main functions *) let tables = [Pdftext.TimesRoman, memoize (fun () -> read_afm (Pdfafmdata.times_roman_afm ())); Pdftext.TimesBold, memoize (fun () -> read_afm (Pdfafmdata.times_bold_afm ())); Pdftext.TimesItalic, memoize (fun () -> read_afm (Pdfafmdata.times_italic_afm ())); Pdftext.TimesBoldItalic, memoize (fun () -> read_afm (Pdfafmdata.times_bold_italic_afm ())); Pdftext.Helvetica, memoize (fun () -> read_afm (Pdfafmdata.helvetica_afm ())); Pdftext.HelveticaBold, memoize (fun () -> read_afm (Pdfafmdata.helvetica_bold_afm ())); Pdftext.HelveticaOblique, memoize (fun () -> read_afm (Pdfafmdata.helvetica_oblique_afm ())); Pdftext.HelveticaBoldOblique, memoize (fun () -> read_afm (Pdfafmdata.helvetica_bold_oblique_afm ())); Pdftext.Courier, memoize (fun () -> read_afm (Pdfafmdata.courier_afm ())); Pdftext.CourierBold, memoize (fun () -> read_afm (Pdfafmdata.courier_bold_afm ())); Pdftext.CourierOblique, memoize (fun () -> read_afm (Pdfafmdata.courier_oblique_afm ())); Pdftext.CourierBoldOblique, memoize (fun () -> read_afm (Pdfafmdata.courier_bold_oblique_afm ())); Pdftext.Symbol, memoize (fun () -> read_afm (Pdfafmdata.symbol_afm ())); Pdftext.ZapfDingbats, memoize (fun () -> read_afm (Pdfafmdata.zapf_dingbats_afm ()))] (* The height of a capital H divided by 2. Allows the text to be placed vertically aligned with its middle rather than baseline *) let baseline_adjustment = function | Pdftext.TimesRoman -> 662 / 2 | Pdftext.TimesBold -> 676 / 2 | Pdftext.TimesItalic -> 653 / 2 | Pdftext.TimesBoldItalic -> 669 / 2 | Pdftext.Helvetica -> 718 / 2 | Pdftext.HelveticaBold -> 718 / 2 | Pdftext.HelveticaOblique -> 718 / 2 | Pdftext.HelveticaBoldOblique -> 718 / 2 | Pdftext.Courier -> 562 / 2 | Pdftext.CourierBold -> 562 / 2 | Pdftext.CourierOblique -> 562 / 2 | Pdftext.CourierBoldOblique -> 562 / 2 | Pdftext.Symbol -> 673 / 2 (* Based on left paren, not H, since no CapHeight in afm file. *) | Pdftext.ZapfDingbats -> 705 / 2 (* Based on majority of characters, not H, since no CapHeight in afm file, *) (* Calculate the width of a list of characters, taking account of kerning. *) let find_kern kerns key = match tryfind kerns key with Some x -> x | None -> 0 (* Take character code --> character name --> width *) let find_width widths charname_to_width encoding encoding_table h = match encoding with | Pdftext.ImplicitInFontFile -> begin match tryfind widths h with Some x -> x | None -> 0 end | _ -> let charname = match tryfind encoding_table h with Some x -> x | None -> "/space" (* Really, a failure *) in match tryfind charname_to_width (implode (List.tl (explode charname))) with Some x -> x | None -> 0 (* Really, a failure *) let rec width dokern widths charname_to_width encoding encoding_table kerns = function | [] -> 0 | [h] -> find_width widths charname_to_width encoding encoding_table h | h::h'::t -> find_width widths charname_to_width encoding encoding_table h + (if dokern then find_kern kerns (h, h') else 0) + width dokern widths charname_to_width encoding encoding_table kerns (h'::t) (* The main function. Give a font and the text string. *) let textwidth dokern encoding f s = let _, widths, kerns, charname_to_width = lookup_failnull f tables () in let encoding_table = Pdftext.table_of_encoding encoding in width dokern widths charname_to_width encoding encoding_table kerns (map int_of_char (explode s)) (* Return the AFM table data itself *) let afm_data f = lookup_failnull f tables () (* StemV *) let stemv_of_standard_font = function Pdftext.TimesRoman -> 116 | Pdftext.TimesBold -> 122 | Pdftext.TimesItalic -> 105 | Pdftext.TimesBoldItalic -> 108 | Pdftext.Helvetica -> 114 | Pdftext.HelveticaBold -> 123 | Pdftext.HelveticaOblique -> 127 | Pdftext.HelveticaBoldOblique -> 136 | Pdftext.Courier -> 88 | Pdftext.CourierBold -> 93 | Pdftext.CourierOblique -> 100 | Pdftext.CourierBoldOblique -> 104 | Pdftext.Symbol -> 0 | Pdftext.ZapfDingbats -> 125 (* Flags *) let flags_of_standard_font = function Pdftext.Symbol -> 65541 | Pdftext.ZapfDingbats -> 4 | Pdftext.Courier | Pdftext.CourierBold | Pdftext.CourierOblique | Pdftext.CourierBoldOblique -> 33 | _ -> 32 camlpdf-2.8.1/pdfstandard14.mli000066400000000000000000000024151477056064700163140ustar00rootroot00000000000000(** Standard PDF Fonts *) (** Calculate the width, in millipoints, of a string in the given font, taking into account kerning if the first argument is true. *) val textwidth : bool -> Pdftext.encoding -> Pdftext.standard_font -> string -> int (** The appropriate amount to subtract from the y-coordinate of a 1pt text line to place it vertically centered around the y coordinate, rather than with the baseline at that y coordinate. *) val baseline_adjustment : Pdftext.standard_font -> int (** The data extracted from the font AFM. This is a 4-tuple, consisting of a table of header pairs, a table of (character number, width) pairs, a table of (first, second, kern) triples representing the kerning table and a table of (character name, width) pairs. The last table is useful for characters which are identified with a custom encoding and which might not be assigned a number in the standard encoding. *) val afm_data : Pdftext.standard_font -> (string, string) Hashtbl.t * (int, int) Hashtbl.t * (int * int, int) Hashtbl.t * (string, int) Hashtbl.t (** Return a suitable StemV value for a standard font *) val stemv_of_standard_font : Pdftext.standard_font -> int (** Return a suitable flags value for a standard font *) val flags_of_standard_font : Pdftext.standard_font -> int camlpdf-2.8.1/pdftext.ml000066400000000000000000001155251477056064700151710ustar00rootroot00000000000000(* Reading and writing text *) open Pdfutil open Pdfio (* Type 3 Specific Glyph Data *) type type3_glpyhs = {fontbbox : float * float * float * float; fontmatrix : Pdftransform.transform_matrix; charprocs : (string * Pdf.pdfobject) list; type3_resources : Pdf.pdfobject} (* A font is either one of the standard 14 fonts, a simple font, or.. *) type simple_fonttype = | Type1 | MMType1 | Type3 of type3_glpyhs | Truetype type fontmetrics = float array (*r widths of glyphs 0..255 *) (* The fontfile is an indirect reference into the document, rather than a PDFobject itself. This preserves polymorphic equality (a pdfobject can contain functional values *) type fontfile = | FontFile of int | FontFile2 of int | FontFile3 of int type fontdescriptor = {ascent : float; descent : float; avgwidth : float; maxwidth : float; flags : int; fontbbox: float * float * float * float; italicangle : float; capheight : float; xheight : float; stemv : float; fontfile : fontfile option; charset : string list option; tounicode : (int, string) Hashtbl.t option} (* Hack. Hide tounicode in fontdescriptor, because no space at top level *) type differences = (string * int) list type encoding = | ImplicitInFontFile | StandardEncoding | MacRomanEncoding | WinAnsiEncoding | MacExpertEncoding | CustomEncoding of encoding * differences | FillUndefinedWithStandard of encoding type simple_font = {fonttype : simple_fonttype; basefont : string; firstchar : int; lastchar : int; widths : int array; fontdescriptor : fontdescriptor option; fontmetrics : fontmetrics option; encoding : encoding} type standard_font = | TimesRoman | TimesBold | TimesItalic | TimesBoldItalic | Helvetica | HelveticaBold | HelveticaOblique | HelveticaBoldOblique | Courier | CourierBold | CourierOblique | CourierBoldOblique | Symbol | ZapfDingbats let string_of_standard_font = function | TimesRoman -> "Times-Roman" | TimesBold -> "Times-Bold" | TimesItalic -> "Times-Italic" | TimesBoldItalic -> "Times-BoldItalic" | Helvetica -> "Helvetica" | HelveticaBold -> "Helvetica-Bold" | HelveticaOblique -> "Helvetica-Oblique" | HelveticaBoldOblique -> "Helvetica-BoldOblique" | Courier -> "Courier" | CourierBold -> "Courier-Bold" | CourierOblique -> "Courier-Oblique" | CourierBoldOblique -> "Courier-BoldOblique" | Symbol -> "Symbol" | ZapfDingbats -> "ZapfDingbats" type cid_system_info = {registry : string; ordering : string; supplement : int} type composite_CIDfont = {cid_system_info : cid_system_info; cid_basefont : string; cid_fontdescriptor : fontdescriptor; cid_widths : (int * float) list; cid_default_width : int} type cmap_encoding = | Predefined of string | CMap of int (* indirect reference to CMap stream *) type font = | StandardFont of standard_font * encoding | SimpleFont of simple_font | CIDKeyedFont of string * composite_CIDfont * cmap_encoding (* string is top-level basefont *) (* For Debug *) let string_of_fonttype = function | Type1 -> "Type 1" | MMType1 -> "MM Type 1" | Type3 {charprocs = charprocs} -> "Type 3: charprocs for" ^ fold_left ( ^ ) "" (map (function (s, _) -> s) charprocs) | Truetype -> "Truetype" let rec string_of_encoding = function | ImplicitInFontFile -> "ImplicitInFontFile" | StandardEncoding -> "StandardEncoding" | MacRomanEncoding -> "MacRomanEncoding" | WinAnsiEncoding -> "WinAnsiEncoding" | MacExpertEncoding -> "MacExpertEncoding" | CustomEncoding (enc, diff) -> Printf.sprintf "CustomEncoding with base %s and differences %s" (string_of_encoding enc) (fold_left ( ^ ) "" (map (function (name, code) -> Printf.sprintf "%i -> %s, " code name) diff)) | FillUndefinedWithStandard enc -> Printf.sprintf "FillUndefinedWithStandard %s" (string_of_encoding enc) let string_of_simple_font font = "fonttype = " ^ string_of_fonttype font.fonttype ^ "\n" ^ "basefont " ^ font.basefont ^ "\n" ^ "encoding is " ^ string_of_encoding font.encoding ^ "\n" let string_of_font = function | StandardFont (s, _) -> "StandardFont " ^ string_of_standard_font s | SimpleFont s -> "SimpleFont " ^ string_of_simple_font s | CIDKeyedFont (s, _, _) -> "CIDKeyedFont " ^ s let read_type3_data pdf font = {fontbbox = (let obj = Pdf.lookup_fail "No fontbbox" pdf "/FontBBox" font in Pdf.parse_rectangle pdf obj); fontmatrix = Pdf.parse_matrix pdf "/FontMatrix" font; charprocs = (match Pdf.lookup_fail "Bad Charprocs" pdf "/CharProcs" font with | Pdf.Dictionary l -> l | _ -> raise (Pdf.PDFError "Bad charprocs")); type3_resources = (match Pdf.lookup_direct pdf "/Resources" font with | None -> Pdf.Dictionary [] | Some d -> d)} let simple_fonttype_of_string pdf font = function | "/Type1" -> Some Type1 | "/MMType1" -> Some MMType1 | "/Type3" -> Some (Type3 (read_type3_data pdf font)) | "/TrueType" -> Some Truetype | _ -> None let read_basefont pdf font = match Pdf.lookup_direct pdf "/BaseFont" font with | Some (Pdf.Name n) -> n | _ -> "" let parse_charset s = let i = Pdfio.input_of_string s in let gs = ref [] in try while true do Pdfread.dropwhite i; begin match Pdfread.lex_name i with | Pdfgenlex.LexName s -> if s = "/" then raise Exit else gs := s::!gs | _ -> raise Exit end done; [] with _ -> rev !gs let read_fontdescriptor pdf font = match Pdf.lookup_direct pdf "/FontDescriptor" font with | None -> None | Some fontdescriptor -> let ascent = match Pdf.lookup_direct pdf "/Ascent" fontdescriptor with | Some x -> Pdf.getnum pdf x | None -> 0. in let descent = match Pdf.lookup_direct pdf "/Descent" fontdescriptor with | Some x -> Pdf.getnum pdf x | None -> 0. in let avgwidth = match Pdf.lookup_direct pdf "/AvgWidth" fontdescriptor with | Some x -> Pdf.getnum pdf x | None -> 0. in let maxwidth = match Pdf.lookup_direct pdf "/MaxWidth" fontdescriptor with | Some x -> Pdf.getnum pdf x | None -> 0. in let fontfile = match Pdf.find_indirect "/FontFile" fontdescriptor with | Some i -> Some (FontFile i) | None -> match Pdf.find_indirect "/FontFile2" fontdescriptor with | Some i -> Some (FontFile2 i) | None -> match Pdf.find_indirect "/FontFile3" fontdescriptor with | Some i -> Some (FontFile3 i) | None -> None in let charset = match Pdf.lookup_direct pdf "/CharSet" fontdescriptor with | Some (Pdf.String s) -> Some (parse_charset s) | _ -> None in Some {ascent = ascent; descent = descent; avgwidth = avgwidth; maxwidth = maxwidth; fontfile = fontfile; charset = charset; flags = 0; fontbbox = (0., 0., 0., 0.); italicangle = 0.; capheight = 0.; xheight = 0.; stemv = 0.; tounicode = None} (* Read the widths from a font. Normally in the font descriptor, but in Type3 fonts at the top level. *) let read_metrics pdf font = let fontdescriptor = match Pdf.lookup_direct pdf "/Subtype" font with | Some (Pdf.Name "/Type3") -> Some font | _ -> Pdf.lookup_direct pdf "/FontDescriptor" font in match fontdescriptor with | None -> None | Some fontdescriptor -> let firstchar = match Pdf.lookup_direct pdf "/FirstChar" font with | Some (Pdf.Integer i) -> if i <= 255 && i >= 0 then i else raise (Pdf.PDFError "Bad /Firstchar") | _ -> raise (Pdf.PDFError "No /FirstChar") in let lastchar = match Pdf.lookup_direct pdf "/LastChar" font with | Some (Pdf.Integer i) -> if i <= 255 && i >= 0 then i else raise (Pdf.PDFError "Bad /Lastchar") | _ -> raise (Pdf.PDFError "No /LastChar") in let missingwidth = match Pdf.lookup_direct pdf "/MissingWidth" fontdescriptor with | Some (Pdf.Integer w) -> float w | Some (Pdf.Real w) -> w | _ -> 0. in let elts = match Pdf.lookup_direct pdf "/Widths" font with | Some (Pdf.Array elts) -> elts | _ -> raise (Pdf.PDFError "No /Widths") in if length elts <> lastchar - firstchar + 1 then raise (Pdf.PDFError "Bad /Widths") else let before = many missingwidth firstchar in let given = map (fun elt -> match Pdf.direct pdf elt with | Pdf.Integer i -> float i | Pdf.Real f -> f | _ -> raise (Pdf.PDFError "Bad /Width entry")) elts in let after = many missingwidth (255 - lastchar) in Some (Array.of_list (before @ given @ after)) (* Parse a /Differences entry to get a list of (name, number) pairs *) let pairs_of_differences pdf differences = let rec groups_of_differences prev elts = match elts with | [] -> prev | Pdf.Integer n::rest -> let stripname = function Pdf.Name n -> n | _ -> assert false in let names, more = cleavewhile (function Pdf.Name _ -> true | _ -> false) rest in groups_of_differences ((n, map stripname names)::prev) more | _ -> raise (Pdf.PDFError "Malformed /Differences") and mappings_of_group (x, es) = let additions = ilist 0 (length es - 1) in map2 (fun e a -> (x + a, e)) es additions in match differences with | Pdf.Array elts -> let direct_elements = map (Pdf.direct pdf) elts in let groups = groups_of_differences [] direct_elements in map (fun (k, v) -> (v, k)) (flatten (map mappings_of_group groups)) | _ -> raise (Pdf.PDFError "Bad /Differences") let standard_font_of_name = function | "/Times-Roman" | "/TimesNewRoman" -> Some TimesRoman | "/Times-Bold" | "/TimesNewRoman,Bold" -> Some TimesBold | "/Times-Italic" | "/TimesNewRoman,Italic" -> Some TimesItalic | "/Times-BoldItalic" | "/TimesNewRoman,BoldItalic" -> Some TimesBoldItalic | "/Helvetica" | "/Arial" -> Some Helvetica | "/Helvetica-Bold" | "/Arial,Bold" -> Some HelveticaBold | "/Helvetica-Oblique" | "/Arial,Italic" -> Some HelveticaOblique | "/Helvetica-BoldOblique" | "/Arial,BoldItalic" -> Some HelveticaBoldOblique | "/Courier" | "/CourierNew" -> Some Courier | "/Courier-Bold" | "/CourierNew,Bold" -> Some CourierBold | "/Courier-Oblique" | "/CourierNew,Italic" -> Some CourierOblique | "/Courier-BoldOblique" | "/CourierNew,BoldItalic" -> Some CourierBoldOblique | "/Symbol" -> Some Symbol | "/ZapfDingbats" -> Some ZapfDingbats | _ -> None (* Predicate: is it a standard 14 font? If it's been overriden (contains widths etc, we treat it as a simple font. *) let is_standard14font pdf font = match Pdf.lookup_direct pdf "/Subtype" font with | Some (Pdf.Name "/Type1") -> begin match Pdf.lookup_direct pdf "/BaseFont" font with | Some (Pdf.Name name) -> begin match standard_font_of_name name with | None -> false | Some _ -> (* Check to see if it's been overriden *) match Pdf.lookup_direct pdf "/Widths" font with | None -> true | _ -> false end | _ -> false end | _ -> false (* Is a font embedded in the document? *) let is_embedded pdf font = match Pdf.lookup_direct pdf "/FontDescriptor" font with | None -> false | Some fontdescriptor -> match Pdf.lookup_direct_orelse pdf "/FontFile" "/FontFile2" fontdescriptor with | Some _ -> true | None -> match Pdf.lookup_direct pdf "/FontFile3" fontdescriptor with | Some _ -> true | None -> false (* Is a font symbolic? (Doesn't deal with standard 14 Zapf and Symbol) *) let is_symbolic pdf font = match Pdf.lookup_direct pdf "/FontDescriptor" font with | None -> false | Some fontdescriptor -> match Pdf.lookup_direct pdf "/Flags" fontdescriptor with | Some (Pdf.Integer flags) -> flags land (1 lsl 3) > 0 | _ -> raise (Pdf.PDFError "No /Flags in font descriptor") (* For now, not for truetype fonts: add pg 399-401 later. Need to clarify what happens if a standard-14 font is overriden. *) let read_encoding pdf font = match Pdf.lookup_direct pdf "/Encoding" font with | Some (Pdf.Name "/MacRomanEncoding") -> MacRomanEncoding | Some (Pdf.Name "/MacExpertEncoding") -> MacExpertEncoding | Some (Pdf.Name "/WinAnsiEncoding") -> WinAnsiEncoding | Some (Pdf.Dictionary _ as encdict) -> begin match Pdf.lookup_direct pdf "/Subtype" font with | Some (Pdf.Name (("/Type1" | "/MMType1" | "/Type3" | "/TrueType") as fonttype)) -> let encoding = let base_encoding = match Pdf.lookup_direct pdf "/BaseEncoding" encdict with | Some (Pdf.Name "/MacRomanEncoding") -> MacRomanEncoding | Some (Pdf.Name "/MacExpertEncoding") -> MacExpertEncoding | Some (Pdf.Name "/WinAnsiEncoding") -> WinAnsiEncoding | None -> if is_embedded pdf font then ImplicitInFontFile else if is_symbolic pdf font then ImplicitInFontFile else StandardEncoding | _ -> raise (Pdf.PDFError "unknown /BaseEncoding") in begin match Pdf.lookup_direct pdf "/Differences" encdict with | Some differences -> CustomEncoding (base_encoding, pairs_of_differences pdf differences) | _ -> base_encoding end in if fonttype = "/Truetype" then FillUndefinedWithStandard encoding else encoding | _ -> raise (Pdf.PDFError "Bad font /Subtype") end | _ -> ImplicitInFontFile let read_simple_font pdf font = match Pdf.lookup_direct pdf "/Subtype" font with | Some (Pdf.Name n) -> begin match simple_fonttype_of_string pdf font n with | Some fonttype -> let fontdescriptor = read_fontdescriptor pdf font in let fontmetrics = read_metrics pdf font in SimpleFont {fonttype = fonttype; basefont = read_basefont pdf font; fontmetrics; firstchar = 0; lastchar = 0; widths = [||]; fontdescriptor = fontdescriptor; encoding = read_encoding pdf font} | None -> raise (Pdf.PDFError "Not a simple font") end | _ -> raise (Pdf.PDFError "No font /Subtype") (* Read a base 14 font *) let read_standard14font pdf font = match Pdf.lookup_direct pdf "/BaseFont" font with | Some (Pdf.Name name) -> begin match standard_font_of_name name with | None -> raise (Pdf.PDFError "Not a base 14 font") | Some f -> StandardFont (f, read_encoding pdf font) end | _ -> raise (Pdf.PDFError "Bad base 14 font") (* Predicate: is it a simple font, assuming it's not a standard 14 font. *) let is_simple_font pdf font = match Pdf.lookup_direct pdf "/Subtype" font with | Some (Pdf.Name ("/Type1" | "/MMType1" | "/Type3" | "/TrueType")) -> true | _ -> false (* Predicate: is it a CIDKeyed font? *) let is_cidkeyed_font pdf font = match Pdf.lookup_direct pdf "/Subtype" font with | Some (Pdf.Name "/Type0") -> true | _ -> false (* Read a CID system info dictionary *) let read_cid_system_info pdf dict = {registry = begin match Pdf.lookup_direct pdf "/Registry" dict with | Some (Pdf.String s) -> s | _ -> raise (Pdf.PDFError "No /Registry") end; ordering = begin match Pdf.lookup_direct pdf "/Ordering" dict with | Some (Pdf.String s) -> s | _ -> raise (Pdf.PDFError "No /Ordering") end; supplement = begin match Pdf.lookup_direct pdf "/Supplement" dict with | Some (Pdf.Integer i) -> i | _ -> raise (Pdf.PDFError "No /Supplement") end} (* This returns the explicit pairs, which need to be combined with the default value to look a width up. *) let rec read_cid_widths = function | Pdf.Integer c::Pdf.Array ws::more -> let nums = map (function | Pdf.Integer i -> float i | Pdf.Real r -> r | _ -> raise (Pdf.PDFError "Bad /W array")) ws in combine (indxn c nums) nums @ read_cid_widths more | Pdf.Integer c_first::Pdf.Integer c_last::w::more -> let w = match w with | Pdf.Integer i -> float i | Pdf.Real r -> r | _ -> raise (Pdf.PDFError "Bad /W array") in if c_last < c_first then raise (Pdf.PDFError "Bad /W array") else let pairs = combine (ilist c_first c_last) (many w (c_last - c_first + 1)) in pairs @ read_cid_widths more | [] -> [] | _ -> raise (Pdf.PDFError "Malformed /W in CIDfont") (* Read a composite CID font *) (* FIXME: Doesn't support vertical modes (DW2 / W2) *) let read_descendant pdf dict = let cid_system_info = match Pdf.lookup_direct pdf "/CIDSystemInfo" dict with | Some cid_dict -> read_cid_system_info pdf cid_dict | None -> raise (Pdf.PDFError "No CIDSystemInfo") in let cid_basefont = match Pdf.lookup_direct pdf "/BaseFont" dict with | Some (Pdf.Name n) -> n | _ -> raise (Pdf.PDFError "No /BaseFont") in let cid_fontdescriptor = match read_fontdescriptor pdf dict with | Some f -> f | None -> raise (Pdf.PDFError "No FontDescriptor in CIDkeyed font") in let cid_widths = match Pdf.lookup_direct pdf "/W" dict with | Some (Pdf.Array ws) -> read_cid_widths ws | _ -> [] in let default_width = match Pdf.lookup_direct pdf "/DW" dict with | Some (Pdf.Integer d) -> d | _ -> 1000 in {cid_system_info = cid_system_info; cid_basefont = cid_basefont; cid_fontdescriptor = cid_fontdescriptor; cid_widths = cid_widths; cid_default_width = default_width} (* Read a CIDKeyed (Type 0) font *) let read_cidkeyed_font pdf font = let basefont = match Pdf.lookup_direct pdf "/BaseFont" font with | Some (Pdf.Name b) -> b | _ -> raise (Pdf.PDFError "Bad /BaseFont") in let composite_CIDfont = match Pdf.lookup_direct pdf "/DescendantFonts" font with | Some (Pdf.Array [e]) -> read_descendant pdf (Pdf.direct pdf e) | _ -> raise (Pdf.PDFError "Bad descendant font") in let encoding = match Pdf.lookup_direct pdf "/Encoding" font with | Some (Pdf.Name e) -> Predefined e | Some (Pdf.Stream _) -> begin match Pdf.find_indirect "/Encoding" font with | Some n -> CMap n | None -> raise (Pdf.PDFError "malformed /Encoding") end | _ -> raise (Pdf.PDFError "malformed or missing /Encoding") in CIDKeyedFont (basefont, composite_CIDfont, encoding) (* We didn't originally parse the /ToUnicode when reading the font, but we should have. The hack now is to hide the parsed /ToUnicode hash table in the fontdescriptor. To avoid complicated code, we read the font as normal, then read the /ToUnicode, and insert it into the Font descriptor. *) let add_tounicode pdf font fontdict = let tounicode = match Pdf.lookup_direct pdf "/ToUnicode" fontdict with | Some tounicode -> begin try Some (hashtable_of_dictionary <| (Pdfcmap.parse_cmap pdf tounicode).map) with e -> Pdfe.log (Printf.sprintf "bad tounicode (%s)\n" (Printexc.to_string e)); None end | None -> None in match font with | SimpleFont ({fontdescriptor = Some fd} as r) -> SimpleFont {r with fontdescriptor = Some {fd with tounicode}} | SimpleFont ({fontdescriptor = None} as r) -> SimpleFont {r with fontdescriptor = (* fabricate one. ok? fix somehow in future... *) Some {ascent = 0.; descent = 0.; avgwidth = 0.; maxwidth = 0.; fontfile = None; charset = None; flags = 0; fontbbox = (0., 0., 0., 0.); italicangle = 0. ; capheight = 0.; xheight = 0.; stemv = 0.; tounicode}} | CIDKeyedFont (a, ({cid_fontdescriptor} as r), c) -> CIDKeyedFont (a, {r with cid_fontdescriptor = {r.cid_fontdescriptor with tounicode}}, c) | x -> x let find_tounicode = function | SimpleFont {fontdescriptor = Some {tounicode}} | CIDKeyedFont (_, {cid_fontdescriptor = {tounicode}}, _) -> tounicode | _ -> None (* Reads a font *) let read_font pdf fontdict = let without_tounicode = if is_standard14font pdf fontdict then read_standard14font pdf fontdict else if is_simple_font pdf fontdict then read_simple_font pdf fontdict else if is_cidkeyed_font pdf fontdict then read_cidkeyed_font pdf fontdict else raise (Pdf.PDFError "Unknown font type") in add_tounicode pdf without_tounicode fontdict let make_font fontname encoding = Pdf.Dictionary [("/Type", Pdf.Name "/Font"); ("/Subtype", Pdf.Name "/Type1"); ("/Encoding", Pdf.Name ("/" ^ string_of_encoding encoding)); ("/BaseFont", Pdf.Name ("/" ^ fontname))] let write_encoding pdf = function | CustomEncoding (ImplicitInFontFile, diffs) -> let diffarray = Pdf.Array (flatten (map (function (name, number) -> [Pdf.Integer number; Pdf.Name name]) diffs)) in let encodingdict = Pdf.Dictionary [("/Type", Pdf.Name "/Encoding"); ("/Differences", diffarray)] in Pdf.addobj pdf encodingdict | _ -> raise (Pdf.PDFError "write_encoding: not supported") let tounicode_preamble = "/CIDInit /ProcSet findresource begin\n\ 12 dict begin\n\ begincmap\n\ /CIDSystemInfo <<\n\ /Registry (Adobe)\n\ /Ordering (UCS)\n\ /Supplement 0\n\ >> def\n\ /CMapName /Adobe-Identity-UCS def\n\ /CMapType 2 def\n\ 1 begincodespacerange\n\ <00>\n\ endcodespacerange\n" let tounicode_postamble = "endbfrange\n\ endcmap\n\ CMapName currentdict /CMap defineresource pop\n\ end\n\ end\n" let hex u = let b = Buffer.create 32 in String.iter (fun x -> Buffer.add_string b (Printf.sprintf "%02X" (int_of_char x))) u; Buffer.contents b let tounicode_map s us = let b = Buffer.create 1024 in let s = ref s in Buffer.add_string b tounicode_preamble; Buffer.add_string b (Printf.sprintf "%i beginbfrange\n" (length us)); iter (fun u -> Buffer.add_string b (Printf.sprintf "<%02x><%02x><%s>\n" !s !s (hex u)); s := !s + 1) us; Buffer.add_string b tounicode_postamble; bytes_of_string (Buffer.contents b) (* Just for the kind produced by the font subsetter for now. *) let write_tounicode pdf u = let bytes = tounicode_map 33 (map (fun (_, s) -> s) (sort compare ((list_of_hashtbl u)))) in Pdf.addobj pdf (Pdf.Stream {contents = (Pdf.Dictionary [("/Length", Pdf.Integer (bytes_size bytes))], Pdf.Got bytes)}) let write_font ?objnum pdf = function | SimpleFont {fonttype = Type3 {fontbbox = fontbbox; fontmatrix = fontmatrix; charprocs = charprocs}; encoding = encoding; fontdescriptor = Some fontdescriptor} -> let encoding_entry = match encoding with | ImplicitInFontFile -> [] | _ -> [("/Encoding", Pdf.Indirect (write_encoding pdf encoding))] in let dict = Pdf.Dictionary ([("/Type", Pdf.Name "/Font"); ("/Subtype", Pdf.Name "/Type3"); ("/FontBBox", Pdf.Array [Pdf.Real 0.; Pdf.Real 0.; Pdf.Real 0.; Pdf.Real 0.]); ("/FontMatrix", Pdf.Array [Pdf.Real 0.; Pdf.Real 0.; Pdf.Real 0.; Pdf.Real 0.; Pdf.Real 0.; Pdf.Real 0.]); ("/CharProcs", Pdf.Dictionary (map (fun (s, _) -> (s, Pdf.Null)) charprocs)); ("/FirstChar", Pdf.Integer 0); ("/LastChar", Pdf.Integer 0); ("/Widths", Pdf.Array [Pdf.Real 0.])] @ encoding_entry) in Pdf.addobj pdf dict | SimpleFont (* This case is for TrueType fonts embedded by cpdf *) {fonttype = Truetype; basefont; firstchar; lastchar; widths; fontdescriptor = Some {ascent; descent; avgwidth; maxwidth; flags; fontbbox = (minx, miny, maxx, maxy); italicangle; capheight; xheight; stemv; fontfile = Some (FontFile2 ttf); tounicode}; encoding} -> let fontdescriptor = Pdf.Dictionary [("/Type", Pdf.Name "/FontDescriptor"); ("/FontName", Pdf.Name basefont); ("/Flags", Pdf.Integer flags); ("/FontBBox", Pdf.Array [Pdf.Integer (int_of_float minx); Pdf.Integer (int_of_float miny); Pdf.Integer (int_of_float maxx); Pdf.Integer (int_of_float maxy)]); ("/ItalicAngle", Pdf.Integer (int_of_float italicangle)); ("/Ascent", Pdf.Integer (int_of_float ascent)); ("/Descent", Pdf.Integer (int_of_float descent)); ("/CapHeight", Pdf.Integer (int_of_float capheight)); ("/StemV", Pdf.Integer (int_of_float stemv)); ("/XHeight", Pdf.Integer (int_of_float xheight)); ("/AvgWidth", Pdf.Integer (int_of_float avgwidth)); ("/MaxWidth", Pdf.Integer (int_of_float maxwidth)); ("/FontFile2", Pdf.Indirect ttf)] in let fontdesc_num = Pdf.addobj pdf fontdescriptor in let font = Pdf.Dictionary ([("/Type", Pdf.Name "/Font"); ("/Subtype", Pdf.Name "/TrueType"); ("/BaseFont", Pdf.Name basefont); ("/FontDescriptor", Pdf.Indirect fontdesc_num); ("/FirstChar", Pdf.Integer firstchar); ("/LastChar", Pdf.Integer lastchar); ("/Widths", Pdf.Array (map (fun i -> Pdf.Integer i) (Array.to_list widths)))] @ (match tounicode with | None -> [("/Encoding", Pdf.Name ("/" ^ string_of_encoding encoding))] | Some u -> [("/ToUnicode", Pdf.Indirect (write_tounicode pdf u))])) in begin match objnum with | None -> Pdf.addobj pdf font | Some o -> Pdf.addobj_given_num pdf (o, font); o end | StandardFont (standard_font, encoding) -> Pdf.addobj pdf (make_font (string_of_standard_font standard_font) encoding) | _ -> raise (Pdf.PDFError "Pdftext.write_font does not support this font") (* Extracting of Text *) (* A text extractor takes a character and returns a decoded PDF codepoint, a glyphname, and a list of unicode codepoints. This may have to be extended when we deal with composite fonts. *) type text_extractor = {convert: int -> string * int list; (* Glyph name, List of unicode codepoints *) font: font} (* Encode utf16be *) let utf16be_of_codepoint u = if u < 0 || u > 0x10FFFF then raise (Invalid_argument "utf16be_of_codepoints") else (* Two bytes, bottom one first *) let bytes_of_double x = [x lsr 8; x land 255] in if u < 0x10000 then bytes_of_double u else let u' = u - 0x10000 in let w1 = 0xD800 in let w2 = 0xDC00 in let w1 = w1 lor (u' lsr 10) in let w2 = w2 lor (u' land 0b1111111111) in bytes_of_double w1 @ bytes_of_double w2 let utf16be_of_codepoints l = implode (['\254'; '\255'] @ map char_of_int (flatten (map utf16be_of_codepoint l))) (* Return a list of codepoints from a UTF-16BE string. See RFC2871 *) let fail2 () = raise (Invalid_argument "codepoints_of_utf16be") let rec codepoints_of_utf16be_inner prev = function | [] -> rev prev | [w1] -> fail2 () | [w1a; w1b] -> let w1 = (w1a lsl 8) lor w1b in if w1 < 0xD800 || w1 > 0xDFFF then codepoints_of_utf16be_inner (w1::prev) [] else fail2 () | [_; _; _] -> fail2 () | w1a::w1b::w2a::w2b::more -> let w1 = (w1a lsl 8) lor w1b in if w1 < 0xD800 || w1 > 0xDFFF then codepoints_of_utf16be_inner (w1::prev) (w2a::w2b::more) else if w1 >= 0xD800 && w1 <= 0xDBFF then let w2 = (w2a lsl 8) lor w2b in if w2 >= 0xDC00 && w2 <= 0xDFFF then let ho = w1 land 0b1111111111 in let lo = w2 lsr 6 in codepoints_of_utf16be_inner ((((ho lsl 10) lor lo) + 0x10000)::prev) more else fail2 () else fail2 () let codepoints_of_utf16be str = codepoints_of_utf16be_inner [] (map int_of_char (explode str)) (* Build a hashtable for lookups based on an encoding *) let rec add_encoding addvals = function | ImplicitInFontFile -> () | StandardEncoding -> addvals Pdfglyphlist.name_to_standard | MacRomanEncoding -> addvals Pdfglyphlist.name_to_macroman | WinAnsiEncoding -> addvals Pdfglyphlist.name_to_win | MacExpertEncoding -> addvals Pdfglyphlist.name_to_macexpert | CustomEncoding (e, ds) -> add_encoding addvals e; addvals ds | FillUndefinedWithStandard e -> addvals Pdfglyphlist.name_to_standard; add_encoding addvals e let table_of_encoding encoding = (*flprint "\nTABLE_OF_ENCODING: encoding is:\n"; flprint (string_of_encoding encoding); flprint "\nEND OF ENCODING\n";*) let table = Hashtbl.create 203 in let addvals = iter (fun (k, v) -> Hashtbl.add table v k) in add_encoding addvals encoding; (*Printf.printf "table_of_encoding: built %i-sized table\n" (Hashtbl.length table); Hashtbl.iter (fun k v -> Printf.printf "%i -> %s, " k v) table; flprint "\n";*) table let reverse_table_of_encoding encoding = let table = Hashtbl.create 203 in let addvals = iter (fun (k, v) -> Hashtbl.add table k v) in add_encoding addvals encoding; table (* Method: 1. If there's a /ToUnicode CMap, use it. 2. If it is a standard 14 or simple font, use the encoding to get a glyph name, then look up the character in the glyph list. 3. If it's a CID font, which we don't understand, just return. The font here is the PDF font structure, not our font data type. If we need to parse it, we do. FIXME: InlineImages2.pdf - Acrobat can extract text, why can't we? *) let text_extractor_of_font_real font = {convert = (let encoding = match font with | StandardFont (_, e) -> e | SimpleFont {encoding = e} -> e | _ -> ImplicitInFontFile (* No support *) in let table = table_of_encoding encoding in let tounicode_table, use_tounicode = match find_tounicode font with | Some tu -> tu, true | None -> null_hash (), false in if use_tounicode then function i -> try begin try "/" ^ Hashtbl.find tounicode_table i with Not_found -> ".notdef" end, codepoints_of_utf16be (Hashtbl.find tounicode_table i) with _ -> (* Failed *) (".notdef", [i]) else function i -> try let decoded = Hashtbl.find table i in try let codepoints = Hashtbl.find (Pdfglyphlist.glyph_hashes ()) decoded in decoded, codepoints with _ -> ("/" ^ decoded, [i]) with _ -> (* Failed *) (".notdef", [i])); font} let text_extractor_of_font pdf fontdict = let font = read_font pdf fontdict in text_extractor_of_font_real font (* For now, the only composite font encoding scheme we understand is /Identity-H *) let is_identity_h = function | CIDKeyedFont (_, _, Predefined "/Identity-H") -> true | _ -> false let glyphnames_and_codepoints_of_text extractor text = if is_identity_h extractor.font then let chars = map int_of_char (explode text) in if odd (length chars) then raise (Pdf.PDFError "Bad Text") else map (fun (h, l) -> extractor.convert ((h lsl 8) lor l)) (pairs_of_list chars) else map (fun c -> extractor.convert (int_of_char c)) (explode text) let codepoints_of_text extractor text = flatten (map snd (glyphnames_and_codepoints_of_text extractor text)) let glyphnames_of_text extractor text = map fst (glyphnames_and_codepoints_of_text extractor text) (* Charcode extractor (the opposite of a text extractor) Return the character code for a given unicode codepoint, if it exists in this encoding and font. *) let charcode_extractor_of_font_real ?(debug=false) font = if debug then flprint ((string_of_font font) ^ "\n"); let encoding = match font with | StandardFont (_, e) -> e | SimpleFont {encoding = e} -> e | _ -> ImplicitInFontFile (* No support *) in let tounicode_reverse_table, use_tounicode = match find_tounicode font with | Some parsed -> if debug then Printf.printf "Found a /ToUnicode table here.\n"; let parsed = list_of_hashtbl parsed in begin try if debug then iter (fun (charcode, utf16be_str) -> Printf.printf "/ToUnicode entry %i --> %s\n" charcode utf16be_str) parsed; let reversed = map (fun (charcode, s) -> (codepoints_of_utf16be s, charcode)) parsed in hashtable_of_dictionary reversed, true with e -> Pdfe.log (Printf.sprintf "bad tounicode (%s)\n" (Printexc.to_string e)); (null_hash (), false) end | None -> null_hash (), false in let table = reverse_table_of_encoding encoding in let reverse_glyph_hashes = Pdfglyphlist.reverse_glyph_hashes () in function codepoint -> if debug then Printf.printf "Input codepoint: %X\n" codepoint; try if use_tounicode then Some (let r = Hashtbl.find tounicode_reverse_table [codepoint] in if debug then Printf.printf "Found charcode %i\n\n" r; r) else let glyphname = Hashtbl.find reverse_glyph_hashes [codepoint] in if debug then Printf.printf "Found glyph name %s\n" glyphname; Some (let r = Hashtbl.find table glyphname in if debug then Printf.printf "Found charcode %i\n\n" r; r) with Not_found -> if debug then Pdfe.log (Printf.sprintf "Found no charcode for unicode codepoint %X.\n" codepoint); None let charcode_extractor_of_font ?(debug=false) pdf fontdict = let font = read_font pdf fontdict in charcode_extractor_of_font_real ~debug font (* Is a PDF string unicode (does it have a byte order marker at the beginning). *) let is_unicode s = (String.length s >= 2) && s.[0] = '\254' && s.[1] = '\255' (* Unicode codepoint from pdfdocencoding character number *) let codepoint_of_pdfdocencoding_character i = if i < 0 || i > 255 then failwith "codepoint_of_pdfdocencoding_character out of range" else try match Hashtbl.find (Pdfglyphlist.glyph_hashes ()) (Hashtbl.find Pdfglyphlist.reverse_name_to_pdf_hashes i) with | [codepoint] -> codepoint | _ -> raise (Pdf.PDFError (Printf.sprintf "codepoint_of_pdfdocencoding: bad text string (char %i)\n" i)) with _ -> raise (Pdf.PDFError (Printf.sprintf "codepoint_of_pdfdocencoding: bad text string 2 (char %i)\n" i)) (* Build a UTF-8 string from a list of unicode codepoints. *) let get_utf8_chars c = if c <= 0x00_00_00_7F then [c] else if c <= 0x00_00_07_FF then [(c lsr 6) lor 0b11_00_00_00; c land 0b11_11_11 lor 0b10_00_00_00] else if c <= 0x00_00_FF_FF then [(c lsr 12) lor 0b11_10_00_00; (c lsr 6) land 0b00_11_11_11 lor 0b10_00_00_00; c land 0b00_11_11_11 lor 0b10_00_00_00] else if c <= 0x00_10_FF_FF then [(c lsr 18) lor 0b11_11_00_00; (c lsr 12) land 0b00_11_11_11 lor 0b10_00_00_00; (c lsr 6) land 0b00_11_11_11 lor 0b10_00_00_00; c land 0b00_11_11_11 lor 0b10_00_00_00] else raise (Pdf.PDFError "bad unicode codepoint") let utf8_of_codepoints codepoints = implode (map char_of_int (flatten (map get_utf8_chars codepoints))) let codepoints_of_pdfdocstring s = if is_unicode s then codepoints_of_utf16be (String.sub s 2 (String.length s - 2)) else map codepoint_of_pdfdocencoding_character (map int_of_char (explode s)) let utf8_of_pdfdocstring s = (*Printf.printf "utf8_of_pdfdocstring: Pdf string is %S\n" s;*) utf8_of_codepoints (codepoints_of_pdfdocstring s) (* Build a PDFDocEncoding or UTF16BE string from a UTF8 encoded string *) let rec codepoints_of_utf8 a = function | [] -> rev a | c::cs when c lsr 7 = 0 -> codepoints_of_utf8 (c::a) cs | c::c2::cs when c lsr 5 = 0b110 && c2 lsr 6 = 0b10 -> codepoints_of_utf8 (((c land 0b000_11111) lsl 6) lor (c2 land 0b00_11_11_11)::a) cs | c::c2::c3::cs when c lsr 4 = 0b1110 && c2 lsr 6 = 0b10 && c3 lsr 6 = 0b10 -> codepoints_of_utf8 (((c land 0b0000_1111) lsl 12) lor ((c2 land 0b00_11_11_11) lsl 6) lor (c3 land 0b00_11_11_11)::a) cs | c::c2::c3::c4::cs when c lsr 3 = 0b11110 && c2 lsr 6 = 0b10 && c3 lsr 6 = 0b10 && c4 lsr 6 = 0b10 -> codepoints_of_utf8 (((c land 0b00000_111) lsl 18) lor ((c2 land 0b00_11_11_11) lsl 12) lor ((c3 land 0b00_11_11_11) lsl 6) lor (c4 land 0b00_11_11_11)::a) cs | _ -> raise (Pdf.PDFError "Bad UTF8 in codepoints_of_utf8\n") let codepoints_of_utf8 s = codepoints_of_utf8 [] (map int_of_char (explode s)) (* Looks up each codepoint in the adobe glyphmap, and look up that name in name_to_pdf above, raising the exception only if we find something that can't be handled. *) let rec pdfdocencoding_of_codepoints sofar = function | [] -> rev sofar | c::cs -> try pdfdocencoding_of_codepoints ((Hashtbl.find Pdfglyphlist.name_to_pdf_hashes (Hashtbl.find (Pdfglyphlist.reverse_glyph_hashes ()) [c]))::sofar) cs with Not_found -> raise Exit let pdfdocstring_of_codepoints codepoints = try implode (map char_of_int (pdfdocencoding_of_codepoints [] codepoints)) with Exit -> utf16be_of_codepoints codepoints let pdfdocstring_of_utf8 s = (*Printf.printf "utf8_of_pdfdocstring: JSON string is %S\n" s;*) pdfdocstring_of_codepoints (codepoints_of_utf8 s) (* PDF strings (except /ID in the trailer dictionary and inside page content streams) are either PDFDocEncoding or UTF16BE. Many times the UTF16BE can all be represented in PDFDocEncoding. In this case, there are just lots of \000 bytes getting in the way making any JSON output hard to edit. So we preprocess such simple UTF16BE strings into PDFDocEncoding. *) let simplify_utf16be s = if is_unicode s then pdfdocstring_of_utf8 (utf8_of_pdfdocstring s) else s camlpdf-2.8.1/pdftext.mli000066400000000000000000000134421477056064700153350ustar00rootroot00000000000000(** Parsing fonts and extracting text from content streams and PDF strings *) (** {2 Data Types } *) type type3_glpyhs = {fontbbox : float * float * float * float; fontmatrix : Pdftransform.transform_matrix; charprocs : (string * Pdf.pdfobject) list; type3_resources : Pdf.pdfobject} type simple_fonttype = | Type1 | MMType1 | Type3 of type3_glpyhs | Truetype type fontfile = | FontFile of int | FontFile2 of int | FontFile3 of int type fontdescriptor = {ascent : float; descent : float; avgwidth : float; maxwidth : float; flags : int; fontbbox: float * float * float * float; italicangle : float; capheight : float; xheight : float; stemv : float; fontfile : fontfile option; charset : string list option; tounicode : (int, string) Hashtbl.t option} type differences = (string * int) list type encoding = | ImplicitInFontFile | StandardEncoding | MacRomanEncoding | WinAnsiEncoding | MacExpertEncoding | CustomEncoding of encoding * differences | FillUndefinedWithStandard of encoding type fontmetrics = float array (*r widths of glyphs 0..255 *) type simple_font = {fonttype : simple_fonttype; basefont : string; firstchar : int; lastchar : int; widths : int array; fontdescriptor : fontdescriptor option; fontmetrics : fontmetrics option; encoding : encoding} type standard_font = | TimesRoman | TimesBold | TimesItalic | TimesBoldItalic | Helvetica | HelveticaBold | HelveticaOblique | HelveticaBoldOblique | Courier | CourierBold | CourierOblique | CourierBoldOblique | Symbol | ZapfDingbats type cid_system_info = {registry : string; ordering : string; supplement : int} type composite_CIDfont = {cid_system_info : cid_system_info; cid_basefont : string; cid_fontdescriptor : fontdescriptor; cid_widths : (int * float) list; cid_default_width : int} type cmap_encoding = | Predefined of string | CMap of int (* indirect reference to CMap stream *) type font = | StandardFont of standard_font * encoding | SimpleFont of simple_font | CIDKeyedFont of string * composite_CIDfont * cmap_encoding (** {2 String representations of fonts } *) (** Returns a string such as "Times-Bold" for Pdftext.TimesBold etc. *) val string_of_standard_font : standard_font -> string (** Parses a string such as "/Times-Bold" or "/TimesNewRoman,Bold" to Pdftext.TimesRomanBold etc. *) val standard_font_of_name : string -> standard_font option (** A debug string for the whole font datatype. *) val string_of_font : font -> string (** {2 Reading a Font} *) (** Read a font from a given document and object *) val read_font : Pdf.t -> Pdf.pdfobject -> font (** {2 Writing a Font} *) (** Write a font to a given document, returning the object number for the main font dictionary *) val write_font : ?objnum:int -> Pdf.t -> font -> int (** {2 Utility functions} *) (** Is a PDF string UTF16be (i.e does it have a byte order marker at the beginning)? *) val is_unicode : string -> bool (** Is a font Identity H? *) val is_identity_h : font -> bool (** A list of unicode codepoints for a UTF8 string *) val codepoints_of_utf8 : string -> int list (** A UTF8 string for a list of unicode codepoints *) val utf8_of_codepoints : int list -> string (** A list of unicode codepoints for a UTF16BE string *) val codepoints_of_utf16be : string -> int list (** A UTF16BE string for a list of unicode codepoints (with BOM) *) val utf16be_of_codepoints : int list -> string (** {2 Text from strings outside page content} *) (** Take a pdf string (which will be either pdfdocencoding or UTF16BE) and return a string representing the same unicode codepoints in UTF8 *) val utf8_of_pdfdocstring : string -> string (** Take a UTF8 string and convert to pdfdocencoding (if no unicode-only characters are used) or UTF16BE (if they are)) *) val pdfdocstring_of_utf8 : string -> string (** Build a pdf string in pdfdocencoding (if no unicode-only characters are used) or UTF16BE (if they are) *) val pdfdocstring_of_codepoints : int list -> string (** Produce a list of unicode codepoints from a pdfdocencoding or UTF16BE pdf document string *) val codepoints_of_pdfdocstring : string -> int list (** Remake a UTF16BE string into a PDFDocEncoding string if all characters are in PDFDocEncoding *) val simplify_utf16be : string -> string (** {2 Text from strings inside page content} *) (** The type of text extractors. *) type text_extractor (** Build a text extractor from a document and font object *) val text_extractor_of_font : Pdf.t -> Pdf.pdfobject -> text_extractor (** Build a text extractor from a document and a font *) val text_extractor_of_font_real : font -> text_extractor (** Return a list of unicode points from a given extractor and string (for example from a [Pdfpages.Op_Tj] or [Op_TJ] operator). *) val codepoints_of_text : text_extractor -> string -> int list (** Return a list of glyph names from a given extractor and string *) val glyphnames_of_text : text_extractor -> string -> string list (** {2 Building text for strings inside page content} *) (** Return the character code for a given unicode codepoint, if it exists in the encoding and font object. If [debug] is set (default false) missing characters are reported to stderr. *) val charcode_extractor_of_font : ?debug:bool -> Pdf.t -> Pdf.pdfobject -> (int -> int option) (** Return the character code for a given unicode codepoint, if it exists in the encoding and font. If [debug] is set (default false) missing characters are reported to stderr. *) val charcode_extractor_of_font_real : ?debug:bool -> font -> (int -> int option) (** Table of all the entries in an encoding. *) val table_of_encoding : encoding -> (int, string) Hashtbl.t (** Reverse table of all the entries in an encoding. *) val reverse_table_of_encoding : encoding -> (string, int) Hashtbl.t camlpdf-2.8.1/pdftransform.ml000066400000000000000000000205551477056064700162160ustar00rootroot00000000000000(* Affine transforms in 2D *) (* This module provides affine transformation on cartesian coordinates, using the standard methods given in Foley96. Two patterns of use are supported: building a single matrix from the composition of the desired transformation operations and then using it repeatedly (preferable when one wishes to transform many points); and transforming a point directly from the transformation operations (requires no state at the caller, so simpler). *) open Pdfutil (* Individual transformation operations. *) type transform_op = | Scale of (float * float) * float * float (*r centre, x scale, y scale. *) | Rotate of (float * float) * float (*r centre, angle in radians. *) | Translate of float * float (*r change in x, change in y. *) | ShearX of (float * float) * float (*r centre, x shear. *) | ShearY of (float * float) * float (*r centre, y shear. *) (* A transform is a list of operations t_n::t_{n-1}::...::t_2::t_1. which means t_1 followed by t_2 etc. *) type transform = transform_op list (* The matrix a c e b d f 0 0 1 for affine transforms in 2D homogeneous coordinates.*) type transform_matrix = {a : float; b : float; c : float; d : float; e : float; f : float} (* Debug printers for transformation operations. *) let string_of_trop = function | Scale ((x, y), sx, sy) -> Printf.sprintf "Scale about (%f, %f) by %f in x and %f in y\n" x y sx sy | Rotate ((x, y), a) -> Printf.sprintf "Rotate by %f about (%f, %f)\n" a x y | Translate (dx, dy) -> Printf.sprintf "Translate by %f, %f\n" dx dy | ShearX ((x, y), sx) -> Printf.sprintf "Shear in X about (%f, %f), proportionality constant %f\n" x y sx | ShearY ((x, y), sy) -> Printf.sprintf "Shear in Y about (%f, %f), proportionality constant %f\n" x y sy (* Same for transforms. *) let string_of_transform tr = fold_left ( ^ ) "" (rev_map string_of_trop tr) (* Building and manipulating transforms *) (* The identity transform. *) let i = ([] : transform) (* Compose a transformation operation t onto an existing transform ts. We perform a simple optimisation --- combining like with like at the head. *) let compose t = function | [] -> [t] | h::r -> match h, t with | Translate (dx, dy), Translate (dx', dy') -> Translate (dx +. dx', dy +. dy')::r | Scale (p, sx, sy), Scale (p', sx', sy') when p = p' -> Scale (p, sx *. sx', sy *. sy')::r | Rotate (p, a), Rotate (p', a') when p = p' -> Rotate (p, a +. a')::r | ShearX (p, a), ShearX (p', a') when p = p' -> ShearX (p, a +. a')::r | ShearY (p, a), ShearY (p', a') when p = p' -> ShearY (p, a +. a')::r | _ -> t::h::r (* Append two transforms. The result is all operations in the second argument followed by all operations in the first. *) let append = (( @ ) : transform -> transform -> transform) (* The identity transformation matrix 1 0 0 0 1 0 0 0 1. *) let i_matrix = {a = 1.; c = 0.; e = 0.; b = 0.; d = 1.; f = 0.} (* Compose two matrices. Applying the result is equivalent to applying m then m'. *) let matrix_compose m' m = {a = m'.a *. m.a +. m'.c *. m.b; c = m'.a *. m.c +. m'.c *. m.d; e = m'.a *. m.e +. m'.c *. m.f +. m'.e; b = m'.b *. m.a +. m'.d *. m.b; d = m'.b *. m.c +. m'.d *. m.d; f = m'.b *. m.e +. m'.d *. m.f +. m'.f} (* String of matrix *) let string_of_matrix m = Printf.sprintf "%f, %f, %f, %f, %f, %f" m.a m.b m.c m.d m.e m.f (* Invert a matrix. The exeption: *) exception NonInvertable (* And the function. *) let matrix_invert m = let det = let divisor = m.a *. m.d -. m.b *. m.c in if divisor = 0. then raise NonInvertable else match 1. /. divisor with | 0. -> raise NonInvertable | d -> ( *. ) d in {a = det m.d; b = det (-.(m.b)); c = det (-.(m.c)); d = det m.a; e = det (m.c *. m.f -. m.d *. m.e); f = det (m.b *. m.e -. m.a *. m.f)} (* These functions build matrices for the transformation operations defined above. *) (* Translate by (tx, ty) *) let mktranslate tx ty = {i_matrix with e = tx; f = ty} (* Scale about an origin (ox, oy) by x factor sx and y factor sy. *) let mkscale (ox, oy) sx sy = let translate = mktranslate (-.ox) (-.oy) in let translateback = mktranslate ox oy in matrix_compose translateback (matrix_compose {i_matrix with a = sx; d = sy} translate) (* Rotate about an origin (ox, oy) by angle (in radians) angle. *) let mkrotate (ox, oy) angle = let translate = mktranslate (-.ox) (-.oy) in let translateback = mktranslate ox oy in matrix_compose translateback (matrix_compose {i_matrix with a = cos angle; c = -. sin angle; b = sin angle; d = cos angle} translate) (* Skew in x about an origin (ox, oy) by factor. *) let mkshearx (ox, oy) factor = let translate = mktranslate (-.ox) (-.oy) in let translateback = mktranslate ox oy in matrix_compose translateback (matrix_compose {i_matrix with c = factor} translate) (* Skew in y about an origin (ox, oy) by factor. *) let mksheary (ox, oy) factor = let translate = mktranslate (-.ox) (-.oy) in let translateback = mktranslate ox oy in matrix_compose translateback (matrix_compose {i_matrix with b = factor} translate) (* Use the preceeding functions to make a matrix from a transformation operation. *) let matrix_of_op = function | Scale (c, sx, sy) -> mkscale c sx sy | Rotate (c, a) -> mkrotate c a | Translate (dx, dy) -> mktranslate dx dy | ShearX (c, a) -> mkshearx c a | ShearY (c, a) -> mksheary c a (* Transform a point (x, y) with a matrix m. *) let transform_matrix m (x, y) = x *. m.a +. y *. m.c +. m.e, x *. m.b +. y *. m.d +. m.f (* Method 1. When transforming many points, it makes sense to calculate the composition of the transformation matrices and then apply this to each of the points. *) let matrix_of_transform tr = let matrices = map matrix_of_op tr in fold_left matrix_compose i_matrix matrices (* Method 2. Transform a point [p] by a transformation [ts]. This is faster when we wish to transform a few points. It requires no state at the caller. *) let transform ts (x, y) = let x = ref x in let y = ref y in iter (function | Scale ((cx, cy), sx, sy) -> let x' = !x -. cx in let y' = !y -. cy in let x'' = x' *. sx in let y'' = y' *. sy in x := x'' +. cx; y := y'' +. cy | Rotate ((cx, cy), a) -> let cosine = cos a in let sine = sin a in let invsine = -.sine in let x' = !x -. cx in let y' = !y -. cy in let x'' = x' *. cosine +. y' *. invsine in let y'' = x' *. sine +. y' *. cosine in x := x'' +. cx; y := y'' +. cy | Translate (dx, dy) -> x := !x +. dx; y := !y +. dy | ShearX ((cx, cy), a) -> let x' = !x -. cx in let y' = !y -. cy in let x'' = x' +. y' *. a in let y'' = y' in x := x'' +. cx; y := y'' +. cy | ShearY ((cx, cy), a) -> let x' = !x -. cx in let y' = !y -. cy in let x'' = x' in let y'' = x' *. a +. y' in x := x'' +. cx; y := y'' +. cy) (rev ts); !x, !y (* Decomposition and Recomposition *) (* Decompose a matrix to a scale, aspect, rotation, shear and translation. *) let decompose m = let axb = m.a *. m.d -. m.c *. m.b in let moda = sqrt (m.a *. m.a +. m.b *. m.b) in let modb = sqrt (m.c *. m.c +. m.d *. m.d) in let adotb = m.a *. m.c +. m.b *. m.d in let scale = axb /. moda in let aspect = if fabs scale = 0. then 1. else moda /. fabs scale in let rotation = atan2 m.b m.a in let shear = if moda *. modb = 0. then 0. else pi /. 2. -. acos (adotb /. (moda *. modb)) in safe_float scale, safe_float aspect, safe_float rotation, safe_float shear, safe_float m.e, safe_float m.f (* Rebuild a matrix from those components. *) let recompose scale aspect rotation shear tx ty = let scale_aspect_shear = {i_matrix with a = fabs scale *. aspect; c = scale *. tan shear; d = scale} in let rotated = matrix_compose (mkrotate (0., 0.) rotation) scale_aspect_shear in matrix_compose (mktranslate tx ty) rotated camlpdf-2.8.1/pdftransform.mli000066400000000000000000000063701477056064700163660ustar00rootroot00000000000000(** Affine Transformations in Two Dimensions *) (** {2 Types} *) (** A single transformation operation. *) type transform_op = | Scale of (float * float) * float * float | Rotate of (float * float) * float | Translate of float * float | ShearX of (float * float) * float | ShearY of (float * float) * float (** A list of transformations, the first at the end of the list (thus, to append another transformation, just cons to the beginning.) *) type transform = transform_op list (** A transformation matrix (first row [a c e], second row [b d f], third row [0 0 1]) *) type transform_matrix = {a : float; b : float; c : float; d : float; e : float; f : float} (** The identity transform *) val i : transform (** Make a string of a transform for debug purposes. *) val string_of_transform : transform -> string (** {2 Making transformation matrices} *) (** The identity matrix *) val i_matrix : transform_matrix (** String of a transformation matrix. *) val string_of_matrix : transform_matrix -> string (** Make a transformation matrix from x and y translation. *) val mktranslate : float -> float -> transform_matrix (** Make a transformation matrix from an x and y scale and a point to scale about. *) val mkscale : (float * float) -> float -> float -> transform_matrix (** Make a rotation matrix to rotate by a number of radians around a point. *) val mkrotate : (float * float) -> float -> transform_matrix (** Matrix to shear in x by a given factor about a point. *) val mkshearx : (float * float) -> float -> transform_matrix (** Matrix to shear in y by a given factor about a point. *) val mksheary : (float * float) -> float -> transform_matrix (** {2 Composing and manipulating transforms} *) (** [compose t ts] adds operation [t] to the transform [ts]. *) val compose : transform_op -> transform -> transform (** [append a b] is a transform with the same effect as performing b then a *) val append : (transform -> transform -> transform) (** [compose a b] produces a matrix equivalent to performing [b] then [a]. *) val matrix_compose : transform_matrix -> transform_matrix -> transform_matrix (** Make a matrix from a single transformation operation *) val matrix_of_op : transform_op -> transform_matrix (** Make a matrix from a transform *) val matrix_of_transform : transform -> transform_matrix (** {2 Inverting transforms} *) (** Exception raised if a matrix is non-invertable *) exception NonInvertable (** Matrix inversion. May raise [NonInvertable] *) val matrix_invert : transform_matrix -> transform_matrix (** Transform a coordinate by a given transform. *) val transform : transform -> float * float -> float * float (** Transform a coordinate by a given transformation matrix. *) val transform_matrix : transform_matrix -> float * float -> float * float (** {2 Decomposing and recomposing matrices} *) (** Decompose a transformation matrix to scale, aspect, rotation, shear, translation in x, translation in y. Always succeeds, but results are not guaranteed to mean anything. *) val decompose : transform_matrix -> float * float * float * float * float * float (** Recompose from the above information. It is not guaranteed that recompose (decompose t) = t *) val recompose : float -> float -> float -> float -> float -> float -> transform_matrix camlpdf-2.8.1/pdftree.ml000066400000000000000000000071751477056064700151450ustar00rootroot00000000000000open Pdfutil (* Reading a name tree *) let rec read_name_tree pdf tree = let names = match Pdf.lookup_direct_orelse pdf "/Names" "/Nums" tree with | Some (Pdf.Array elts) -> if odd (length elts) then begin Pdfe.log "Bad /Names array. Name tree will be read as empty\n"; [] end else pairs_of_list elts | _ -> [] in match Pdf.lookup_direct pdf "/Kids" tree with | Some (Pdf.Array kids) -> names @ flatten (map (read_name_tree pdf) kids) | _ -> names (* A malformed PDF with duplicate keys will cause problems e.g in merging. We remove them. NB the assumption the tree is still properly ordered remains. *) let rec remove_duplicates = function | (k, _)::((k', _) as h)::t when k = k' -> Pdfe.log "Warning Duplicate name/number tree key (malformed file). Discarding.\n"; remove_duplicates (h::t) | h::t -> h::remove_duplicates t | [] -> [] let read_number_tree pdf tree = let r = remove_duplicates (read_name_tree pdf tree) in try map (function (Pdf.Integer i, x) -> (string_of_int i, x) | _ -> raise Exit) r with Exit -> Pdfe.log "Pdftree.read_number_tree: skipping malformed number tree\n"; [] let read_name_tree pdf tree = let r = remove_duplicates (read_name_tree pdf tree) in try map (function (Pdf.String s, x) -> (s, x) | _ -> raise Exit) r with Exit -> Pdfe.log "Pdftree.read_name_tree: skipping malformed name tree\n"; [] let maxsize = 10 type ('k, 'v) nt = Br of 'k * ('k, 'v) nt list * 'k | Lf of 'k * ('k * 'v) list * 'k let left l = fst (hd l) let right l = fst (last l) let rec build_nt_tree l = if length l = 0 then assert false; if length l <= maxsize then Lf (left l, l, right l) else Br (left l, map build_nt_tree (splitinto maxsize l), right l) let rec name_tree_of_nt isnum isroot pdf = function Lf (llimit, items, rlimit) -> let entry = [((if isnum then "/Nums" else "/Names"), Pdf.Array (flatten (map (fun (k, v) -> [(if isnum then Pdf.Integer (int_of_string k) else Pdf.String k); v]) items)))] in let ll, rl = if isnum then Pdf.Integer (int_of_string llimit), Pdf.Integer (int_of_string rlimit) else Pdf.String llimit, Pdf.String rlimit in Pdf.Dictionary (entry @ if isroot then [] else [("/Limits", Pdf.Array [ll; rl])]) | Br (llimit, nts, rlimit) -> let indirects = let kids = map (name_tree_of_nt isnum false pdf) nts in map (function Pdf.Dictionary _ | Pdf.Stream _ | Pdf.Array _ as x -> Pdf.Indirect (Pdf.addobj pdf x) | x -> x) kids in let ll, rl = if isnum then Pdf.Integer (int_of_string llimit), Pdf.Integer (int_of_string rlimit) else Pdf.String llimit, Pdf.String rlimit in Pdf.Dictionary [("/Kids", Pdf.Array indirects); ("/Limits", Pdf.Array [ll; rl])] let compare_any isnum a b = if isnum then compare (int_of_string (fst a)) (int_of_string (fst b)) else compare a b let build_name_tree isnum pdf = function | [] -> if isnum then Pdf.Dictionary [("/Nums", Pdf.Array [])] else Pdf.Dictionary [("/Names", Pdf.Array [])] | ls -> let nt = build_nt_tree (sort (compare_any isnum) ls) in Pdf.remove_dict_entry (name_tree_of_nt isnum true pdf nt) "/Limits" (* Once we know there are no clashes *) let merge_name_trees_no_clash pdf trees = build_name_tree false pdf (flatten (map (read_name_tree pdf) trees)) let merge_number_trees_no_clash pdf trees = build_name_tree true pdf (flatten (map (read_number_tree pdf) trees)) camlpdf-2.8.1/pdftree.mli000066400000000000000000000014731477056064700153110ustar00rootroot00000000000000(** Name and Number Trees *) (** NB. Subject to API changes. *) (** Read a name tree as a flat (key, value) list. *) val read_name_tree : Pdf.t -> Pdf.pdfobject -> (string * Pdf.pdfobject) list (** Read a number tree as a flat (key, value) list but with the numbers as strings. *) val read_number_tree : Pdf.t -> Pdf.pdfobject -> (string * Pdf.pdfobject) list (** Build a name or number tree (bool: true if number, false otherwise) from flat (key, value) list. *) val build_name_tree : bool -> Pdf.t -> (string * Pdf.pdfobject) list -> Pdf.pdfobject (** Merge name trees, assuming no duplicate keys. *) val merge_name_trees_no_clash : Pdf.t -> Pdf.pdfobject list -> Pdf.pdfobject (** Merge number trees, assuming no duplicate keys. *) val merge_number_trees_no_clash : Pdf.t -> Pdf.pdfobject list -> Pdf.pdfobject camlpdf-2.8.1/pdfunits.ml000066400000000000000000000007311477056064700153370ustar00rootroot00000000000000type t = PdfPoint | Inch | Centimetre | Millimetre let points x = function | PdfPoint -> x | Inch -> x *. 72. | Centimetre -> x *. 28.3465 | Millimetre -> x *. 2.83465 let inches x = function | Inch -> x | PdfPoint -> x /. 72. | Centimetre -> x /. 2.54 | Millimetre -> x /. 25.4 let centimetres x = function | Centimetre -> x | Inch -> x *. 2.54 | Millimetre -> x /. 10. | PdfPoint -> x /. 28.3456 let millimetres x u = centimetres x u *. 10. camlpdf-2.8.1/pdfunits.mli000066400000000000000000000006461477056064700155150ustar00rootroot00000000000000(** Units and Unit Conversion *) (** The type of units *) type t = PdfPoint | Inch | Centimetre | Millimetre (** Convert a measurement to points *) val points : float -> t -> float (** Convert a measurement to inches *) val inches : float -> t -> float (** Convert a measurement to centimetres *) val centimetres : float -> t -> float (** Convert a measurement to millimetres *) val millimetres : float -> t -> float camlpdf-2.8.1/pdfutil.ml000066400000000000000000001052641477056064700151610ustar00rootroot00000000000000(* This module contains general-purpose functions used in many modules. Typically a module will use the [open] keyword to bring these definitions up to top level, so their names are considered reserved words in other modules. All functions in this module are tail-recursive, unless otherwise noted. *) let rec position_gen n e = function [] -> None | e'::t when e = e' -> Some n | _::t -> position_gen (n + 1) e t let position e l = position_gen 0 e l let position_1 e l = position_gen 1 e l (* Replace all instances of x with x' in s *) let string_replace_all x x' s = if x = "" then s else let p = ref 0 and slen = String.length s and xlen = String.length x in let output = Buffer.create (slen * 2) in while !p < slen do try if String.sub s !p xlen = x then (Buffer.add_string output x'; p := !p + xlen) else (Buffer.add_char output s.[!p]; incr p) with _ -> Buffer.add_char output s.[!p]; incr p done; Buffer.contents output let string_replace_all_lazy x x' s = if x = "" then s else let p = ref 0 and slen = String.length s and xlen = String.length x in let output = Buffer.create (slen * 2) in while !p < slen do try if String.sub s !p xlen = x then (Buffer.add_string output (x' ()); p := !p + xlen) else (Buffer.add_char output s.[!p]; incr p) with _ -> Buffer.add_char output s.[!p]; incr p done; Buffer.contents output (* Print something and then flush standard output. *) let flprint s = print_string s; flush stdout let fleprint s = print_string s; flush stderr (* Debug printing *) let dp_print = ref false let dpr s = if !dp_print then flprint s (* [xxx] is a tail-recursive version of [List.xxx]. See [List] module for details. *) let sort = List.sort let hd = List.hd let tl = List.tl let rev = List.rev let iter = List.iter let iter2 = List.iter2 let rec iter3 f a b c = match a, b, c with | [], [], [] -> () | ah::a', bh::b', ch::c' -> f ah bh ch; iter3 f a' b' c' | _ -> raise (Invalid_argument "Pdfutil.iter3") let append a b = List.rev_append (rev a) b let ( @ ) = append let flatten lists = let rec flatten out = function | [] -> out | l::ls -> flatten (append l out) ls in flatten [] (rev lists) let rev_map = List.rev_map let map f l = rev (List.rev_map f l) let map2 f a b = rev (List.rev_map2 f a b) let split l = let rec split_inner (l1, l2) = function | [] -> rev l1, rev l2 | (a, b)::t -> split_inner (a::l1, b::l2) t in split_inner ([], []) l let split3 l = let rec split3_inner (l1, l2, l3) = function | [] -> rev l1, rev l2, rev l3 | (a, b, c)::t -> split3_inner (a::l1, b::l2, c::l3) t in split3_inner ([], [], []) l let split5 l = let rec split5_inner (l1, l2, l3, l4, l5) = function | [] -> rev l1, rev l2, rev l3, rev l4, rev l5 | (a, b, c, d, e)::t -> split5_inner (a::l1, b::l2, c::l3, d::l4, e::l5) t in split5_inner ([], [], [], [], []) l let split6 l = let rec split6_inner (l1, l2, l3, l4, l5, l6) = function | [] -> rev l1, rev l2, rev l3, rev l4, rev l5, rev l6 | (a, b, c, d, e, f)::t -> split6_inner (a::l1, b::l2, c::l3, d::l4, e::l5, f::l6) t in split6_inner ([], [], [], [], [], []) l let split8 l = let rec split8_inner (l1, l2, l3, l4, l5, l6, l7, l8) = function | [] -> rev l1, rev l2, rev l3, rev l4, rev l5, rev l6, rev l7, rev l8 | (a, b, c, d, e, f, g, h)::t -> split8_inner (a::l1, b::l2, c::l3, d::l4, e::l5, f::l6, g::l7, h::l8) t in split8_inner ([], [], [], [], [], [], [], []) l let combine a b = let pairs = ref [] in try List.iter2 (fun x y -> pairs := (x, y)::!pairs) a b; rev !pairs with Invalid_argument _ -> raise (Invalid_argument "Pdfutil.combine") let combine3 a b c = let pairs = ref [] in try iter3 (fun x y z -> pairs := (x, y, z)::!pairs) a b c; rev !pairs with Invalid_argument _ -> raise (Invalid_argument "Pdfutil.combine3") let fold_left f b l = List.fold_left f b l let fold_right f l e = List.fold_left (fun x y -> f y x) e (rev l) let length = List.length let rec rev_map3_inner f a b c outputs = match a, b, c with | [], [], [] -> outputs | ha::ta, hb::tb, hc::tc -> rev_map3_inner f ta tb tc (f ha hb hc::outputs) | _ -> raise (Invalid_argument "Pdfutil.map3") let rev_map3 f a b c = rev_map3_inner f a b c [] let map3 f a b c = rev (rev_map3 f a b c) let rec rev_map4_inner f a b c d outputs = match a, b, c, d with | [], [], [], [] -> outputs | ha::ta, hb::tb, hc::tc, hd::td -> rev_map4_inner f ta tb tc td (f ha hb hc hd::outputs) | _ -> raise (Invalid_argument "Pdfutil.map4") let rev_map4 f a b c d = rev_map4_inner f a b c d [] let map4 f a b c d = rev (rev_map4 f a b c d) let rec rev_map5_inner f a b c d e outputs = match a, b, c, d, e with | [], [], [], [], [] -> outputs | ha::ta, hb::tb, hc::tc, hd::td, he::te -> rev_map5_inner f ta tb tc td te (f ha hb hc hd he::outputs) | _ -> raise (Invalid_argument "Pdfutil.map5") let rev_map5 f a b c d e = rev_map5_inner f a b c d e [] let map5 f a b c d e = rev (rev_map5 f a b c d e) let rec rev_map6_inner f a b c d e g outputs = match a, b, c, d, e, g with | [], [], [], [], [], [] -> outputs | ha::ta, hb::tb, hc::tc, hd::td, he::te, hg::tg -> rev_map6_inner f ta tb tc td te tg (f ha hb hc hd he hg::outputs) | _ -> raise (Invalid_argument "Pdfutil.map6") let rev_map6 f a b c d e g = rev_map6_inner f a b c d e g [] let map6 f a b c d e g = rev (rev_map6 f a b c d e g) let sum = fold_left ( + ) 0 let fsum = fold_left ( +. ) 0. (* Calculate the cumulative sum of a list given a base e.g [cumulative_sum 5 [1;2;3] = [6; 8; 11]] *) let cumulative_sum b l = let rec cumulative_sum prev bse = function | [] -> rev prev | h::t -> cumulative_sum ((bse + h)::prev) (bse + h) t in cumulative_sum [] b l (* Split a list into a list of lists at every point where [p] is true *) let rec split_around_inner p prev curr = function | [] -> if curr = [] then (rev prev) else (rev (rev curr::prev)) | h::t -> if p h then split_around_inner p (rev curr::prev) [] t else split_around_inner p prev (h::curr) t let split_around p l = split_around_inner p [] [] l (* Count the number of elements matching a predicate. *) let rec lcount_inner p c = function | [] -> c | h::t -> if p h then lcount_inner p (c + 1) t else lcount_inner p c t let lcount p l = lcount_inner p 0 l (* Find the position of the first element matching a predicate. The first element is number one. *) let rec index_inner n p = function | [] -> dpr "b"; raise Not_found | h::_ when p h -> n | _::t -> index_inner (n + 1) p t let index n p = index_inner 1 n p (* Functions on Strings *) let firstchar s = try Some s.[0] with Invalid_argument _ -> dpr "3R"; None let lastchar s = try Some s.[String.length s - 1] with Invalid_argument _ -> dpr "3S"; None (* Make a list of characters from a string, preserving order. *) let explode s = let l = ref [] in for p = String.length s downto 1 do l := String.unsafe_get s (p - 1)::!l done; !l (* Make a string from a list of characters, preserving order. *) let implode l = let s = Bytes.create (length l) in let rec list_loop x = function [] -> () | i::t -> Bytes.unsafe_set s x i; list_loop (x + 1) t in list_loop 0 l; Bytes.to_string s (* String of character. *) let string_of_char c = String.make 1 c (* Long-integer function abbreviations *) let i32ofi = Int32.of_int let i32toi = Int32.to_int let i32tof = Int32.to_float let i32add = Int32.add let i32sub = Int32.sub let i32mul = Int32.mul let i32div = Int32.div let sr32 = Int32.shift_right let lsr32 = Int32.shift_right_logical let lsl32 = Int32.shift_left let lor32 = Int32.logor let land32 = Int32.logand let lnot32 = Int32.lognot let lxor32 = Int32.logxor let i32succ = Int32.succ let i32pred = Int32.pred let i32max = Stdlib.max let i32min = Stdlib.min let i64ofi = Int64.of_int let i64toi = Int64.to_int let i64tof = Int64.to_float let i64add = Int64.add let i64sub = Int64.sub let i64mul = Int64.mul let i64div = Int64.div let sr64 = Int64.shift_right let lsr64 = Int64.shift_right_logical let lsl64 = Int64.shift_left let land64 = Int64.logand let lor64 = Int64.logor let lnot64 = Int64.lognot let lxor64 = Int64.logxor let i64succ = Int64.succ let i64pred = Int64.pred let i64max = Stdlib.max let i64min = Stdlib.min let i32ofi64 = Int64.to_int32 let i64ofi32 = Int64.of_int32 (* Sign extension for integer of number of bits l. *) let sign_extend l n = let shift = (if Nativeint.size = 32 then 33 else Nativeint.size) - 1 - l in (* 33 for js_of_ocaml *) (n lsl shift) asr shift (* Set each element of array [a] to value [v]. *) let set_array a v = Array.fill a 0 (Array.length a) v (* Evaluate [v ()], evaluate and ignore [f ()], return [v ()], in that order. *) let do_return v f = let r = v () in ignore (f ()); r (* Call [f ()] some number of times. *) let rec do_many f = function | n when n < 0 -> raise (Invalid_argument "Pdfutil.do_many") | 0 -> () | n -> f (); do_many f (n - 1) (* Interleave an element among a list, so that [interleave 0 [1; 2; 3]] yields [[1; 0; 2; 0; 3]]. An empty or singleton list is unchanged. *) let interleave e l = let rec interleave_inner result elt = function | [] -> rev result | [e] -> interleave_inner (e::result) elt [] | h::t -> interleave_inner (elt::h::result) elt t in interleave_inner [] e l (* Interleave two same-length lists together, taking from the first list first. *) let interleave_lists a b = let rec interleave_lists_inner r a b = match a, b with | [], [] -> rev r | h::t, h'::t' -> interleave_lists_inner (h'::h::r) t t' | _ -> raise (Invalid_argument "Pdfutil.interleave_lists") in interleave_lists_inner [] a b (* Cons on list references *) let ( =| ) r e = r := e::!r (* Append on list references *) let ( =@ ) r l = r := l @ !r (* Functions on characters. *) let isdigit = function | x when x >= '0' && x <= '9' -> true | _ -> false (* Abbreviation. *) let toint x = int_of_float x (* Invert a predicate. *) let notpred f = function e -> not (f e) (* Prefix equality *) let eq = ( = ) let neq = ( <> ) (* Map on the individual (inner) elements of a list of lists *) let map_lol f = map (map f) (* Raise [x] to the power [i]. *) let rec pow i x = match i with | 0 -> 1 | 1 -> x | i -> pow (i / 2) (x * x) * (if i mod 2 = 0 then 1 else x) (* Dictionaries implemented as association lists *) (* Look something up in a dictionary. *) let rec lookup k' = function | [] -> None | (k, v)::t -> if k = k' then Some v else lookup k' t (* Same, but no [option] type. *) let rec lookup_failnull k' = function | [] -> dpr "e"; raise Not_found | (k, v)::t -> if k = k' then v else lookup_failnull k' t (* Add something to a dictionary, replacing it if it's already there. *) let add k' v d = let rec add_inner r k' v = function | [] -> (k', v)::r | (k, _)::t when k = k' -> r @ ((k', v)::t) | h::t -> add_inner (h::r) k' v t in add_inner [] k' v d (* Replace something in a dictionary, failing if it doesn't exist. *) let replace k' v l = let rec replace_inner r k' v = function | [] -> dpr "f"; raise Not_found | (k, _)::t when k = k' -> List.rev_append r ((k', v)::t) | h::t -> replace_inner (h::r) k' v t in replace_inner [] k' v l (* Remove something from a dictionary. *) let remove k' l = let rec remove_inner r k' = function | [] -> r | (k, _)::t when k = k' -> List.rev_append r t | h::t -> remove_inner (h::r) k' t in remove_inner [] k' l (* Merge two dictionaries, prefering elements in the second in the case of clashes. *) let rec mergedict d = function | [] -> d | (k, v)::es -> mergedict (add k v d) es (* An infix operator for the composition of functions. *) let ( <| ) a b = a b (* Opposite version of [@], the reverse append. *) let ( @@ ) a b = b @ a (* In order to return pairs of list from recursive functions without recourse to accumulating arguments. *) let conspair ((x, y), (xs, ys)) = x::xs, y::ys (* The same with options determining whether or not each element is included in the output list. *) let conspairopt ((xo, yo), (xs, ys)) = (match xo with None -> xs | Some x -> x::xs), (match yo with None -> ys | Some y -> y::ys) (* Make consecutive elements of an even-length list into a list of pairs. *) let pairs_of_list l = let rec pairs_of_list_inner r = function | [] -> rev r | [_] -> raise (Invalid_argument "Pdfutil.pairs_of_list") | h::h'::t -> pairs_of_list_inner ((h, h')::r) t in pairs_of_list_inner [] l (* Return a list identical to the input but with any item true under predicate [p] replaced with [o]. *) let replaceinlist p o l = let rec replaceinlist_inner r p o = function | [] -> rev r | h::t -> if p h then replaceinlist_inner (o::r) p o t else replaceinlist_inner (h::r) p o t in replaceinlist_inner [] p o l (* Produce a list of overlapping pairs of elements in a list in order, producing the empty list if on singleton input. *) let pairs l = let rec pairs_inner r = function | [] | [_] -> rev r | a::b::rest -> pairs_inner ((a, b)::r) (b::rest) in pairs_inner [] l (* Predicate to test if [x] is a member of a list. *) let mem = List.mem (* The same, with reversed arguments. *) let mem' l x = mem x l (* Return the set of distinct elements in a list. Does not preserve order. *) let setify_simple l = let rec setify_inner r = function | [] -> r | h::t -> if mem h t then setify_inner r t else setify_inner (h::r) t in setify_inner [] l (* The same, preserving the order of the first occurance of each distinct element in the input list. *) let setify_preserving_order l = setify_simple (rev l) let rec sorted_setify prev = function [] -> rev prev | [x] -> rev (x::prev) | a::b::t when a = b -> sorted_setify prev (b::t) | h::t -> sorted_setify (h::prev) t let setify l = sorted_setify [] (List.sort compare l) let setify_large l = let h = Hashtbl.create (length l) in iter (fun k -> Hashtbl.replace h k ()) l; Hashtbl.fold (fun k _ acc -> k::acc) h [] (* Remove all elts of l' from l if l, l' sets. *) let setminus l l' = let rec setminus_inner r l l' = match l with | [] -> r | h::t -> if mem h l' then setminus_inner r t l' else setminus_inner (h::r) t l' in setminus_inner [] l l' let setminus_preserving_order l l' = rev (setminus l l') (* Return a list of the heads of a list of lists. *) let heads l = let rec heads_inner r = function | [] -> rev r | h::t -> heads_inner (hd h::r) t in heads_inner [] l (* Return a list of the tails of a list of lists, failing if any of them are the empty list. *) let tails l = let rec tails_inner r = function | [] -> rev r | h::t -> tails_inner (tl h::r) t in tails_inner [] l (* Take a list of lists of equal length, and turn into a list of lists, the first containing all the first elements of the original lists, the second the second, and so on. *) let zipn l = let rec zipn_inner r = function | [] | []::_ -> rev r | l -> zipn_inner (heads l::r) (tails l) in zipn_inner [] l (* Remove the second, fourth etc elements from a list, saving the last element (if of even length) e.g [drop_evens [1;2;3;4;5;6] is [1;3;5;6]]. *) let drop_evens l = let rec drop_evens_inner r = function | h::_::h''::t -> drop_evens_inner (h::r) (h''::t) | h::h'::[] -> rev (h'::h::r) | [x] -> rev (x::r) | _ -> rev r in drop_evens_inner [] l (* Same, but don't save the last even one. *) let really_drop_evens l = let rec really_drop_evens_inner r = function | [] -> rev r | [h] -> really_drop_evens_inner (h::r) [] | h::_::more -> really_drop_evens_inner (h::r) more in really_drop_evens_inner [] l (* Remove the first, third etc. The last odd element is not saved. e.g [drop_odds [1;2;3;4;5;6;7] is [2;4;6]]. *) let drop_odds l = let rec drop_odds_inner r = function | _::h'::t -> drop_odds_inner (h'::r) t | _ -> rev r in drop_odds_inner [] l (* tl but silent failure. *) let tail_no_fail = function | [] -> [] | _::t -> t (* Couple the elements of a list [l] using function [f]. For instance, [couple ( + ) [[1; 3; 5]]] $\Longrightarrow$ [[4; 8]]. The two elements are applied to [f] in the order in which they appear in the input list. *) let couple f l = let rec couple_inner r f = function | x::x'::xs -> couple_inner (f x x'::r) f (x'::xs) | _ -> rev r in couple_inner [] f l (* As above, but an extra function [g] is applied to any last (odd) element. *) let couple_ext f g l = let rec couple_ext_inner r f g = function | x::x'::xs -> couple_ext_inner (f x x'::r) f g (x'::xs) | x::[] -> couple_ext_inner (g x::r) f g [] | [] -> rev r in couple_ext_inner [] f g l (* Apply [couple] repeatedly until only one element remains. Return that element. *) let rec couple_reduce f = function | [] -> raise (Invalid_argument "Pdfutil.couple_reduce") | [a] -> a | l -> couple_reduce f (couple f l) (* A similar function to [couple], but the coupling is non-overlapping. *) let pair f l = let rec pair_inner r f = function | [] -> rev r | [a] -> pair_inner (a::r) f [] | a::b::t -> pair_inner (f a b::r) f t in pair_inner [] f l (* A version of [pair] which adds a unary function for the singleton, much like [couple_ext]. *) let pair_ext f g l = let rec pair_ext_inner r f g = function | [] -> rev r | [a] -> pair_ext_inner (g a::r) f g [] | a::b::t -> pair_ext_inner (f a b::r) f g t in pair_ext_inner [] f g l (* As [couple_reduce] is to [couple], so this is to [pair]. *) let rec pair_reduce f = function | [] -> raise (Invalid_argument "Pdfutil.pair_reduce") | [a] -> a | l -> pair_reduce f (pair f l) (* [List.filter] has a confusing name, so we define [keep] and [lose] to avoid error. *) let keep = List.filter let rec lose_inner prev p = function | [] -> rev prev | h::t -> if p h then lose_inner prev p t else lose_inner (h::prev) p t let lose p = lose_inner [] p (* Make a list of length [n] with each element equal to [x]. *) let many x n = Array.to_list (Array.make n x) (* A version where we need to apply unit each time, for instance when producing a list of random numbers. Result is ordered. *) let manyunique f n = let rec manyunique_inner r f n = if n = 0 then rev r else manyunique_inner (f ()::r) f (n - 1) in manyunique_inner [] f n (* Take [n] elements from the front of a list [l], returning them in order. *) let take l n = if n < 0 then raise (Invalid_argument "Pdfutil.take") else let rec take_inner r l n = if n = 0 then rev r else match l with | [] -> raise (Invalid_argument "Pdfutil.take") | h::t -> take_inner (h::r) t (n - 1) in take_inner [] l n let take' n l = take l n (* Same, but order is reversed *) let takewhile_reverse p l = let rec takewhile_reverse_inner r p = function | [] -> r | h::t -> if p h then takewhile_reverse_inner (h::r) p t else r in takewhile_reverse_inner [] p l (* Take from the list [l] while the predicate [p] is true. *) let takewhile p l = let rec takewhile_inner r p l = match l with | [] -> rev r | h::t -> if p h then takewhile_inner (h::r) p t else rev r in takewhile_inner [] p l (* Drop [n] elements from the front of a list, returning the remainder in order. *) let rec drop_inner n = function | [] -> raise (Invalid_argument "Pdfutil.drop") | _::t -> if n = 1 then t else drop_inner (n - 1) t let drop l n = if n < 0 then raise (Invalid_argument "Pdfutil.drop") else if n = 0 then l else drop_inner n l let drop' n l = drop l n let rec dropwhile p = function | [] -> [] | h::t -> if p h then dropwhile p t else (h::t) (* Split a list [l] into two parts, the first part containing [n] elements. *) let cleave l n = let rec cleave_inner l left n = if n = 0 then rev left, l else match l with | [] -> raise (Invalid_argument "Pdfutil.cleave: not enough elements") | _ -> cleave_inner (tl l) (hd l::left) (n - 1) in if n < 0 then raise (Invalid_argument "Pdfutil.cleave: negative argument") else cleave_inner l [] n (* Returns elements for which p is true, until one is not, paired with the remaining list. The same as [takewhile p l], [dropwhile p l], but requiring only one pass over the list. *) let cleavewhile p l = let rec cleavewhile_inner p l elts = match l with | [] -> rev elts, [] | e::es -> if p e then cleavewhile_inner p es (e::elts) else rev elts, l in cleavewhile_inner p l [] (* The same, faster, but output lists are unordered. *) let cleavewhile_unordered p l = let rec cleavewhile_unordered_inner p l elts = match l with | [] -> elts, [] | e::es -> if p e then cleavewhile_unordered_inner p es (e::elts) else elts, l in cleavewhile_unordered_inner p l [] (* Isolate a central section of a list, from the first element after the element for which predicate [p] is true, to the element before [p'] is first true. *) let isolate p p' l = let _, during_and_after = cleavewhile (notpred p) l in match during_and_after with | [] -> [] | _::t -> fst (cleavewhile (notpred p') t) (* Collate a list into a list of lists based upon a comparison function by which it has already been sorted. e.g [collate [1; 2; 2; 3; 3]] calculates [[[1]; [2;2]; [3;3]]]. *) let collate cmp l = let rec collate_inner prev = function | [] -> rev prev | h::t -> let x, y = cleavewhile (fun a -> cmp h a = 0) (h::t) in collate_inner (x::prev) y in collate_inner [] l (* Split a list into some lists of length [n] (and possibly a final one of length < [n]). *) let splitinto n l = let rec splitinto_inner a n l len = match l with [] -> rev a | _ -> if len < n then rev (l::a) else let h, t = cleave l n in splitinto_inner (h::a) n t (len - n) in splitinto_inner [] n l (length l) (* Non-tail recursive version, for use when [n] is small and fixed. *) let rec takeatmost n l = match l with | h::t when n > 0 -> h :: takeatmost (n - 1) t | _ -> [] let rec dropatmost n l = match l with | _::t when n > 0 -> dropatmost (n - 1) t | l -> l let rec splitinto_small n l = match l with | [] -> [] | _ -> let first = takeatmost n l in first :: splitinto_small n (dropatmost n l) (* Split a list [l] at the given points. Point 1 means after the first element. *) let rec splitat_inner prev l = function | [] -> begin match l with [] -> rev prev | _ -> rev (l::prev) end | h::t -> let this, rest = cleave l h in splitat_inner (this::prev) rest t let splitat points l = splitat_inner [] l (couple (fun a b -> b - a) (0::points)) (* Select the nth element in a list (first is element 1) *) let select n l = try hd (drop l (n - 1)) with Invalid_argument _ (*"drop"*) | Failure _ (*"hd"*) -> raise (Invalid_argument "Pdfutil.select") (* Replace the nth element of a list (first is element 1) *) let rec replace_number_inner prev n e = function | [] -> rev prev | l::ls -> if n = 1 then replace_number_inner (e::prev) (n - 1) e ls else replace_number_inner (l::prev) (n - 1) e ls let replace_number n e l = replace_number_inner [] n e l (* Simple list utilities. *) let isnull = function [] -> true | _ -> false let notnull = function [] -> false | _ -> true (* Find the last element of a list. *) let rec last = function | [] -> raise (Invalid_argument "Pdfutil.last") | x::[] -> x | _::xs -> last xs (* Produce a list containing all but the last element of a list *) let all_but_last = function | [] | [_] -> [] | l -> rev (tl (rev l)) (* Find the first and last element of a list. If the list has one element, that is returned twice. *) let extremes = function | [] -> raise (Invalid_argument "Pdfutil.extremes") | x::[] -> x, x | x::xs -> x, last xs (* Return the first, middle and last elements of a list which has length at least two. *) let extremes_and_middle = function | [] | [_] -> raise (Invalid_argument "Pdfutil.extremes_and_middle") | h::t -> let m, l = cleave t (length t - 1) in h, m, hd l (* Set a boolean reference. *) let set r = r := true (* Clear a boolean reference. *) let clear r = r := false (* Change the value of a boolean reference. *) let flip r = r := not !r (* Increment and decrement integer references [r] by an integer [n]. *) let ( += ) r n = r := !r + n let ( -= ) r n = r := !r - n let ( /= ) r n = r := !r / n let ( *= ) r n = r := !r * n (* Similar functions on floating-point references. *) let ( +.= ) r n = r := !r +. n let ( -.= ) r n = r := !r -. n let ( /.= ) r n = r := !r /. n let ( *.= ) r n = r := !r *. n (* Vectors in two dimensions. *) type vector = float * float (* Make a vector from a point [(x0, y0)] to a point [(x1, y1)]. *) let mkvector (x0, y0) (x1, y1) = x1 -. x0, y1 -. y0 (* Invert a vector. *) let invert (a, b) = -.a, -.b (* Offset a point [(px, py)] by a vector [(x, y)]. *) let offset_point (x, y) (px, py) = px +. x, py +. y (* Find the vector pi / 2 anticlockwise from the given one. *) let perpendicular (a, b) = -.b, a (* Square a number *) let sqr x = x *. x (* Find the length of a vector. *) let veclength (x, y) = sqrt (sqr x +. sqr y) (* Scale a vector to a length [l]. *) let scalevectolength l (a, b) = let currentlength = veclength (a, b) in if currentlength = 0. then (a, b) else let factor = l /. currentlength in a *. factor, b *. factor (* Make a unit vector from [s] to [e] *) let mkunitvector s e = scalevectolength 1. (mkvector s e) (* Find the point equidistant between two others. *) let between (x, y) (x', y') = (x +. x') /. 2., (y +. y') /. 2. (* The cartesian distance between two points. *) let distance_between (px, py) (px', py') = sqrt (sqr (px -. px') +. sqr (py' -. py)) (* The largest power of two by which [n] is exactly divisible. *) let largest_pow2_divisible n = let rec s test n = if n mod test = 0 then s (test * 2) n else test / 2 in s 1 n (* Find the largest power of two smaller or equal to an integer [t]. *) let pow2lt t = let rec pow2lt_i target current = if current * 2 > target then current else pow2lt_i target (current * 2) in pow2lt_i t 1 (* Find the largest power of two greater or equal to an integer [t]. *) let pow2gt t = let lt = pow2lt t in if lt = t then t else lt * 2 (* Find the integer base two logarithm of a number. *) let log2of t = let rec log2of_i target num = if num * 2 > target then 0 else let n = log2of_i target (num * 2) in n + 1 in log2of_i t 1 (* Integer compare function --- saves the cost of polymorphic comparisons. *) let compare_i (a : int) b = if a < b then -1 else if a > b then 1 else 0 (* Reverse comparison *) let rev_compare a b = -compare a b (* The integer range between $[s..e]$ inclusive. *) let ilist s e = if e < s then raise (Invalid_argument "Pdfutil.ilist") else let nums = ref [] in let rec ilist s e = if s = e then nums =| e else (nums =| s; ilist (s + 1) e) in ilist s e; rev !nums (* Same, but return null list for ilist x x rather than [x] *) let ilist_null s e = if s = e then [] else ilist s e (* Same, but upon failure just return null. *) let ilist_fail_null s e = if s > e then [] else ilist_null s e (* A common case: Make indexes for a list *) let indx l = if l = [] then [] else ilist 1 (length l) (* Same zero-indexed. *) let indx0 l = if l = [] then [] else ilist 0 (length l - 1) (* Same, n-indexed. *) let indxn n l = if l = [] then [] else ilist n (n + length l - 1) (* Even/odd predicates. Zero is considered even, -1 odd, -2 even etc. *) let even x = x mod 2 = 0 let odd = notpred even (* Exclusive Or of [a] and [b]. *) let ( |&| ) a b = (a || b) && not (a && b) (* The identity function. *) let ident x = x (* An array analog of [List.iter2].*) let array_iter2 f a b = if Array.length a = Array.length b then if Array.length a = 0 then () else for x = 0 to (Array.length a) - 1 do f (Array.get a x) (Array.get b x) done else raise (Invalid_argument "Pdfutil.array_iter2") let array_map2 f a b = if Array.length a = Array.length b then Array.init (Array.length a) (function i -> f a.(i) b.(i)) else raise (Invalid_argument "Pdfutil.array_map2") (* Some simple functions for working with the [option] type. *) let some = function None -> false | _ -> true let none = function None -> true | _ -> false let unopt = function | Some x -> x | None -> failwith "unopt" let rec losenones prev = function | [] -> rev prev | None::t -> losenones prev t | Some h::t -> losenones (h::prev) t let losenones l = losenones [] l let option_map f l = losenones (map f l) let option_map2 f a b = losenones (map2 f a b) (* Integer-specialised minimum and maximum functions for speed, overriding Stdlib.min and Stdlib.max. *) let min (a : int) b = if a < b then a else b let max (a : int) b = if a > b then a else b (* Floating point ones. *) let fmin (a : float) b = if a < b then a else b let fmax (a : float) b = if a > b then a else b let fabs x = abs_float x (* The union of two rectangles, each defined by its minimum and maximum coordinates *) let box_union (xmin0, xmax0, ymin0, ymax0) (xmin1, xmax1, ymin1, ymax1) = min xmin0 xmin1, max xmax0 xmax1, min ymin0 ymin1, max ymax0 ymax1 (* The union of two rectangles, each defined by its minimum and maximum coordinates *) let box_union_float (xmin0, xmax0, ymin0, ymax0) (xmin1, xmax1, ymin1, ymax1) = fmin xmin0 xmin1, fmax xmax0 xmax1, fmin ymin0 ymin1, fmax ymax0 ymax1 (* The intersection rectangle of two rectangles defined by integers. [x0, y0] etc refer to the top left, [x1, y1] etc. to the bottom right. *) let box_overlap ax0 ay0 ax1 ay1 bx0 by0 bx1 by1 = if ax0 > bx1 || ay0 > by1 || ax1 < bx0 || ay1 < by0 then None else Some (max ax0 bx0, max ay0 by0, min ax1 bx1, min ay1 by1) (* The same for floating point coordinates. *) let box_overlap_float ax0 ay0 ax1 ay1 bx0 by0 bx1 by1 = if ax0 > bx1 || ay0 > by1 || ax1 < bx0 || ay1 < by0 then None else Some (fmax ax0 bx0, fmax ay0 by0, fmin ax1 bx1, fmin ay1 by1) (* Apply a function [f] [n] times to initial argument [arg]. *) let rec applyn f n arg = if n = 0 then arg else applyn f (n - 1) (f arg) (* The type of binary trees. *) type 'a tree = Lf | Br of 'a * 'a tree * 'a tree (* Define pi. *) let pi = 4. *. atan 1. (* Define sqrt 2. *) let root2 = sqrt 2. (* Radians of degrees. *) let rad_of_deg a = a *. pi /. 180. (* Degrees of radians. *) let deg_of_rad a = a *. 180. /. pi (* Constant boolean predicates *) let always _ = true let never _ = false (* A null hash table. *) let null_hash () = Hashtbl.create 0 let tryfind table k = try Some (Hashtbl.find table k) with Not_found -> None (* Extract all (key, value) pairs from a hash table. *) let list_of_hashtbl t = let contents = ref [] in Hashtbl.iter (fun k v -> contents =| (k, v)) t; !contents (* Build a hashtable from a dictionary *) let hashtable_of_dictionary pairs = let table = Hashtbl.create (length pairs * 2) in iter (fun (k, v) -> Hashtbl.add table k v) pairs; table (* Build a hash set from a dictionary. *) let hashset_of_list l = let table = Hashtbl.create (length l * 2) in iter (fun k -> Hashtbl.add table k ()) l; table (* Round a number. *) let round x = let c = ceil x in let f = floor x in if c -. x <= x -. f then c else f let iround x = int_of_float (round x) (* Render a float normal by replacing anything abnormal by 0. *) let safe_float f = match classify_float f with | FP_nan | FP_infinite | FP_zero | FP_subnormal -> 0. | _ -> f (* Build a tuple *) let tuple x y = x, y (* Make a unit function. *) let mkunit f x = fun () -> f x (* Swap two elements of an array. *) let swap a i j = let t = a.(i) in a.(i) <- a.(j); a.(j) <- t (* Print floats, integers or int32 values with spaces between them. *) let print_floats fs = iter (fun x -> print_float x; print_string " ") fs; print_newline () let print_ints is = iter (fun x -> print_int x; print_string " ") is; print_newline () let print_int32s is = iter (fun x -> Printf.printf "%li " x) is; print_newline () let leafnames_of_dir d = Array.to_list (Sys.readdir d) (* Roman numerals. *) let roman_vals = [(900, "CM"); (500, "D"); (400, "CD"); (100, "C"); (100, "C"); (100, "C"); (90, "XC"); (50, "L"); (40, "XL"); (10, "X"); (10, "X"); (10, "X"); (9, "IX"); (5, "V"); (4, "IV"); (1, "I"); (1, "I"); (1, "I")] let rec roman n = if n < 1 then "" else if n >= 1000 then implode (many 'M' (n / 1000)) ^ roman (n mod 1000) else let rec roman_recurse n = function | [] -> "" | (n', s)::t -> if n >= n' then s ^ roman_recurse (n - n') t else roman_recurse n t in assert (n > 0 && n < 1000); roman_recurse n roman_vals let roman_upper = roman let roman_lower n = String.lowercase_ascii (roman n) let memoize f = let result = ref None in fun () -> match !result with | Some thing -> thing | None -> result := Some (f ()); unopt !result let contents_of_file filename = let ch = open_in_bin filename in try let s = really_input_string ch (in_channel_length ch) in close_in ch; s with e -> close_in ch; raise e (* A clock for debugging huge files without needing the Unix module. Does not work on Windows. Needs GNU version of POSIX date command (gdate with homebrew on MacOS). *) let clock () = let tempfile = Filename.temp_file "cpdf" "strftime" in let command = Filename.quote_command "gdate" ~stdout:tempfile ["+%S-%M-%H-%3N"] in let outcode = Sys.command command in if outcode > 0 then raise (Failure "Date command returned non-zero exit code") else let r = contents_of_file tempfile in Sys.remove tempfile; let get_int o l = int_of_string (String.sub r o l) in float_of_int (get_int 6 2 * 3600 + get_int 3 2 * 60 + get_int 0 2) +. float_of_int (get_int 9 3) /. 1000. let time = ref 0. (*ref (clock ())*) let tt' () = () (*(*Gc.major ();*) let t = clock () in Pdfe.log (Printf.sprintf "Elapsed: %.2f\n" (t -. !time)); time := t*) let starts_with prefix s = let len_s = String.length s and len_pre = String.length prefix in let rec aux i = if i = len_pre then true else if String.get s i <> String.get prefix i then false else aux (i + 1) in len_s >= len_pre && aux 0 camlpdf-2.8.1/pdfutil.mli000066400000000000000000000575741477056064700153440ustar00rootroot00000000000000(** General functions Typically one will [open Pdfutil]. *) (** {2 Debug Printing} *) (** Print a string to standard output and flush. *) val flprint : string -> unit (** Print a string to standard error and flush. *) val fleprint : string -> unit (** Print a list of floating point numbers separated by spaces. *) val print_floats : float list -> unit (** Print a list of integers separated by spaces *) val print_ints : int list -> unit (** Print a list of [int32]s separated by spaces *) val print_int32s : int32 list -> unit (** {2 Strings} *) (** Return the first character of a string, should it have one. Otherwise return [None]. *) val firstchar : string -> char option (** Return the first character of a string, should it have one. Otherwise return [None]. *) val lastchar : string -> char option (** List of characters representing a string. *) val explode : string -> char list (** String representing a list of characters. Fails if list is longer than [Sys.max_string_length]. *) val implode : char list -> string (** Make a string from a character. *) val string_of_char : char -> string (** Calling [string_replace_all x x' s] replaces all instances of [x] with [x'] in [s], returning a new string. *) val string_replace_all : string -> string -> string -> string (** The same, but provide a function for the replacement string *) val string_replace_all_lazy : string -> (unit -> string) -> string -> string (** The standard OCaml [starts_with] function, for versions of OCaml too old to have it. *) val starts_with : string -> string -> bool (** {2 Lists} *) val hd : ('a list -> 'a) val tl : ('a list -> 'a list) val rev : ('a list -> 'a list) val iter : (('a -> unit) -> 'a list -> unit) val iter2 : (('a -> 'b -> unit) -> 'a list -> 'b list -> unit) val iter3 : ('a -> 'b -> 'c -> unit) -> 'a list -> 'b list -> 'c list -> unit val append : 'a list -> 'a list -> 'a list val ( @ ) : ('a list -> 'a list -> 'a list) val flatten : 'a list list -> 'a list val rev_map : (('a -> 'b) -> 'a list -> 'b list) val map : ('a -> 'b) -> 'a list -> 'b list val map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list val split : ('a * 'b) list -> 'a list * 'b list val split3 : ('a * 'b * 'c) list -> 'a list * 'b list * 'c list val split5 : ('a * 'b * 'c * 'd * 'e) list -> 'a list * 'b list * 'c list * 'd list * 'e list val split6 : ('a * 'b * 'c * 'd * 'e * 'f) list -> 'a list * 'b list * 'c list * 'd list * 'e list * 'f list val split8 : ('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h) list -> 'a list * 'b list * 'c list * 'd list * 'e list * 'f list * 'g list * 'h list val combine : 'a list -> 'b list -> ('a * 'b) list val combine3 : 'a list -> 'b list -> 'c list -> ('a * 'b * 'c) list val fold_left : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a val fold_right : ('a -> 'b -> 'b) -> 'a list -> 'b -> 'b val length : ('a list -> int) val sort : (('a -> 'a -> int) -> 'a list -> 'a list) (** Tail-recursive versions of list functions (and some simple variations). See [Stdlib] for documentation. *) (** Sum of a list of integers. *) val sum : int list -> int (** Sum of a list of floats. *) val fsum : float list -> float (** Cumulative sum of a list given an initial value. For example, [cumulative_sum 1 [2; 3; 4]] is [[3; 6; 10]] *) val cumulative_sum : int -> int list -> int list (** Count the number of elements in a list for which predicate is true. *) val lcount : ('a -> bool) -> 'a list -> int (** Return just the non-[None] elements of an ['a option list] *) val losenones : 'a option list -> 'a list (** Map with a function returning an [option], dropping all [None] results and extracting all [Some] ones. *) val option_map : ('a -> 'b option) -> 'a list -> 'b list (** Like [option_map] but with a two-argument function and two (equal-length) input lists. Uses [List.rev_map2] internally and may raise the same exception. *) val option_map2 : ('a -> 'b -> 'c option) -> 'a list -> 'b list -> 'c list (** Synonym for [List.mem]. *) val mem : ('a -> 'a list -> bool) (** Position of an element in a list, or [None] if not found *) val position : 'a -> 'a list -> int option (** Position (1-based) in a list, or [None] if not found *) val position_1 : 'a -> 'a list -> int option (** Similar to [rev_map], but 3 arguments. *) val rev_map3 : ('a -> 'b -> 'c -> 'd) -> 'a list -> 'b list -> 'c list -> 'd list (** Similar to [map2], but 3 arguments. *) val map3 : ('a -> 'b -> 'c -> 'd) -> 'a list -> 'b list -> 'c list -> 'd list (** Similar to [rev_map], but 4 arguments. *) val rev_map4 : ('a -> 'b -> 'c -> 'd -> 'e) -> 'a list -> 'b list -> 'c list -> 'd list -> 'e list (** Similar to [map2], but 4 arguments. *) val map4 : ('a -> 'b -> 'c -> 'd -> 'e) -> 'a list -> 'b list -> 'c list -> 'd list -> 'e list (** Similar to [rev_map], but 5 arguments. *) val rev_map5 : ('a -> 'b -> 'c -> 'd -> 'e -> 'f) -> 'a list -> 'b list -> 'c list -> 'd list -> 'e list -> 'f list (** Similar to [map2], but 5 arguments. *) val map5 : ('a -> 'b -> 'c -> 'd -> 'e -> 'f) -> 'a list -> 'b list -> 'c list -> 'd list -> 'e list -> 'f list (** Similar to [rev_map], but 6 arguments. *) val rev_map6 : ('a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'g) -> 'a list -> 'b list -> 'c list -> 'd list -> 'e list -> 'f list -> 'g list (** Similar to [map2], but 6 arguments. *) val map6 : ('a -> 'b -> 'c -> 'd -> 'e -> 'f -> 'g) -> 'a list -> 'b list -> 'c list -> 'd list -> 'e list -> 'f list -> 'g list (** [take l n] takes [n] elements from the list raising [Invalid_argument] if there are not enough elements to take or if n < 0. *) val take : 'a list -> int -> 'a list (** The same as [take], but with the arguments reversed. *) val take' : int -> 'a list -> 'a list (** [drop l n] drops [n] elements from the list raising [Invalid_argument] if [n] < 0 or there are not enough elements. *) val drop : 'a list -> int -> 'a list (** Same as [drop], but with the arguments reversed. *) val drop' : int -> 'a list -> 'a list (** Take elements from a list while a given predicate is true, returning them in order. *) val takewhile : ('a -> bool) -> 'a list -> 'a list (** The same as [takewhile], but the list is returned in reverse order. *) val takewhile_reverse : ('a -> bool) -> 'a list -> 'a list (** Drop elements from a list while a given predicate is true. *) val dropwhile : ('a -> bool) -> 'a list -> 'a list (** [cleave l n] splits [l] into two parts, returned as a tuple. The first contains the first [n] elements, the second the remainder. Order is preserved. [Invalid_argument] is raised on negative argument or not enough elements in list. *) val cleave : 'a list -> int -> 'a list * 'a list (** Same, but split point controlled by a predicate, which is true for elements in the first returned list. e.g [cleavewhile even [2;4;5;6]] produces [([2;4], [5;6])] *) val cleavewhile : ('a -> bool) -> 'a list -> 'a list * 'a list (** The same as [cleavewhile], but the output lists are each unordered. *) val cleavewhile_unordered : ('a -> bool) -> 'a list -> 'a list * 'a list (** [isolate p p' l] isolate a central section of a list [l], from the first element after the elements for which predicate [p] is true, to the element before [p'] is first true. *) val isolate : ('a -> bool) -> ('a -> bool) -> 'a list -> 'a list (** Interleave an element among a list, so that [interleave 0 [1; 2; 3]] yields [[1; 0; 2; 0; 3]]. An empty or singleton list is unchanged. *) val interleave : 'a -> 'a list -> 'a list (** Interleave two equal-length lists, taking from the first list first. *) val interleave_lists : 'a list -> 'a list -> 'a list (** Collate a list into a list of lists based upon a comparison function by which it has already been sorted. e.g [collate compare [1; 2; 2; 3; 3]] calculates [[[1]; [2;2]; [3;3]]]. *) val collate : ('a -> 'a -> int) -> 'a list -> 'a list list (** Map on lists of lists. So [map_lol f] is [map (map f)]. *) val map_lol : ('a -> 'b) -> ('a list list -> 'b list list) (** Produce a list of overlapping pairs of elements in a list in order, producing the empty list if on singleton input. e.g [pairs [1; 2; 3]] is [[(1, 2); (2, 3)]]. *) val pairs : 'a list -> ('a * 'a) list (** [List.mem] with arguments reversed. *) val mem' : 'a list -> 'a -> bool (** Remove duplicates from a list. *) val setify : 'a list -> 'a list (** Same as [setify], but preserve order. *) val setify_preserving_order : 'a list -> 'a list (** Same as [setify] but with good performance for large lists. *) val setify_large : 'a list -> 'a list (** The set [setminus a b] contains all those elements which are in [a] but are do not appear in [b]. *) val setminus : 'a list -> 'a list -> 'a list (** The same, but preserving order *) val setminus_preserving_order : 'a list -> 'a list -> 'a list (** Return a list of the heads of a list of lists, each of which has at least one element, preserving order. *) val heads : 'a list list -> 'a list (** Ditto, tails. *) val tails : 'a list list -> 'a list list (** Take a list of lists of equal length, and turn into a list of lists, the first containing all the first elements of the original lists, the second the second, and so on. *) val zipn : 'a list list -> 'a list list (** Couple the elements of a list [l] using given function. For instance, [couple ( + ) [[1; 3; 5]]] is [[4; 8]]. The two elements are applied to [f] in the order in which they appear in the input list. *) val couple : ('a -> 'a -> 'b) -> 'a list -> 'b list (** As [couple], but an extra unary function is applied to any last (odd) element. *) val couple_ext : ('a -> 'a -> 'b) -> ('a -> 'b) -> 'a list -> 'b list (** Apply [couple] repeatedly until only one element remains. Return that element. *) val couple_reduce : ('a -> 'a -> 'a) -> 'a list -> 'a (** A similar function to [couple], but the coupling is non-overlapping. So [pair ( + ) [1; 2; 3; 4]] is [3; 7]. *) val pair : ('a -> 'a -> 'a) -> 'a list -> 'a list (** A version of [pair] which adds a unary function for the singleton, much like [couple_ext]. *) val pair_ext : ('a -> 'a -> 'b) -> ('a -> 'b) -> 'a list -> 'b list (** As [couple_reduce] is to [couple], so [pair_reduce] is to [pair]. *) val pair_reduce : ('a -> 'a -> 'a) -> 'a list -> 'a val keep : (('a -> bool) -> 'a list -> 'a list) (** [List.filter] has a confusing name, so we define [keep] and [lose] to avoid error. [keep] keeps all those matching the predicate, [lose] loses all thos matching a predicate. *) val lose : ('a -> bool) -> ('a list -> 'a list) (** [many x n] makes a list of length [n] with each element equal to [x]. *) val many : 'a -> int -> 'a list (** A version where we need to apply unit each time, for instance when producing a list of random numbers. Result is ordered. *) val manyunique : (unit -> 'a) -> int -> 'a list (** Split a list into some lists of length [n] (and possibly a final one of length [< n]), preserving order. *) val splitinto : int -> 'a list -> 'a list list (** Non-tail recursive version of splitinto, for use only when [n] is small and fixed. *) val splitinto_small : int -> 'a list -> 'a list list (** Split a list at the given positions. Point 1 means after the first element *) val splitat : int list -> 'a list -> 'a list list (** Select the nth element in a list (first is element 1). Raises [Invalid_argument] if the number is out-of-range. *) val select : int -> 'a list -> 'a (** [replace n x xs] replaces the [n]th element of the list [xs] with [x] (the first is element 1) *) val replace_number : int -> 'a -> 'a list -> 'a list val isnull : 'a list -> bool val notnull : 'a list -> bool (** Predicates on the nullness of a list. *) (** Find the last element of a list. Raises [Invalid_argument] on empty list. *) val last : 'a list -> 'a (** Produce a list containing all but the last element of a list. For the empty list, returns the empty list. *) val all_but_last : 'a list -> 'a list (** Find the first and last element of a list. If the list has one element, that is returned twice. If it has no elements, raise [Invalid_argument]. *) val extremes : 'a list -> 'a * 'a (** Return the first, middle and last elements of a list which has length at least two. Otherwise, raise [Invalid_argument]. *) val extremes_and_middle : 'a list -> 'a * 'a list * 'a (** [ilist 2 5] returns [[2; 3; 4; 5]]. However, [ilist 5 2] raises [Invalid_argument]. *) val ilist : int -> int -> int list (** Same as [ilist], but return the empty list for [ilist x x] rather than [[x]] *) val ilist_null : int -> int -> int list (** Same as [ilist_null], but return empty list if start [>] end, instead of failing *) val ilist_fail_null : int -> int -> int list (** [indx l] returns [[1; 2; 3]] if [l] has length 3, for example. *) val indx : 'a list -> int list (** Same as [indx], but 0-based. *) val indx0 : 'a list -> int list (** Same as [indx], but n-based. *) val indxn : int -> 'a list -> int list (** Remove the second, fourth etc. elements from a list, saving the last element (if of even length) e.g [drop_evens [1; 2; 3; 4; 5; 6]] is [[1; 3; 5; 6]]. *) val drop_evens : 'a list -> 'a list (** Same as [drop_evens], but don't save the last element. *) val really_drop_evens : 'a list -> 'a list (** Remove the first, third etc. The last odd element is not saved. e.g [drop_odds [1;2;3;4;5;6;7]] is [[2;4;6]]. *) val drop_odds : 'a list -> 'a list (** Like [List.tl] but [[]] yields [[]]. *) val tail_no_fail : 'a list -> 'a list (** Append with reversed arguments. *) val ( @@ ) : 'a list -> 'a list -> 'a list (** [replaceinlist f x l] replaces any element of [l] for which [f l] is true with [x]. *) val replaceinlist : ('a -> bool) -> 'a -> 'a list -> 'a list (** Find the position of the first element matching a predicate. The first element is number one. Fails with [Not_found] if no element matches the predicate. *) val index : ('a -> bool) -> 'a list -> int (** Split a list into a list of lists at every point where a predicate is true *) val split_around : ('a -> bool) -> 'a list -> 'a list list (** {2 32 and 64 bit integers} *) val i32ofi : (int -> int32) val i32toi : (int32 -> int) val i32tof : (int32 -> float) val i32add : (int32 -> int32 -> int32) val i32sub : (int32 -> int32 -> int32) val i32div : (int32 -> int32 -> int32) val i32mul : (int32 -> int32 -> int32) val sr32 : (int32 -> int -> int32) val lsr32 : (int32 -> int -> int32) val lsl32 : (int32 -> int -> int32) val lor32 : (int32 -> int32 -> int32) val land32 : (int32 -> int32 -> int32) val lnot32 : (int32 -> int32) val lxor32 : (int32 -> int32 -> int32) val i32succ : (int32 -> int32) val i32pred : (int32 -> int32) val i32max : (int32 -> int32 -> int32) val i32min : (int32 -> int32 -> int32) val i64ofi : (int -> int64) val i64toi : (int64 -> int) val i64tof : (int64 -> float) val i64add : (int64 -> int64 -> int64) val i64sub : (int64 -> int64 -> int64) val i64div : (int64 -> int64 -> int64) val i64mul : (int64 -> int64 -> int64) val sr64 : (int64 -> int -> int64) val lsr64 : (int64 -> int -> int64) val lsl64 : (int64 -> int -> int64) val lor64 : (int64 -> int64 -> int64) val land64 : (int64 -> int64 -> int64) val lnot64 : (int64 -> int64) val lxor64 : (int64 -> int64 -> int64) val i64succ : (int64 -> int64) val i64pred : (int64 -> int64) val i64max : (int64 -> int64 -> int64) val i64min : (int64 -> int64 -> int64) val i32ofi64 : (int64 -> int32) val i64ofi32 : (int32 -> int64) (** Shortened names for functions from [Int32] and [Int64]. *) (** {2 Association lists} *) (** [lookup x l] looks up something, returning [None] if not found. *) val lookup : 'a -> ('a * 'b) list -> 'b option (** Same as [lookup], but no option type. Raises [Not_found] if the key is not there. *) val lookup_failnull : 'a -> ('a * 'b) list -> 'b (** [add k v l] Adds [(k, v)] to a dictionary, replacing any existing binding of [k]. *) val add : 'a -> 'b -> ('a * 'b) list -> ('a * 'b) list (** [replace k v l] replaces the existing binding of [k] in [l] with one with binds [k] to [v]. Raises [Not_found] if there is nothing to replace. *) val replace : 'a -> 'b -> ('a * 'b) list -> ('a * 'b) list (** Remove something from a list, if it's there. If not, don't complain. *) val remove : 'a -> ('a * 'b) list -> ('a * 'b) list (** Merge two lists, preferring elements in the second in the case of clashes. *) val mergedict : ('a * 'b) list -> ('a * 'b) list -> ('a * 'b) list (** {2 References} *) (** Set a boolean reference to [true] *) val set : bool ref -> unit (** Set a boolean reference to [false] *) val clear : bool ref -> unit (** Flip a boolean reference *) val flip : bool ref -> unit val ( += ) : int ref -> int -> unit val ( -= ) : int ref -> int -> unit val ( /= ) : int ref -> int -> unit val ( *= ) : int ref -> int -> unit (** Operations on integer references *) val ( +.= ) : float ref -> float -> unit val ( -.= ) : float ref -> float -> unit val ( /.= ) : float ref -> float -> unit val ( *.= ) : float ref -> float -> unit (** Operations on floating point references *) (** Cons something onto the contents of a list reference. *) val ( =| ) : 'a list ref -> 'a -> unit (** Append something to the front of the contents of a list reference. *) val ( =@ ) : 'a list ref -> 'a list -> unit (** {2 Geometry} *) (** The type of vectors. *) type vector = float * float (** [mkvector (a, b) (c, d)] makes a vector from point [(a, b)] to point [(c, d)]. *) val mkvector : float * float -> float * float -> vector (** Invert a vector. *) val invert : vector -> vector (** Offset a point by a vector. *) val offset_point : vector -> float * float -> vector (** Find the vector [pi / 2] anticlockwise from the given one. *) val perpendicular : 'a * float -> float * 'a (** Square a number *) val sqr : float -> float (** The length of a vector. *) val veclength : vector -> float (** Scale a vector to a given length. *) val scalevectolength : float -> vector -> vector (** Make a unit vector in the direction from one point to a second. *) val mkunitvector : float * float -> float * float -> vector (** Find the point equidistant between two others. *) val between : float * float -> float * float -> float * float (** Cartesian distance between two points. *) val distance_between : float * float -> float * float -> float (** {2 Numbers} *) (** Round a real. *) val round : float -> float (** The same, returning an integer. *) val iround : float -> int (** The largest power of two by which a number is exactly divisible. *) val largest_pow2_divisible : int -> int (** Largest power of two smaller or equal to an integer. *) val pow2lt : int -> int (** Largest power of two greater or equal to an integer. *) val pow2gt : int -> int (** Base two logarithm *) val log2of : int -> int (** [pow x y] is y to the power x *) val pow : int -> int -> int (** Monomorphic integer version of [Stdlib.compare] *) val compare_i : int -> int -> int val min : int -> int -> int val max : int -> int -> int (** Monomorphic integer versions of [Stdlib] functions. *) val fmin : float -> float -> float val fmax : float -> float -> float val fabs : float -> float (** Monomorphic floating-point versions of [Stdlib] functions *) val even : int -> bool val odd : (int -> bool) (** Even and odd predicates on integers. Work for negative numbers. *) (** Pi. *) val pi : float (** Square root of two. *) val root2 : float val rad_of_deg : float -> float val deg_of_rad : float -> float (** Convert between radians and degrees. *) (** The call [sign_extend l n] extends [n] of length [l] bits to fit a native integer *) val sign_extend : int -> int -> int (** A character is a decimal digit. *) val isdigit : char -> bool (** Same as [Stdlib.int_of_float] *) val toint : float -> int (** Make sure a floating point number is no degenarate, by making it zero if it is. *) val safe_float : float -> float (** {2 Options} *) val some : 'a option -> bool val none : 'a option -> bool (** Predicates on the someness or noneness of an ['a option]. *) (** Strip the [Some] from an option. Fail if it's [None]. *) val unopt : 'a option -> 'a (** {2 Hash tables} *) (** The empty zero-sized hash table. *) val null_hash : unit -> ('a, 'b) Hashtbl.t (** Option lookup on hashtables *) val tryfind : (('a, 'b) Hashtbl.t -> 'a -> 'b option) (** Make a list of key-value pairs reflecting the contents of a hash table. *) val list_of_hashtbl : ('a, 'b) Hashtbl.t -> ('a * 'b) list (** Build a hashtable from a dictionary (list of key-value pairs). Items are added from left to right, with no checking for duplicate keys being performed. *) val hashtable_of_dictionary : ('a * 'b) list -> ('a, 'b) Hashtbl.t (** Build a hash set from a list of keys. The values here are (). *) val hashset_of_list : 'a list -> ('a, unit) Hashtbl.t (** {2 Trees} *) (** The type for binary trees. *) type 'a tree = Lf | Br of 'a * 'a tree * 'a tree (** {2 Arrays} *) (** [iter2] on arrays. *) val array_iter2 : ('a -> 'b -> unit) -> 'a array -> 'b array -> unit (** [map2] on arrays. *) val array_map2 : ('a -> 'b -> 'c) -> 'a array -> 'b array -> 'c array (** Swaps the data at the given indexes in an array. *) val swap : 'a array -> int -> int -> unit (** Set all the values of an array. *) val set_array : 'a array -> 'a -> unit (** {2 Control flow} *) (** [memoize f] builds a memoized version of the function [f]. *) val memoize : (unit -> 'a) -> unit -> 'a (** The identity function. *) val ident : 'a -> 'a (** Apply a function [f] [n] times to initial argument [arg]. *) val applyn : ('a -> 'a) -> int -> 'a -> 'a (** This is equivalent to [let ( <| ) a b = a b] *) val ( <| ) : ('a -> 'b) -> 'a -> 'b (** [mkunit f x] gives [fun () -> f x] *) val mkunit : ('a -> 'b) -> 'a -> unit -> 'b (** {2 Tuples} *) (** Make a tuple. *) val tuple : 'a -> 'b -> 'a * 'b (** Consing to each of a pair of lists at the same time. *) val conspair : ('a * 'b) * ('a list * 'b list) -> 'a list * 'b list (** Version of [conspair] where there may or may not be somthing to cons in each case. *) val conspairopt : ('a option * 'b option) * ('a list * 'b list) -> 'a list * 'b list (** Make consecutive elements of an even-length list into a list of pairs. *) val pairs_of_list : 'a list -> ('a * 'a) list (** [do_return f g] Evaluate [f ()], evaluate and ignore [g ()], return [f ()], in that order. *) val do_return : (unit -> 'a) -> (unit -> 'b) -> 'a (** [do_many f n] calls [f ()] n times. *) val do_many : (unit -> unit) -> int -> unit (** {2 Equality} *) (** Equality. *) val eq : ('a -> 'a -> bool) (** Inequality. *) val neq : ('a -> 'a -> bool) (** Like [Stdlib.compare], but the other way around. *) val rev_compare : 'a -> 'a -> int (** {2 Logic} *) (** The always-true predicate. *) val always : 'a -> bool (** The always-false predicate. *) val never : 'a -> bool (** Exclusive OR *) val ( |&| ) : bool -> bool -> bool (** Invert a predicate. *) val notpred : ('a -> bool) -> 'a -> bool (** {2 Boxes} *) (** The smallest box enclosing both given integer boxes. Each box is [(xmin, xmax, ymin, ymax)]. *) val box_union : int * int * int * int -> int * int * int * int -> int * int * int * int (** The smallest box enclosing both given floating-point boxes. Each box is [(xmin, xmax, ymin, ymax)]. *) val box_union_float : float * float * float * float -> float * float * float * float -> float * float * float * float (** The intersection box (if any) of two integer boxes, each defined as [xmin ymin xmax ymax]. *) val box_overlap : int -> int -> int -> int -> int -> int -> int -> int -> (int * int * int * int) option (** The intersection box (if any) of two floating-point boxes, each defined as [xmin ymin xmax ymax]. *) val box_overlap_float : float -> float -> float -> float -> float -> float -> float -> float -> (float * float * float * float) option (** {2 Filenames and files} *) (** Return a list of leafnames for the given folder in the current folder *) val leafnames_of_dir : string -> string list (** Return the contents of a (binary) file as a string *) val contents_of_file : string -> string (** {2 Roman numerals} *) (** Uppercase roman representation of a number *) val roman_upper : int -> string (** Lowercase roman representation of a number *) val roman_lower : int -> string (**/**) (* This is legitimately not documented because it requires altering the source to use. See the .ml *) val tt' : unit -> unit camlpdf-2.8.1/pdfwrite.ml000066400000000000000000000610451477056064700153340ustar00rootroot00000000000000open Pdfutil open Pdfio (* If set, extra debug information will be printed to screen *) let write_debug = ref false (* The file header. *) let header pdf = Printf.sprintf "%%PDF-%i.%i\n%%\128\129\130\131\n" pdf.Pdf.major pdf.Pdf.minor (* Write the cross-reference table to a channel. *) let output_string_of_xref i n = let s = string_of_int n in let l = String.length s in for x = 0 to 10 - l - 1 do i.output_char '0' done; i.output_string s; i.output_string " 00000 n \n" let write_xrefs xrefs i = i.output_string "xref\n"; i.output_string "0 "; i.output_string (string_of_int (length xrefs + 1)); i.output_string " \n"; i.output_string "0000000000 65535 f \n"; iter (output_string_of_xref i) xrefs (* Convert a string to one suitable for output. *) let b = Buffer.create 30 let make_pdf_string s = Buffer.clear b; Buffer.add_char b '('; String.iter (function | ('(' | ')' | '\\') as c -> Buffer.add_char b '\\'; Buffer.add_char b c | '\n' -> Buffer.add_char b '\\'; Buffer.add_char b 'n' | '\r' -> Buffer.add_char b '\\'; Buffer.add_char b 'r' | '\t' -> Buffer.add_char b '\\'; Buffer.add_char b 't' | '\b' -> Buffer.add_char b '\\'; Buffer.add_char b 'b' | '\012' -> Buffer.add_char b '\\'; Buffer.add_char b 'f' | c -> Buffer.add_char b c) s; Buffer.add_char b ')'; Buffer.contents b let make_hex_pdf_string s = Buffer.clear b; Buffer.add_char b '<'; String.iter (fun c -> Buffer.add_string b (Printf.sprintf "%02x" (int_of_char c))) s; Buffer.add_char b '>'; Buffer.contents b (* We have two kinds of flat data to write: Strings and streams (we cannot represent streams as strings, since there is a langauge limit on the length of strings. *) type writeout = | WString of string | WStream of Pdf.stream (* Format a real number. We want real numbers with no exponents (format compliance), and no trailing zeroes (compactness). (Jan 2012 - have added special case for whole numbers. Can still get trailing zeroes on small values e.g 0.00001 => 0.000010, but no printf way to prevent this). In addition, on 32 bit systems, we now read in numbers > 2^30 or < -2^30 as floating point values so that we can preserve them. We should write such numbers out as integers too. But int_of_float gives the wrong answer here. So we must pre-check and produce an integer instead. *) let max_int_float = float_of_int max_int let min_int_float = float_of_int min_int let format_real x = let fl = floor x in if fl = x then begin if x > max_int_float || x < min_int_float then implode (all_but_last (explode (string_of_float x))) else string_of_int (int_of_float fl) end else if x < 0.0001 && x > -. 0.0001 then Printf.sprintf "%f" x else string_of_float x (* Character codes in a name < 33 or > 126 are replaced with hashed combinations (e.g #20 for space). If the name contains the null character, a warning is printed. *) let hexchar = function | 0 -> '0' | 1 -> '1' | 2 -> '2' | 3 -> '3' | 4 -> '4' | 5 -> '5' | 6 -> '6' | 7 -> '7' | 8 -> '8' | 9 -> '9' | 10 -> 'A' | 11 -> 'B' | 12 -> 'C' | 13 -> 'D' | 14 -> 'E' | 15 -> 'F' | _ -> raise (Failure "hexchar") let make_pdf_name_inner b s = for x = 1 to String.length s - 1 do (* skip / *) match String.get s x with | '\000' -> Pdfe.log (Printf.sprintf "Warning: name %S contains the null character\n" s); Buffer.add_string b "#00" | h when h < '\033' || h > '\126' || Pdf.is_delimiter h || h = '#' -> Buffer.add_char b '#'; Buffer.add_char b (hexchar ((int_of_char h) / 16)); Buffer.add_char b (hexchar ((int_of_char h) mod 16)); | h -> Buffer.add_char b h done (* See if a name needs altering by [make_pdf_name_inner]. We ignore the first character, since a '/' is a delimter, and this is fine... *) let rec needs_processing_inner s p l = (p <= l - 1) && (match String.unsafe_get s p with | x when x < '\033' || x > '\126' || Pdf.is_delimiter x || x = '#' -> true | _ -> needs_processing_inner s (p + 1) l) let needs_processing s = let l = String.length s in if l < 2 then false else needs_processing_inner s 1 l let b = Buffer.create 30 let make_pdf_name n = if needs_processing n then if n = "" || String.unsafe_get n 0 <> '/' then begin Pdfe.log "warning: bad name"; "/" end else begin Buffer.clear b; Buffer.add_char b '/'; make_pdf_name_inner b n; Buffer.contents b end else n (* Calculate a strings and streams representing the given pdf datatype instance, assuming it has no unresolved indirect references. *) let rec strings_of_array ?(hex=false) f changetable = function | [] -> () | [x] -> strings_of_pdf ~hex f changetable x | h::(h'::_ as tail) -> strings_of_pdf ~hex f changetable h; begin match h' with Pdf.Name _ | Pdf.String _ | Pdf.Array _ | Pdf.Dictionary _ -> () | _ -> match h with Pdf.String _ | Pdf.Array _ | Pdf.Dictionary _ -> () | _ -> f (WString " ") end; strings_of_array ~hex f changetable tail and strings_of_dictionary ?(hex=false) f changetable = function | [] -> () | [(k, v)] -> f (WString (make_pdf_name k)); begin match v with Pdf.Name _ | Pdf.String _ | Pdf.Array _ | Pdf.Dictionary _ -> () | _ -> f (WString " ") end; strings_of_pdf ~hex:(hex && k = "/ID") f changetable v | (k, v)::t -> f (WString (make_pdf_name k)); begin match v with Pdf.Name _ | Pdf.String _ | Pdf.Array _ | Pdf.Dictionary _ -> () | _ -> f (WString " ") end; strings_of_pdf ~hex:(hex && k = "/ID") f changetable v; strings_of_dictionary ~hex f changetable t and strings_of_pdf ?(hex=false) f changetable = function | Pdf.Null -> f (WString "null") | Pdf.Boolean b -> f (WString (string_of_bool b)) | Pdf.Integer n -> f (WString (string_of_int n)) | Pdf.Real r -> f (WString (format_real r)) | Pdf.String s -> if hex then f (WString (make_hex_pdf_string s)) else f (WString (make_pdf_string s)) | Pdf.Name n -> f (WString (make_pdf_name n)) | Pdf.Array elts -> f (WString "["); strings_of_array ~hex f changetable elts; f (WString "]"); | Pdf.Dictionary entries -> f (WString "<<"); strings_of_dictionary ~hex f changetable entries; f (WString ">>"); | Pdf.Stream {contents = (dict, data)} -> strings_of_pdf ~hex f changetable dict; f (WString "\010stream\010"); f (WStream data); f (WString "\010endstream"); | Pdf.Indirect n -> let n' = try Hashtbl.find changetable n with Not_found -> n in f (WString (string_of_int n')); f (WString " 0 R") (* Produce a single string from a PDF object. *) let b = Buffer.create 100 let string_of_pdf s = Buffer.clear b; strings_of_pdf (function (WString x) -> Buffer.add_string b x | _ -> ()) (Hashtbl.create 0) s; Buffer.contents b let string_of_pdf_including_data s = begin match s with Pdf.Stream _ -> Pdf.getstream s | _ -> () end; Buffer.clear b; strings_of_pdf (function | WString x -> Buffer.add_string b x | WStream stream -> match stream with | Got data -> Buffer.add_string b (string_of_bytes data) | ToGet _ -> Printf.printf "WARNING: toget in string_of_pdf_including_data\n") (Hashtbl.create 0) s; Buffer.contents b (* Inter-module recursion, for debug *) let _ = Pdfcrypt.string_of_pdf := string_of_pdf let _ = Pdfcodec.string_of_pdf := string_of_pdf let _ = Pdf.string_of_pdf := string_of_pdf let debug_whole_pdf pdf = Pdfe.log (Printf.sprintf "trailerdict = %s\n" (string_of_pdf pdf.Pdf.trailerdict)); Pdf.objiter (fun i o -> Pdfe.log (Printf.sprintf "%i = %s\n" i (string_of_pdf o))) pdf let strings_of_pdf_object f (_, pdfobject) n' changetable = f (WString (string_of_int n')); f (WString " 0 obj\n"); strings_of_pdf f changetable pdfobject; f (WString "\nendobj\n") (* Output a stream. *) let output_stream o s = Pdf.getstream s; match s with | Pdf.Stream {contents = _, Pdf.Got arr} -> if bytes_size arr > 0 then getinit o arr 0 (bytes_size arr) | _ -> raise (Pdf.PDFError "output_stream") (* Encrypting a PDF while writing *) type encryption_method = | PDF40bit | PDF128bit | AES128bit of bool (* true = encrypt metadata, false = don't. *) | AES256bit of bool (* as above *) | AES256bitISO of bool (* as above *) | AlreadyEncrypted (* Used as a flag to prevent garbage collection *) type encryption = {encryption_method : encryption_method; owner_password : string; user_password : string; permissions : Pdfcrypt.permission list} let crypt_if_necessary pdf = function | None -> pdf | Some enc -> let f = match enc.encryption_method with | PDF40bit -> Pdfcrypt.encrypt_pdf_40bit | PDF128bit -> Pdfcrypt.encrypt_pdf_128bit | AES128bit em -> Pdfcrypt.encrypt_pdf_AES em | AES256bit em -> Pdfcrypt.encrypt_pdf_AES256 em | AES256bitISO em -> Pdfcrypt.encrypt_pdf_AES256ISO em | AlreadyEncrypted -> fun _ _ _ pdf -> pdf in f enc.user_password enc.owner_password enc.permissions pdf let flatten_W o = function | WString s -> o.output_string s | WStream data -> output_stream o (Pdf.Stream {contents = Pdf.Null, data}) (* Functions for object streams. NB no attempt is made to catch objects which shouldn't be in a stream - this is the responsibility of the caller. *) let bake_object_streams compress pdf numbers = iter (fun (tostream, objects) -> let data, first = let output, d = Pdfio.input_output_of_bytes 32000 in let strings = map (fun x -> string_of_pdf (Pdf.lookup_obj pdf x) ^ " ") objects in iter (Pdf.removeobj pdf) objects; let lengths = map String.length strings in let byte_offsets = 0 :: all_but_last (cumulative_sum 0 lengths) in iter2 (fun o boff -> output.Pdfio.output_string (string_of_int o); output.Pdfio.output_string " "; output.Pdfio.output_string (string_of_int boff); output.Pdfio.output_string " ") objects byte_offsets; let first = output.Pdfio.pos_out () in iter output.Pdfio.output_string strings; (extract_bytes_from_input_output output d, first) in let dict = Pdf.Dictionary [("/Type", Pdf.Name "/ObjStm"); ("/Length", Pdf.Integer (bytes_size data)); ("/N", Pdf.Integer (length objects)); ("/First", Pdf.Integer first)] in let obj = Pdf.Stream {contents = (dict, Pdf.Got data)} in if compress then Pdfcodec.encode_pdfstream ~only_if_smaller:true pdf Pdfcodec.Flate obj; Pdf.addobj_given_num pdf (tostream, obj)) numbers (* Modify PDF to reinstate object streams from the saved hints. Then returns the xref stream. Hints are now invalid, of course. Numbering scheme: 1...n object streams n+1...m objects in object streams m+1...p objects not in object streams p+1 xref stream *) let reinstate_object_streams compress we_will_be_encrypting pdf = (* Adobe Reader can't cope with the document catalog being in a stream in an encrypted file, despite the ISO standard clearly allowing it. Make sure that, if we're encrypting, we remove any existing hint *) if we_will_be_encrypting then Hashtbl.remove pdf.Pdf.objects.Pdf.object_stream_ids pdf.Pdf.root; (* Build stream_objnum (streamnum, objects_for_this_stream) pairs. Take account of missing objects! *) let objects_for_streams = let table = null_hash () and keys = null_hash () in Hashtbl.iter (fun objnum instream -> if not (Hashtbl.mem keys instream) then Hashtbl.add keys instream (); Hashtbl.add table instream objnum) pdf.Pdf.objects.Pdf.object_stream_ids; let lists = ref [] in Hashtbl.iter (fun instream _ -> lists =| (instream, Hashtbl.find_all table instream)) keys; !lists in (* The nonstream objects are any not included in the objects_for_streams *) let nonstream_objects = let all_in_stream = null_hash () in iter (fun x -> Hashtbl.add all_in_stream x ()) (flatten (map snd objects_for_streams)); option_map (fun x -> if not (Hashtbl.mem all_in_stream x) then Some x else None) (Pdf.objnumbers pdf) in (* Now renumber the PDF such that we have (1...n, [n + 1....m]) used for the and renumber the nonstream objects to (m + 1).... Also renumber objects_for_streams and nonstream_objects *) let n = length objects_for_streams in let m = n + sum (map length (map snd objects_for_streams)) in let changetable = null_hash () in (* Add all the objects_for_streams *) iter2 (Hashtbl.add changetable) (map fst objects_for_streams) (indx objects_for_streams); (* Add all the changes for the objects within streams *) let x = flatten (map snd objects_for_streams) in iter2 (Hashtbl.add changetable) x (indxn (n + 1) x); (* Add all the changes for the nonstream objects *) iter2 (Hashtbl.add changetable) nonstream_objects (indxn (m + 1) nonstream_objects); let pdf' = Pdf.renumber changetable pdf in pdf.Pdf.root <- pdf'.Pdf.root; pdf.Pdf.objects <- pdf'.Pdf.objects; pdf.Pdf.trailerdict <- pdf'.Pdf.trailerdict; (* Apply the changes to objects_for_streams *) let renumbered_objects_for_streams = combine (indx (map (Hashtbl.find changetable) (map fst objects_for_streams))) (map_lol (Hashtbl.find changetable) (map snd objects_for_streams)) in (* Now build the object streams and bake them into the PDF *) bake_object_streams compress pdf renumbered_objects_for_streams; renumbered_objects_for_streams (* Build the xref stream from collected data. The input xref positions 1..n and m+1...p. We build xreferences to a) The 1...n ones from xrefs b) The n+1...m ones from renumbered_objects_for_streams c) The m+1...p ones from xrefs This stream is then returned - it will be written as object p + 1. *) (* Maximum bytes required to represent the numbers in a list *) let max_bytes_required l = if l = [] then raise (Failure "max_bytes_required") else let r = ref (fold_left max min_int l) and b = ref 0 in while let v = !r > 0 in r := !r lsr 8; v do b += 1 done; max 1 !b (* Output nbytes bytes from x, highest byte first to the list reference given *) let output_bytes nbytes x o = for pos = nbytes - 1 downto 0 do o.output_byte ((x land (255 lsl (pos * 8))) lsr (pos * 8)) done let make_xref_stream pdf xrefs renumbered_objects_for_streams = let entries = ref [(0, 65535, 0)] in (* 1...n ones from xrefs *) let type1s, type1s_tranche2 = cleave xrefs (length renumbered_objects_for_streams) in entries =@ rev (map (fun x -> (1, x, 0)) type1s); (* n+1...m ones from renumbered_objects_for_streams *) iter (fun (snum, objnums) -> entries =@ rev (map (fun i -> (2, snum, i)) (indx0 objnums))) renumbered_objects_for_streams; (* m+1...p ones from xrefs *) entries =@ rev (map (fun x -> (1, x, 0)) type1s_tranche2); let w1 = max_bytes_required (map (fun (x, _, _) -> x) !entries) and w2 = max_bytes_required (map (fun (_, x, _) -> x) !entries) and w3 = max_bytes_required (map (fun (_, _, x) -> x) !entries) in let data = let o, bytes = Pdfio.input_output_of_bytes 4096 in iter (function (typ, a, b) -> output_bytes w1 typ o; output_bytes w2 a o; output_bytes w3 b o) (rev !entries); Pdfio.extract_bytes_from_input_output o bytes in let dict = Pdf.Dictionary (fold_right (fun (k, v) d -> add k v d) [("/Type", Pdf.Name "/XRef"); ("/Root", Pdf.Indirect pdf.Pdf.root); ("/Size", Pdf.Integer (length !entries)); ("/W", Pdf.Array [Pdf.Integer w1; Pdf.Integer w2; Pdf.Integer w3]); ("/Length", Pdf.Integer (bytes_size data))] (match pdf.Pdf.trailerdict with Pdf.Dictionary d -> d | _ -> [])) in let xrefstream = Pdf.Stream {contents = (dict, Pdf.Got data)} in Pdfcodec.encode_pdfstream ~only_if_smaller:true pdf Pdfcodec.Flate ~predictor:Pdfcodec.PNGUp ~predictor_columns:(w1 + w2 + w3) xrefstream; xrefstream (* Build hints for object streams from nothing, optionally preserving existing streams. *) let generate_object_stream_hints we_will_be_encrypting pdf preserve_existing = if not preserve_existing then Hashtbl.clear pdf.Pdf.objects.Pdf.object_stream_ids; (* Adobe Reader can't cope with the document catalog being in a stream in an encrypted file, despite the ISO standard clearly allowing it. Make sure that, if we're encrypting, we remove any existing hint *) if we_will_be_encrypting then Hashtbl.remove pdf.Pdf.objects.Pdf.object_stream_ids pdf.Pdf.root; let biggest_hint = max (fold_left max min_int (map snd (list_of_hashtbl pdf.Pdf.objects.Pdf.object_stream_ids))) 0 in let possibles = option_map (fun x -> if not (Hashtbl.mem pdf.Pdf.objects.Pdf.object_stream_ids x) then Some x else None) (Pdf.objnumbers pdf) in let for_streams, indirect_lengths = let indirect_lengths = null_hash () in (option_map (fun x -> match Pdf.lookup_obj pdf x with | Pdf.Stream {contents = (Pdf.Dictionary d, _)} -> begin begin match lookup "/Length" d with | Some (Pdf.Indirect i) -> Hashtbl.add indirect_lengths i () | _ -> () end; None end | _ -> Some x) possibles, indirect_lengths) in (* Remove indirect lengths and catalog. *) let final = option_map (fun x -> if Hashtbl.mem indirect_lengths x || (x = pdf.Pdf.root && we_will_be_encrypting) then None else Some x) for_streams in let groups = splitinto 250 (sort compare final) in iter2 (fun items groupnum -> iter (fun i -> Hashtbl.add pdf.Pdf.objects.Pdf.object_stream_ids i groupnum) items) groups (indxn (biggest_hint + 1) groups) (* Used when recrypting *) let dummy_encryption = {encryption_method = AlreadyEncrypted; owner_password = ""; user_password = ""; permissions = []} (* Flatten a PDF document to an Pdfio.output. *) let pdf_to_output ?(preserve_objstm = false) ?(generate_objstm = false) ?(compress_objstm = true) ?(recrypt = None) encrypt mk_id pdf o = if mk_id then Pdf.change_id pdf (string_of_float (Random.float 1.)); let renumbered_objects_for_streams, preserve_objstm = if generate_objstm then generate_object_stream_hints (match encrypt with Some _ -> true | _ -> false) pdf preserve_objstm; if (preserve_objstm || generate_objstm) && Hashtbl.length pdf.Pdf.objects.Pdf.object_stream_ids > 0 then (reinstate_object_streams compress_objstm (match encrypt with Some _ -> true | _ -> match recrypt with Some _ -> true | _ -> false) pdf, true) else ([], false) (* Weren't asked to preserve, or nothing to put in streams *) in let encrypt = match recrypt with None -> encrypt | Some _ -> Some dummy_encryption in let pdf = if preserve_objstm || generate_objstm then pdf else begin match encrypt with | Some e when e.encryption_method = AlreadyEncrypted -> pdf (* Already been renumbered *) | Some _ -> (* Need to renumber before encrypting. Will remove once encryption-on-demand-on-writing is done...*) Pdf.renumber (Pdf.changes pdf) pdf | _ -> pdf end in let pdf = match recrypt with None -> pdf | Some pw -> Pdfcrypt.recrypt_pdf ~renumber:(not (preserve_objstm || generate_objstm)) pdf pw in let pdf = crypt_if_necessary pdf encrypt in o.output_string (header pdf); let xrefs = ref [] and objiter = if Pdfcrypt.is_encrypted pdf || preserve_objstm || generate_objstm then Pdf.objiter_inorder else Pdf.objiter and changetable = if Pdfcrypt.is_encrypted pdf || preserve_objstm || generate_objstm then Hashtbl.create 0 else Pdf.changes pdf and currobjnum = ref 1 in objiter (fun ob p -> xrefs =| o.pos_out (); strings_of_pdf_object (flatten_W o) (ob, p) (if preserve_objstm then ob else !currobjnum) changetable; incr currobjnum) pdf; let xrefstart = o.pos_out () in if preserve_objstm || generate_objstm then begin let xrefstream = make_xref_stream pdf (rev !xrefs) renumbered_objects_for_streams in let thisnum = match Pdf.lookup_direct pdf "/Size" xrefstream with | Some (Pdf.Integer i) -> i | _ -> failwith "bad xref stream generated\n" in o.output_string (string_of_int thisnum); o.output_string " 0 obj\n"; strings_of_pdf ~hex:true (flatten_W o) changetable xrefstream; o.output_string "\nendobj\n"; o.output_string "startxref\n"; o.output_string (string_of_int xrefstart); o.output_string "\n%%EOF\n" end else begin write_xrefs (rev !xrefs) o; o.output_string "trailer\n"; let trailerdict' = match pdf.Pdf.trailerdict with | Pdf.Dictionary trailerdict -> Pdf.Dictionary (add "/Size" (Pdf.Integer (length !xrefs + 1)) (add "/Root" (Pdf.Indirect pdf.Pdf.root) trailerdict)) | _ -> raise (Pdf.PDFError "Pdf.pdf_to_output: Bad trailer dictionary") in strings_of_pdf ~hex:true (flatten_W o) changetable trailerdict'; o.output_string "\nstartxref\n"; o.output_string (string_of_int xrefstart); o.output_string "\n%%EOF\n" end (* Write a PDF to a channel. Don't use mk_id when the file is encrypted.*) let pdf_to_channel ?(preserve_objstm = false) ?(generate_objstm = false) ?(compress_objstm = true) ?(recrypt = None) encrypt mk_id pdf ch = pdf_to_output ~preserve_objstm ~generate_objstm ~compress_objstm ~recrypt encrypt mk_id pdf (output_of_channel ch) (* Similarly to a named file. If mk_id is set, the /ID entry in the document's trailer dictionary is updated using the current date and time and the filename. Don't use mk_id when the file is encrypted. If [preserve_objstm] is set, existing object streams will be preserved. If [generate_objstm] is set, new ones will be generated in addition. To get totally fresh object streams, set [preserve_objstm=false, generate_objstm=true]. *) let pdf_to_file_options ?(preserve_objstm = false) ?(generate_objstm = false) ?(compress_objstm = true) ?(recrypt = None) encrypt mk_id pdf f = if mk_id then Pdf.change_id pdf f; let ch = open_out_bin f in try pdf_to_channel ~preserve_objstm ~generate_objstm ~compress_objstm ~recrypt encrypt false pdf ch; close_out ch with e -> close_out ch; raise e let pdf_to_file pdf f = pdf_to_file_options ~preserve_objstm:true ~generate_objstm:false ~compress_objstm:true None true pdf f camlpdf-2.8.1/pdfwrite.mli000066400000000000000000000051251477056064700155020ustar00rootroot00000000000000(** Writing PDF Files *) (** When set to [true], various pieces of information are printed to standard output when a PDF is written. On library startup, is [false]. *) val write_debug : bool ref (** {2 Encryption methods} *) (** Encryption methods. The boolean for [AES128bit], [AES256bit] and [AES256BitISO] indicates encryption of metadata or lack thereof. AlreadyEncrypted is used as a flag to prevent garbage collection internally by [pdf_to_file_recrypting]. *) type encryption_method = | PDF40bit | PDF128bit | AES128bit of bool | AES256bit of bool | AES256bitISO of bool | AlreadyEncrypted (** The type of an encryption with certain user permissions. *) type encryption = {encryption_method : encryption_method; owner_password : string; user_password : string; permissions : Pdfcrypt.permission list} (** {2 Writing to outputs, channels and files.} *) (** Write a PDF document to an [Pdfio.output], optionally encrypting. If [?preserve_objstm] is set (default is false), object streams which were in the original file will be preserved. If [?create_objstm] is set (default is false), additional new object streams will be created. To re-encrypt the file using its existing encryption, provide the user or owner password in the [?recrypt] argument. *) val pdf_to_output : ?preserve_objstm:bool -> ?generate_objstm:bool -> ?compress_objstm:bool -> ?recrypt:string option -> encryption option -> bool -> Pdf.t -> Pdfio.output -> unit (** As [pdf_to_output] but to an OCaml channel. If the second boolean is set, build a new /ID (don't set this for encrypted documents). *) val pdf_to_channel : ?preserve_objstm:bool -> ?generate_objstm:bool -> ?compress_objstm:bool -> ?recrypt:string option -> encryption option -> bool -> Pdf.t -> out_channel -> unit (** As [pdf_to_channel] but to a named file. *) val pdf_to_file_options : ?preserve_objstm:bool -> ?generate_objstm:bool -> ?compress_objstm:bool -> ?recrypt:string option -> encryption option -> bool -> Pdf.t -> string -> unit (** Simple write to given file name. Equivalent to [pdf_to_file_options false None true] *) val pdf_to_file : Pdf.t -> string -> unit (** {2 String of a PDF object} *) (** Calculate a string of a pdf object. *) val string_of_pdf : Pdf.pdfobject -> string (** Calculate a string of a pdf object, but include binary data too. *) val string_of_pdf_including_data : Pdf.pdfobject -> string (** For debug, print out the PDFs objects to standard output. *) val debug_whole_pdf : Pdf.t -> unit (** Convert a PDF string to Hex PDF string representation *) val make_hex_pdf_string : string -> string camlpdf-2.8.1/rijndael-alg-fst.c000066400000000000000000001743541477056064700164550ustar00rootroot00000000000000/** * rijndael-alg-fst.c * * @version 3.0 (December 2000) * * Optimised ANSI C code for the Rijndael cipher (now AES) * * @author Vincent Rijmen * @author Antoon Bosselaers * @author Paulo Barreto * * This code is hereby placed in the public domain. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "rijndael-alg-fst.h" /* Te0[x] = S [x].[02, 01, 01, 03]; Te1[x] = S [x].[03, 02, 01, 01]; Te2[x] = S [x].[01, 03, 02, 01]; Te3[x] = S [x].[01, 01, 03, 02]; Te4[x] = S [x].[01, 01, 01, 01]; Td0[x] = Si[x].[0e, 09, 0d, 0b]; Td1[x] = Si[x].[0b, 0e, 09, 0d]; Td2[x] = Si[x].[0d, 0b, 0e, 09]; Td3[x] = Si[x].[09, 0d, 0b, 0e]; Td4[x] = Si[x].[01, 01, 01, 01]; */ static const u32 Te0[256] = { 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, }; static const u32 Te1[256] = { 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, }; static const u32 Te2[256] = { 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, }; static const u32 Te3[256] = { 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, }; static const u32 Te4[256] = { 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, }; static const u32 Td0[256] = { 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, }; static const u32 Td1[256] = { 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, }; static const u32 Td2[256] = { 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, }; static const u32 Td3[256] = { 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, }; static const u32 Td4[256] = { 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, }; static const u32 rcon[] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ }; #define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00) #ifdef _MSC_VER #define GETU32(p) SWAP(*((u32 *)(p))) #define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); } #else #define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) #define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } #endif /** * Expand the cipher key into the encryption key schedule. * * @return the number of rounds for the given cipher key size. */ int camlpdf_rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) { int i = 0; u32 temp; rk[0] = GETU32(cipherKey ); rk[1] = GETU32(cipherKey + 4); rk[2] = GETU32(cipherKey + 8); rk[3] = GETU32(cipherKey + 12); if (keyBits == 128) { for (;;) { temp = rk[3]; rk[4] = rk[0] ^ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te4[(temp ) & 0xff] & 0x0000ff00) ^ (Te4[(temp >> 24) ] & 0x000000ff) ^ rcon[i]; rk[5] = rk[1] ^ rk[4]; rk[6] = rk[2] ^ rk[5]; rk[7] = rk[3] ^ rk[6]; if (++i == 10) { return 10; } rk += 4; } } rk[4] = GETU32(cipherKey + 16); rk[5] = GETU32(cipherKey + 20); if (keyBits == 192) { for (;;) { temp = rk[ 5]; rk[ 6] = rk[ 0] ^ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te4[(temp ) & 0xff] & 0x0000ff00) ^ (Te4[(temp >> 24) ] & 0x000000ff) ^ rcon[i]; rk[ 7] = rk[ 1] ^ rk[ 6]; rk[ 8] = rk[ 2] ^ rk[ 7]; rk[ 9] = rk[ 3] ^ rk[ 8]; if (++i == 8) { return 12; } rk[10] = rk[ 4] ^ rk[ 9]; rk[11] = rk[ 5] ^ rk[10]; rk += 6; } } rk[6] = GETU32(cipherKey + 24); rk[7] = GETU32(cipherKey + 28); if (keyBits == 256) { for (;;) { temp = rk[ 7]; rk[ 8] = rk[ 0] ^ (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ (Te4[(temp ) & 0xff] & 0x0000ff00) ^ (Te4[(temp >> 24) ] & 0x000000ff) ^ rcon[i]; rk[ 9] = rk[ 1] ^ rk[ 8]; rk[10] = rk[ 2] ^ rk[ 9]; rk[11] = rk[ 3] ^ rk[10]; if (++i == 7) { return 14; } temp = rk[11]; rk[12] = rk[ 4] ^ (Te4[(temp >> 24) ] & 0xff000000) ^ (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(temp ) & 0xff] & 0x000000ff); rk[13] = rk[ 5] ^ rk[12]; rk[14] = rk[ 6] ^ rk[13]; rk[15] = rk[ 7] ^ rk[14]; rk += 8; } } return 0; } /** * Expand the cipher key into the decryption key schedule. * * @return the number of rounds for the given cipher key size. */ int camlpdf_rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) { int Nr, i, j; u32 temp; /* expand the cipher key: */ Nr = camlpdf_rijndaelKeySetupEnc(rk, cipherKey, keyBits); /* invert the order of the round keys: */ for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) { temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; } /* apply the inverse MixColumn transform to all round keys but the first and the last: */ for (i = 1; i < Nr; i++) { rk += 4; rk[0] = Td0[Te4[(rk[0] >> 24) ] & 0xff] ^ Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^ Td3[Te4[(rk[0] ) & 0xff] & 0xff]; rk[1] = Td0[Te4[(rk[1] >> 24) ] & 0xff] ^ Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^ Td3[Te4[(rk[1] ) & 0xff] & 0xff]; rk[2] = Td0[Te4[(rk[2] >> 24) ] & 0xff] ^ Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^ Td3[Te4[(rk[2] ) & 0xff] & 0xff]; rk[3] = Td0[Te4[(rk[3] >> 24) ] & 0xff] ^ Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^ Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^ Td3[Te4[(rk[3] ) & 0xff] & 0xff]; } return Nr; } void camlpdf_rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) { u32 s0, s1, s2, s3, t0, t1, t2, t3; #ifndef FULL_UNROLL int r; #endif /* ?FULL_UNROLL */ /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(pt ) ^ rk[0]; s1 = GETU32(pt + 4) ^ rk[1]; s2 = GETU32(pt + 8) ^ rk[2]; s3 = GETU32(pt + 12) ^ rk[3]; #ifdef FULL_UNROLL /* round 1: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7]; /* round 2: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11]; /* round 3: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15]; /* round 4: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19]; /* round 5: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23]; /* round 6: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27]; /* round 7: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31]; /* round 8: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35]; /* round 9: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39]; if (Nr > 10) { /* round 10: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43]; /* round 11: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47]; if (Nr > 12) { /* round 12: */ s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48]; s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49]; s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50]; s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51]; /* round 13: */ t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52]; t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53]; t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54]; t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55]; } } rk += Nr << 2; #else /* !FULL_UNROLL */ /* * Nr - 1 full rounds: */ r = Nr >> 1; for (;;) { t0 = Te0[(s0 >> 24) ] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[(s3 ) & 0xff] ^ rk[4]; t1 = Te0[(s1 >> 24) ] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[(s0 ) & 0xff] ^ rk[5]; t2 = Te0[(s2 >> 24) ] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[(s1 ) & 0xff] ^ rk[6]; t3 = Te0[(s3 >> 24) ] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[(s2 ) & 0xff] ^ rk[7]; rk += 8; if (--r == 0) { break; } s0 = Te0[(t0 >> 24) ] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[(t3 ) & 0xff] ^ rk[0]; s1 = Te0[(t1 >> 24) ] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[(t0 ) & 0xff] ^ rk[1]; s2 = Te0[(t2 >> 24) ] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[(t1 ) & 0xff] ^ rk[2]; s3 = Te0[(t3 >> 24) ] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[(t2 ) & 0xff] ^ rk[3]; } #endif /* ?FULL_UNROLL */ /* * apply last round and * map cipher state to byte array block: */ s0 = (Te4[(t0 >> 24) ] & 0xff000000) ^ (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t3 ) & 0xff] & 0x000000ff) ^ rk[0]; PUTU32(ct , s0); s1 = (Te4[(t1 >> 24) ] & 0xff000000) ^ (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t0 ) & 0xff] & 0x000000ff) ^ rk[1]; PUTU32(ct + 4, s1); s2 = (Te4[(t2 >> 24) ] & 0xff000000) ^ (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t1 ) & 0xff] & 0x000000ff) ^ rk[2]; PUTU32(ct + 8, s2); s3 = (Te4[(t3 >> 24) ] & 0xff000000) ^ (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(t2 ) & 0xff] & 0x000000ff) ^ rk[3]; PUTU32(ct + 12, s3); } void camlpdf_rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]) { u32 s0, s1, s2, s3, t0, t1, t2, t3; #ifndef FULL_UNROLL int r; #endif /* ?FULL_UNROLL */ /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(ct ) ^ rk[0]; s1 = GETU32(ct + 4) ^ rk[1]; s2 = GETU32(ct + 8) ^ rk[2]; s3 = GETU32(ct + 12) ^ rk[3]; #ifdef FULL_UNROLL /* round 1: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7]; /* round 2: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11]; /* round 3: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15]; /* round 4: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19]; /* round 5: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23]; /* round 6: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27]; /* round 7: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31]; /* round 8: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35]; /* round 9: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39]; if (Nr > 10) { /* round 10: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43]; /* round 11: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47]; if (Nr > 12) { /* round 12: */ s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48]; s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49]; s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50]; s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51]; /* round 13: */ t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52]; t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53]; t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54]; t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55]; } } rk += Nr << 2; #else /* !FULL_UNROLL */ /* * Nr - 1 full rounds: */ r = Nr >> 1; for (;;) { t0 = Td0[(s0 >> 24) ] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[(s1 ) & 0xff] ^ rk[4]; t1 = Td0[(s1 >> 24) ] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[(s2 ) & 0xff] ^ rk[5]; t2 = Td0[(s2 >> 24) ] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[(s3 ) & 0xff] ^ rk[6]; t3 = Td0[(s3 >> 24) ] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[(s0 ) & 0xff] ^ rk[7]; rk += 8; if (--r == 0) { break; } s0 = Td0[(t0 >> 24) ] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[(t1 ) & 0xff] ^ rk[0]; s1 = Td0[(t1 >> 24) ] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[(t2 ) & 0xff] ^ rk[1]; s2 = Td0[(t2 >> 24) ] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[(t3 ) & 0xff] ^ rk[2]; s3 = Td0[(t3 >> 24) ] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[(t0 ) & 0xff] ^ rk[3]; } #endif /* ?FULL_UNROLL */ /* * apply last round and * map cipher state to byte array block: */ s0 = (Td4[(t0 >> 24) ] & 0xff000000) ^ (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t1 ) & 0xff] & 0x000000ff) ^ rk[0]; PUTU32(pt , s0); s1 = (Td4[(t1 >> 24) ] & 0xff000000) ^ (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t2 ) & 0xff] & 0x000000ff) ^ rk[1]; PUTU32(pt + 4, s1); s2 = (Td4[(t2 >> 24) ] & 0xff000000) ^ (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t3 ) & 0xff] & 0x000000ff) ^ rk[2]; PUTU32(pt + 8, s2); s3 = (Td4[(t3 >> 24) ] & 0xff000000) ^ (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(t0 ) & 0xff] & 0x000000ff) ^ rk[3]; PUTU32(pt + 12, s3); } #ifdef INTERMEDIATE_VALUE_KAT void camlpdf_rijndaelEncryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds) { int r; u32 s0, s1, s2, s3, t0, t1, t2, t3; /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(block ) ^ rk[0]; s1 = GETU32(block + 4) ^ rk[1]; s2 = GETU32(block + 8) ^ rk[2]; s3 = GETU32(block + 12) ^ rk[3]; rk += 4; /* * Nr - 1 full rounds: */ for (r = (rounds < Nr ? rounds : Nr - 1); r > 0; r--) { t0 = Te0[(s0 >> 24) ] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[(s3 ) & 0xff] ^ rk[0]; t1 = Te0[(s1 >> 24) ] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[(s0 ) & 0xff] ^ rk[1]; t2 = Te0[(s2 >> 24) ] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[(s1 ) & 0xff] ^ rk[2]; t3 = Te0[(s3 >> 24) ] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[(s2 ) & 0xff] ^ rk[3]; s0 = t0; s1 = t1; s2 = t2; s3 = t3; rk += 4; } /* * apply last round and * map cipher state to byte array block: */ if (rounds == Nr) { t0 = (Te4[(s0 >> 24) ] & 0xff000000) ^ (Te4[(s1 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(s2 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(s3 ) & 0xff] & 0x000000ff) ^ rk[0]; t1 = (Te4[(s1 >> 24) ] & 0xff000000) ^ (Te4[(s2 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(s3 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(s0 ) & 0xff] & 0x000000ff) ^ rk[1]; t2 = (Te4[(s2 >> 24) ] & 0xff000000) ^ (Te4[(s3 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(s0 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(s1 ) & 0xff] & 0x000000ff) ^ rk[2]; t3 = (Te4[(s3 >> 24) ] & 0xff000000) ^ (Te4[(s0 >> 16) & 0xff] & 0x00ff0000) ^ (Te4[(s1 >> 8) & 0xff] & 0x0000ff00) ^ (Te4[(s2 ) & 0xff] & 0x000000ff) ^ rk[3]; s0 = t0; s1 = t1; s2 = t2; s3 = t3; } PUTU32(block , s0); PUTU32(block + 4, s1); PUTU32(block + 8, s2); PUTU32(block + 12, s3); } void camlpdf_rijndaelDecryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds) { int r; u32 s0, s1, s2, s3, t0, t1, t2, t3; /* * map byte array block to cipher state * and add initial round key: */ s0 = GETU32(block ) ^ rk[0]; s1 = GETU32(block + 4) ^ rk[1]; s2 = GETU32(block + 8) ^ rk[2]; s3 = GETU32(block + 12) ^ rk[3]; rk += 4; /* * Nr - 1 full rounds: */ for (r = (rounds < Nr ? rounds : Nr) - 1; r > 0; r--) { t0 = Td0[(s0 >> 24) ] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[(s1 ) & 0xff] ^ rk[0]; t1 = Td0[(s1 >> 24) ] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[(s2 ) & 0xff] ^ rk[1]; t2 = Td0[(s2 >> 24) ] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[(s3 ) & 0xff] ^ rk[2]; t3 = Td0[(s3 >> 24) ] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[(s0 ) & 0xff] ^ rk[3]; s0 = t0; s1 = t1; s2 = t2; s3 = t3; rk += 4; } /* * complete the last round and * map cipher state to byte array block: */ t0 = (Td4[(s0 >> 24) ] & 0xff000000) ^ (Td4[(s3 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(s2 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(s1 ) & 0xff] & 0x000000ff); t1 = (Td4[(s1 >> 24) ] & 0xff000000) ^ (Td4[(s0 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(s3 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(s2 ) & 0xff] & 0x000000ff); t2 = (Td4[(s2 >> 24) ] & 0xff000000) ^ (Td4[(s1 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(s0 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(s3 ) & 0xff] & 0x000000ff); t3 = (Td4[(s3 >> 24) ] & 0xff000000) ^ (Td4[(s2 >> 16) & 0xff] & 0x00ff0000) ^ (Td4[(s1 >> 8) & 0xff] & 0x0000ff00) ^ (Td4[(s0 ) & 0xff] & 0x000000ff); if (rounds == Nr) { t0 ^= rk[0]; t1 ^= rk[1]; t2 ^= rk[2]; t3 ^= rk[3]; } PUTU32(block , t0); PUTU32(block + 4, t1); PUTU32(block + 8, t2); PUTU32(block + 12, t3); } #endif /* INTERMEDIATE_VALUE_KAT */ camlpdf-2.8.1/rijndael-alg-fst.h000066400000000000000000000037331477056064700164520ustar00rootroot00000000000000/** * rijndael-alg-fst.h * * @version 3.0 (December 2000) * * Optimised ANSI C code for the Rijndael cipher (now AES) * * @author Vincent Rijmen * @author Antoon Bosselaers * @author Paulo Barreto * * This code is hereby placed in the public domain. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __RIJNDAEL_ALG_FST_H #define __RIJNDAEL_ALG_FST_H #define MAXKC (256/32) #define MAXKB (256/8) #define MAXNR 14 typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; int camlpdf_rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits); int camlpdf_rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits); void camlpdf_rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]); void camlpdf_rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]); #ifdef INTERMEDIATE_VALUE_KAT void camlpdf_rijndaelEncryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds); void camlpdf_rijndaelDecryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds); #endif /* INTERMEDIATE_VALUE_KAT */ #endif /* __RIJNDAEL_ALG_FST_H */ camlpdf-2.8.1/sha2.c000066400000000000000000001016531477056064700141570ustar00rootroot00000000000000/* * FIPS 180-2 SHA-224/256/384/512 implementation * Last update: 02/02/2007 * Issue date: 04/30/2005 * * Copyright (C) 2005, 2007 Olivier Gay * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #define UNROLL_LOOPS /* Enable loops unrolling */ #endif #include #include "sha2.h" #define SHFR(x, n) (x >> n) #define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) #define ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) #define CH(x, y, z) ((x & y) ^ (~x & z)) #define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) #define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) #define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) #define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3)) #define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10)) #define SHA512_F1(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39)) #define SHA512_F2(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41)) #define SHA512_F3(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHFR(x, 7)) #define SHA512_F4(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ SHFR(x, 6)) #define UNPACK32(x, str) \ { \ *((str) + 3) = (unsigned char) ((x) ); \ *((str) + 2) = (unsigned char) ((x) >> 8); \ *((str) + 1) = (unsigned char) ((x) >> 16); \ *((str) + 0) = (unsigned char) ((x) >> 24); \ } #define PACK32(str, x) \ { \ *(x) = ((unsigned int) *((str) + 3) ) \ | ((unsigned int) *((str) + 2) << 8) \ | ((unsigned int) *((str) + 1) << 16) \ | ((unsigned int) *((str) + 0) << 24); \ } #define UNPACK64(x, str) \ { \ *((str) + 7) = (unsigned char) ((x) ); \ *((str) + 6) = (unsigned char) ((x) >> 8); \ *((str) + 5) = (unsigned char) ((x) >> 16); \ *((str) + 4) = (unsigned char) ((x) >> 24); \ *((str) + 3) = (unsigned char) ((x) >> 32); \ *((str) + 2) = (unsigned char) ((x) >> 40); \ *((str) + 1) = (unsigned char) ((x) >> 48); \ *((str) + 0) = (unsigned char) ((x) >> 56); \ } #define PACK64(str, x) \ { \ *(x) = ((unsigned long long) *((str) + 7) ) \ | ((unsigned long long) *((str) + 6) << 8) \ | ((unsigned long long) *((str) + 5) << 16) \ | ((unsigned long long) *((str) + 4) << 24) \ | ((unsigned long long) *((str) + 3) << 32) \ | ((unsigned long long) *((str) + 2) << 40) \ | ((unsigned long long) *((str) + 1) << 48) \ | ((unsigned long long) *((str) + 0) << 56); \ } /* Macros used for loops unrolling */ #define SHA256_SCR(i) \ { \ w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \ + SHA256_F3(w[i - 15]) + w[i - 16]; \ } #define SHA512_SCR(i) \ { \ w[i] = SHA512_F4(w[i - 2]) + w[i - 7] \ + SHA512_F3(w[i - 15]) + w[i - 16]; \ } #define SHA256_EXP(a, b, c, d, e, f, g, h, j) \ { \ t1 = wv[h] + SHA256_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \ + sha256_k[j] + w[j]; \ t2 = SHA256_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \ wv[d] += t1; \ wv[h] = t1 + t2; \ } #define SHA512_EXP(a, b, c, d, e, f, g ,h, j) \ { \ t1 = wv[h] + SHA512_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \ + sha512_k[j] + w[j]; \ t2 = SHA512_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \ wv[d] += t1; \ wv[h] = t1 + t2; \ } unsigned int sha224_h0[8] = {0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4}; unsigned int sha256_h0[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; unsigned long long sha384_h0[8] = {0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL, 0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL, 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL}; unsigned long long sha512_h0[8] = {0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL}; unsigned int sha256_k[64] = {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; unsigned long long sha512_k[80] = {0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL}; /* SHA-256 functions */ void camlpdf_sha256_transf(sha256_ctx *ctx, const unsigned char *message, unsigned int block_nb) { unsigned int w[64]; unsigned int wv[8]; unsigned int t1, t2; const unsigned char *sub_block; int i; #ifndef UNROLL_LOOPS int j; #endif for (i = 0; i < (int) block_nb; i++) { sub_block = message + (i << 6); #ifndef UNROLL_LOOPS for (j = 0; j < 16; j++) { PACK32(&sub_block[j << 2], &w[j]); } for (j = 16; j < 64; j++) { SHA256_SCR(j); } for (j = 0; j < 8; j++) { wv[j] = ctx->h[j]; } for (j = 0; j < 64; j++) { t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha256_k[j] + w[j]; t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); wv[7] = wv[6]; wv[6] = wv[5]; wv[5] = wv[4]; wv[4] = wv[3] + t1; wv[3] = wv[2]; wv[2] = wv[1]; wv[1] = wv[0]; wv[0] = t1 + t2; } for (j = 0; j < 8; j++) { ctx->h[j] += wv[j]; } #else PACK32(&sub_block[ 0], &w[ 0]); PACK32(&sub_block[ 4], &w[ 1]); PACK32(&sub_block[ 8], &w[ 2]); PACK32(&sub_block[12], &w[ 3]); PACK32(&sub_block[16], &w[ 4]); PACK32(&sub_block[20], &w[ 5]); PACK32(&sub_block[24], &w[ 6]); PACK32(&sub_block[28], &w[ 7]); PACK32(&sub_block[32], &w[ 8]); PACK32(&sub_block[36], &w[ 9]); PACK32(&sub_block[40], &w[10]); PACK32(&sub_block[44], &w[11]); PACK32(&sub_block[48], &w[12]); PACK32(&sub_block[52], &w[13]); PACK32(&sub_block[56], &w[14]); PACK32(&sub_block[60], &w[15]); SHA256_SCR(16); SHA256_SCR(17); SHA256_SCR(18); SHA256_SCR(19); SHA256_SCR(20); SHA256_SCR(21); SHA256_SCR(22); SHA256_SCR(23); SHA256_SCR(24); SHA256_SCR(25); SHA256_SCR(26); SHA256_SCR(27); SHA256_SCR(28); SHA256_SCR(29); SHA256_SCR(30); SHA256_SCR(31); SHA256_SCR(32); SHA256_SCR(33); SHA256_SCR(34); SHA256_SCR(35); SHA256_SCR(36); SHA256_SCR(37); SHA256_SCR(38); SHA256_SCR(39); SHA256_SCR(40); SHA256_SCR(41); SHA256_SCR(42); SHA256_SCR(43); SHA256_SCR(44); SHA256_SCR(45); SHA256_SCR(46); SHA256_SCR(47); SHA256_SCR(48); SHA256_SCR(49); SHA256_SCR(50); SHA256_SCR(51); SHA256_SCR(52); SHA256_SCR(53); SHA256_SCR(54); SHA256_SCR(55); SHA256_SCR(56); SHA256_SCR(57); SHA256_SCR(58); SHA256_SCR(59); SHA256_SCR(60); SHA256_SCR(61); SHA256_SCR(62); SHA256_SCR(63); wv[0] = ctx->h[0]; wv[1] = ctx->h[1]; wv[2] = ctx->h[2]; wv[3] = ctx->h[3]; wv[4] = ctx->h[4]; wv[5] = ctx->h[5]; wv[6] = ctx->h[6]; wv[7] = ctx->h[7]; SHA256_EXP(0,1,2,3,4,5,6,7, 0); SHA256_EXP(7,0,1,2,3,4,5,6, 1); SHA256_EXP(6,7,0,1,2,3,4,5, 2); SHA256_EXP(5,6,7,0,1,2,3,4, 3); SHA256_EXP(4,5,6,7,0,1,2,3, 4); SHA256_EXP(3,4,5,6,7,0,1,2, 5); SHA256_EXP(2,3,4,5,6,7,0,1, 6); SHA256_EXP(1,2,3,4,5,6,7,0, 7); SHA256_EXP(0,1,2,3,4,5,6,7, 8); SHA256_EXP(7,0,1,2,3,4,5,6, 9); SHA256_EXP(6,7,0,1,2,3,4,5,10); SHA256_EXP(5,6,7,0,1,2,3,4,11); SHA256_EXP(4,5,6,7,0,1,2,3,12); SHA256_EXP(3,4,5,6,7,0,1,2,13); SHA256_EXP(2,3,4,5,6,7,0,1,14); SHA256_EXP(1,2,3,4,5,6,7,0,15); SHA256_EXP(0,1,2,3,4,5,6,7,16); SHA256_EXP(7,0,1,2,3,4,5,6,17); SHA256_EXP(6,7,0,1,2,3,4,5,18); SHA256_EXP(5,6,7,0,1,2,3,4,19); SHA256_EXP(4,5,6,7,0,1,2,3,20); SHA256_EXP(3,4,5,6,7,0,1,2,21); SHA256_EXP(2,3,4,5,6,7,0,1,22); SHA256_EXP(1,2,3,4,5,6,7,0,23); SHA256_EXP(0,1,2,3,4,5,6,7,24); SHA256_EXP(7,0,1,2,3,4,5,6,25); SHA256_EXP(6,7,0,1,2,3,4,5,26); SHA256_EXP(5,6,7,0,1,2,3,4,27); SHA256_EXP(4,5,6,7,0,1,2,3,28); SHA256_EXP(3,4,5,6,7,0,1,2,29); SHA256_EXP(2,3,4,5,6,7,0,1,30); SHA256_EXP(1,2,3,4,5,6,7,0,31); SHA256_EXP(0,1,2,3,4,5,6,7,32); SHA256_EXP(7,0,1,2,3,4,5,6,33); SHA256_EXP(6,7,0,1,2,3,4,5,34); SHA256_EXP(5,6,7,0,1,2,3,4,35); SHA256_EXP(4,5,6,7,0,1,2,3,36); SHA256_EXP(3,4,5,6,7,0,1,2,37); SHA256_EXP(2,3,4,5,6,7,0,1,38); SHA256_EXP(1,2,3,4,5,6,7,0,39); SHA256_EXP(0,1,2,3,4,5,6,7,40); SHA256_EXP(7,0,1,2,3,4,5,6,41); SHA256_EXP(6,7,0,1,2,3,4,5,42); SHA256_EXP(5,6,7,0,1,2,3,4,43); SHA256_EXP(4,5,6,7,0,1,2,3,44); SHA256_EXP(3,4,5,6,7,0,1,2,45); SHA256_EXP(2,3,4,5,6,7,0,1,46); SHA256_EXP(1,2,3,4,5,6,7,0,47); SHA256_EXP(0,1,2,3,4,5,6,7,48); SHA256_EXP(7,0,1,2,3,4,5,6,49); SHA256_EXP(6,7,0,1,2,3,4,5,50); SHA256_EXP(5,6,7,0,1,2,3,4,51); SHA256_EXP(4,5,6,7,0,1,2,3,52); SHA256_EXP(3,4,5,6,7,0,1,2,53); SHA256_EXP(2,3,4,5,6,7,0,1,54); SHA256_EXP(1,2,3,4,5,6,7,0,55); SHA256_EXP(0,1,2,3,4,5,6,7,56); SHA256_EXP(7,0,1,2,3,4,5,6,57); SHA256_EXP(6,7,0,1,2,3,4,5,58); SHA256_EXP(5,6,7,0,1,2,3,4,59); SHA256_EXP(4,5,6,7,0,1,2,3,60); SHA256_EXP(3,4,5,6,7,0,1,2,61); SHA256_EXP(2,3,4,5,6,7,0,1,62); SHA256_EXP(1,2,3,4,5,6,7,0,63); ctx->h[0] += wv[0]; ctx->h[1] += wv[1]; ctx->h[2] += wv[2]; ctx->h[3] += wv[3]; ctx->h[4] += wv[4]; ctx->h[5] += wv[5]; ctx->h[6] += wv[6]; ctx->h[7] += wv[7]; #endif /* !UNROLL_LOOPS */ } } void camlpdf_sha256(const unsigned char *message, unsigned int len, unsigned char *digest) { sha256_ctx ctx; camlpdf_sha256_init(&ctx); camlpdf_sha256_update(&ctx, message, len); camlpdf_sha256_final(&ctx, digest); } void camlpdf_sha256_init(sha256_ctx *ctx) { #ifndef UNROLL_LOOPS int i; for (i = 0; i < 8; i++) { ctx->h[i] = sha256_h0[i]; } #else ctx->h[0] = sha256_h0[0]; ctx->h[1] = sha256_h0[1]; ctx->h[2] = sha256_h0[2]; ctx->h[3] = sha256_h0[3]; ctx->h[4] = sha256_h0[4]; ctx->h[5] = sha256_h0[5]; ctx->h[6] = sha256_h0[6]; ctx->h[7] = sha256_h0[7]; #endif /* !UNROLL_LOOPS */ ctx->len = 0; ctx->tot_len = 0; } void camlpdf_sha256_update(sha256_ctx *ctx, const unsigned char *message, unsigned int len) { unsigned int block_nb; unsigned int new_len, rem_len, tmp_len; const unsigned char *shifted_message; tmp_len = SHA256_BLOCK_SIZE - ctx->len; rem_len = len < tmp_len ? len : tmp_len; memcpy(&ctx->block[ctx->len], message, rem_len); if (ctx->len + len < SHA256_BLOCK_SIZE) { ctx->len += len; return; } new_len = len - rem_len; block_nb = new_len / SHA256_BLOCK_SIZE; shifted_message = message + rem_len; camlpdf_sha256_transf(ctx, ctx->block, 1); camlpdf_sha256_transf(ctx, shifted_message, block_nb); rem_len = new_len % SHA256_BLOCK_SIZE; memcpy(ctx->block, &shifted_message[block_nb << 6], rem_len); ctx->len = rem_len; ctx->tot_len += (block_nb + 1) << 6; } void camlpdf_sha256_final(sha256_ctx *ctx, unsigned char *digest) { unsigned int block_nb; unsigned int pm_len; unsigned int len_b; #ifndef UNROLL_LOOPS int i; #endif block_nb = (1 + ((SHA256_BLOCK_SIZE - 9) < (ctx->len % SHA256_BLOCK_SIZE))); len_b = (ctx->tot_len + ctx->len) << 3; pm_len = block_nb << 6; memset(ctx->block + ctx->len, 0, pm_len - ctx->len); ctx->block[ctx->len] = 0x80; UNPACK32(len_b, ctx->block + pm_len - 4); camlpdf_sha256_transf(ctx, ctx->block, block_nb); #ifndef UNROLL_LOOPS for (i = 0 ; i < 8; i++) { UNPACK32(ctx->h[i], &digest[i << 2]); } #else UNPACK32(ctx->h[0], &digest[ 0]); UNPACK32(ctx->h[1], &digest[ 4]); UNPACK32(ctx->h[2], &digest[ 8]); UNPACK32(ctx->h[3], &digest[12]); UNPACK32(ctx->h[4], &digest[16]); UNPACK32(ctx->h[5], &digest[20]); UNPACK32(ctx->h[6], &digest[24]); UNPACK32(ctx->h[7], &digest[28]); #endif /* !UNROLL_LOOPS */ } /* SHA-512 functions */ void camlpdf_sha512_transf(sha512_ctx *ctx, const unsigned char *message, unsigned int block_nb) { unsigned long long w[80]; unsigned long long wv[8]; unsigned long long t1, t2; const unsigned char *sub_block; int i, j; for (i = 0; i < (int) block_nb; i++) { sub_block = message + (i << 7); #ifndef UNROLL_LOOPS for (j = 0; j < 16; j++) { PACK64(&sub_block[j << 3], &w[j]); } for (j = 16; j < 80; j++) { SHA512_SCR(j); } for (j = 0; j < 8; j++) { wv[j] = ctx->h[j]; } for (j = 0; j < 80; j++) { t1 = wv[7] + SHA512_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha512_k[j] + w[j]; t2 = SHA512_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); wv[7] = wv[6]; wv[6] = wv[5]; wv[5] = wv[4]; wv[4] = wv[3] + t1; wv[3] = wv[2]; wv[2] = wv[1]; wv[1] = wv[0]; wv[0] = t1 + t2; } for (j = 0; j < 8; j++) { ctx->h[j] += wv[j]; } #else PACK64(&sub_block[ 0], &w[ 0]); PACK64(&sub_block[ 8], &w[ 1]); PACK64(&sub_block[ 16], &w[ 2]); PACK64(&sub_block[ 24], &w[ 3]); PACK64(&sub_block[ 32], &w[ 4]); PACK64(&sub_block[ 40], &w[ 5]); PACK64(&sub_block[ 48], &w[ 6]); PACK64(&sub_block[ 56], &w[ 7]); PACK64(&sub_block[ 64], &w[ 8]); PACK64(&sub_block[ 72], &w[ 9]); PACK64(&sub_block[ 80], &w[10]); PACK64(&sub_block[ 88], &w[11]); PACK64(&sub_block[ 96], &w[12]); PACK64(&sub_block[104], &w[13]); PACK64(&sub_block[112], &w[14]); PACK64(&sub_block[120], &w[15]); SHA512_SCR(16); SHA512_SCR(17); SHA512_SCR(18); SHA512_SCR(19); SHA512_SCR(20); SHA512_SCR(21); SHA512_SCR(22); SHA512_SCR(23); SHA512_SCR(24); SHA512_SCR(25); SHA512_SCR(26); SHA512_SCR(27); SHA512_SCR(28); SHA512_SCR(29); SHA512_SCR(30); SHA512_SCR(31); SHA512_SCR(32); SHA512_SCR(33); SHA512_SCR(34); SHA512_SCR(35); SHA512_SCR(36); SHA512_SCR(37); SHA512_SCR(38); SHA512_SCR(39); SHA512_SCR(40); SHA512_SCR(41); SHA512_SCR(42); SHA512_SCR(43); SHA512_SCR(44); SHA512_SCR(45); SHA512_SCR(46); SHA512_SCR(47); SHA512_SCR(48); SHA512_SCR(49); SHA512_SCR(50); SHA512_SCR(51); SHA512_SCR(52); SHA512_SCR(53); SHA512_SCR(54); SHA512_SCR(55); SHA512_SCR(56); SHA512_SCR(57); SHA512_SCR(58); SHA512_SCR(59); SHA512_SCR(60); SHA512_SCR(61); SHA512_SCR(62); SHA512_SCR(63); SHA512_SCR(64); SHA512_SCR(65); SHA512_SCR(66); SHA512_SCR(67); SHA512_SCR(68); SHA512_SCR(69); SHA512_SCR(70); SHA512_SCR(71); SHA512_SCR(72); SHA512_SCR(73); SHA512_SCR(74); SHA512_SCR(75); SHA512_SCR(76); SHA512_SCR(77); SHA512_SCR(78); SHA512_SCR(79); wv[0] = ctx->h[0]; wv[1] = ctx->h[1]; wv[2] = ctx->h[2]; wv[3] = ctx->h[3]; wv[4] = ctx->h[4]; wv[5] = ctx->h[5]; wv[6] = ctx->h[6]; wv[7] = ctx->h[7]; j = 0; do { SHA512_EXP(0,1,2,3,4,5,6,7,j); j++; SHA512_EXP(7,0,1,2,3,4,5,6,j); j++; SHA512_EXP(6,7,0,1,2,3,4,5,j); j++; SHA512_EXP(5,6,7,0,1,2,3,4,j); j++; SHA512_EXP(4,5,6,7,0,1,2,3,j); j++; SHA512_EXP(3,4,5,6,7,0,1,2,j); j++; SHA512_EXP(2,3,4,5,6,7,0,1,j); j++; SHA512_EXP(1,2,3,4,5,6,7,0,j); j++; } while (j < 80); ctx->h[0] += wv[0]; ctx->h[1] += wv[1]; ctx->h[2] += wv[2]; ctx->h[3] += wv[3]; ctx->h[4] += wv[4]; ctx->h[5] += wv[5]; ctx->h[6] += wv[6]; ctx->h[7] += wv[7]; #endif /* !UNROLL_LOOPS */ } } void camlpdf_sha512(const unsigned char *message, unsigned int len, unsigned char *digest) { sha512_ctx ctx; camlpdf_sha512_init(&ctx); camlpdf_sha512_update(&ctx, message, len); camlpdf_sha512_final(&ctx, digest); } void camlpdf_sha512_init(sha512_ctx *ctx) { #ifndef UNROLL_LOOPS int i; for (i = 0; i < 8; i++) { ctx->h[i] = sha512_h0[i]; } #else ctx->h[0] = sha512_h0[0]; ctx->h[1] = sha512_h0[1]; ctx->h[2] = sha512_h0[2]; ctx->h[3] = sha512_h0[3]; ctx->h[4] = sha512_h0[4]; ctx->h[5] = sha512_h0[5]; ctx->h[6] = sha512_h0[6]; ctx->h[7] = sha512_h0[7]; #endif /* !UNROLL_LOOPS */ ctx->len = 0; ctx->tot_len = 0; } void camlpdf_sha512_update(sha512_ctx *ctx, const unsigned char *message, unsigned int len) { unsigned int block_nb; unsigned int new_len, rem_len, tmp_len; const unsigned char *shifted_message; tmp_len = SHA512_BLOCK_SIZE - ctx->len; rem_len = len < tmp_len ? len : tmp_len; memcpy(&ctx->block[ctx->len], message, rem_len); if (ctx->len + len < SHA512_BLOCK_SIZE) { ctx->len += len; return; } new_len = len - rem_len; block_nb = new_len / SHA512_BLOCK_SIZE; shifted_message = message + rem_len; camlpdf_sha512_transf(ctx, ctx->block, 1); camlpdf_sha512_transf(ctx, shifted_message, block_nb); rem_len = new_len % SHA512_BLOCK_SIZE; memcpy(ctx->block, &shifted_message[block_nb << 7], rem_len); ctx->len = rem_len; ctx->tot_len += (block_nb + 1) << 7; } void camlpdf_sha512_final(sha512_ctx *ctx, unsigned char *digest) { unsigned int block_nb; unsigned int pm_len; unsigned int len_b; #ifndef UNROLL_LOOPS int i; #endif block_nb = 1 + ((SHA512_BLOCK_SIZE - 17) < (ctx->len % SHA512_BLOCK_SIZE)); len_b = (ctx->tot_len + ctx->len) << 3; pm_len = block_nb << 7; memset(ctx->block + ctx->len, 0, pm_len - ctx->len); ctx->block[ctx->len] = 0x80; UNPACK32(len_b, ctx->block + pm_len - 4); camlpdf_sha512_transf(ctx, ctx->block, block_nb); #ifndef UNROLL_LOOPS for (i = 0 ; i < 8; i++) { UNPACK64(ctx->h[i], &digest[i << 3]); } #else UNPACK64(ctx->h[0], &digest[ 0]); UNPACK64(ctx->h[1], &digest[ 8]); UNPACK64(ctx->h[2], &digest[16]); UNPACK64(ctx->h[3], &digest[24]); UNPACK64(ctx->h[4], &digest[32]); UNPACK64(ctx->h[5], &digest[40]); UNPACK64(ctx->h[6], &digest[48]); UNPACK64(ctx->h[7], &digest[56]); #endif /* !UNROLL_LOOPS */ } /* SHA-384 functions */ void camlpdf_sha384(const unsigned char *message, unsigned int len, unsigned char *digest) { sha384_ctx ctx; camlpdf_sha384_init(&ctx); camlpdf_sha384_update(&ctx, message, len); camlpdf_sha384_final(&ctx, digest); } void camlpdf_sha384_init(sha384_ctx *ctx) { #ifndef UNROLL_LOOPS int i; for (i = 0; i < 8; i++) { ctx->h[i] = sha384_h0[i]; } #else ctx->h[0] = sha384_h0[0]; ctx->h[1] = sha384_h0[1]; ctx->h[2] = sha384_h0[2]; ctx->h[3] = sha384_h0[3]; ctx->h[4] = sha384_h0[4]; ctx->h[5] = sha384_h0[5]; ctx->h[6] = sha384_h0[6]; ctx->h[7] = sha384_h0[7]; #endif /* !UNROLL_LOOPS */ ctx->len = 0; ctx->tot_len = 0; } void camlpdf_sha384_update(sha384_ctx *ctx, const unsigned char *message, unsigned int len) { unsigned int block_nb; unsigned int new_len, rem_len, tmp_len; const unsigned char *shifted_message; tmp_len = SHA384_BLOCK_SIZE - ctx->len; rem_len = len < tmp_len ? len : tmp_len; memcpy(&ctx->block[ctx->len], message, rem_len); if (ctx->len + len < SHA384_BLOCK_SIZE) { ctx->len += len; return; } new_len = len - rem_len; block_nb = new_len / SHA384_BLOCK_SIZE; shifted_message = message + rem_len; camlpdf_sha512_transf(ctx, ctx->block, 1); camlpdf_sha512_transf(ctx, shifted_message, block_nb); rem_len = new_len % SHA384_BLOCK_SIZE; memcpy(ctx->block, &shifted_message[block_nb << 7], rem_len); ctx->len = rem_len; ctx->tot_len += (block_nb + 1) << 7; } void camlpdf_sha384_final(sha384_ctx *ctx, unsigned char *digest) { unsigned int block_nb; unsigned int pm_len; unsigned int len_b; #ifndef UNROLL_LOOPS int i; #endif block_nb = (1 + ((SHA384_BLOCK_SIZE - 17) < (ctx->len % SHA384_BLOCK_SIZE))); len_b = (ctx->tot_len + ctx->len) << 3; pm_len = block_nb << 7; memset(ctx->block + ctx->len, 0, pm_len - ctx->len); ctx->block[ctx->len] = 0x80; UNPACK32(len_b, ctx->block + pm_len - 4); camlpdf_sha512_transf(ctx, ctx->block, block_nb); #ifndef UNROLL_LOOPS for (i = 0 ; i < 6; i++) { UNPACK64(ctx->h[i], &digest[i << 3]); } #else UNPACK64(ctx->h[0], &digest[ 0]); UNPACK64(ctx->h[1], &digest[ 8]); UNPACK64(ctx->h[2], &digest[16]); UNPACK64(ctx->h[3], &digest[24]); UNPACK64(ctx->h[4], &digest[32]); UNPACK64(ctx->h[5], &digest[40]); #endif /* !UNROLL_LOOPS */ } /* SHA-224 functions */ void camlpdf_sha224(const unsigned char *message, unsigned int len, unsigned char *digest) { sha224_ctx ctx; camlpdf_sha224_init(&ctx); camlpdf_sha224_update(&ctx, message, len); camlpdf_sha224_final(&ctx, digest); } void camlpdf_sha224_init(sha224_ctx *ctx) { #ifndef UNROLL_LOOPS int i; for (i = 0; i < 8; i++) { ctx->h[i] = sha224_h0[i]; } #else ctx->h[0] = sha224_h0[0]; ctx->h[1] = sha224_h0[1]; ctx->h[2] = sha224_h0[2]; ctx->h[3] = sha224_h0[3]; ctx->h[4] = sha224_h0[4]; ctx->h[5] = sha224_h0[5]; ctx->h[6] = sha224_h0[6]; ctx->h[7] = sha224_h0[7]; #endif /* !UNROLL_LOOPS */ ctx->len = 0; ctx->tot_len = 0; } void camlpdf_sha224_update(sha224_ctx *ctx, const unsigned char *message, unsigned int len) { unsigned int block_nb; unsigned int new_len, rem_len, tmp_len; const unsigned char *shifted_message; tmp_len = SHA224_BLOCK_SIZE - ctx->len; rem_len = len < tmp_len ? len : tmp_len; memcpy(&ctx->block[ctx->len], message, rem_len); if (ctx->len + len < SHA224_BLOCK_SIZE) { ctx->len += len; return; } new_len = len - rem_len; block_nb = new_len / SHA224_BLOCK_SIZE; shifted_message = message + rem_len; camlpdf_sha256_transf(ctx, ctx->block, 1); camlpdf_sha256_transf(ctx, shifted_message, block_nb); rem_len = new_len % SHA224_BLOCK_SIZE; memcpy(ctx->block, &shifted_message[block_nb << 6], rem_len); ctx->len = rem_len; ctx->tot_len += (block_nb + 1) << 6; } void camlpdf_sha224_final(sha224_ctx *ctx, unsigned char *digest) { unsigned int block_nb; unsigned int pm_len; unsigned int len_b; #ifndef UNROLL_LOOPS int i; #endif block_nb = (1 + ((SHA224_BLOCK_SIZE - 9) < (ctx->len % SHA224_BLOCK_SIZE))); len_b = (ctx->tot_len + ctx->len) << 3; pm_len = block_nb << 6; memset(ctx->block + ctx->len, 0, pm_len - ctx->len); ctx->block[ctx->len] = 0x80; UNPACK32(len_b, ctx->block + pm_len - 4); camlpdf_sha256_transf(ctx, ctx->block, block_nb); #ifndef UNROLL_LOOPS for (i = 0 ; i < 7; i++) { UNPACK32(ctx->h[i], &digest[i << 2]); } #else UNPACK32(ctx->h[0], &digest[ 0]); UNPACK32(ctx->h[1], &digest[ 4]); UNPACK32(ctx->h[2], &digest[ 8]); UNPACK32(ctx->h[3], &digest[12]); UNPACK32(ctx->h[4], &digest[16]); UNPACK32(ctx->h[5], &digest[20]); UNPACK32(ctx->h[6], &digest[24]); #endif /* !UNROLL_LOOPS */ } #ifdef TEST_VECTORS /* FIPS 180-2 Validation tests */ #include #include void test(const char *vector, unsigned char *digest, unsigned int digest_size) { char output[2 * SHA512_DIGEST_SIZE + 1]; int i; output[2 * digest_size] = '\0'; for (i = 0; i < (int) digest_size ; i++) { sprintf(output + 2 * i, "%02x", digest[i]); } printf("H: %s\n", output); if (strcmp(vector, output)) { fprintf(stderr, "Test failed.\n"); exit(EXIT_FAILURE); } } int main(void) { static const char *vectors[4][3] = { /* SHA-224 */ { "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525", "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67", }, /* SHA-256 */ { "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0", }, /* SHA-384 */ { "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed" "8086072ba1e7cc2358baeca134c825a7", "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712" "fcc7c71a557e2db966c3e9fa91746039", "9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b" "07b8b3dc38ecc4ebae97ddd87f3d8985", }, /* SHA-512 */ { "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a" "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018" "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909", "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb" "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b" } }; static const char message1[] = "abc"; static const char message2a[] = "abcdbcdecdefdefgefghfghighijhi" "jkijkljklmklmnlmnomnopnopq"; static const char message2b[] = "abcdefghbcdefghicdefghijdefghijkefghij" "klfghijklmghijklmnhijklmnoijklmnopjklm" "nopqklmnopqrlmnopqrsmnopqrstnopqrstu"; unsigned char *message3; unsigned int message3_len = 1000000; unsigned char digest[SHA512_DIGEST_SIZE]; message3 = malloc(message3_len); if (message3 == NULL) { fprintf(stderr, "Can't allocate memory\n"); return -1; } memset(message3, 'a', message3_len); printf("SHA-2 FIPS 180-2 Validation tests\n\n"); printf("SHA-224 Test vectors\n"); camlpdf_sha224((const unsigned char *) message1, strlen(message1), digest); test(vectors[0][0], digest, SHA224_DIGEST_SIZE); camlpdf_sha224((const unsigned char *) message2a, strlen(message2a), digest); test(vectors[0][1], digest, SHA224_DIGEST_SIZE); camlpdf_sha224(message3, message3_len, digest); test(vectors[0][2], digest, SHA224_DIGEST_SIZE); printf("\n"); printf("SHA-256 Test vectors\n"); camlpdf_sha256((const unsigned char *) message1, strlen(message1), digest); test(vectors[1][0], digest, SHA256_DIGEST_SIZE); camlpdf_sha256((const unsigned char *) message2a, strlen(message2a), digest); test(vectors[1][1], digest, SHA256_DIGEST_SIZE); camlpdf_sha256(message3, message3_len, digest); test(vectors[1][2], digest, SHA256_DIGEST_SIZE); printf("\n"); printf("SHA-384 Test vectors\n"); camlpdf_sha384((const unsigned char *) message1, strlen(message1), digest); test(vectors[2][0], digest, SHA384_DIGEST_SIZE); camlpdf_sha384((const unsigned char *)message2b, strlen(message2b), digest); test(vectors[2][1], digest, SHA384_DIGEST_SIZE); camlpdf_sha384(message3, message3_len, digest); test(vectors[2][2], digest, SHA384_DIGEST_SIZE); printf("\n"); printf("SHA-512 Test vectors\n"); camlpdf_sha512((const unsigned char *) message1, strlen(message1), digest); test(vectors[3][0], digest, SHA512_DIGEST_SIZE); camlpdf_sha512((const unsigned char *) message2b, strlen(message2b), digest); test(vectors[3][1], digest, SHA512_DIGEST_SIZE); camlpdf_sha512(message3, message3_len, digest); test(vectors[3][2], digest, SHA512_DIGEST_SIZE); printf("\n"); printf("All tests passed.\n"); return 0; } #endif /* TEST_VECTORS */ camlpdf-2.8.1/sha2.h000066400000000000000000000075631477056064700141710ustar00rootroot00000000000000/* * FIPS 180-2 SHA-224/256/384/512 implementation * Last update: 02/02/2007 * Issue date: 04/30/2005 * * Copyright (C) 2005, 2007 Olivier Gay * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef SHA2_H #define SHA2_H #define SHA224_DIGEST_SIZE ( 224 / 8) #define SHA256_DIGEST_SIZE ( 256 / 8) #define SHA384_DIGEST_SIZE ( 384 / 8) #define SHA512_DIGEST_SIZE ( 512 / 8) #define SHA256_BLOCK_SIZE ( 512 / 8) #define SHA512_BLOCK_SIZE (1024 / 8) #define SHA384_BLOCK_SIZE SHA512_BLOCK_SIZE #define SHA224_BLOCK_SIZE SHA256_BLOCK_SIZE #ifndef SHA2_TYPES #define SHA2_TYPES /*typedef unsigned char uint8; typedef unsigned int uint32; typedef unsigned long long uint64;*/ #endif #ifdef __cplusplus extern "C" { #endif typedef struct { unsigned int tot_len; unsigned int len; unsigned char block[2 * SHA256_BLOCK_SIZE]; unsigned int h[8]; } sha256_ctx; typedef struct { unsigned int tot_len; unsigned int len; unsigned char block[2 * SHA512_BLOCK_SIZE]; unsigned long long h[8]; } sha512_ctx; typedef sha512_ctx sha384_ctx; typedef sha256_ctx sha224_ctx; void camlpdf_sha224_init(sha224_ctx *ctx); void camlpdf_sha224_update(sha224_ctx *ctx, const unsigned char *message, unsigned int len); void camlpdf_sha224_final(sha224_ctx *ctx, unsigned char *digest); void camlpdf_sha224(const unsigned char *message, unsigned int len, unsigned char *digest); void camlpdf_sha256_init(sha256_ctx * ctx); void camlpdf_sha256_update(sha256_ctx *ctx, const unsigned char *message, unsigned int len); void camlpdf_sha256_final(sha256_ctx *ctx, unsigned char *digest); void camlpdf_sha256(const unsigned char *message, unsigned int len, unsigned char *digest); void camlpdf_sha384_init(sha384_ctx *ctx); void camlpdf_sha384_update(sha384_ctx *ctx, const unsigned char *message, unsigned int len); void camlpdf_sha384_final(sha384_ctx *ctx, unsigned char *digest); void camlpdf_sha384(const unsigned char *message, unsigned int len, unsigned char *digest); void camlpdf_sha512_init(sha512_ctx *ctx); void camlpdf_sha512_update(sha512_ctx *ctx, const unsigned char *message, unsigned int len); void camlpdf_sha512_final(sha512_ctx *ctx, unsigned char *digest); void camlpdf_sha512(const unsigned char *message, unsigned int len, unsigned char *digest); #ifdef __cplusplus } #endif #endif /* !SHA2_H */ camlpdf-2.8.1/stubs-aes.c000066400000000000000000000052431477056064700152260ustar00rootroot00000000000000/***********************************************************************/ /* */ /* The Cryptokit library */ /* */ /* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ /* */ /* Copyright 2002 Institut National de Recherche en Informatique et */ /* en Automatique. All rights reserved. This file is distributed */ /* under the terms of the GNU Library General Public License, with */ /* the special exception on linking described in file LICENSE. */ /* */ /***********************************************************************/ /* $Id: stubs-aes.c 53 2010-08-30 10:53:00Z gildor-admin $ */ /* Stub code for AES */ #include "rijndael-alg-fst.h" #include #include #include #define Cooked_key_NR_offset ((4 * (MAXNR + 1)) * sizeof(u32)) #define Cooked_key_size (Cooked_key_NR_offset + 1) CAMLprim value camlpdf_caml_aes_cook_encrypt_key(value key) { CAMLparam1(key); value ckey = caml_alloc_string(Cooked_key_size); int nr = camlpdf_rijndaelKeySetupEnc((u32 *) String_val(ckey), (const u8 *) String_val(key), 8 * caml_string_length(key)); Byte(ckey, Cooked_key_NR_offset) = nr; CAMLreturn(ckey); } CAMLprim value camlpdf_caml_aes_cook_decrypt_key(value key) { CAMLparam1(key); value ckey = caml_alloc_string(Cooked_key_size); int nr = camlpdf_rijndaelKeySetupDec((u32 *) String_val(ckey), (const u8 *) String_val(key), 8 * caml_string_length(key)); Byte(ckey, Cooked_key_NR_offset) = nr; CAMLreturn(ckey); } CAMLprim value camlpdf_caml_aes_encrypt(value ckey, value src, value src_ofs, value dst, value dst_ofs) { camlpdf_rijndaelEncrypt((const u32 *) String_val(ckey), Byte(ckey, Cooked_key_NR_offset), (const u8 *) &Byte(src, Long_val(src_ofs)), (u8 *) &Byte(dst, Long_val(dst_ofs))); return Val_unit; } CAMLprim value camlpdf_caml_aes_decrypt(value ckey, value src, value src_ofs, value dst, value dst_ofs) { camlpdf_rijndaelDecrypt((const u32 *) String_val(ckey), Byte(ckey, Cooked_key_NR_offset), (const u8 *) &Byte(src, Long_val(src_ofs)), (u8 *) &Byte(dst, Long_val(dst_ofs))); return Val_unit; } camlpdf-2.8.1/stubs-sha2.c000066400000000000000000000017121477056064700153100ustar00rootroot00000000000000#include "sha2.h" #include #include #include CAMLprim value camlpdf_caml_sha256(value message) { CAMLparam1(message); value digest = caml_alloc_string(32); camlpdf_sha256((const unsigned char *) (String_val(message)), caml_string_length(message), ((unsigned char *) String_val(digest))); CAMLreturn(digest); } CAMLprim value camlpdf_caml_sha384(value message) { CAMLparam1(message); value digest = caml_alloc_string(48); camlpdf_sha384((const unsigned char *) (String_val(message)), caml_string_length(message), ((unsigned char *) String_val(digest))); CAMLreturn(digest); } CAMLprim value camlpdf_caml_sha512(value message) { CAMLparam1(message); value digest = caml_alloc_string(64); camlpdf_sha512((const unsigned char *) (String_val(message)), caml_string_length(message), ((unsigned char *) String_val(digest))); CAMLreturn(digest); }