podofo-0.9.5/0000775000175000017500000000000013044451162012663 5ustar dominikdominikpodofo-0.9.5/INSTALL0000664000175000017500000000012310625114670013712 0ustar dominikdominikPlease see the file README for instruction on howto install PoDoFo on your system. podofo-0.9.5/CONTRIBUTIONS.txt0000664000175000017500000000624211336742344015501 0ustar dominikdominikThis document describes how to contribute code to PoDoFo. 2010 Dominik Seichter 0. Code quality =============== Before you submit or commit code to PoDoFo (assuming you made a modification), you should make sure that your code adheres to the codingstyle guidelines (see CODINGSTYLE.txt). Note that the codingstyle guidelines also include documenting every newly introduced method (Doxygen syntax). Additionally, your code should work on at least Linux and Windows operating systems. Portability is one main goal of PoDoFo, so it is important that the code is always buildable and runnable on all supported platforms. We usually test at least using GCC on Linux and using Visual Studio on Windows. Both 32bit and 64bit systems are target platforms. So if your code needs to work at bit and byte-levels, take this into account. Last but not least, all unit tests - especially test/unit/podofo-test - should run after your modification. 1. Submitting code ================== If you are contributing code for the first time, the usual procedure is to send a patch containing your modifications to the PoDoFo mailing list . We will check your code and commit it for you to the repository. A patch should always be created against latest SVN trunk. Such a patch can be created using the SVN command "svn diff" on the commandline. It is recommended that you also add a unit test for the modification you have made. If your modification is a bug fix, a unit test assures that no regression for this bug is introduced at a later point of time (as everyone runs the unit tests after every modification and before every commit). If you added a new feature, the unit test guarantees that the new code was at least tested once. Another very useful test is to run the test/ParserTest executable and see if is able to parse and write the PDFReference1*.pdf from Adobe correctly. 2. Getting a SVN account ======================== After we integrated some patches of yours successfully into SVN, you usually can also get a SVN account. Feel free to ask for it, or if we think of it we will offer an SVN account to you. Frequent submitters of patches are encouraged to ask for an SVN account, as it is easier for everyone if submitters of good quality patches can integrate these themselves. 3. Committing code ================== Using a SVN account you can commit your code yourself. If you are working on the main part of PoDoFo, you should announce or discuss your intended changes on the mailing lists. If you are maintaining a tool (under tools/) you can add features or make changes as you like. An important point is that every commit has to go with a commit log message that tells the other developers what your change does and why you made it. These changes can be tracked and discussed on the PoDoFo SVN mailinglist . Every commit is automatically send to this list. 4. Non-code contributions ========================= Besides to code, we are also interested in other contributions like documentation, feedback, examples, webpage, articles ... Ask on the mailinglist if you are interested in helping or joining the project. podofo-0.9.5/debian/0000775000175000017500000000000013044451156014110 5ustar dominikdominikpodofo-0.9.5/debian/CMakeLists.txt0000664000175000017500000000002711500641065016642 0ustar dominikdominik ADD_SUBDIRECTORY(man) podofo-0.9.5/debian/man/0000775000175000017500000000000013044451156014663 5ustar dominikdominikpodofo-0.9.5/debian/man/podofoimg2pdf.10000664000175000017500000000252311544447143017512 0ustar dominikdominik.TH "PODOFOIMG2PDF" "1" "2010-12-09" "PoDoFo" "podofoimg2pdf" .PP .SH NAME podofoimg2pdf \- Convert images to PDF files .PP .SH SYNOPSIS \fBpodofoimg2pdf\fR [output\.pdf] [\-useimgsize] [image1 image2 image3 \.\.\.] .PP .SH DESCRIPTION .B podofoimg2pdf is one of the command line tools from the PoDoFo library that provide several useful operations to work with PDF files\. This tool will combine any number of images into a single PDF\. This is useful for creating a document from scanned images\. Large pages will be scaled to fit the page and images smaller than the defined page size will be centered\. .PP Supported image formats: .RS JPEG .br PNG .br TIFF .RE .PP .SH OPTIONS \fB\-useimgsize\fR .RS Use the image size as page size instead of A4 .RE .PP .SH SEE ALSO .BR podofobox (1), .BR podofocolor (1), .BR podofocountpages (1), .BR podofocrop (1), .BR podofoencrypt (1), .BR podofogc (1), .BR podofoimgextract (1), .BR podofoincrementalupdates (1), .BR podofoimpose (1), .BR podofomerge (1), .BR podofopages (1), .BR podofopdfinfo (1), .BR podofotxt2pdf (1), .BR podofotxtextract (1), .BR podofouncompress (1), .BR podofoxmp (1) .PP .SH AUTHORS .PP PoDoFo is written by Dominik Seichter and others\. .PP This manual page was written by Oleksandr Moskalenko for the Debian Project (but may be used by others)\. podofo-0.9.5/debian/man/podofotxtextract.10000664000175000017500000000204211544447143020370 0ustar dominikdominik.TH "PODOFOTXTEXTRACT" "1" "2010-12-09" "PoDoFo" "podofotxtextract" .PP .SH NAME podofotxtextract \- Extract all text from a PDF file .PP .SH SYNOPSIS \fBpodofotxtextract\fR [inputfile] .PP .SH DESCRIPTION .B podofotxtextract is one of the command line tools from the PoDoFo library that provide several useful operations to work with PDF files\. It can extract text from a PDF file\. .PP .SH "OPTIONS" .PP \fB[inputfile]\fR .RS .PP Input PDF file\. .RE .PP .SH SEE ALSO .BR podofobox (1), .BR podofocolor (1), .BR podofocountpages (1), .BR podofocrop (1), .BR podofoencrypt (1), .BR podofogc (1), .BR podofoimg2pdf (1), .BR podofoimgextract (1), .BR podofoimpose (1), .BR podofoincrementalupdates (1), .BR podofomerge (1), .BR podofopages (1), .BR podofopdfinfo (1), .BR podofotxt2pdf (1), .BR podofouncompress (1), .BR podofoxmp (1) .PP .SH AUTHORS .PP PoDoFo is written by Dominik Seichter and others\. .PP This manual page was written by Oleksandr Moskalenko for the Debian Project (but may be used by others)\. podofo-0.9.5/debian/man/CMakeLists.txt0000664000175000017500000000054112113724117017417 0ustar dominikdominik INSTALL(FILES podofobox.1 podofocolor.1 podofocountpages.1 podofocrop.1 podofogc.1 podofoencrypt.1 podofoimg2pdf.1 podofoimgextract.1 podofoimpose.1 podofoincrementalupdates.1 podofomerge.1 podofopages.1 podofopdfinfo.1 podofotxt2pdf.1 podofotxtextract.1 podofouncompress.1 podofoxmp.1 DESTINATION ${MANDIR}man1 ) podofo-0.9.5/debian/man/podofoencrypt.10000664000175000017500000000447111544447143017652 0ustar dominikdominik.TH "PODOFOENCRYPT" "1" "2010-12-09" "PoDoFo" "podofoencrypt" .PP .SH NAME podofoencrypt \- encrypt PDF files and set PDF security settings .PP .SH SYNOPSIS \fBpodofoencrypt\fR [\-\-rc4v1] [\-\-rc4v2] [\-\-aes] [\-u ] \-o .PP .SH DESCRIPTION .B podofoencrypt is one of the command line tools from the PoDoFo library that provide several useful operations to work with PDF files\. It can encrypt PDF files using RC4 or AES encoding and can set PDF security settings\. .PP .SH "OPTIONS" \fB\-\-help\fR .RS Display the help text .RE .PP Algorithm: .PP .RS \fB\-\-rc4v1\fR .RS Use rc4v1 encryption .RE .PP \fB\-\-rc4v2\fR .RS Use rc4v2 encryption (Default value) .RE .PP \fB\-\-aes\fR .RS Use aes encryption (currently not supported) .RE .RE .PP Passwords: .PP .RS \fB\-u \fR .RS An optional user password .RE .PP \fB\-o \fR .RS The required owner password .RE .RE .PP Permissions: .RS .PP \fB\-\-print\fR .RS .PP Allow printing the document .RE .PP \fB\-\-edit\fR .RS .PP Allow modification of the document besides annotations, form fields or changing pages .RE .PP \fB\-\-copy\fR .RS .PP Allow extraction of text and graphics .RE .PP \fB\-\-editnotes\fR .RS .PP Add or modify text annoations or form fields (if ePdfPermissions_Edit is set also allow to create interactive form fields including signature) .RE .PP \fB\-\-fillandsign\fR .RS .PP Fill in existing form or signature fields .RE .PP \fB\-\-accessible\fR .RS .PP Extract text and graphics to support user with disabillities .RE .PP \fB\-\-assemble\fR .RS .PP Assemble the document: insert, create, rotate delete pages or add bookmarks .RE .PP \fB\-\-highprint \fR .RS .PP Print a high resolution version of the document .PP .SH SEE ALSO .BR podofobox (1), .BR podofocolor (1), .BR podofocountpages (1), .BR podofocrop (1), .BR podofogc (1), .BR podofoimg2pdf (1), .BR podofoimgextract (1), .BR podofoincrementalupdates (1), .BR podofoimpose (1), .BR podofomerge (1), .BR podofopages (1), .BR podofopdfinfo (1), .BR podofotxt2pdf (1), .BR podofotxtextract (1), .BR podofouncompress (1), .BR podofoxmp (1) .PP .SH AUTHORS .PP PoDoFo is written by Dominik Seichter and others\. .PP This manual page was written by Oleksandr Moskalenko for the Debian Project (but may be used by others)\. podofo-0.9.5/debian/man/podofouncompress.10000664000175000017500000000225411544447143020361 0ustar dominikdominik.TH "PODOFOUNCOMPRESS" "1" "2010-12-09" "PoDoFo" "podofouncompress" .PP .SH NAME podofouncompress \- Uncompress PDF files .PP .SH SYNOPSIS \fBpodofouncompress\fR [inputfile] [outputfile] .PP .SH DESCRIPTION .B podofouncompress is one of the command line tools from the PoDoFo library that provide several useful operations to work with PDF files\. It can remove compression from a PDF file\. It is useful for debugging errors in PDF files or analysing their structure\. .PP .SH "OPTIONS" .PP \fB[inputfile]\fR .RS .PP Input PDF file\. .RE .PP \fB[outputfile]\fR .RS .PP Output PDF file\. .RE .PP .SH SEE ALSO .BR podofobox (1), .BR podofocolor (1), .BR podofocountpages (1), .BR podofocrop (1), .BR podofoencrypt (1), .BR podofogc (1), .BR podofoimg2pdf (1), .BR podofoimgextract (1), .BR podofoimpose (1), .BR podofoincrementalupdates (1), .BR podofomerge (1), .BR podofopages (1), .BR podofopdfinfo (1), .BR podofotxt2pdf (1), .BR podofotxtextract (1), .BR podofoxmp (1) .PP .SH AUTHORS .PP PoDoFo is written by Dominik Seichter and others\. .PP This manual page was written by Oleksandr Moskalenko for the Debian Project (but may be used by others)\. podofo-0.9.5/debian/man/podofoincrementalupdates.10000664000175000017500000000243311544447143022051 0ustar dominikdominik.TH "PODOFOINCREMENTALUPDATES" "1" "2010-12-09" "PoDoFo" "podofoincrementalupdates" .PP .SH NAME podofoincrementalupdates \- Provides information about incremental updates in PDF files .PP .SH SYNOPSIS \fBpodofoincrementalupdates\fR [\-e N out\.pdf] file\.pdf .PP .SH DESCRIPTION .B podofoincrementalupdates is one of the command line tools from the PoDoFo library that provide several useful operations to work with PDF files\. It can print information of incremental updates to file\.pdf\. By default the number of incremental updates will be printed\. .PP .SH "OPTIONS" .PP \fB\-e N\fR .RS Extract the Nth update .RE .PP \fBout\.pdf\fR .RS Output PDF file\. .RE .PP \fBfile\.pdf\fR .RS Input PDF file\. .RE .PP .SH SEE ALSO .BR podofobox (1), .BR podofocolor (1), .BR podofocountpages (1), .BR podofocrop (1), .BR podofoencrypt (1), .BR podofogc (1), .BR podofoimg2pdf (1), .BR podofoimgextract (1), .BR podofoimpose (1), .BR podofomerge (1), .BR podofopages (1), .BR podofopdfinfo (1), .BR podofotxt2pdf (1), .BR podofotxtextract (1), .BR podofouncompress (1), .BR podofoxmp (1) .PP .SH AUTHORS .PP PoDoFo is written by Dominik Seichter and others\. .PP This manual page was written by Oleksandr Moskalenko for the Debian Project (but may be used by others)\. podofo-0.9.5/debian/man/podofoimpose.10000664000175000017500000000247011544447143017457 0ustar dominikdominik.TH "PODOFOIMPOSE" "1" "2010-12-09" "PoDoFo" "podofoimpose" .PP .SH NAME podofoimpose \- A powerful PDF imposition tool .PP .SH SYNOPSIS \fBpodofoimpose\fR Input Output Plan [Interpretor] .PP .SH DESCRIPTION .B podofoimpose is one of the command line tools from the PoDoFo library that provide several useful operations to work with PDF files\. It can do imposition of the final output according to the specified imposition plan. .PP .SH "OPTIONS" .PP \fBInput\fR .RS PDF file or a file which contains a list of PDF file paths\. .RE .PP \fBOutput\fR .RS Resulting PDF file\. .RE .PP \fBPlan\fR .RS Imposition plan file\. .RE .PP \fB[Interpretor]\fR .RS Imposition interpretor\. It can be "native" (default value) or "lua"\. .RE .PP .SH SEE ALSO .BR podofobox (1), .BR podofocolor (1), .BR podofocountpages (1), .BR podofocrop (1), .BR podofoencrypt (1), .BR podofogc (1), .BR podofoimg2pdf (1), .BR podofoimgextract (1), .BR podofomerge (1), .BR podofoincrementalupdates (1), .BR podofopages (1), .BR podofopdfinfo (1), .BR podofotxt2pdf (1), .BR podofotxtextract (1), .BR podofouncompress (1), .BR podofoxmp (1) .PP .SH AUTHORS .PP PoDoFo is written by Dominik Seichter and others\. .PP This manual page was written by Oleksandr Moskalenko for the Debian Project (but may be used by others)\. podofo-0.9.5/debian/man/podofocrop.10000664000175000017500000000175511544447143017133 0ustar dominikdominik.TH "PODOFOCROP" "1" "2010-12-09" "PoDoFo" "podofocrop" .PP .SH NAME podofocrop \- crop all pages .PP .SH SYNOPSIS \fBpodofocrop\fR input\.pdf output\.pdf .PP .SH DESCRIPTION .B podofocrop is one of the command line tools from the PoDoFo library that provide several useful operations to work with PDF files\. It can crop all pages in a PDF file\. It requires ghostscript to be in your PATH\. .PP .SH "SEE ALSO" .BR podofobox (1), .BR podofocolor (1), .BR podofocountpages (1), .BR podofoencrypt (1), .BR podofogc (1), .BR podofoimg2pdf (1), .BR podofoimgextract (1), .BR podofoimpose (1), .BR podofoincrementalupdates (1), .BR podofomerge (1), .BR podofopages (1), .BR podofopdfinfo (1), .BR podofotxt2pdf (1), .BR podofotxtextract (1), .BR podofouncompress (1), .BR podofoxmp (1) .PP .SH AUTHORS .PP PoDoFo is written by Dominik Seichter and others\. .PP This manual page was written by Oleksandr Moskalenko for the Debian Project (but may be used by others)\. podofo-0.9.5/debian/man/podofocountpages.10000664000175000017500000000223311544447143020330 0ustar dominikdominik.TH "PODOFOCOUNTPAGES" "1" "2010-12-09" "PoDoFo" "podofocountpages" .PP .SH NAME podofocountpages \- count the number of pages in a pdf file .PP .SH SYNOPSIS \fBpodofocountpages\fR [\-s] [\-t] file1.pdf \.\.\. .PP .SH DESCRIPTION .B podofocountpages is one of the command line tools from the PoDoFo library that provide several useful operations to work with PDF files\. It counts the pages in a PDF file\. .PP .SH "OPTIONS" .PP \fB\-s\fR .RS enable the short format, which omits printing of the filename to the output .RE .PP \fB\-t\fR .RS print the total number of pages .PP .SH "SEE ALSO" .BR podofobox (1), .BR podofocolor (1), .BR podofocrop (1), .BR podofoencrypt (1), .BR podofogc (1), .BR podofoimg2pdf (1), .BR podofoimgextract (1), .BR podofoimpose (1), .BR podofoincrementalupdates (1), .BR podofomerge (1), .BR podofopages (1), .BR podofopdfinfo (1), .BR podofotxt2pdf (1), .BR podofotxtextract (1), .BR podofouncompress (1), .BR podofoxmp (1) .PP .SH AUTHOR .PP PoDoFo is written by Dominik Seichter and others\. .PP This manual page was written by Oleksandr Moskalenko for the Debian Project (but may be used by others)\. podofo-0.9.5/debian/man/podofotxt2pdf.10000664000175000017500000000246511544447143017562 0ustar dominikdominik.TH "PODOFOTXT2PDF" "1" "2010-12-09" "PoDoFo" "podofotxt2pdf" .PP .SH NAME podofotxt2pdf \- convert plain text files into PDF files .PP .SH SYNOPSIS \fBpodofotxt2pdf\fR [\-fontname ] [\-utf8] [inputfile] [outputfile] .PP .SH DESCRIPTION .B podofotxt2pdf is one of the command line tools from the PoDoFo library that provide several useful operations to work with PDF files\. It can convert a plain text file into a PDF file. .PP .SH "OPTIONS" .PP \fB\-fontname\fR .RS .PP Use the font \. .RE .PP \fB\-utf8\fR .RS .PP specifies that the input text is UTF8 encoded instead of Windows ANSI encoding\. .RE .PP \fB[inputfile]\fR .RS .PP Input PDF file\. .RE .PP \fB[outputfile]\fR .RS .PP Output PDF file\. .RE .PP .SH SEE ALSO .BR podofobox (1), .BR podofocolor (1), .BR podofocountpages (1), .BR podofocrop (1), .BR podofoencrypt (1), .BR podofogc (1), .BR podofoimg2pdf (1), .BR podofoimgextract (1), .BR podofoimpose (1), .BR podofoincrementalupdates (1), .BR podofomerge (1), .BR podofopages (1), .BR podofopdfinfo (1), .BR podofotxtextract (1), .BR podofouncompress (1), .BR podofoxmp (1) .PP .SH AUTHORS .PP PoDoFo is written by Dominik Seichter and others\. .PP This manual page was written by Oleksandr Moskalenko for the Debian Project (but may be used by others)\. podofo-0.9.5/debian/man/podofogc.10000664000175000017500000000205511544447143016553 0ustar dominikdominik.TH "PODOFOGC" "1" "2011-03-26" "PoDoFo" "podofogc" .PP .SH NAME podofogc \- Garbage collection in a PDF file\. .PP .SH SYNOPSIS \fBpodofogc \fR [inputfile] [outpufile] .PP .SH DESCRIPTION .B podofogc is one of the command line tools from the PoDoFo library that provide several useful operations to work with PDF files\. It can perform a garbage collection operation on a PDF file. All objects that are not reachable from within the trailer are deleted\. .PP .SH "SEE ALSO" .BR podofobox (1), .BR podofocolor (1), .BR podofocountpages (1), .BR podofocrop (1), .BR podofoencrypt (1), .BR podofoimg2pdf (1), .BR podofoimgextract (1), .BR podofoimpose (1), .BR podofomerge (1), .BR podofoincrementalupdates (1), .BR podofopages (1), .BR podofopdfinfo (1), .BR podofotxt2pdf (1), .BR podofotxtextract (1), .BR podofouncompress (1), .BR podofoxmp (1) .PP .SH AUTHOR .PP PoDoFo is written by Dominik Seichter and others\. .PP This manual page was written by Oleksandr Moskalenko for the Debian Project (but may be used by others)\. podofo-0.9.5/debian/man/podofoxmp.10000664000175000017500000000257311544447143016773 0ustar dominikdominik.TH "PODOFOXMP" "1" "2010-12-09" "PoDoFo" "podofoxmp" .PP .SH NAME podofoxmp \- Modify or extract XMP information from a PDF file .PP .SH SYNOPSIS \fBpodofoxmp\fR [inputfile] [xmpfile outputfile] .PP .SH DESCRIPTION .B podofoxmp is one of the command line tools from the PoDoFo library that provide several useful operations to work with PDF files\. It can extract or modify XMP information in a PDF file\. .PP .SH "OPTIONS" .PP \fB[inputfile]\fR .RS .PP Input PDF file\. This is the only option needed to extract the XMP information from a PDF file\. .RE .PP \fB[xmpfile]\fR .RS .PP Optional file that provides PDF XMP structure\. It must be used in conjuction with an [outputfile]\. .RE .PP \fB[outputfile]\fR .RS .PP Output PDF file\. It is only used in conjuction with an [xmpfile]\. .RE .PP .SH SEE ALSO .BR podofobox (1), .BR podofocolor (1), .BR podofocountpages (1), .BR podofocrop (1), .BR podofoencrypt (1), .BR podofogc (1), .BR podofoimg2pdf (1), .BR podofoimgextract (1), .BR podofoimpose (1), .BR podofoincrementalupdates (1), .BR podofomerge (1), .BR podofopages (1), .BR podofopdfinfo (1), .BR podofotxt2pdf (1), .BR podofotxtextract (1), .BR podofouncompress (1) .PP .SH AUTHORS .PP PoDoFo is written by Dominik Seichter and others\. .PP This manual page was written by Oleksandr Moskalenko for the Debian Project (but may be used by others)\. podofo-0.9.5/debian/man/podofopages.10000664000175000017500000000263611544447143017266 0ustar dominikdominik.TH "PODOFOPAGES" "1" "2010-12-09" "PoDoFo" "podofopages" .PP .SH NAME podofopages \- move and delete pages in a PDF document .PP .SH SYNOPSIS \fBpodofopages\fR [\-\-delete] [\-\-move] [inputfile] [outputfile] .PP .SH DESCRIPTION .B podofopages is one of the command line tools from the PoDoFo library that provide several useful operations to work with PDF files\. It can move and delete pages in a PDF document\. .PP .SH "OPTIONS" .PP \fB\-\-delete NUMBER\fR .RS .PP Deletes the page NUMBER (number is 0\-based)\. The page will not really be deleted from the PDF\. It is only removed from the so called pagestree and therefore becomes hidden\. The content of the page can still be retrieved from the document though\. .RE .PP \fB\-\-move FROM TO\fR .RS .PP Moves a page FROM TO in the document (FROM and TO are 0\-based)\. .RE .PP .SH SEE ALSO .BR podofobox (1), .BR podofocolor (1), .BR podofocountpages (1), .BR podofocrop (1), .BR podofoencrypt (1), .BR podofogc (1), .BR podofoimg2pdf (1), .BR podofoimgextract (1), .BR podofoimpose (1), .BR podofoincrementalupdates (1), .BR podofomerge (1), .BR podofopdfinfo (1), .BR podofotxt2pdf (1), .BR podofotxtextract (1), .BR podofouncompress (1), .BR podofoxmp (1) .PP .SH AUTHORS .PP PoDoFo is written by Dominik Seichter and others\. .PP This manual page was written by Oleksandr Moskalenko for the Debian Project (but may be used by others)\. podofo-0.9.5/debian/man/podofomerge.10000664000175000017500000000173011544447143017260 0ustar dominikdominik.TH "PODOFOMERGE" "1" "2010-12-09" "PoDoFo" "podofomerge" .PP .SH NAME podofomerge \- merge several PDF files .PP .SH SYNOPSIS \fBpodofomerge\fR [inputfile1] [inputfile2] [outputfile] .PP .SH DESCRIPTION .B podofomerge is one of the command line tools from the PoDoFo library that provide several useful operations to work with PDF files\. It can merge several PDF files\. .PP .SH SEE ALSO .BR podofobox (1), .BR podofocolor (1), .BR podofocountpages (1), .BR podofocrop (1), .BR podofoencrypt (1), .BR podofogc (1), .BR podofoimg2pdf (1), .BR podofoimgextract (1), .BR podofoimpose (1), .BR podofoincrementalupdates (1), .BR podofopages (1), .BR podofopdfinfo (1), .BR podofotxt2pdf (1), .BR podofotxtextract (1), .BR podofouncompress (1), .BR podofoxmp (1) .PP .SH AUTHORS .PP PoDoFo is written by Dominik Seichter and others\. .PP This manual page was written by Oleksandr Moskalenko for the Debian Project (but may be used by others)\. podofo-0.9.5/debian/man/podofobox.10000664000175000017500000000320311544447143016746 0ustar dominikdominik.TH "PODOFOCOLOR" "1" "2011-01-06" "PoDoFo" "podofocolor" .PP .SH NAME podofocolor \- modify colors in a PDF file. .PP .SH SYNOPSIS \fBpodofocolor\fR [converter] [inputfile] [outpufile] .PP .SH DESCRIPTION .B podofocolor is one of the command line tools from the PoDoFo library that provide several useful operations to work with colors in PDF files\. It can parse and/or modify all colors or colorspaces in a PDF file\. The modifications can be defined via C++ or a Lua script\. Custom conversions like \fconvert all colors to grayscale\f are included. Please note that only colors of vector objects on pages and in XObjects are affected\. This tool does not transform colos in images at the moment\. .PP .SH CONVERTERS [converter] can be any of .RS dummy - Convert all colors to red\. Just a dummy and test implementation which serves as an example for developers\. grayscale - Convert all colors of vector objects in a PDF to grayscale\. lua - Convert all colors based on a Lua description\. A lua script has to be passed as an additional parameter. .RE .PP .SH "SEE ALSO" .BR podofocolor (1), .BR podofocountpages (1), .BR podofocrop (1), .BR podofoencrypt (1), .BR podofogc (1), .BR podofoimg2pdf (1), .BR podofoimgextract (1), .BR podofoimpose (1), .BR podofomerge (1), .BR podofoincrementalupdates (1), .BR podofopages (1), .BR podofopdfinfo (1), .BR podofotxt2pdf (1), .BR podofotxtextract (1), .BR podofouncompress (1), .BR podofoxmp (1) .PP .SH AUTHOR .PP PoDoFo is written by Dominik Seichter and others\. .PP This manual page was written by Dominik Seichter for the PoDoFo Project (but may be used by others)\. podofo-0.9.5/debian/man/podofocolor.10000664000175000017500000000323211544447143017276 0ustar dominikdominik.TH "PODOFOCOLOR" "1" "2011-01-06" "PoDoFo" "podofocolor" .PP .SH NAME podofocolor \- modify colors in a PDF file. .PP .SH SYNOPSIS \fBpodofocolor\fR [converter] [inputfile] [outpufile] .PP .SH DESCRIPTION .B podofocolor is one of the command line tools from the PoDoFo library that provide several useful operations to work with colors in PDF files\. It can parse and/or modify all colors or colorspaces in a PDF file\. The modifications can be defined via C++ or a Lua script\. Custom conversions like \fconvert all colors to grayscale\f are included. Please note that only colors of vector objects on pages and in XObjects are affected\. This tool does not transform colos in images at the moment\. .PP .SH CONVERTERS [converter] can be any of .RS dummy - Convert all colors to red\. Just a dummy and test implementation which serves as an example for developers\. .RE .RS grayscale - Convert all colors of vector objects in a PDF to grayscale\. .RE .RS lua [script] - Convert all colors based on a Lua description\. A lua script has to be passed as an additional parameter. .RE .PP .SH "SEE ALSO" .BR podofobox (1), .BR podofocountpages (1), .BR podofocrop (1), .BR podofoencrypt (1), .BR podofogc (1), .BR podofoimg2pdf (1), .BR podofoimgextract (1), .BR podofoimpose (1), .BR podofomerge (1), .BR podofoincrementalupdates (1), .BR podofopages (1), .BR podofopdfinfo (1), .BR podofotxt2pdf (1), .BR podofotxtextract (1), .BR podofouncompress (1), .BR podofoxmp (1) .PP .SH AUTHOR .PP PoDoFo is written by Dominik Seichter and others\. .PP This manual page was written by Dominik Seichter for the PoDoFo Project (but may be used by others)\. podofo-0.9.5/debian/man/podofopdfinfo.10000664000175000017500000000260411544447143017607 0ustar dominikdominik.TH "PODOFOPDFINFO" "1" "2010-12-09" "PoDoFo" "podofopdfinfo" .PP .SH NAME podofopdfinfo \- provide information about a PDF file .PP .SH SYNOPSIS \fBpodofopdfinfo\fR [DCPON] [inputfile] .PP .SH DESCRIPTION .B podofopdfinfo is one of the command line tools from the PoDoFo library that provide several useful operations to work with PDF files\. It can provide a number of facts about a PDF document according to the formatting instructions. If the instructions are not provided, complete information is shown\. .PP .SH "OPTIONS" .PP \fBD\fR .RS .PP display Document Info\. .RE .PP \fBC\fR .RS .PP display Classic Metadata\. .RE .PP \fBP\fR .RS .PP display Page Info\. .RE .PP \fBO\fR .RS .PP display Outlines\. .RE .PP \fBN\fR .RS .PP display Names\. .RE .PP \fB[inputfile]\fR .RS .PP Input PDF file\. .RE .PP .SH SEE ALSO .BR podofobox (1), .BR podofocolor (1), .BR podofocountpages (1), .BR podofocrop (1), .BR podofoencrypt (1), .BR podofogc (1), .BR podofoimg2pdf (1), .BR podofoimgextract (1), .BR podofoimpose (1), .BR podofoincrementalupdates (1), .BR podofomerge (1), .BR podofopages (1), .BR podofotxt2pdf (1), .BR podofotxtextract (1), .BR podofouncompress (1), .BR podofoxmp (1) .PP .SH AUTHORS .PP PoDoFo is written by Dominik Seichter and others\. .PP This manual page was written by Oleksandr Moskalenko for the Debian Project (but may be used by others)\. podofo-0.9.5/debian/man/podofoimgextract.10000664000175000017500000000203411544447143020326 0ustar dominikdominik.TH "PODOFOIMGEXTRACT" "1" "2010-12-09" "PoDoFo" "podofoimgextract" .PP .SH NAME podofoimgextract \- Extract all images from a PDF file .PP .SH SYNOPSIS \fBpodofoimgextract\fR [inputfile] [outputdirectory] .PP .SH DESCRIPTION .B podofoimgextract is one of the command line tools from the PoDoFo library that provide several useful operations to work with PDF files\. Itw can extract all images from a PDF file into the specified output directory\. .PP .SH SEE ALSO .BR podofobox (1), .BR podofocolor (1), .BR podofocountpages (1), .BR podofocrop (1), .BR podofoencrypt (1), .BR podofogc (1), .BR podofoimg2pdf (1), .BR podofoincrementalupdates (1), .BR podofoimpose (1), .BR podofomerge (1), .BR podofopages (1), .BR podofopdfinfo (1), .BR podofotxt2pdf (1), .BR podofotxtextract (1), .BR podofouncompress (1), .BR podofoxmp (1) .PP .SH AUTHORS .PP PoDoFo is written by Dominik Seichter and others\. .PP This manual page was written by Oleksandr Moskalenko for the Debian Project (but may be used by others)\. podofo-0.9.5/Doxyfile0000664000175000017500000020540613037215266014405 0ustar dominikdominik# Doxyfile 1.7.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = PoDoFo # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = 0.9.5 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = doc # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this # tag. The format is ext=language, where ext is a file extension, and language # is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, # C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. EXTENSION_MAPPING = # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen to replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penality. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will rougly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = YES # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = YES # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = NO # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. The create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = src/ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = *.cpp \ *.h # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = test/ \ ./ # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = YES # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = Pdf #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the stylesheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list. USE_INLINE_TREES = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = NO # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client # using Javascript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows # full text search. The disadvances is that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will write a font called FreeSans.ttf to the output # directory and reference it in all dot files that doxygen generates. This # font does not include all possible unicode characters however, so when you need # these (or just want a differently looking font) you can specify the font name # using DOT_FONTNAME. You need need to make sure dot is able to find the font, # which can be done by putting it in a standard location or by setting the # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. DOT_FONTNAME = FreeSans.ttf # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the output directory to look for the # FreeSans.ttf font (which doxygen will put there itself). If you specify a # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = YES # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 1000 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES podofo-0.9.5/test/0000775000175000017500000000000013044451156013645 5ustar dominikdominikpodofo-0.9.5/test/SignTest/0000775000175000017500000000000013044451151015400 5ustar dominikdominikpodofo-0.9.5/test/SignTest/SignTest.cpp0000664000175000017500000001002713013650710017642 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2011 by Dominik Seichter * * domseichter@web.de * * by Petr Pytelka * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "../../src/podofo.h" #include "../PdfTest.h" #include #include #include using namespace PoDoFo; #define CONVERSION_CONSTANT 0.002834645669291339 void CreateSimpleForm( PdfPage* pPage, PdfStreamedDocument* pDoc, const PdfData &signatureData ) { PdfPainter painter; PdfFont* pFont = pDoc->CreateFont( "Courier" ); painter.SetPage( pPage ); painter.SetFont( pFont ); painter.DrawText( 10000 * CONVERSION_CONSTANT, 280000 * CONVERSION_CONSTANT, "PoDoFo Sign Test" ); painter.FinishPage(); PdfSignatureField signField( pPage, PdfRect( 70000 * CONVERSION_CONSTANT, 10000 * CONVERSION_CONSTANT, 50000 * CONVERSION_CONSTANT, 50000 * CONVERSION_CONSTANT ), pDoc ); signField.SetFieldName("SignatureFieldName"); signField.SetSignature(signatureData); signField.SetSignatureReason("I agree"); } int main( int argc, char* argv[] ) { PdfPage* pPage; if( argc != 2 ) { printf("Usage: SignTest [output_filename]\n"); printf(" - Create a PDF ready to be signed\n"); return 0; } try { PdfSignOutputDevice signer(argv[1]); // Reserve space for signature signer.SetSignatureSize(1024); PdfStreamedDocument writer( &signer, PoDoFo::ePdfVersion_1_5 ); // Disable default appearance writer.GetAcroForm(ePdfCreateObject, PdfAcroForm::ePdfAcroFormDefaultAppearance_None); pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); TEST_SAFE_OP( CreateSimpleForm( pPage, &writer, *signer.GetSignatureBeacon() ) ); TEST_SAFE_OP( writer.Close() ); // Adjust ByteRange for signature if(signer.HasSignaturePosition()) { signer.AdjustByteRange(); // read data for signature and count it signer.Seek(0); // generate digest and count signature // use NSS, MS Crypto API or OpenSSL // to generate signature in DER format char buff[65536]; size_t len; while( (len = signer.ReadForSignature(buff, 65536))>0 ) { } // Paste signature to the file PdfData sigData("my-real-signature"); signer.SetSignature(sigData); } signer.Flush(); } catch( PdfError & e ) { std::cerr << "Error: An error " << e.GetError() << " ocurred." << std::endl; e.PrintErrorMsg(); return e.GetError(); } return 0; } podofo-0.9.5/test/SignTest/CMakeLists.txt0000664000175000017500000000035111520343546020144 0ustar dominikdominikADD_EXECUTABLE(SignTest SignTest.cpp) TARGET_LINK_LIBRARIES(SignTest ${PODOFO_LIB} ${PODOFO_LIB_DEPENDS}) SET_TARGET_PROPERTIES(SignTest PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(SignTest ${PODOFO_DEPEND_TARGET}) podofo-0.9.5/test/FormTest/0000775000175000017500000000000013044451151015403 5ustar dominikdominikpodofo-0.9.5/test/FormTest/CMakeLists.txt0000664000175000017500000000035110631070103020133 0ustar dominikdominikADD_EXECUTABLE(FormTest FormTest.cpp) TARGET_LINK_LIBRARIES(FormTest ${PODOFO_LIB} ${PODOFO_LIB_DEPENDS}) SET_TARGET_PROPERTIES(FormTest PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(FormTest ${PODOFO_DEPEND_TARGET}) podofo-0.9.5/test/FormTest/FormTest.cpp0000664000175000017500000003333513013650710017657 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "../../src/podofo.h" #include "../PdfTest.h" #include #include using namespace PoDoFo; #define CONVERSION_CONSTANT 0.002834645669291339 void CreateComplexForm( PdfPage* pPage, PdfStreamedDocument* pDoc ) { PdfRect rect = pPage->GetPageSize(); PdfPainter painter; PdfFont* pFont = pDoc->CreateFont( "Courier" ); painter.SetPage( pPage ); painter.SetFont( pFont ); const char* pszTitle = "PoDoFo Sample Feedback Form"; pFont->SetFontSize( 18.0 ); double x = (rect.GetWidth() - pFont->GetFontMetrics()->StringWidth( pszTitle )) / 2.0; double y = rect.GetHeight() - (20000.0 * CONVERSION_CONSTANT); painter.DrawText( x, y, pszTitle ); pFont->SetFontSize( 10.0 ); y -= 10000.0 * CONVERSION_CONSTANT; x = 10000.0 * CONVERSION_CONSTANT; double h = 10000.0 * CONVERSION_CONSTANT; // Name y -= 10000.0 * CONVERSION_CONSTANT; painter.DrawText( x, y, "Your Name:" ); PdfTextField textName( pPage, PdfRect( 80000.0 * CONVERSION_CONSTANT, y - 2500.0 * CONVERSION_CONSTANT, 80000.0 * CONVERSION_CONSTANT, h ), pDoc ); textName.SetFieldName("field_name"); textName.SetBorderColor( 1.0 ); // E-Mail y -= 10000.0 * CONVERSION_CONSTANT; painter.DrawText( x, y, "E-Mail Address:" ); PdfTextField textMail( pPage, PdfRect( 80000.0 * CONVERSION_CONSTANT, y - 2500.0 * CONVERSION_CONSTANT, 80000.0 * CONVERSION_CONSTANT, h ), pDoc ); textMail.SetFieldName("field_mail"); textMail.SetBorderColor( 1.0 ); // Interest y -= 10000.0 * CONVERSION_CONSTANT; painter.DrawText( x, y, "Job:" ); PdfComboBox comboJob( pPage, PdfRect( 80000.0 * CONVERSION_CONSTANT, y - 2500.0 * CONVERSION_CONSTANT, 80000.0 * CONVERSION_CONSTANT, h ), pDoc ); comboJob.SetFieldName("field_combo"); comboJob.SetBorderColor( 1.0 ); comboJob.InsertItem( "Software Engineer" ); comboJob.InsertItem( "Student" ); comboJob.InsertItem( "Publisher" ); comboJob.InsertItem( "Other" ); // Open Source y -= 11000.0 * CONVERSION_CONSTANT; painter.DrawText( x, y, "I wan't to use PoDoFo in an Open Source application" ); PdfCheckBox checkOpenSource( pPage, PdfRect( 120000.0 * CONVERSION_CONSTANT, y - 2500.0 * CONVERSION_CONSTANT, h, h ), pDoc ); checkOpenSource.SetFieldName("field_check_oss"); // Commercial y -= 11000.0 * CONVERSION_CONSTANT; painter.DrawText( x, y, "I wan't to use PoDoFo in a commercial application" ); PdfCheckBox checkCom( pPage, PdfRect( 120000.0 * CONVERSION_CONSTANT, y - 2500.0 * CONVERSION_CONSTANT, h, h ), pDoc ); checkCom.SetFieldName("field_check_com"); y -= 10000.0 * CONVERSION_CONSTANT; painter.DrawText( x, y, "Some comments you want to send to the PoDoFo developers:" ); PdfTextField textComment( pPage, PdfRect( 20000.0 * CONVERSION_CONSTANT, y - 120000.0 * CONVERSION_CONSTANT, 160000.0 * CONVERSION_CONSTANT, 100000.0 * CONVERSION_CONSTANT ), pDoc ); textComment.SetFieldName("field_comment"); textComment.SetMultiLine( true ); textComment.SetRichText( true ); textComment.SetText( "

Here is some bold italic text

This text uses default text state parameters but changes the font size to 16.

"); PdfPushButton buttonSend( pPage, PdfRect( 10000 * CONVERSION_CONSTANT, 10000 * CONVERSION_CONSTANT, 25000 * CONVERSION_CONSTANT, 25000 * CONVERSION_CONSTANT ), pDoc ); buttonSend.SetFieldName("field_send"); buttonSend.SetCaption("Send"); buttonSend.SetBackgroundColor( 0.5 ); PdfPushButton buttonClear( pPage, PdfRect( 40000 * CONVERSION_CONSTANT, 10000 * CONVERSION_CONSTANT, 25000 * CONVERSION_CONSTANT, 25000 * CONVERSION_CONSTANT ), pDoc ); buttonClear.SetFieldName("field_clear"); buttonClear.SetCaption("Clear"); buttonClear.SetBackgroundColor( 0.5 ); PdfAction actionClear( ePdfAction_JavaScript, pDoc ); actionClear.SetScript( PdfString("this.getField(\"field_name\").value = \"\";" \ "this.getField(\"field_mail\").value = \"\";" \ "this.getField(\"field_combo\").value = \"\";" "this.getField(\"field_check_oss.\").checkThisBox( 0, false );" \ "this.getField(\"field_check_com.\").checkThisBox( 0, false );" \ "this.getField(\"field_comment\").value = \"\";" ) ); buttonClear.SetMouseDownAction( actionClear ); PdfAction actionSubmit( ePdfAction_SubmitForm, pDoc ); buttonSend.SetMouseDownAction( actionSubmit ); painter.FinishPage(); } void CreateSimpleForm( PdfPage* pPage, PdfStreamedDocument* pDoc ) { PdfPainter painter; PdfFont* pFont = pDoc->CreateFont( "Courier" ); painter.SetPage( pPage ); painter.SetFont( pFont ); painter.DrawText( 10000 * CONVERSION_CONSTANT, 280000 * CONVERSION_CONSTANT, "PoDoFo Interactive Form Fields Test" ); painter.FinishPage(); PdfPushButton button( pPage, PdfRect( 10000 * CONVERSION_CONSTANT, 10000 * CONVERSION_CONSTANT, 50000 * CONVERSION_CONSTANT, 50000 * CONVERSION_CONSTANT ), pDoc ); button.SetFieldName("ButtonFieldName"); button.SetAlternateName("ButtonAlternateName"); button.SetMappingName("ButtonMappingName"); button.SetCaption("Hallo Welt"); PdfAction action( ePdfAction_JavaScript, pDoc ); action.SetScript( PdfString("var str = this.getField(\"TextFieldName\").value;" \ "var j = 4*5;" \ "app.alert(\"Hello World! 4 * 5 = \" + j + \" Text Field: \" + str );") ); button.SetMouseDownAction( action ); PdfTextField text( pPage, PdfRect( 70000 * CONVERSION_CONSTANT, 10000 * CONVERSION_CONSTANT, 50000 * CONVERSION_CONSTANT, 50000 * CONVERSION_CONSTANT ), pDoc ); text.SetFieldName("TextFieldName"); text.SetMultiLine( true ); text.SetMultiLine( false ); text.SetFileField( true ); printf("Text IsMultiLine: %i\n", text.IsMultiLine() ); PdfComboBox combo( pPage, PdfRect( 10000 * CONVERSION_CONSTANT, 250000 * CONVERSION_CONSTANT, 50000 * CONVERSION_CONSTANT, 10000 * CONVERSION_CONSTANT ), pDoc ); combo.SetFieldName("ComboFieldName"); combo.InsertItem( "Value1" ); combo.InsertItem( "Value2" ); combo.InsertItem( "Value3" ); combo.InsertItem( "XXXX", "Displayed Text" ); combo.SetEditable( true ); combo.SetSelectedItem( 1 ); printf("IsComboBox: %i\n", combo.IsComboBox() ); printf("Count : %i\n", static_cast(combo.GetItemCount()) ); printf("Selected : %i\n", combo.GetSelectedItem() ); PdfListBox listBox( pPage, PdfRect( 70000 * CONVERSION_CONSTANT, 200000 * CONVERSION_CONSTANT, 50000 * CONVERSION_CONSTANT, 50000 * CONVERSION_CONSTANT ), pDoc ); listBox.SetFieldName("ListBoxFieldName"); listBox.InsertItem( "Value1", "Display 1" ); listBox.InsertItem( "Value2", "Display 2" ); listBox.InsertItem( "Value3", "Display 3" ); //listBox.InsertItem( "XXXX", "Displayed Text" ); listBox.SetMultiSelect( true ); listBox.SetSelectedItem( 2 ); } void FillTextField( PdfTextField & rField ) { const char* pszCur = rField.GetText().GetString(); std::cout << " Current value:" << (pszCur ? pszCur : "") << std::endl; std::string value; std::cout << " Enter new value (if empty value is unchanged):" << std::endl; #if defined(_MSC_VER) && _MSC_VER <= 1200 // Visual Studio 6 { char buff[10240]; if (gets(buff)) value = buff; } #else getline( std::cin, value ); #endif if( value.length() ) { rField.SetText( value ); } } void FillListField( PdfListField & rField ) { const char* pszCur = ( rField.GetSelectedItem() == -1 ? NULL : rField.GetItemDisplayText( rField.GetSelectedItem() ).GetString() ); std::cout << " Current value:" << (pszCur ? pszCur : "") << std::endl; std::cout << " Values:" << std::endl; for( int i=0;i(rField.GetItemCount());i++ ) { pszCur = rField.GetItemDisplayText( i ).GetString(); std::cout << " " << i << " " << (pszCur ? pszCur : "") << std::endl; } int nValue; std::cout << " Enter index of new value:" << std::endl; std::cin >> nValue; if( nValue >= 0 && nValue < static_cast(rField.GetItemCount()) ) rField.SetSelectedItem( nValue ); } void FillForm( const char* pszFilename, const char* pszOutput ) { PdfMemDocument doc( pszFilename ); PdfPage* pPage; int nPageCount = doc.GetPageCount(); int nFieldCount; for( int i=0;iGetNumFields(); std::cout << "Page " << i + 1 << " contains " << nFieldCount << " fields." << std::endl; for( int n=0;nGetField( n ); EPdfField eType = field.GetType(); std::cout << " Field: " << field.GetFieldName().GetString() << std::endl; std::cout << " Type : "; switch( eType ) { case ePdfField_PushButton: std::cout << "PushButton" << std::endl; break; case ePdfField_CheckBox: std::cout << "CheckBox" << std::endl; break; case ePdfField_RadioButton: std::cout << "RadioButton" << std::endl; break; case ePdfField_TextField: { std::cout << "TextField" << std::endl; PdfTextField text( field ); FillTextField( text ); break; } case ePdfField_ComboBox: { std::cout << "ComboBox" << std::endl; PdfListField lst( field ); FillListField( lst ); break; } case ePdfField_ListBox: { std::cout << "ListBox" << std::endl; PdfListField lst( field ); FillListField( lst ); break; } case ePdfField_Signature: std::cout << "Signature" << std::endl; break; case ePdfField_Unknown: default: std::cout << "Unknown" << std::endl; break; } std::cout << std::endl; } } doc.Write( pszOutput ); } int main( int argc, char* argv[] ) { PdfPage* pPage; if( argc != 2 && argc != 3 ) { printf("Usage: FormTest [output_filename]\n"); printf(" - Create a new example PDF form\n"); printf(" Formtest [input_filename] [output_filename]\n"); printf(" - Fill out an existing form and save it to a PDF file\n"); return 0; } try { if( argc == 3 ) { TEST_SAFE_OP( FillForm( argv[1], argv[2] ) ); } else { PdfStreamedDocument writer( argv[1] ); pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); TEST_SAFE_OP( CreateComplexForm( pPage, &writer ) ); pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); TEST_SAFE_OP( CreateSimpleForm( pPage, &writer ) ); TEST_SAFE_OP( writer.Close() ); } } catch( PdfError & e ) { std::cerr << "Error: An error " << e.GetError() << " ocurred." << std::endl; e.PrintErrorMsg(); return e.GetError(); } return 0; } podofo-0.9.5/test/CMakeLists.txt0000664000175000017500000000025112706437606016413 0ustar dominikdominikSUBDIRS( ContentParser CreationTest FilterTest FormTest LargeTest ObjectParserTest ParserTest SignatureTest TokenizerTest VariantTest WatermarkTest unit ) podofo-0.9.5/test/LargeTest/0000775000175000017500000000000013044451150015531 5ustar dominikdominikpodofo-0.9.5/test/LargeTest/CMakeLists.txt0000664000175000017500000000055111057763005020301 0ustar dominikdominikIF(WANT_FONTCONFIG) # We don't build LargeTest on win32 since it depends on # fontconfig to operate ADD_EXECUTABLE(LargeTest LargeTest.cpp) TARGET_LINK_LIBRARIES(LargeTest ${PODOFO_LIB} ${PODOFO_LIB_DEPENDS}) SET_TARGET_PROPERTIES(LargeTest PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(LargeTest ${PODOFO_DEPEND_TARGET}) ENDIF(WANT_FONTCONFIG) podofo-0.9.5/test/LargeTest/LargeTest.cpp0000664000175000017500000001465313013650710020137 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include using namespace PoDoFo; #define MIN_PAGES 100 bool writeImmediately = true; void AddPage( PdfDocument* pDoc, const char* pszFontName, const char* pszImagePath ) { PdfPainter painter; PdfPage* pPage; PdfFont* pFont; PdfFont* pArial; PdfImage* pImage; PdfRect rect; try { pFont = pDoc->CreateFont( pszFontName ); } catch ( PdfError & e ) { e.PrintErrorMsg(); return; } pPage = pDoc->CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); pArial = pDoc->CreateFont( "Arial" ); pImage = new PdfImage( pDoc ); rect = pPage->GetMediaBox(); const char* pszText = "The red brown fox jumps over the lazy dog!"; double dX = rect.GetLeft() + 20.0; double dY = rect.GetBottom() + rect.GetHeight() - 20.0; double dW, dH; pFont->SetFontSize( 16.0 ); pArial->SetFontSize( 24.0 ); painter.SetPage( pPage ); painter.SetFont( pFont ); dW = pFont->GetFontMetrics()->StringWidth( pszText ); dH = -pFont->GetFontMetrics()->GetDescent(); // GetDescent is usually negative! pFont->SetFontSize( 24.0 ); dH += pFont->GetFontMetrics()->GetLineSpacing() * 2.0; painter.Rectangle( dX, dY, dW, dH ); painter.Stroke(); dY -= pFont->GetFontMetrics()->GetLineSpacing(); painter.DrawText( dX, dY, "Hello World!" ); dY -= pFont->GetFontMetrics()->GetLineSpacing(); pFont->SetFontSize( 16.0 ); painter.DrawText( dX, dY, pszText ); painter.SetFont( pArial ); dY -= pArial->GetFontMetrics()->GetLineSpacing(); painter.DrawText( dX, dY, "The font used in this example is:" ); dY -= pArial->GetFontMetrics()->GetLineSpacing(); painter.DrawText( dX, dY, pszFontName ); dY -= pArial->GetFontMetrics()->GetLineSpacing(); #if defined PODOFO_HAVE_JPEG_LIB || defined PODOFO_HAVE_TIFF_LIB try { pImage->LoadFromFile( pszImagePath ); } catch( PdfError & e ) { e.PrintErrorMsg(); } dY -= (pImage->GetHeight() * 0.5); dX = ((rect.GetWidth() - (pImage->GetWidth()*0.5))/2.0); painter.DrawImage( dX, dY, pImage, 0.5, 0.5 ); delete pImage; // delete image right after drawing #endif painter.FinishPage(); } void CreateLargePdf( const char* pszFilename, const char* pszImagePath ) { PdfDocument* pDoc = NULL; FcObjectSet* pObjectSet; FcFontSet* pFontSet; FcPattern* pPattern; if( !FcInit() ) { fprintf( stderr, "Cannot load fontconfig!\n"); return; } pPattern = FcPatternCreate(); pObjectSet = FcObjectSetBuild( FC_FAMILY, FC_STYLE, NULL ); pFontSet = FcFontList( 0, pPattern, pObjectSet ); FcObjectSetDestroy( pObjectSet ); FcPatternDestroy( pPattern ); if( writeImmediately ) pDoc = new PdfStreamedDocument( pszFilename ); else pDoc = new PdfMemDocument(); if( pFontSet ) { for( int i=0; i< (pFontSet->nfont > MIN_PAGES ? MIN_PAGES : pFontSet->nfont );i++ ) { FcValue v; //FcPatternPrint( pFontSet->fonts[i] ); FcPatternGet( pFontSet->fonts[i], FC_FAMILY, 0, &v ); //font = FcNameUnparse( pFontSet->fonts[i] ); printf(" -> Drawing with font: %s\n", reinterpret_cast(v.u.s) ); AddPage( pDoc, reinterpret_cast(v.u.s), pszImagePath ); } FcFontSetDestroy( pFontSet ); } if( writeImmediately ) static_cast(pDoc)->Close(); else static_cast(pDoc)->Write( pszFilename ); delete pDoc; } void usage() { printf("Usage: LargetTest [-m] output_filename image_file\n" " output_filename: filename to write produced pdf to\n" " image_file: An image to embed in the PDF file\n" "Options:\n" " -m Build entire document in memory before writing\n" "\n" "Note that output should be the same with and without the -m option.\n"); } int main( int argc, char* argv[] ) { if( argc < 3 || argc > 4 ) { usage(); return 1; } else if ( argc == 4) { // Handle options // Is this argument an option? if (argv[1][0] != '-') { usage(); return 1; } // Is it a recognised option? if (argv[1][1] == 'm') { // User wants us to build the whole doc in RAM before writing it out. writeImmediately = false; ++argv; } else { printf("Unrecognised argument: %s", argv[1]); usage(); return 1; } } try { CreateLargePdf( argv[1], argv[2] ); printf("\nWrote the PDF file %s successfully\n", argv[1] ); } catch( PdfError & e ) { e.PrintErrorMsg(); return e.GetError(); } return 0; } podofo-0.9.5/test/SignatureTest/0000775000175000017500000000000013044451151016441 5ustar dominikdominikpodofo-0.9.5/test/SignatureTest/SignTest.cpp0000664000175000017500000001346213013650710020711 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2011 by Dominik Seichter * * domseichter@web.de * * by Petr Pytelka * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "../../src/podofo.h" #include "../PdfTest.h" #include "SignatureGenerator.h" #include "SimpleSignatureGenerator.h" //#include "NSSSignatureGenerator.h" //#include //#include #include #include #include using namespace PoDoFo; #define CONVERSION_CONSTANT 0.002834645669291339 /* static CERTCertificate* read_cert() { CERTCertificate* pCert = NULL; SECStatus status; CERTCertDBHandle* pDbHandle; const char* pszDbName = "/home/dominik/Desktop/Documents"; / * status = CERT_InitCertDB( pDbHandle ); printf("Init database: %i\n", status ); status = CERT_OpenCertDBFilename( pDbHandle, strdup(pszDbName), 0 ); printf("Open database: %i\n", status ); */ /* pCert = CERT_FindCertByName ( pDbHandle, "domseichter@web.de" ); * / return pCert; } */ void CreateSimpleForm( PdfPage* pPage, PdfStreamedDocument* pDoc, const PdfData &signatureData ) { PdfPainter painter; PdfFont* pFont = pDoc->CreateFont( "Courier" ); painter.SetPage( pPage ); painter.SetFont( pFont ); painter.DrawText( 10000 * CONVERSION_CONSTANT, 280000 * CONVERSION_CONSTANT, "PoDoFo Sign Test" ); painter.FinishPage(); PdfSignatureField signField( pPage, PdfRect( 70000 * CONVERSION_CONSTANT, 10000 * CONVERSION_CONSTANT, 50000 * CONVERSION_CONSTANT, 50000 * CONVERSION_CONSTANT ), pDoc ); signField.SetFieldName("SignatureFieldName"); signField.SetSignature(signatureData); signField.SetSignatureReason("I agree"); // Set time of signing signField.SetSignatureDate( PdfDate() ); } int main( int argc, char* argv[] ) { PdfPage* pPage; if( argc != 2 ) { printf("Usage: SignTest [output_filename]\n"); printf(" - Create a PDF ready to be signed\n"); return 0; } try { PdfSignOutputDevice signer(argv[1]); // Reserve space for signature signer.SetSignatureSize(1024); PdfStreamedDocument writer( &signer, PoDoFo::ePdfVersion_1_5 ); // Disable default appearance writer.GetAcroForm(ePdfCreateObject, ePdfAcroFormDefaultAppearance_None); pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); TEST_SAFE_OP( CreateSimpleForm( pPage, &writer, *signer.GetSignatureBeacon() ) ); TEST_SAFE_OP( writer.Close() ); // Check if position of signature was found if(signer.HasSignaturePosition()) { // Adjust ByteRange for signature signer.AdjustByteRange(); // Read data for signature and count it // We have to seek at the beginning of the file signer.Seek(0); // Generate digest and count signature // use NSS, MS Crypto API or OpenSSL // to generate signature in DER format // This is example of generation process // with dummy generator. Check example for // NSS generator /* SimpleSignatureGenerator sg; // Read data to be signed and send them to the // signature generator char buff[65536]; size_t len; while( (len = signer.ReadForSignature(buff, 65536))>0 ) { sg.appendData(buff, len); } sg.finishData(); // Paste signature to the file const PdfData *pSignature = sg.getSignature(); */ /* CERTCertificate* pCert = read_cert(); NSSSignatureGenerator ng(pCert); char buff[65536]; size_t len; while( (len = signer.ReadForSignature(buff, 65536))>0 ) { ng.appendData(buff, len); } ng.finishData(); // Paste signature to the file const PdfData *pSignature = ng.getSignature(); CERT_DestroyCertificate(pCert); if(pSignature!=NULL) { signer.SetSignature(*pSignature); } */ } signer.Flush(); } catch( PdfError & e ) { std::cerr << "Error: An error " << e.GetError() << " ocurred." << std::endl; e.PrintErrorMsg(); return e.GetError(); } return 0; } podofo-0.9.5/test/SignatureTest/NSSSignatureGenerator.h0000664000175000017500000000236411536423656023030 0ustar dominikdominik/** NSS signature generator * * Mozilla has two APIs for generating signatures (older SEC_PKCS7) * and newer SMIME (CMS). We are using newer API. * * You have to have certificate (CERTCertificate * )which will be * used for signing. */ #ifndef _NSS_SIGNATURE_GENERATOR_H_ #define _NSS_SIGNATURE_GENERATOR_H_ #include #include #include #include #include "SignatureGenerator.h" namespace PoDoFo { class PdfData; }; class NSSSignatureGenerator : public SignatureGenerator { private: PoDoFo::PdfData *pSignature; CERTCertificate *pCert; NSSCMSMessage *cmsg; NSSCMSEncoderContext *enc; std::string signature; static void sm_write_stream(void *arg, const char *buf, unsigned long len); protected: // get digest algoritm for the signing algoritm static SECOidTag getDigestAlgor(CERTCertificate *pCert); // create message with signature static NSSCMSMessage *createSign(CERTCertificate *cert); public: NSSSignatureGenerator(CERTCertificate *pCert); virtual ~NSSSignatureGenerator(); virtual bool init(); virtual bool appendData(const char *pData, unsigned int dataSize); virtual bool finishData(); virtual const PoDoFo::PdfData *getSignature(); }; #endif // _NSS_SIGNATURE_GENERATOR_H_ podofo-0.9.5/test/SignatureTest/CMakeLists.txt0000664000175000017500000000101111536424150021175 0ustar dominikdominikSET(sign_srcs SignTest.cpp ) #IF(FALSE) # SET(sign_extra_libs -L/usr/lib -lssl3 -lsmime3 -lnss3 -lnssutil3) # SET(sign_srcs ${sign_srcs} NSSSignatureGenerator.cpp) # ADD_DEFINITIONS(-I/usr/include/nss -I/usr/include/nspr ) #ENDIF(FALSE) ADD_EXECUTABLE(SignatureTest ${sign_srcs}) TARGET_LINK_LIBRARIES(SignatureTest ${PODOFO_LIB} ${PODOFO_LIB_DEPENDS} ${sign_extra_libs} ) SET_TARGET_PROPERTIES(SignatureTest PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(SignatureTest ${PODOFO_DEPEND_TARGET}) podofo-0.9.5/test/SignatureTest/SimpleSignatureGenerator.h0000664000175000017500000000130312347347566023614 0ustar dominikdominik #ifndef _SIMPLE_SIGNATURE_GENERATOR_H_ #define _SIMPLE_SIGNATURE_GENERATOR_H_ #include "SignatureGenerator.h" #include /** Simple signature generator */ class SimpleSignatureGenerator :public SignatureGenerator { PoDoFo::PdfData *pSignature; public: SimpleSignatureGenerator() { pSignature = NULL; } virtual ~SimpleSignatureGenerator() { delete pSignature; } virtual bool appendData(const char * /*pData*/, unsigned int /*dataSize*/) { return true; } virtual bool finishData() { pSignature = new PoDoFo::PdfData("My-Test-Signature"); return true; } virtual const PoDoFo::PdfData *getSignature() { return pSignature; } }; #endif // _SIMPLE_SIGNATURE_GENERATOR_H_ podofo-0.9.5/test/SignatureTest/SignatureGenerator.h0000664000175000017500000000057211536423656022443 0ustar dominikdominik #ifndef _SIGNATURE_GENERATOR_H_ #define _SIGNATURE_GENERATOR_H_ namespace PoDoFo { class PdfData; }; /** Abstract class for signature generator */ class SignatureGenerator { public: virtual bool appendData(const char* pData, unsigned int dataSize)=0; virtual bool finishData()=0; virtual const PoDoFo::PdfData* getSignature()=0; }; #endif // _SIGNATURE_GENERATOR_H_ podofo-0.9.5/test/SignatureTest/NSSSignatureGenerator.cpp0000664000175000017500000001306511536423656023363 0ustar dominikdominik/** NSS signature generator * * Mozilla has two APIs for generating signatures (older SEC_PKCS7) * and newer SMIME (CMS). We are using newer API. * * You have to have certificate (CERTCertificate * )which will be * used for signing. */ #include "NSSSignatureGenerator.h" #include void NSSSignatureGenerator::sm_write_stream(void *arg, const char *buf, unsigned long len) { NSSSignatureGenerator* pThis = static_cast(arg); pThis->signature.append(buf, len); } SECOidTag NSSSignatureGenerator::getDigestAlgor(CERTCertificate *pCert) { SECAlgorithmID *algID = &pCert->signature; if(algID==NULL) return SEC_OID_MD5; SECOidTag algOIDTag = SECOID_FindOIDTag(&algID->algorithm); switch(algOIDTag) { case SEC_OID_MD5: case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC: return SEC_OID_MD5; case SEC_OID_SHA1: case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE: case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC: case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4: case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4: case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC: case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: case SEC_OID_PKCS12_RSA_SIGNATURE_WITH_SHA1_DIGEST: case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4: case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4: case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC: case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC: case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: case SEC_OID_HMAC_SHA1: return SEC_OID_SHA1; case SEC_OID_SHA256: case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: case SEC_OID_HMAC_SHA256: return SEC_OID_SHA256; case SEC_OID_SHA384: case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: case SEC_OID_HMAC_SHA384: return SEC_OID_SHA384; case SEC_OID_SHA512: case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: case SEC_OID_HMAC_SHA512: return SEC_OID_SHA512; } PODOFO_ASSERT(0); return SEC_OID_MD5; } // create message with signature NSSCMSMessage* NSSSignatureGenerator::createSign(CERTCertificate *cert) { NSSCMSSignedData *sigd = NULL; NSSCMSContentInfo *cinfo = NULL; NSSCMSSignerInfo *signerinfo = NULL; SECOidTag hash=getDigestAlgor(cert); NSSCMSMessage *cmsg = NSS_CMSMessage_Create(NULL); // create a message on its own pool if (cmsg == NULL) return NULL; if ((sigd = NSS_CMSSignedData_Create(cmsg)) == NULL) { NSS_CMSMessage_Destroy(cmsg); return NULL; } cinfo = NSS_CMSMessage_GetContentInfo(cmsg); if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd) != SECSuccess) { NSS_CMSMessage_Destroy(cmsg); return NULL; } // if !detatched, the contentinfo will alloc a data item for us cinfo = NSS_CMSSignedData_GetContentInfo(sigd); if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_TRUE ) != SECSuccess) { NSS_CMSMessage_Destroy(cmsg); return NULL; } signerinfo = NSS_CMSSignerInfo_Create(cmsg, cert, hash); if (signerinfo == NULL) { NSS_CMSMessage_Destroy(cmsg); return NULL; } // we want the cert chain included for this one if (NSS_CMSSignerInfo_IncludeCerts(signerinfo, NSSCMSCM_CertChainWithRoot, certUsageEmailSigner) != SECSuccess) { NSS_CMSMessage_Destroy(cmsg); return NULL; } // SMIME RFC says signing time should always be added if (NSS_CMSSignerInfo_AddSigningTime(signerinfo, PR_Now()) != SECSuccess) { NSS_CMSMessage_Destroy(cmsg); return NULL; } if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) { NSS_CMSMessage_Destroy(cmsg); return NULL; } return cmsg; } NSSSignatureGenerator::NSSSignatureGenerator(CERTCertificate *pCert) :pCert(pCert) { pSignature = NULL; } NSSSignatureGenerator::~NSSSignatureGenerator() { delete pSignature; if(enc!=NULL) NSS_CMSEncoder_Cancel(enc); if(cmsg!=NULL) NSS_CMSMessage_Destroy(cmsg); } bool NSSSignatureGenerator::init() { cmsg = createSign(pCert); if(cmsg==NULL) return false; // Prepare encoder enc = NSS_CMSEncoder_Start(cmsg, sm_write_stream, this, // DER output callback NULL, NULL, // destination storage NULL, NULL, // password callback NULL, NULL, // decrypt key callback NULL, NULL ); // detached digests } bool NSSSignatureGenerator::appendData(const char *pData, unsigned int dataSize) { if(enc == NULL) return false; if (NSS_CMSEncoder_Update(enc, pData, dataSize) != SECSuccess) { NSS_CMSEncoder_Cancel(enc); enc = NULL; return false; } return true; } bool NSSSignatureGenerator::finishData() { if(enc == NULL) return false; if (NSS_CMSEncoder_Finish(enc) != SECSuccess) { enc = NULL; return false; } enc = NULL; return true; } const PoDoFo::PdfData* NSSSignatureGenerator::getSignature() { if(pSignature==NULL) { pSignature = new PoDoFo::PdfData(signature.c_str(), signature.size()); } return pSignature; } podofo-0.9.5/test/VariantTest/0000775000175000017500000000000013044451156016111 5ustar dominikdominikpodofo-0.9.5/test/VariantTest/VariantTest.cpp0000664000175000017500000002617211460071654021072 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "../PdfTest.h" #include #include #include #include using namespace PoDoFo; // // Test encoding of names. // pszString : internal representation, ie unencoded name // pszExpectedEncoded: the encoded string PoDoFo should produce // void TestName( const char* pszString, const char* pszExpectedEncoded ) { printf("Testing name: %s\n", pszString ); PdfName name( pszString ); printf(" -> Expected Value: %s\n", pszExpectedEncoded ); printf(" -> Got Value: %s\n", name.GetEscapedName().c_str() ); printf(" -> Unescaped Value: %s\n", name.GetName().c_str() ); if( strcmp( pszExpectedEncoded, name.GetEscapedName().c_str() ) != 0 ) { PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } // Ensure the encoded string compares equal to its unencoded // variant if( name != PdfName::FromEscaped(pszExpectedEncoded) ) { PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } } void TestEncodedName( const char* pszString, const char* pszExpected ) { PdfName name( PdfName::FromEscaped(pszString) ); printf("Testing encoded name: %s\n", pszString ); printf(" -> Expected Value: %s\n", pszExpected ); printf(" -> Got Value: %s\n", name.GetName().c_str() ); printf(" -> Escaped Value: %s\n", name.GetEscapedName().c_str() ); if ( strcmp( pszExpected, name.GetName().c_str() ) != 0 ) { PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } // Ensure the name compares equal with one constructed from the // expected unescaped form if ( ! (name == PdfName(pszExpected)) ) { PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } } void TestNameEquality( const char * pszName1, const char* pszName2 ) { PdfName name1( PdfName::FromEscaped(pszName1) ); PdfName name2( PdfName::FromEscaped(pszName2) ); printf("Testing equality of encoded names '%s' and '%s'\n", pszName1, pszName2); printf(" -> Name1 Decoded Value: %s\n", name1.GetName().c_str()); printf(" -> Name2 Decoded Value: %s\n", name2.GetName().c_str()); if (name1 != name2) { PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } } void Test( const char* pszString, EPdfDataType eDataType, const char* pszExpected = NULL ) { PdfVariant variant; std::string ret; if( !pszExpected ) pszExpected = pszString; printf("Testing with value: %s\n", pszString ); PdfTokenizer tokenizer( pszString, strlen( pszString ) ); tokenizer.GetNextVariant( variant, NULL ); printf(" -> Expected Datatype: %i\n", eDataType ); printf(" -> Got Datatype: %i\n", variant.GetDataType() ); if( variant.GetDataType() != eDataType ) { PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } variant.ToString( ret ); printf(" -> Convert To String: %s\n", ret.c_str() ); if( strcmp( pszExpected, ret.c_str() ) != 0 ) { PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } } int main() { PdfError eCode; printf("This test tests the PdfVariant class.\n"); printf("---\n"); std::auto_ptr pFilter = PdfFilterFactory::Create( ePdfFilter_ASCIIHexDecode ); // testing strings TEST_SAFE_OP( Test( "(Hallo Welt!)", ePdfDataType_String ) ); TEST_SAFE_OP( Test( "(Hallo \\(schöne\\) Welt!)", ePdfDataType_String ) ); TEST_SAFE_OP( Test( "(Balanced () brackets are (ok ()) in PDF Strings)", ePdfDataType_String, "(Balanced \\(\\) brackets are \\(ok \\(\\)\\) in PDF Strings)" ) ); TEST_SAFE_OP( Test( "()", ePdfDataType_String ) ); TEST_SAFE_OP( Test( "(Test: \\064)", ePdfDataType_String, "(Test: \064)" ) ); TEST_SAFE_OP( Test( "(Test: \\0645)", ePdfDataType_String, "(Test: 45)" ) ); TEST_SAFE_OP( Test( "(Test: \\478)", ePdfDataType_String, "(Test: '8)" ) ); printf("---\n"); // testing HEX Strings TEST_SAFE_OP( Test( "", ePdfDataType_HexString ) ); TEST_SAFE_OP( Test( "", ePdfDataType_HexString, "" ) ); TEST_SAFE_OP( Test( "<>", ePdfDataType_HexString ) ); printf("---\n"); // testing bool TEST_SAFE_OP( Test( "false", ePdfDataType_Bool ) ); TEST_SAFE_OP( Test( "true", ePdfDataType_Bool ) ); printf("---\n"); // testing null TEST_SAFE_OP( Test( "null", ePdfDataType_Null ) ); printf("---\n"); // testing numbers TEST_SAFE_OP( Test( "145", ePdfDataType_Number ) ); TEST_SAFE_OP( Test( "-12", ePdfDataType_Number ) ); TEST_SAFE_OP( Test( "3.140000", ePdfDataType_Real ) ); TEST_SAFE_OP( Test( "-2.970000", ePdfDataType_Real ) ); TEST_SAFE_OP( Test( "0", ePdfDataType_Number ) ); TEST_SAFE_OP_IGNORE( Test( "4.", ePdfDataType_Real ) ); printf("---\n"); // testing references TEST_SAFE_OP( Test( "2 0 R", ePdfDataType_Reference ) ); TEST_SAFE_OP( Test( "3 0 R", ePdfDataType_Reference ) ); TEST_SAFE_OP( Test( "4 1 R", ePdfDataType_Reference ) ); printf("---\n"); // testing names TEST_SAFE_OP( Test( "/Type", ePdfDataType_Name ) ); TEST_SAFE_OP( Test( "/Length", ePdfDataType_Name ) ); TEST_SAFE_OP( Test( "/Adobe#20Green", ePdfDataType_Name ) ); TEST_SAFE_OP( Test( "/$$", ePdfDataType_Name ) ); TEST_SAFE_OP( Test( "/1.2", ePdfDataType_Name ) ); TEST_SAFE_OP( Test( "/.notdef", ePdfDataType_Name ) ); TEST_SAFE_OP( Test( "/@pattern", ePdfDataType_Name ) ); TEST_SAFE_OP( Test( "/A;Name_With-Various***Characters?", ePdfDataType_Name ) ); TEST_SAFE_OP( Test( "/", ePdfDataType_Name ) ); // empty names are legal, too! printf("---\n"); // testing arrays TEST_SAFE_OP_IGNORE( Test( "[]", ePdfDataType_Array ) ); // this test may fail as the formating is different TEST_SAFE_OP( Test( "[ ]", ePdfDataType_Array ) ); TEST_SAFE_OP( Test( "[ 1 2 3 4 ]", ePdfDataType_Array ) ); TEST_SAFE_OP_IGNORE( Test( "[1 2 3 4]", ePdfDataType_Array ) ); // this test may fail as the formating is different TEST_SAFE_OP( Test( "[ 2 (Hallo Welt!) 3.500000 /FMC ]", ePdfDataType_Array ) ); TEST_SAFE_OP( Test( "[ [ 1 2 ] (Hallo Welt!) 3.500000 /FMC ]", ePdfDataType_Array ) ); TEST_SAFE_OP_IGNORE( Test( "[/ImageA/ImageB/ImageC]", ePdfDataType_Array ) ); // this test may fail as the formating is different TEST_SAFE_OP_IGNORE( Test( "[<530464995927cef8aaf46eb953b93373><530464995927cef8aaf46eb953b93373>]", ePdfDataType_Array ) ); TEST_SAFE_OP_IGNORE( Test( "[ 2 0 R (Test Data) 4 << /Key /Data >> 5 0 R ]", ePdfDataType_Array ) ); TEST_SAFE_OP_IGNORE( Test( "[<>2 0 R]", ePdfDataType_Array ) ); printf("---\n"); // Test some names. The first argument is the unencoded representation, the second // is the expected encoded result. The result must not only be /a/ correct encoded // name for the unencoded form, but must be the exact one PoDoFo should produce. TEST_SAFE_OP( TestName( "Length With Spaces", "Length#20With#20Spaces" ) ); TEST_SAFE_OP( TestName( "Length\001\002\003Spaces\177", "Length#01#02#03Spaces#7F" ) ); TEST_SAFE_OP( TestName( "Length#01#02#03Spaces#7F", "Length#2301#2302#2303Spaces#237F" ) ); TEST_SAFE_OP( TestName( "Tab\tTest", "Tab#09Test" ) ); printf("---\n"); // Test some pre-encoded names. The first argument is the encoded name that'll be // read from the PDF; the second is the expected representation. TEST_SAFE_OP( TestEncodedName( "PANTONE#205757#20CV", "PANTONE 5757 CV") ); TEST_SAFE_OP( TestEncodedName( "paired#28#29parentheses", "paired()parentheses") ); TEST_SAFE_OP( TestEncodedName( "The_Key_of_F#23_Minor", "The_Key_of_F#_Minor") ); TEST_SAFE_OP( TestEncodedName( "A#42", "AB") ); printf("---\n"); // Make sure differently encoded names compare equal if their decoded values // are equal. TEST_SAFE_OP( TestNameEquality( "With Spaces", "With#20Spaces" ) ); TEST_SAFE_OP( TestNameEquality( "#57#69#74#68#20#53#70#61#63#65#73", "With#20Spaces" ) ); printf("---\n"); // TODO: Move to AlgorithmTest char* pszHex = static_cast(malloc( sizeof(char) * 256 )); memset(pszHex, 0, 256); strcpy( pszHex, "Hallo Du schoene Welt!" ); pdf_long lLen = strlen( pszHex ); char* pszResult = NULL; pdf_long lRes = -1; std::string out; TEST_SAFE_OP( pFilter->Encode( pszHex, lLen, &pszResult, &lRes ) ); free( pszHex ); pszHex = pszResult; lLen = lRes; out.assign(pszHex, lLen); std::cerr << "Encoded buffer: (" << out << ')' << std::endl; TEST_SAFE_OP( pFilter->Decode( pszHex, lLen, &pszResult, &lRes ) ); free( pszHex ); pszHex = pszResult; lLen = lRes; out.assign(pszHex, lLen); std::cerr << "Encoded buffer: (" << out << ')' << std::endl; TEST_SAFE_OP( pFilter->Encode( pszHex, lLen, &pszResult, &lRes ) ); free( pszHex ); pszHex = pszResult; lLen = lRes; out.assign(pszHex, lLen); std::cerr << "Encoded buffer: (" << out << ')' << std::endl; TEST_SAFE_OP( pFilter->Decode( pszHex, lLen, &pszResult, &lRes ) ); free( pszHex ); pszHex = pszResult; lLen = lRes; out.assign(pszHex, lLen); std::cerr << "Encoded buffer: (" << out << ')' << std::endl; free( pszHex ); // test a hex string containing a whitespace character pszHex = static_cast(malloc( sizeof(char) * 256 )); strcpy( pszHex, "48616C6C6F2044\n75207363686F656E652057656C7421"); lLen = strlen( pszHex ); TEST_SAFE_OP( pFilter->Decode( pszHex, lLen, &pszResult, &lRes ) ); free( pszHex ); pszHex = pszResult; lLen = lRes; out.assign(pszHex, lLen); std::cerr << "Encoded buffer: (" << out << ')' << std::endl; free( pszResult ); // TODO: test variant equality comparisons printf("Test completed with error code: %i\n", eCode.GetError() ); return eCode.GetError(); } podofo-0.9.5/test/VariantTest/CMakeLists.txt0000664000175000017500000000037010614703752020653 0ustar dominikdominikADD_EXECUTABLE(VariantTest VariantTest.cpp) TARGET_LINK_LIBRARIES(VariantTest ${PODOFO_LIB} ${PODOFO_LIB_DEPENDS}) SET_TARGET_PROPERTIES(VariantTest PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(VariantTest ${PODOFO_DEPEND_TARGET}) podofo-0.9.5/test/system/0000775000175000017500000000000013044451150015163 5ustar dominikdominikpodofo-0.9.5/test/system/data/0000775000175000017500000000000013044451150016074 5ustar dominikdominikpodofo-0.9.5/test/system/podofo-system.sh0000775000175000017500000000326011306524712020337 0ustar dominikdominik#!/bin/bash if [ $# -ne 1 ]; then echo "Usage:" echo "./podofo-system.sh PATH_TO_PARSER_TEST_EXECUTABLE" exit -1 fi BAVARIA_DOWNLOAD="http://www.pdflib.com/fileadmin/pdflib/Bavaria/2009-04-03-Bavaria-pdfa.zip" BAVARIA_NAME="2009-04-03-Bavaria-pdfa.zip" DATA_DIR=data OUTPUT_DIR=output/$(date +%Y%m%d-%H:%M) PREFIX_OUT="podofo_" SUFFIX_LOG=".log" PARSER_TEST=$1 FAILED_TESTS="" echo "Starting PoDoFo system test session." echo "" echo "Reading input data from: $DATA_DIR" echo "Writing output to : $OUTPUT_DIR" echo "Using parser test : $PARSER_TEST" echo "" if [ ! -e $DATA_DIR/$BAVARIA_NAME ]; then echo "Bavaria test suite missing, downloading ..." wget -O $DATA_DIR/$BAVARIA_NAME $BAVARIA_DOWNLOAD unzip -d $DATA_DIR $DATA_DIR/$BAVARIA_NAME echo "Download done." fi mkdir -p $OUTPUT_DIR count=0 errors=0 SAVED_IFS=$IFS # Make for loop work with filenames containing spaces IFS=$(echo -en "\n\b") FILES=$(find $DATA_DIR -name '*.pdf' -print) for file in $FILES do FILENAME=$(basename "$file") echo -n -e "Running system test for: $file " $PARSER_TEST "$file" "$OUTPUT_DIR/$PREFIX_OUT$FILENAME" &> "$OUTPUT_DIR/$PREFIX_OUT$FILENAME$SUFFIX_LOG" RET=$? export count=$(( $count + 1 )) if [ $RET -eq 0 ]; then echo -n -e "OK\n" else export errors=$(( $errors + 1)) echo -n -e "FAIL\n" FAILED_TESTS="$FAILED_TESTS\n$file" fi done echo "" echo "Number of files parsed : "$count echo "Number of files in error: "$errors echo "" IFS=$SAVED_IFS if [ $errors -eq 0 ]; then echo "SUCCESS" exit 0 else echo "List of failed tests:" echo -e $FAILED_TESTS echo "" echo "FAILED" exit -2 fi podofo-0.9.5/test/ParserTest/0000775000175000017500000000000013044451150015733 5ustar dominikdominikpodofo-0.9.5/test/ParserTest/CMakeLists.txt0000664000175000017500000000036311534747027020512 0ustar dominikdominikADD_EXECUTABLE(ParserTest ParserTest.cpp) TARGET_LINK_LIBRARIES(ParserTest ${PODOFO_LIB} ${PODOFO_LIB_DEPEND} ) SET_TARGET_PROPERTIES(ParserTest PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(ParserTest ${PODOFO_DEPEND_TARGET}) podofo-0.9.5/test/ParserTest/ParserTest.cpp0000664000175000017500000002143713013650710020541 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include using std::cerr; using std::cout; using std::cin; using std::flush; using std::endl; using std::string; using namespace PoDoFo; void print_help() { cerr << "Usage: ParserTest [-d] [-clean] [-compact] []\n" << " -d Enable demand loading of objects\n" << " -clean Write a clean PDF that is readable in a text editor\n" << " -compact Write the PDF as compact as possible\n" << flush; } void enc_test() { /* PdfString documentId; documentId.SetHexData( "BF37541A9083A51619AD5924ECF156DF", 32 ); PdfEncrypt enc( "user", "podofo", 0 ); enc.GenerateEncryptionKey( documentId ); printf("\n\nTrying authentication!\n"); PdfOutputDevice debug( &(std::cout) ); printf("Debug: "); documentId.Write( &debug ); printf("\n\n"); std::string documentIdStr( documentId.GetString(), documentId.GetLength() ); std::string password = "user"; std::string uValue( reinterpret_cast(enc.GetUValue()), 32 ); std::string oValue( reinterpret_cast(enc.GetOValue()), 32 ); if( enc.Authenticate(documentIdStr, password, uValue, oValue, enc.GetPValue(), 40, 2) ) { printf("Successfull\n"); } else printf("FAILED\n"); enc.SetCurrentReference( PdfReference( 7, 0 ) ); const char* pBuffer1 = "Somekind of drawing \001 buffer that possibly \003 could contain PDF drawing commands"; const char* pBuffer2 = " possibly could contain PDF drawing\003 commands"; long lLen = strlen( pBuffer1 ) + 2 * strlen( pBuffer2 ); char* pEncBuffer = static_cast(malloc( sizeof(char) * lLen )); memcpy( pEncBuffer, pBuffer1, strlen( pBuffer1 ) * sizeof(char) ); memcpy( pEncBuffer + strlen(pBuffer1), pBuffer2, strlen( pBuffer2 ) ); memcpy( pEncBuffer + strlen(pBuffer1) + strlen( pBuffer2 ), pBuffer2, strlen( pBuffer2 ) ); enc.Encrypt( reinterpret_cast(pEncBuffer), lLen ); PdfMemoryOutputStream mem( lLen ); PdfOutputStream* pStream = enc.CreateEncryptionOutputStream( &mem ); pStream->Write( pBuffer1, strlen( pBuffer1 ) ); pStream->Write( pBuffer2, strlen( pBuffer2 ) ); pStream->Write( pBuffer2, strlen( pBuffer2 ) ); pStream->Close(); printf("Result: %i \n", memcmp( pEncBuffer, mem.TakeBuffer(), lLen ) ); enc.Encrypt( reinterpret_cast(pEncBuffer), lLen ); printf("Decrypted buffer: %s\n", pEncBuffer ); */ } void write_back( PdfParser* pParser, const char* pszFilename, EPdfWriteMode eWriteMode ) { //enc_test(); PdfWriter writer( pParser ); writer.SetWriteMode( eWriteMode ); /* PdfEncrypt encrypt( "user", "podofo", 0, PdfEncrypt::ePdfEncryptAlgorithm_RC4V2, PdfEncrypt::ePdfKeyLength_128 ); */ //writer.SetUseXRefStream( true ); //writer.SetLinearized( true ); writer.SetPdfVersion( ePdfVersion_1_6 ); //writer.SetEncrypted( encrypt ); writer.Write( pszFilename ); } int main( int argc, char* argv[] ) { PdfError::EnableLogging(true); PdfError::EnableDebug(true); PdfVecObjects objects; PdfParser parser( &objects ); EPdfWriteMode eWriteMode = ePdfWriteMode_Default; objects.SetAutoDelete( true ); bool useDemandLoading = false; bool useStrictMode = false; const char* pszInput = NULL; const char* pszFilename = NULL; for( int i=1; i []\n" << " -d Enable demand loading of objects\n" << " -s Enable strict parsing mode\n" << " -clean Enable clean writing mode\n" << " -compact Enable compact writing mode\n" << flush; return 0; } cerr << "This test reads a PDF file from disk and writes it to a new pdf file." << endl; cerr << "The PDF file should look unmodified in any viewer" << endl; cerr << "---" << endl; cerr << "Number of incremental updates: " << parser.GetNumberOfIncrementalUpdates() << endl; try { cerr << "Parsing " << pszInput << " with demand loading " << (useDemandLoading ? "on" : "off") << " with strict parsing " << (useStrictMode ? "on" : "off") << " ..." << flush; bool bIncorrectPw = false; std::string pw; parser.SetStrictParsing( useStrictMode ); do { try { if( !bIncorrectPw ) parser.ParseFile( pszInput, useDemandLoading ); else parser.SetPassword( pw ); bIncorrectPw = false; } catch( PdfError & e ) { if( e.GetError() == ePdfError_InvalidPassword ) { cout << endl << "Password :"; std::getline( cin, pw ); cout << endl; // try to continue with the new password bIncorrectPw = true; } else throw e; } } while( bIncorrectPw ); cerr << " done" << endl; cerr << "PdfVersion=" << parser.GetPdfVersion() << endl; cerr << "PdfVersionString=" << parser.GetPdfVersionString() << endl; /* cerr << "=============\n"); PdfObject* pCheat = objects.CreateObject( "Cheat" ); std::reverse( objects.begin(), objects.end() ); objects.RenumberObjects( const_cast(parser.GetTrailer()) ); pCheat = objects.CreateObject("LastObject"); cerr << "=============\n"); */ if (pszFilename) { cerr << "Writing..." << flush; write_back( &parser, pszFilename, eWriteMode ); cerr << " done" << endl; } } catch( PdfError & e ) { e.PrintErrorMsg(); return e.GetError(); } if (pszFilename) cerr << "Parsed and wrote successfully" << endl; else cerr << "Parsed successfully" << endl; /* cerr << "Now with PdfMemDocument" << endl; PdfMemDocument document; document.Load( pszInput ); document.Write( pszFilename ); cerr << "DONE: Now with PdfMemDocument" << endl; */ return 0; } podofo-0.9.5/test/valgrind.suppressions0000664000175000017500000000015610564241471020155 0ustar dominikdominik{ SeeZLibFAQ Memcheck:Cond obj:/usr/lib/libz.so.1.2.3 obj:/usr/lib/libz.so.1.2.3 fun:deflate } podofo-0.9.5/test/ObjectParserTest/0000775000175000017500000000000013044451150017062 5ustar dominikdominikpodofo-0.9.5/test/ObjectParserTest/CMakeLists.txt0000664000175000017500000000100310614703752021624 0ustar dominikdominikADD_EXECUTABLE(ObjectParserTest ObjectParserTest.cpp) TARGET_LINK_LIBRARIES(ObjectParserTest ${PODOFO_LIB} ${PODOFO_LIB_DEPENDS}) SET_TARGET_PROPERTIES(ObjectParserTest PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(ObjectParserTest ${PODOFO_DEPEND_TARGET}) # Copy the test samples over to the build tree ADD_CUSTOM_COMMAND( TARGET ObjectParserTest POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/objects" "${CMAKE_CURRENT_BINARY_DIR}/objects" ) podofo-0.9.5/test/ObjectParserTest/objects/0000775000175000017500000000000013044451150020513 5ustar dominikdominikpodofo-0.9.5/test/ObjectParserTest/objects/613_0_R.obj0000664000175000017500000000035210521414263022221 0ustar dominikdominik613 0 obj << /Length 141 /Filter [ /ASCII85Decode /FlateDecode ] >> stream 8;T)[:bY^""(EJg"_2%r'LT#i/jg!MO=63+VIuj#CB,WCF1If'\b*cS$n]!]4b-F8 qG%(:$AMg^T"YOX7AZtgSh=:Jjo>@Es8PIc5D/l`2DCV(kR[]C"pTDsic=_Q$KM6s !3MJ]jo~> endstream endobj podofo-0.9.5/test/ObjectParserTest/objects/27_0_R.info0000664000175000017500000000012610517701505022323 0ustar dominikdominik- This sample object has an invalid LZW decode dictionary and produces bad results. podofo-0.9.5/test/ObjectParserTest/objects/27_0_R.exp0000664000175000017500000000000010517701505022153 0ustar dominikdominikpodofo-0.9.5/test/ObjectParserTest/objects/27_0_R.obj0000664000175000017500000002251110517701505022144 0ustar dominikdominik27 0 obj << /Length 6469 /Filter /LZWDecode >> stream €Š€ÃP¼¨1ˆ"¡š0 FB„P@-ˆD¡C1ˆ¸p8 ÆC1pÃ’&T6ÃÄx!° ‘Êp³9ÃŒ@E,A1IPÕÂFñb¡tN:›L§#IŒÂlžÃÃCQ„‚+E‚Ã…Ó)ÃÃo‹Fc  È).• PA˜äiD£Â…cyÊ£@Dê÷ExËw G¨eð¯€ÂŽn£iC½ÎŽØ®±r¿Ã ƒ‹~FäE8ÂL'CI¼Ã€ƒ Fèd8-Õ°¡¶xQ‡Ã†õl-dQŒ‡A€ Ç¦9šL”»ÈoÄcx<û)ÞÑj‚ uX»–7r4Ší²}üµÆµÀml¦]ÂK§éô ænoS‹~æðì·C‘·®µ ¨:&…¡¨#‚¢¨D¾­BÕÀÂphÞ2á@¸AÈÔ"¶<­ðð¬!‹À²ŽÂúÔ jÂ;°S$ØÀi:ø:D­Ê ¡ÆAºØFÉøâC0TKmÇP{YÂPœ[ Ȳ{];ŠÔ?Äo¼M»qÂc6Âä_&Æ2<°ÂB£Àñ Ã…2„Ëà{*ÆAà ޮRi8JÈ i%O´1&ÃST:¹G*”Q@Æo 3OT[&QÃ’te)L´=3DÊÃ=-D „º¾Ëô|Ã…2OÂ’®1ÈAHWJÃŽA›g2†˜m@SlU;ZJô]_T±¡­0U#ÃŒlí&ҔDÂ(Të1¨p­1ÓR=9IÓÖåA`ŲÃ8µÌä²£‚±¬³½“qZmsgB£<3ÛÃL‚¹5äÔ¡ÈÂ\¸ ÇÊs=?z»-[m70F%BÛp ӅÆ7ýQsÃ’“‚²¥¥HTT-ÃOà Ãðó]—peSÞNÄÈ0-”[}QæP¡–+à“¬…pæùEMù7=ä¸t ÕÂ9>+C¸Ò¯9µ8àæº [K°,£"›®ºÈâÂã¨Ü2 #ÂòæÞ+·ëoxçº: SRCk„éÒ8n…¶Ó¼›Hèü§"p²€m[ëFàÕË(÷ï÷t&YH9÷\ïwº ŠoœÃæ9©#HÃ}u Ñ¿^zLzWÔÂs]ò0—{ õ™>ŸÂßtƒÀ…cØ‚¶h¸÷‹‡ùZ‚ùžSùô% Bºž×¸A£f±Lº´º¬;«Š9ÂêWÒâm¢ÅvÃ(Ò»,_‚ñ2}ÃÈ¡©îgæƒôúÃxl…§¾D€Ó±Æ)áŒ:†ÃG¤ì}82\¾Ã(~Ë©þw&¥œÓÀHʅ ­ ‚5T¦Ò%£J]imS,w:ËL ¬2ì̆+ú \SÔL@Ã’1 ‚òQ‘yyŠKÄfôX3ÆRÆÙF®)ÂXÎà1|³9+4Ãà\9A½ „ÔµÒ9Ã6`ÈÙ¡P°Œƒ Þ~—ÃüÃT‚Ö;‹ ¹ל¦XÚö°Zzƾ“gÂÔP`‚:OꌈM[%ð5M„Ԥ­0ċªç›=è ŸŠÎôdpK} ¤èReBâ,Ñ\D-§Y)ñ®2¨¶‡¯GªEÃÉ«B³^›$y´Ñ€QZ ´– ‚Š{,Öêr=3ÉÂ2iÂ¥8Ô,Ã¥Lž”Å£YÕ KouUP­v=I^ú¶¬“†¸.ClÓ]ÙbèVwWÓ7 )Ã¥jYiA=NÂ’@'`+©¨Æ'*6®*Dⱖ!>ƒGÃ’85¤,zį¬[Ù%nVVÂ9Â’@lÂ…(ô›ΊgGÂ’lȟFґ“ ÖƒÂ iu ӕ¼ÒÒ™S3!ñ"Ü`h85l1 Ûô›q«Š-x fà¤p¨ ‰UÂ'@önÙ¥ìp§•zB¡ ÖàmhÔ-Ö´Ì,…Ú–ŽÃћK±UÂ…+ÖÕc~J34A”2;ÔÌM¿¶µ\¹xtÓ&=9Ó1‘GpPNK³“®nWœV¶Rà_ZÃX߉#K,¡Ž%YXóàA. ˺`ˆ¼èd³*Q?`Ëåò\Oh¶dud«|æp ÃŒÂc¢âèoYõ*:Rßìªö8uòØd‘g°0Ÿ“yoµÒñ³ÙRùü׏€Uc6Ù 0dDg‘¦~d1Y;#߄’ãóÃdLÇg|«¯ÃTެyìd©³P,%I یƒ2Â…l˜E `(8¨ \UH±#—&ƒ0n ‹ ±„-b&ÉH A%Â…r‰ÂF· ¡(=t ÂHMÃ9PÊAHD‚]h‚‰-ÓddÂj-¨4¶§K„j‰é¬ACÞS4fÂ¥0J¢Ÿ4¼ì AJö™²mérúH©ÜŒyœ3Â’|¡Â0ß´¤3úejNéoiUpÂ3NCp.ó«úèk·ÃÕފé†ÛJNEæÓ%ÃŒVNŚç1ªèà5ªEð;ÃyœûË6ÛÃï¹9™æÃ…Të!›qÔW5JÓ21ð¾¼7‡KéLsaœ6bc Öšä«:õ›pi2‘K4˜²P©ŒÃ"Ã’ Âb,dI„U\ÕEÜÉÃàmÖï¿(¿.‰ne™{ž3 Ê©Éç0F)|ïv$.K·ÂÃŒ{Ø»¾Žª×ù>ãÌc€Kå€ðNK¸X^æã{¯Â­y¯½®ù†ÜçXÂDŒ„ƒ(@¾s&`¬Þ>ìª=ø—&60™ 4î9š¬n!AGÃ¥ BéÂ7§JžŸYÛ[R£9ª5T ¸‘êýc¬õ®¿× Ã…ëÃ}ó.ÃØ{c€­“²önÃÚ:Ëi‘ªEöº÷ÕO§ü>3¸7Üܒôٛ \¡Aø—È‹FoG—V´ÞÔÕïöFTìÃÃÎêÿOÂO^™ïà…jìMΧ”{⿋ܿzø­à g'O²ŒÖî ’˯H]0¯0 ±éØLà ÃÖ0 fµÆÒâø MÚËê8¯î&B‚ù,z¡.ÃQ‹ "D ‰ÃþQ ˆMPpHG ÀŠŠ¿Kð7b. … £RÃŽÃîcÃÒòj@œúíP2³§@ÃŒÂzìp¸XP,ć 羞d[PVÃã`‰ –Ã"t PdáäV¸'B®XÃP–åðìÎ,ðßd>ßÌìà%ž¿ 6° ãEtÃPüËûL¤%Šƒ,à ïTp'BàOü2ê+@Ȇc  ÂÃŽhJÃj¾¯èP B›Éô#fVÈ¢3ç^ˆƒUÃŽp/ ÒÂìT, àn(\óÃä~Q„=` lD;oL ›ÃŒ>CÜ4њÂˆ©ÃðsÂ鄉ÃŽÊBž4CIDq¦~£šÃèúw#jê´€Ê ñ  ˆãbÊ ‰]ƒŠ.€Ø‘ŒDt£lkL4‰ƒœ#H P£ø´¢ðò¬.”Ȩ’&â= BÔFÿilF0„B°ê*Q #D·DÆ1G@cÃö[ܼanÄôd™\¯íú¸HrŒÌíI´6\ãPÑ E¼¾¬ø.@â0 4 Âpøn(RMFJF¨ø@PrˆÃÃ`%­žílú^ùoš×­~úMˆØÃÂÙM˜Mœ ¶ PB!ï¼Ô/Ã,ãTÔã¶$Ç ÂP'R~{îU‘¾¯hBªç'Jê›d*¯ð-ÂÚÿTïÊÃB¦ç.Â’R笠E×'Þl±Jì™Z¸“ JœE²öÃì /ÊHâotÃŽ ÂŒ6Òç“0®æÃt5kìð±:ñ)¼©cmLcÊӃ¸Ÿ°NVS ŽÜ0*f³A C­ö,Â’cGHµZP³S,¤g+d.S;9Ê@®Å 0¤G4°xE³§Ó6ó[dÂds é…Ç¡+‘ 3©7D*ßÊØâ³ã ,¸›Ò:/“ÒÎıâù<°T¦"Þ£¢ø¦«–p+‚Ãâ I²NâF¼’>  l1D¤B´*S+±Cú·'•&H2l‘':g à >ðf ÚB´ ðŠô§|îS´´&—D-šöç>ÛF.÷„¤<m)@A)ÂQ)ÃÂ*2¦× ~ùÒ²ØR¶ú¯¯+òÂÚ ¤ñc\ÚòŒÚôÂüt–d@]. Ã8/ito8k›8Û4tÂ9 9Ʋhµò/“² Ìà-³@'S½<ÃŽ/6ðg4Ã¥ Np¦d0ÂsÃ’L'=ŠË=ÓÃsJ.õ MÆÂDÂ’"©ù@Ãæ0ÿT4L¦òB£Œ /Â’J@4.PRRǒXÃŒ&{E ÿ&”—Òq@'•'“Q(„R‰H²Ó)*Õ­@- h#ÂDžÖT ùT§+©+O©+¯±,µK°KòÃL2Ô´MP5l˜¯ˆªMÃFõ gä[O ¼¢tö'Tûs·P"Ã¥Ps\¯SbPÓf'SRîŸ tâùÂÃ9³2¯Ç+2 »΁ÃŽk=IÔìS1^‡ 6 :N&ik$âÅ©:4'T3Äz!Rà/• ììóÓ/8ôFM @îG ríªž[weÓÕ [^&X„;/u-Ž—jYU˜øÒ ù2©*ÃwZ„OZÒ¸úÒ¼û2Ã…[”À"ÃF#CÃ’" bÛe\âý<©QU3rp'ÂþìöMQ+ðÜê7FPÿFÂ’zÔÎû4Â$Ln%3éG¤¡6Öà72‚Ó…#«Ñ\¤9ÃN7lš-֗YԟiÔ¥*”©Z´­Zö­[4·,m75Ö¶÷–¼íNɶƬrã6PÇ<΃V§ ¶;?e˜ tJËÓíe ½NÃ<ßdÃ]Ó©&¶|çOó¹/óE`PÿQ@ޖY6öú™y=µú.P75×Ã’.Õw"u?Q4v8FQS0?lât°ßBs'v†BlãTy5Öyxomh/sl7r5ÃŒ*—#Ydõi•¡r j_s6§sv«K6±K¹,Â5\4-·ö"uËl—VÜ7ÃŒ*vÓ:ñ/m’ø½Ê‰Bvó=Ã¥ vl¼®,Â… x³>ÿñeW¿yX>;0Äu*°– t–1RwªÂØ©Sç~3pÓG{ÓÃ?U6¦ã„É•QfbÃ¥#kE¸¡%jTòFPµV ÕZJ5_Cde%¦U%ô-&8‘x5r§p½WÂ…7WÖ5pՃXvˆ"ÂŒUÂÉ­XÂXù J8ZoŸ€ï§Â6¯[V³Âµ»Âÿk¤\N)µ–«],É4wÂÂä£/'…•ë…Ãõ0xyu£m_ölW·o>·ÃaðÃŒ¹- ±AS%•2LBÃ2ä8s7NÚh­AFÖ7 p%"Ö@|´dx|— 5Të 44ÃDÄÚó×Օ¿Y¶ÜÓÂqî÷u‹hÂHɘíYxñr–›ÂuÂ¥s¤ú8Ksöµ[ö¸ÚãÒ$‚ß‘Ã[Â’"u=0V¨ÃamJÜÌX=dŠ­„9Â:„CØ8¿tþÔVï†ÓVÈöûG%ÓpÂ…4Ôšïpƒïˆ7”Œ—Lõ“Žôœr¥œ²¯ÂùÑÂ9ÕsÕ·Â×EÂ×H"c…Ž•›ž™!l®ÓÙuó{vP%8vq—qNWvïW|9+a)zöy3FwÂ4,oP¸KPðÃe-ÿ‹õz8É_tÕ—zóÕ{0s`iÉ7ƒ=7Ã…c ÂŽh·ßŸ¶kNƒ\t¹«:-hWñÂï{iBM݉#¤8œ–ŸÂÔ«¥±KZW,€trӂ7$šÂ°š™ë¦ÂåŸǟx9 ùÿpXAmùy©ôuÚxÃØR6Ù4MZ›PW“Pח†¹{=ýRLÕz»–³å”¹-{Â}™UeéòÂiöEÂ’<75G‰ø¼Ÿ8­U"u‹ ©‹{áÔ‹õeÂŒK¹Œ‘9&„é&úÙÂRvá¸Ú*W(uǎ/{)&ªÉ¤DÑaÂ5£¯ùäÃÂÂ;ÂwA:›‘KxÕ¸)™Ã½²ñ’uÛ.â/xl ú,S®+LD.¬Ã¦ÖæóI¦!s¢|ÂÕÈ52yc2¶)ƒ'}-‡6`1Zâ'Wë›A*8WUü•—¼ùůºG½ZK°4¯½ù › ©¥Û¦Qi;ñÂ-cÀÌn¬Â#Â’+MEEí²ôüÃ{5@ûW„µgÜ~Â… À;0-ÂŒ À©<ÃQ,OÆÆ íÊۙÀN °Â†\ƈCy×aST½0[ª9™ˆ‰å­viÃĎýüCgøÃ~ÜK®Ä¤F˜è„#œV©uŸÂ\_rücs[s» ¼oˆd¡¾m¯ÃÃ>ɼ~Ûã}Àê»ÌÂŽLVY²œ—|«„\£‡䨘TÀZ˜Ç<¹Ô\¿Ã\ÄáwÀÞæCÃ3¢Ù®ãgZ)Ãû8âã|3‡eœ#Ÿ¸…]zß4{°NLĞYwÊî£T˜VE¸k,·šU†CC6t·PÂ…C÷tºýǶ‚ ¹—`<ôUÑmÃř3oÜcÚ†4kÛ?ØרÚÞ¤[N{»H{¿ÄÂM\贁[Ãї+¯Ã!j;ÙjšSÒ¼mt3ÕÓRÃá"=ÓÕÃÈo:–÷M´OÃÂ1Ú>¨tîþZ•ÊýgÀ‡+ÖÜÈÑzÂ.Z‰Õ3emÂ\Ê,§QýüóÓl9­Û.=NËo˜uJYŠsB]Ë]×w°Ë™{šŸ4;Iu@.VSDg?”ø…ÃÅÖ ½âl(‹b= (¢6) zp]}EÈÂIæëÃÙ3Oí Ù¢uª†pÜç17vë¡UØæµgƒ^SðLãQ°¯à¹/£;Ãq¨ ÛÉpô’PvYÑ»Óâ8 œûÛÒxÆ»ã­Ù¼½ò.(=4Â’0{õ«xI³vÃŽ3pgmBÂõ¢´Vvz:ߨÔZžÛÀ_ï ¥æLæŒMþäje¬5fEµÃÑÊ@Š]qâÂGô,rɎ  J&–9ŽÕ ®VìÓRšÊNºæs(NI”feȌQÃ`È®©§Ö‹H¸ŠŒâi:"ÑÂÃŒa  '#9ӌBaF“qÂÊx2œÅÑ(œ(¨h2Ç¢‚ƒ™ÀÙŠKÂ¥BP4/* FBˆ€¨f˜ F#ÈÀ@9š•“ 0¤¨j˜L‡iÄè3ètPP ÕHÂ¥Lfcjtæ`6ˆ'•YÂlQ0Â"Cy,6G·BÂŽgRàÀb61šL¦édºÂ0ˆ(K=¤Øy‰$§3i¾%%7Àí²Rà Ê.3Çe²úäÒ¿P ¸IÃ…XeM*ðæ¡ð§G 8_óÓ+Ά`1Ãðµl.°h. qvó•Äe± Fó¬\ÊdâŒ'8—(Pf7› ™ ìÀn7¯ohÇ~µ&—3šÃì©àâÜ Aôôo=n™¸¨Ôôjº²ô3êóبm*Êúªìº´ô´"`¦¯"®Q=T,Eԫڃ4«ËT«\]]RÔü6ÅÑ #define unlink _unlink #else #include #endif #include #include #include #include #include #include #define HEADER_LEN 15 #define BUFFER_SIZE 4096 using namespace PoDoFo; using namespace std; #ifdef _WIN32 static const string sTmp("%TEMP%"); #else static const string sTmp("/tmp/pdfobjectparsertest_"); #endif static const bool KeepTempFiles = true; // Undefine if you want to let the tests crash when an exception // is thrown, so you can see the full call path. #ifndef CATCH_EXCEPTIONS #define CATCH_EXCEPTIONS #endif #ifdef CATCH_EXCEPTIONS #define TRY try #else #define TRY #endif // Print out an object in a human readable form. void PrintObject( const std::string & objectData, ostream & s, bool escapeNewlines, bool wrap ) { int wrapCtr = 0, numNonprintables = 0; for (string::const_iterator it = objectData.begin(); it != objectData.end(); ++it) { ++wrapCtr; char ch = *it; if ( ch != '\\' && ( ( !escapeNewlines && (ch == '\r' || ch == '\n') ) || ch == ' ' || PdfTokenizer::IsPrintable(ch) ) ) s << ch; else if (ch == '\r') s << "\\r"; else if (ch == '\n') s << "\\n"; else { static const char hx[17] = "0123456789ABCDEF"; s << '\\' << 'x' << hx[ch / 16] << hx[ch % 16]; wrapCtr += 3; // If we're processing binary data, just print part of it. ++numNonprintables; if (numNonprintables > 72) { cerr << "... [snip]"; break; } } if (wrap && wrapCtr > 72) { wrapCtr = 0; s << endl; } } } string WriteTempFile( const string & sFilename, const string & sData, long lObjNo, long lGenNo ) { std::ostringstream ss; ss << sFilename << lObjNo << '_' << lGenNo << "_obj"; string sNewFileName = ss.str(); ofstream f; f.open( sNewFileName.c_str(), ios_base::out|ios_base::trunc|ios_base::binary ); f.write( sData.data(), sData.length() ); return sNewFileName; } string ReadFile( string sFilename ) { FILE * f = fopen(sFilename.c_str(), "r"); fseek(f, 0L, SEEK_END); size_t bytes = ftell(f); fseek(f, 0L, SEEK_SET); char* buf = new char[bytes]; size_t bytesRead = fread(buf, 1, bytes, f); if (bytesRead != bytes) { cerr << "Failed to read file " << sFilename < Object Number: " << obj.Reference().ObjectNumber() << " Generation Number: " << obj.Reference().GenerationNumber() << endl; if( lObjNo != obj.Reference().ObjectNumber() || lGenNo != obj.Reference().GenerationNumber() ) { PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } if (bHasStream != obj.HasStream()) { cerr << "ERROR: This object should've had an associated stream, but none was loaded" << endl; PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } if (bHasStream) { char* pBuffer; pdf_long lLen; cerr << " -> Has Stream, loading ... " << flush; PdfMemStream * const ps = dynamic_cast(obj.GetStream()); PODOFO_ASSERT(ps); cerr << " ok, length: " << ps->GetLength() << endl; ps->GetFilteredCopy( &pBuffer, &lLen ); cerr << " got a filtered copy of length: " << lLen << endl; cerr << "Data:\n" << endl; cerr.write( pBuffer, lLen ); cerr << "\n====\n" << endl; podofo_free( pBuffer ); } string str; obj.ToString( str ); { size_t objOff = sOrigData.find(" obj")+5; if (sOrigData[objOff] == '\r' || sOrigData[objOff] == '\n') objOff++; const size_t endobjOff = sOrigData.rfind(string("endobj")); const string sOrigData_Base(sOrigData, objOff, endobjOff-objOff-1); cerr << " -> Input object data ("; PrintObject(sOrigData_Base, cerr, true, false); cerr << ")\n"; } cerr << " -> Parsed Value in this object : ("; PrintObject(str, cerr, true, false); cerr << ')' << endl; // TODO: ensure comparison correct after nulls if (bTestExpected) { cerr << " -> Expected value of this object: ("; PrintObject(sExpectedData, cerr, true, false); cerr << ')' << endl; if( str != sExpectedData ) { PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } } const unsigned long lObjLen = obj.GetObjectLength( ePdfWriteMode_Default ); cerr << " -> Object Length: " << lObjLen << endl; std::ostringstream os; PdfOutputDevice deviceTest( &os ); obj.WriteObject( &deviceTest, ePdfWriteMode_Default, NULL ); string sLen = os.str(); cerr << " -> Object String Length: " << sLen.length() << endl; if( lObjLen != sLen.length() ) { cerr << "Object length does not match! Object Length: " << lObjLen << " String Length: " << sLen.length() << endl; cerr << " -> Object String begins\n" << "----------- begin " << lObjNo << ' ' << lGenNo << " --------------" << endl; PrintObject(sLen, cerr, false, false); cerr << "------------ end " << lObjNo << ' ' << lGenNo << " ---------------\n\n" << flush; PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } cerr << "\n\n"; } // Test an object passed as a string against the expected value, also a string. void TestObject_String( const string & sData, long lObjNo, long lGenNo, bool bTestExpected = false, const string & sExpectedData = string(), bool bHasStream = false) { string sTempFile = WriteTempFile(sTmp, sData.c_str(), lObjNo, lGenNo); TRY { TestObject(sTempFile, lObjNo, lGenNo, bTestExpected, sExpectedData, bHasStream); if (!KeepTempFiles) unlink(sTempFile.c_str()); #ifdef CATCH_EXCEPTIONS } catch (PdfError & e) { if (!KeepTempFiles) unlink(sTempFile.c_str()); e.AddToCallstack( __FILE__, __LINE__ ); throw e; #endif } } // overload of TestObject_String that takes a `const char*' expected data argument that may be null. // This may only be used for objects without associated streams. void TestObject_String( const string & sData, long lObjNo, long lGenNo, const char * expectedData ) { TestObject_String(sData, lObjNo, lGenNo, expectedData != NULL, string( expectedData ? expectedData : "" ), false); } // Test an object stored in a file against the expected value, also a file (if provided). // Also ensures an object has a stream if set. void TestObject_File( const string & sFilename, long lObjNo, long lGenNo, bool bTestExpected = false, const string & sExpectedFile = string(), bool bHasStream = false ) { string sExpectedData; if (bTestExpected) sExpectedData = ReadFile(sExpectedFile); TestObject(sFilename, lObjNo, lGenNo, bTestExpected, sExpectedData, bHasStream); } const char* pszSimpleObjectBoolean = "1 0 obj\ntrue\nendobj\n"; const char* pszSimpleObjectNumber = "2 1 obj\n23\nendobj\n"; const char* pszSimpleObjectReal = "3 0 obj\n3.14\nendobj\n"; const char* pszSimpleObjectString = "4 0 obj\n(Hallo Welt!)\nendobj\n"; const char* pszSimpleObjectString2 = "5 0 obj\n(Hallo \\(schöne\\) Welt!)\nendobj\n"; const char* pszSimpleObjectHex = "6 0 obj\n<48656C6C6F20576F726C64>\nendobj\n"; // Hello World const char* pszSimpleObjectRef = "7 0 obj\n6 0 R\nendobj\n"; const char* pszSimpleObjectArray = "8 0 obj\n[100 200 300 400 500]\nendobj\n"; const char* pszSimpleObjectArray2 = "9 0 obj\n[100 (Hallo Welt) 3.14 400 500]\nendobj\n"; const char* pszSimpleObjectArray3 = "9 1 obj\n[100/Name(Hallo Welt)[1 2]3.14 400 500]\nendobj\n"; const char* pszSimpleObjectArray4 = "9 1 obj\n[100/Name(Hallo Welt)[1 2]3.14 400 500 /Dict << /A (Hallo) /B [21 22] >> /Wert /Farbe]\nendobj\n"; const char* pszSimpleObjectArray5 = "1 2 obj\n[123 0 R]\nendobj\n"; const char* pszObject = "10 0 obj\n" "<<\n" "/Type/Test\n" "/Key /Value\n" "/Hard>>\n" "endobj\n"; const char* pszObject2 = "11 0 obj\n" "<<\n" "/Type/Test2\n" "/Key /Value\n" "/Key2[100/Name(Hallo Welt)[1 2] 3.14 400 500]/Key2/Key4(Hallo \\(Welt!)\n" "/ID[<530464995927cef8aaf46eb953b93373><530464995927cef8aaf46eb953b93373>]\n" ">>\n" "endobj\n"; const char* pszObject3 = "12 0 obj\n" "<<\n" "/Type/Test3\n" "/Font<>\n" ">>\n" "endobj\n"; const char* pszObject4 = "271 0 obj\n" "<< /Type /Pattern /PatternType 1 /PaintType 1 /TilingType 1 /BBox [ 0 0 45 45 ] \n" "/Resources << /ProcSet [ /ImageI ] /XObject << /BGIm 7 0 R >> >> \n" "/XStep 45 /YStep 45 /Matrix [ 1 0 0 1 0 27 ] /Length 272 0 R >>\nendobj\n"; // PDF reference, Example 3.2 (LZW and ASCII85 encoded stream) const char* pszObject5 ="32 0 obj\n" " << /Length 534\n" " /Filter [/ASCII85Decode /LZWDecode]\n" " >>\n" "stream\n" "J..)6T`?p&c!Jnl@\n" "RM]WM;jjH6Gnc75idkL5]+cPZKEBPWdR>FF(kj1_R%W_d\n" "&/jS!;iuad7h?[L.F$+]]0A3Ck*$I0KZ?;<)CJtqi65Xb\n" "Vc3\\n5ua:Q/=0$W<#N3U;H,MQKqfg1?:lUpR;6oN[C2E4\n" "ZNr8Udn.'p+?#X+1>0Kuk$bCDF/(3fL5]Oq)^kJZ!C2H1\n" "'TO]Rl?Q:&'<5&iP!$Rq;BXRecDN[IJB`,)o8XJOSJ9sD\n" "S]hQ;Rj@!ND)bD_q&C\\g:inYC%)&u#:u,M6Bm%IY!Kb1+\n" "\":aAa'S`ViJglLb8iG1p&i;eVoK&juJHs9%;Xomop\"5KatWRT\"JQ#qYuL,\n" "JD?M$0QP)lKn06l1apKDC@\\qJ4B!!(5m+j.7F790m(Vj8\n" "8l8Q:_CZ(Gm1%X\\N1&u!FKHMB~>\n" "endstream\n" "endobj\n"; // PDF reference, Example 3.4 const char * pszObject6 = "33 0 obj\n" "<< /Length 568 >>\n" "stream\n" "2 J\n" "BT\n" "/F1 12 Tf\n" "0 Tc\n" "0 Tw\n" "72.5 712 TD\n" "[(Unencoded streams can be read easily) 65 (, )] TJ\n" "0 .14 TD\n" "[(b) 20 (ut generally tak ) 10 (e more space than \\311)] TJ\n" "T* (encoded streams.) Tj\n" "0 .28 TD\n" "[(Se) 25 (v) 15 (eral encoding methods are a) 20 (v) 25 (ailable in PDF ) 80 (.)] TJ\n" "0 .14 TD\n" "(Some are used for compression and others simply ) Tj\n" "T* [(to represent binary data in an ) 55 (ASCII format.)] TJ\n" "T* (Some of the compression encoding methods are \\\n" "suitable ) Tj\n" "T* (for both data and images, while others are \\\n" "suitable only ) Tj\n" "T* (for continuous.tone images.) Tj\n" "ET\n" "endstream\n" "endobj\n"; // Comment tokenizer test adapted from PDF Reference, section 3.1.2 . Should parse as [ /abc 123 ] . const char* pszCommentObject = "91 0 obj\n[/abc% comment {/%) blah blah blah\n123]\nendobj\n"; // Use a FULL statement in this macro, it will not add any trailing // semicolons etc. #ifdef CATCH_EXCEPTIONS #define TRY_TEST(x) \ try {\ ++tests;\ x\ ++tests_ok;\ } \ catch (PdfError & e) \ {\ e.PrintErrorMsg();\ ++tests_error;\ } #else #define TRY_TEST(x) \ {\ ++tests;\ x\ ++tests_ok;\ } #endif int main() { int tests = 0, tests_error = 0, tests_ok=0; PdfError eCode; fprintf(stderr,"This test tests the PdfParserObject class.\n"); fprintf(stderr,"---\n"); TRY_TEST(TestObject_String( pszSimpleObjectBoolean, 1, 0, "true" );) TRY_TEST(TestObject_String( pszSimpleObjectNumber , 2, 1, "23" );) TRY_TEST(TestObject_String( pszSimpleObjectReal , 3, 0, "3.140000" );) TRY_TEST(TestObject_String( pszSimpleObjectString , 4, 0, "(Hallo Welt!)" );) TRY_TEST(TestObject_String( pszSimpleObjectString2, 5, 0, "(Hallo \\(schöne\\) Welt!)" );) TRY_TEST(TestObject_String( pszSimpleObjectHex , 6, 0, "<48656C6C6F20576F726C64>" );) TRY_TEST(TestObject_String( pszSimpleObjectRef , 7, 0, "6 0 R" );) TRY_TEST(TestObject_String( pszSimpleObjectArray , 8, 0, "[ 100 200 300 400 500 ]" );) TRY_TEST(TestObject_String( pszSimpleObjectArray2 , 9, 0, "[ 100 (Hallo Welt) 3.140000 400 500 ]" );) TRY_TEST(TestObject_String( pszSimpleObjectArray3 , 9, 1, "[ 100 /Name (Hallo Welt) [ 1 2 ] 3.140000 400 500 ]" );) TRY_TEST(TestObject_String( pszSimpleObjectArray4 , 9, 1, "[ 100 /Name (Hallo Welt) [ 1 2 ] 3.140000 400 500 /Dict <<\n/A (Hallo)\n/B [ 21 22 ]\n>> /Wert\n/Farbe ]" );) TRY_TEST(TestObject_String( pszSimpleObjectArray5 , 1, 2, "[ 123 0 R ]" );) TRY_TEST(TestObject_String( pszCommentObject, 91, 0, "[ /abc 123 ]" );) fprintf(stderr,"---\n"); TRY_TEST(TestObject_String( pszObject, 10, 0 );) TRY_TEST(TestObject_String( pszObject2, 11, 0 );) TRY_TEST(TestObject_String( pszObject3, 12, 0 );) TRY_TEST(TestObject_String( pszObject4, 271, 0 );) // These ones have attached streams TRY_TEST(TestObject_String( pszObject5, 32, 0, false, string(), true);) TRY_TEST(TestObject_String( pszObject6, 33, 0, false, string(), true);) TRY_TEST(TestObject_File( "objects/27_0_R.obj", 27, 0, false, string(), true );) TRY_TEST(TestObject_File( "objects/613_0_R.obj", 613, 0, false, string(), true );) cerr << "---\n" << flush; if (!tests_error) cerr << "All " << tests << " tests succeeded!" << endl; else cerr << tests_error << " of " << tests << " tests failed, " << tests_ok << " succeeded" << endl; return tests_error; } podofo-0.9.5/test/ContentParser/0000775000175000017500000000000013044451150016426 5ustar dominikdominikpodofo-0.9.5/test/ContentParser/CMakeLists.txt0000664000175000017500000000037211460071654021177 0ustar dominikdominik ADD_EXECUTABLE(ContentParser main.cpp) TARGET_LINK_LIBRARIES(ContentParser ${PODOFO_LIB} ${PODOFO_LIB_DEPENDS}) SET_TARGET_PROPERTIES(ContentParser PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(ContentParser ${PODOFO_DEPEND_TARGET}) podofo-0.9.5/test/ContentParser/main.cpp0000664000175000017500000001242413013650710020060 0ustar dominikdominik#include "podofo.h" #include "../PdfTest.h" #include #include #include #include #include #include using namespace std; using namespace PoDoFo; static bool print_output = false; void parse_contents( PdfContentsTokenizer* pTokenizer ) { const char* pszToken = NULL; PdfVariant var; EPdfContentsType eType; std::string str; int numKeywords = 0; int numVariants = 0; std::stack stack; while( pTokenizer->ReadNext( eType, pszToken, var ) ) { if( eType == ePdfContentsType_Keyword ) { ++numKeywords; if (print_output) std::cout << setw(12) << (numKeywords+numVariants) << " Keyword: " << pszToken << std::endl; // support 'l' and 'm' tokens if( strcmp( pszToken, "l" ) == 0 ) { double dPosY = stack.top().GetReal(); stack.pop(); double dPosX = stack.top().GetReal(); stack.pop(); if(print_output) std::cout << string(12,' ') << " LineTo: " << dPosX << " " << dPosY << std::endl; } else if( strcmp( pszToken, "m" ) == 0 ) { double dPosY = stack.top().GetReal(); stack.pop(); double dPosX = stack.top().GetReal(); stack.pop(); if(print_output) std::cout << string(12,' ') << " MoveTo: " << dPosX << " " << dPosY << std::endl; } } else if ( eType == ePdfContentsType_Variant ) { ++numVariants; var.ToString( str ); if(print_output) std::cout << setw(12) << (numKeywords+numVariants) << " Variant: " << str << std::endl; stack.push( var ); } else if (eType == ePdfContentsType_ImageData) { if (print_output) { std::string d ( var.GetRawData().data() ); std::cout << string(13, ' ') << "Inline image data: " << d.size() << " bytes. Hex follows." << std::hex << std::endl; std::cout << std::hex << std::setfill('0'); for ( std::string::iterator i = d.begin(); i != d.end(); i ++) { std::cout << std::setw(2) << (static_cast(*i) & 0x00FF); } std::cout << std::dec << std::setfill(' ') << std::endl; } } else { // Impossible; type must be keyword or variant PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } } cout << ' ' << setw(12) << numKeywords << " keywords, " << setw(12) << numVariants << " variants"; } void parse_page( PdfMemDocument*, PdfPage* pPage ) { PdfContentsTokenizer tokenizer( pPage ); parse_contents( &tokenizer ); } void usage() { printf("Usage: ContentParser [-g] [-a] [-p] input_filename\n"); printf(" -a Process all pages of input, not just first\n"); printf(" -p Print parsed content stream to stdout\n"); } int main( int argc, char* argv[] ) { bool all_pages = false; int firstPageNo = 0; string inputFileName; ++argv; --argc; while (argc) { if( argv[0][0] == '-' ) { // Single character flag switch( argv[0][1] ) { case 'a': // Process all pages, not just first page all_pages = true; break; case 'p': // Print output, rather than parsing & checking // silently. print_output = true; break; case 'n': // Page number request. Chars 2+ are page number int. Let's do // this the quick and dirty way... firstPageNo = atoi(argv[0]+2) - 1; cerr << "Will process page: " << (firstPageNo+1) << endl; break; default: usage(); return 1; } } else { // Input filename if (inputFileName.empty()) { inputFileName = argv[0]; } else { usage(); return 1; } } ++argv; --argc; } if (inputFileName.empty()) { usage(); return 1; } try { PdfMemDocument doc( inputFileName.c_str() ); if( !doc.GetPageCount() ) { std::cerr << "This document contains no page!" << std::endl; return 1; } int toPage = all_pages ? doc.GetPageCount() : firstPageNo + 1 ; for ( int i = firstPageNo; i < toPage; ++i ) { cout << "Processing page " << setw(6) << (i+1) << "..." << std::flush; PdfPage* page = doc.GetPage( i ); PODOFO_RAISE_LOGIC_IF( !page, "Got null page pointer within valid page range" ); parse_page( &doc, page ); cout << " - page ok" << endl; } } catch( PdfError & e ) { e.PrintErrorMsg(); return e.GetError(); } cout << endl; return 0; } podofo-0.9.5/test/TokenizerTest/0000775000175000017500000000000013044451156016457 5ustar dominikdominikpodofo-0.9.5/test/TokenizerTest/CMakeLists.txt0000664000175000017500000000076110673174162021227 0ustar dominikdominikADD_EXECUTABLE(TokenizerTest TokenizerTest.cpp) TARGET_LINK_LIBRARIES(TokenizerTest ${PODOFO_LIB} ${PODOFO_LIB_DEPENDS}) SET_TARGET_PROPERTIES(TokenizerTest PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(TokenizerTest ${PODOFO_DEPEND_TARGET}) # Copy the test samples over to the build tree ADD_CUSTOM_COMMAND( TARGET TokenizerTest POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/objects" "${CMAKE_CURRENT_BINARY_DIR}/objects" ) podofo-0.9.5/test/TokenizerTest/TokenizerTest.cpp0000664000175000017500000000427213013650710021773 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "../PdfTest.h" #include #define BUFFER_SIZE 4096 using namespace PoDoFo; int main( int argc, char* argv[] ) { printf("Tokenizer Test\n"); printf("==============\n"); if( argc != 2 ) { printf("Usage: TokenizerTest [input_filename]\n"); return 0; } try { PdfRefCountedInputDevice device( argv[1], "rb" ); PdfRefCountedBuffer buffer( BUFFER_SIZE ); PdfTokenizer tokenizer( device, buffer ); const char* pszToken; while ( tokenizer.GetNextToken(pszToken) ) { printf("Got token: %s\n", pszToken ); } } catch( PdfError & e ) { e.PrintErrorMsg(); return e.GetError(); } return 0; } podofo-0.9.5/test/CreationTest/0000775000175000017500000000000013044451156016251 5ustar dominikdominikpodofo-0.9.5/test/CreationTest/CMakeLists.txt0000664000175000017500000000075710714372313021020 0ustar dominikdominikADD_EXECUTABLE(CreationTest CreationTest.cpp) TARGET_LINK_LIBRARIES(CreationTest ${PODOFO_LIB} ${PODOFO_LIB_DEPENDS}) SET_TARGET_PROPERTIES(CreationTest PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(CreationTest ${PODOFO_DEPEND_TARGET}) # Copy the test samples over to the build tree ADD_CUSTOM_COMMAND( TARGET CreationTest POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/resources" "${CMAKE_CURRENT_BINARY_DIR}/resources" ) podofo-0.9.5/test/CreationTest/CreationTest.cpp0000664000175000017500000011453613013650710021364 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "../PdfTest.h" #include #include #include using namespace PoDoFo; #define CONVERSION_CONSTANT 0.002834645669291339 const char* pszLoremIpsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse lacinia sollicitudin viverra. Praesent augue tellus, feugiat vel tempus ac, semper in tellus. Maecenas et vehicula urna. Suspendisse ullamcorper molestie leo id aliquet. Mauris ultricies porttitor lectus vel facilisis. Integer euismod libero ut lectus mattis sed venenatis metus molestie. Aliquam feugiat, dolor a adipiscing ullamcorper, sapien orci ultrices erat, eget porttitor ipsum purus id magna. Morbi malesuada malesuada sagittis. Curabitur viverra posuere sem, quis condimentum eros viverra et. Pellentesque tristique aliquam orci a aliquam.\n\nIn hac habitasse platea dictumst. Maecenas vitae lorem velit. Donec at ultrices arcu. Phasellus et justo in quam fermentum volutpat. Nam vestibulum tempus lorem nec lacinia. Cras ac dignissim tortor. Morbi pellentesque, nisi sit amet sollicitudin accumsan, ante quam egestas lorem, a dapibus quam orci quis nulla. Donec quis orci ut lacus dictum sollicitudin at eget turpis. Nam condimentum iaculis enim, id volutpat est dapibus id. Quisque sed enim in est condimentum convallis. Cras at posuere ipsum. Cras tempor dui nunc, vel malesuada odio."; void WriteStringToStream( const PdfString & rsString, std::ostringstream & oss, PdfFont* pFont ) { PdfEncoding* pEncoding = new PdfIdentityEncoding( 0, 0xffff, true ); PdfRefCountedBuffer buffer = pEncoding->ConvertToEncoding( rsString, pFont ); pdf_long lLen = 0; char* pBuffer = NULL; std::auto_ptr pFilter = PdfFilterFactory::Create( ePdfFilter_ASCIIHexDecode ); pFilter->Encode( buffer.GetBuffer(), buffer.GetSize(), &pBuffer, &lLen ); oss << "<"; oss << std::string( pBuffer, lLen ); oss << ">"; free( pBuffer ); delete pEncoding; } void CreateUnicodeAnnotationText( PdfPage* pPage, PdfDocument* /*pDocument*/ ) { PdfString sJap(reinterpret_cast("「PoDoFoã€ã¯ä»Šã‹ã‚‰æ—¥æœ¬èªžã‚‚話ã›ã¾ã™ã€‚")); PdfAnnotation* pAnnotation = pPage->CreateAnnotation( ePdfAnnotation_Text, PdfRect( 400.0, 200.0, 20.0, 20.0 ) ); PdfString sGerman(reinterpret_cast("Unicode Umlauts: ÄÖÜß")); pAnnotation->SetTitle( sGerman ); pAnnotation->SetContents( sJap ); pAnnotation->SetOpen( true ); } void CreateUnicodeAnnotationFreeText( PdfPage* pPage, PdfDocument* pDocument ) { PdfString sJap(reinterpret_cast("「PoDoFoã€ã¯ä»Šã‹ã‚‰æ—¥æœ¬èªžã‚‚話ã›ã¾ã™ã€‚")); PdfFont* pFont = pDocument->CreateFont( "Arial Unicode MS", false, new PdfIdentityEncoding( 0, 0xffff, true ) ); PdfRect rect( 200.0, 200.0, 200.0, 200.0 ); /* PdfXObject xObj( rect, pDocument ); PdfPainter painter; painter.SetPage( &xObj ); painter.SetFont( pFont ); painter.SetColor( 1.0, 0.0, 0.0 ); painter.Rectangle( 10.0, 10.0, 100.0, 100.0 ); painter.FillAndStroke(); painter.DrawText( 100.0, 100.0, sJap ); painter.FinishPage(); */ std::ostringstream oss; oss << "BT" << std::endl << "/" << pFont->GetIdentifier().GetName() << " " << pFont->GetFontSize() << " Tf " << std::endl; WriteStringToStream( sJap, oss, pFont ); oss << "Tj ET" << std::endl; PdfDictionary fonts; fonts.AddKey(pFont->GetIdentifier().GetName(), pFont->GetObject()->Reference()); PdfDictionary resources; resources.AddKey( PdfName("Fonts"), fonts ); PdfAnnotation* pAnnotation = pPage->CreateAnnotation( ePdfAnnotation_FreeText, rect ); PdfString sGerman(reinterpret_cast("Unicode Umlauts: ÄÖÜß")); pAnnotation->SetTitle( sGerman ); pAnnotation->SetContents( sJap ); //pAnnotation->SetAppearanceStream( &xObj ); pAnnotation->GetObject()->GetDictionary().AddKey( PdfName("DA"), PdfString(oss.str()) ); pAnnotation->GetObject()->GetDictionary().AddKey( PdfName("DR"), resources ); } void LineTest( PdfPainter* pPainter, PdfPage* pPage, PdfDocument* pDocument ) { double x = 10000 * CONVERSION_CONSTANT; double y = pPage->GetPageSize().GetHeight() - 10000 * CONVERSION_CONSTANT; PdfFont* pFont; const double dLineLength = 50000 * CONVERSION_CONSTANT; // 5cm double h; double w; int i; /* pFont = pDocument->CreateFont( "Arial Unicode MS", new PdfIdentityEncoding( 0, 0xffff, true ) ); printf("GOT: %s\n", pFont->GetFontMetrics()->GetFontname() ); PdfString sJap(reinterpret_cast("「Po\tDoFoã€ã¯ä»Šã‹ã‚‰æ—¥æœ¬èªžã‚‚話ã›ã¾ã™ã€‚")); const long lUtf8BufferLen = 256; pdf_utf8 pUtf8Buffer[lUtf8BufferLen]; PdfString::ConvertUTF16toUTF8( sJap.GetUnicode(), sJap.GetUnicodeLength(), pUtf8Buffer, lUtf8BufferLen ); printf("UNIC: %s\n", pUtf8Buffer ); pFont->SetFontSize( 8.0 ); pPainter->SetFont( pFont ); pPainter->DrawText( 100.0, 100.0, sJap ); */ std::vector vecCharacters; vecCharacters.push_back( static_cast('C') ); vecCharacters.push_back( static_cast('G') ); vecCharacters.push_back( static_cast('a') ); vecCharacters.push_back( static_cast('c') ); vecCharacters.push_back( static_cast('e') ); vecCharacters.push_back( static_cast('l') ); vecCharacters.push_back( static_cast('o') ); vecCharacters.push_back( static_cast('p') ); vecCharacters.push_back( static_cast('s') ); vecCharacters.push_back( static_cast('r') ); vecCharacters.push_back( static_cast('y') ); vecCharacters.push_back( static_cast(' ') ); vecCharacters.push_back( static_cast('-') ); pFont = pDocument->CreateFont( "Comic Sans MS", false, false ); //, vecCharacters ); if( !pFont ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } pFont->SetFontSize( 16.0 ); const wchar_t* msg = L"Grayscale - Colorspace"; h = pFont->GetFontMetrics()->GetLineSpacing(); w = pFont->GetFontMetrics()->StringWidth( msg ); pPainter->SetFont( pFont ); pPainter->DrawText( 120000 * CONVERSION_CONSTANT, y - pFont->GetFontMetrics()->GetLineSpacing(), msg ); pPainter->Rectangle( 120000 * CONVERSION_CONSTANT, y - pFont->GetFontMetrics()->GetLineSpacing(), w, h ); pPainter->Stroke(); // Draw 10 lines in gray scale for( i = 0; i < 10; i++ ) { x += (10000 * CONVERSION_CONSTANT); pPainter->SetStrokeWidth( (i*1000) * CONVERSION_CONSTANT ); pPainter->SetStrokingGray( static_cast(i)/10.0 ); pPainter->DrawLine( x, y, x, y - dLineLength ); } x = 10000 * CONVERSION_CONSTANT; y -= dLineLength; y -= (10000 * CONVERSION_CONSTANT); pFont = pDocument->CreateFont( "Arial", true, false ); // arial bold - not italic if( !pFont ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } pFont->SetFontSize( 16.0 ); pPainter->SetFont( pFont ); pPainter->DrawText( 120000 * CONVERSION_CONSTANT, y - pFont->GetFontMetrics()->GetLineSpacing(), "RGB Colorspace" ); // Draw 10 lines in rgb for( i = 0; i < 10; i++ ) { x += (10000 * CONVERSION_CONSTANT); pPainter->SetStrokeWidth( (i*1000) * CONVERSION_CONSTANT ); pPainter->SetStrokingColor( static_cast(i)/10.0, 0.0, static_cast(10-i)/10.0 ); pPainter->DrawLine( x, y, x, y - dLineLength ); } x = 10000 * CONVERSION_CONSTANT; y -= dLineLength; y -= (10000 * CONVERSION_CONSTANT); pFont = pDocument->CreateFont( "Arial", false, true ); // arial italic - not bold if( !pFont ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } pFont->SetFontSize( 16.0 ); pPainter->SetFont( pFont ); pPainter->DrawText( 120000 * CONVERSION_CONSTANT, y - pFont->GetFontMetrics()->GetLineSpacing(), "CMYK Colorspace" ); // Draw 10 lines in cmyk for( i = 0; i < 10; i++ ) { x += (10000 * CONVERSION_CONSTANT); pPainter->SetStrokeWidth( (i*1000) * CONVERSION_CONSTANT ); pPainter->SetStrokingColorCMYK( static_cast(i)/10.0, 0.0, static_cast(10-i)/10.0, 0.0 ); pPainter->DrawLine( x, y, x, y - dLineLength ); } x = 20000 * CONVERSION_CONSTANT; y -= 60000 * CONVERSION_CONSTANT; pPainter->SetStrokeWidth( 1000 * CONVERSION_CONSTANT ); pPainter->SetStrokingColor( 0.0, 0.0, 0.0 ); pPainter->SetStrokeStyle( ePdfStrokeStyle_Solid ); pPainter->DrawLine( x, y, x + (100000 * CONVERSION_CONSTANT), y ); y -= (10000 * CONVERSION_CONSTANT); pPainter->SetStrokeStyle( ePdfStrokeStyle_Dash ); pPainter->DrawLine( x, y, x + (100000 * CONVERSION_CONSTANT), y ); y -= (10000 * CONVERSION_CONSTANT); pPainter->SetStrokeStyle( ePdfStrokeStyle_Dot ); pPainter->DrawLine( x, y, x + (100000 * CONVERSION_CONSTANT), y ); y -= (10000 * CONVERSION_CONSTANT); pPainter->SetStrokeStyle( ePdfStrokeStyle_DashDot ); pPainter->DrawLine( x, y, x + (100000 * CONVERSION_CONSTANT), y ); y -= (10000 * CONVERSION_CONSTANT); pPainter->SetStrokeStyle( ePdfStrokeStyle_DashDotDot ); pPainter->DrawLine( x, y, x + (100000 * CONVERSION_CONSTANT), y ); y -= (10000 * CONVERSION_CONSTANT); pPainter->SetStrokeStyle( ePdfStrokeStyle_Custom, "[7 9 2] 4" ); pPainter->DrawLine( x, y, x + (100000 * CONVERSION_CONSTANT), y ); y -= (10000 * CONVERSION_CONSTANT); //CreateUnicodeAnnotationText( pPage, pDocument ); CreateUnicodeAnnotationFreeText( pPage, pDocument ); return; /////////////////////// pPage = pDocument->CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); pPainter->SetPage( pPage ); x = 10000 * CONVERSION_CONSTANT; y = pPage->GetPageSize().GetHeight() - 10000 * CONVERSION_CONSTANT; char buffer[1024]; double dStroke = 0.01; double dLine = pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); for( i=0;i<23; i++ ) { sprintf( buffer, "Linewidth: %.3fpt", dStroke ); pPainter->DrawText( x, y, PdfString( buffer ) ); pPainter->Save(); pPainter->SetStrokeWidth( dStroke ); pPainter->DrawLine( x + 60000 * CONVERSION_CONSTANT, y + dLine/2.0, x + 140000 * CONVERSION_CONSTANT, y + dLine/2.0 ); pPainter->DrawLine( x + 60000 * CONVERSION_CONSTANT, y, x + 140000 * CONVERSION_CONSTANT, y ); pPainter->DrawLine( x + 60000 * CONVERSION_CONSTANT, y + dLine, x + 140000 * CONVERSION_CONSTANT, y + dLine ); pPainter->DrawLine( x + 60000 * CONVERSION_CONSTANT, y, x + 60000 * CONVERSION_CONSTANT, y + dLine ); pPainter->DrawLine( x + 140000 * CONVERSION_CONSTANT, y, x + 140000 * CONVERSION_CONSTANT, y + dLine ); pPainter->Restore(); dStroke += 0.05; y -= dLine*2.0; } } void RectTest( PdfPainter* pPainter, PdfPage* pPage, PdfDocument* pDocument ) { double x = 10000 * CONVERSION_CONSTANT; double y = pPage->GetPageSize().GetHeight() - 10000 * CONVERSION_CONSTANT; PdfFont* pFont; const double dWidth = 50000 * CONVERSION_CONSTANT; // 5cm const double dHeight = 30000 * CONVERSION_CONSTANT; // 3cm y -= dHeight; pFont = pDocument->CreateFont( "Arial" ); if( !pFont ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } pFont->SetFontSize( 16.0 ); pPainter->SetFont( pFont ); pPainter->DrawText( 125000 * CONVERSION_CONSTANT, y - pFont->GetFontMetrics()->GetLineSpacing(), "Rectangles" ); pPainter->SetStrokeWidth( 100 * CONVERSION_CONSTANT ); pPainter->SetStrokingColor( 0.0, 0.0, 0.0 ); pPainter->Rectangle( x, y, dWidth, dHeight ); pPainter->Stroke(); PdfString sMultiLine("Hello World! We try to draw text using PdfPainter and DrawMultiLineText into an rectangle - including wordwrapping."); pPainter->DrawMultiLineText( x, y, dWidth, dHeight, sMultiLine); x += dWidth; x += 10000 * CONVERSION_CONSTANT; pPainter->SetStrokeWidth( 1000 * CONVERSION_CONSTANT ); pPainter->SetStrokingColor( 0.0, 0.0, 0.0 ); pPainter->Rectangle( x, y, dWidth, dHeight ); pPainter->Stroke(); y -= dHeight; y -= 10000 * CONVERSION_CONSTANT; x = 10000 * CONVERSION_CONSTANT; pPainter->SetStrokeWidth( 100 * CONVERSION_CONSTANT ); pPainter->SetStrokingColor( 1.0, 0.0, 0.0 ); pPainter->Rectangle( x, y, dWidth, dHeight ); pPainter->Stroke(); x += dWidth; x += 10000 * CONVERSION_CONSTANT; pPainter->SetStrokeWidth( 1000 * CONVERSION_CONSTANT ); pPainter->SetStrokingColor( 0.0, 1.0, 0.0 ); pPainter->Rectangle( x, y, dWidth, dHeight ); pPainter->Stroke(); y -= dHeight; y -= 10000 * CONVERSION_CONSTANT; x = 10000 * CONVERSION_CONSTANT; pPainter->SetStrokeWidth( 100 * CONVERSION_CONSTANT ); pPainter->SetStrokingColor( 0.0, 0.0, 0.0 ); pPainter->SetColor( 1.0, 0.0, 0.0 ); pPainter->Rectangle( x, y, dWidth, dHeight ); pPainter->FillAndStroke(); x += dWidth; x += 10000 * CONVERSION_CONSTANT; pPainter->SetStrokeWidth( 100 * CONVERSION_CONSTANT ); pPainter->SetStrokingColor( 0.0, 1.0, 0.0 ); pPainter->SetColor( 0.0, 0.0, 1.0 ); x = 0.0; y = 0.0; pPainter->Rectangle( x, y, 50000 * CONVERSION_CONSTANT, 50000 * CONVERSION_CONSTANT); pPainter->FillAndStroke(); y -= dHeight; y -= 10000 * CONVERSION_CONSTANT; x = (10000 * CONVERSION_CONSTANT) + dWidth; pPainter->DrawText( 120000 * CONVERSION_CONSTANT, y - pFont->GetFontMetrics()->GetLineSpacing(), "Triangles" ); // Draw a triangle at the current position pPainter->SetColor( 0.0, 1.0, 1.0 ); pPainter->MoveTo( x, y ); pPainter->LineTo( x+dWidth, y-dHeight ); pPainter->LineTo( x-dWidth, y-dHeight ); pPainter->ClosePath(); pPainter->Fill(); y -= dHeight; y -= 10000 * CONVERSION_CONSTANT; x = (10000 * CONVERSION_CONSTANT) + dWidth; pPainter->SetStrokingColor( 0.0, 0.0, 0.0 ); pPainter->MoveTo( x, y ); pPainter->LineTo( x+dWidth, y-dHeight ); pPainter->LineTo( x-dWidth, y-dHeight ); pPainter->ClosePath(); pPainter->Stroke(); } void TextTest( PdfPainter* pPainter, PdfPage* pPage, PdfDocument* pDocument ) { double x = 10000 * CONVERSION_CONSTANT; double y = pPage->GetPageSize().GetHeight() - 10000 * CONVERSION_CONSTANT; printf("Embedding Font\n"); printf("!!!!!!!!!!!!!!!\n"); pPainter->SetFont( pDocument->CreateFont( "Times New Roman" ) ); pPainter->GetFont()->SetFontSize( 24.0 ); printf("!!!!!!!!!!!!!!!\n"); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); pPainter->SetColor( 0.0, 0.0, 0.0 ); pPainter->DrawText( x, y, "Hallo Welt!" ); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); pPainter->GetFont()->SetUnderlined( true ); pPainter->SetStrokingColor( 1.0, 0.0, 0.0 ); pPainter->DrawText( x, y, "Underlined text in the same font!" ); pPainter->GetFont()->SetUnderlined( false ); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); pPainter->DrawText( x, y, "Disabled the underline again..." ); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); PdfFont* pFont = pDocument->CreateFont( "Arial" ); pFont->SetFontSize( 12.0 ); pPainter->SetFont( pFont ); pPainter->DrawText( x, y, "Normal" ); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); pPainter->GetFont()->SetUnderlined( true ); pPainter->DrawText( x, y, "Normal+underlinded" ); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); pPainter->GetFont()->SetUnderlined( false ); pFont->SetFontCharSpace( 100.0 ); pPainter->DrawText( x, y, "Mormal+spaced" ); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); pPainter->GetFont()->SetUnderlined( true ); pPainter->DrawText( x, y, "Normal+underlined+spaced" ); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); pPainter->GetFont()->SetUnderlined( false ); pFont->SetFontCharSpace( 0.0 ); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); pFont->SetFontScale( 50.0 ); pPainter->DrawText( x, y, "Condensed" ); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); pFont->SetFontCharSpace( 0.0 ); pPainter->GetFont()->SetUnderlined( true ); pPainter->DrawText( x, y, "Condensed+underlinded" ); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); pPainter->GetFont()->SetUnderlined( false ); pFont->SetFontCharSpace( 100.0 ); pPainter->DrawText( x, y, "Condensed+spaced" ); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); pPainter->GetFont()->SetUnderlined( true ); pPainter->DrawText( x, y, "Condensed+underlined+spaced" ); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); pPainter->GetFont()->SetUnderlined( false ); pFont->SetFontCharSpace( 0.0 ); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); pFont->SetFontScale( 200.0 ); pPainter->DrawText( x, y, "Expanded" ); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); pPainter->GetFont()->SetUnderlined( true ); pPainter->DrawText( x, y, "Expanded+underlinded" ); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); pPainter->GetFont()->SetUnderlined( false ); pFont->SetFontCharSpace( 100.0 ); pPainter->DrawText( x, y, "Expanded+spaced" ); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); pPainter->GetFont()->SetUnderlined( true ); pPainter->DrawText( x, y, "Expanded+underlined+spaced" ); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); pPainter->GetFont()->SetUnderlined( false ); pFont->SetFontCharSpace( 0.0 ); pFont->SetFontScale( 100.0 ); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); pPainter->GetFont()->SetStrikeOut( true ); pPainter->DrawText( x, y, "Strikeout" ); y -= pPainter->GetFont()->GetFontMetrics()->GetLineSpacing(); pPainter->GetFont()->SetUnderlined( false ); pPainter->DrawText( x, y, "PoDoFo rocks!" ); } void ImageTest( PdfPainter* pPainter, PdfPage* pPage, PdfDocument* pDocument ) { double y = pPage->GetPageSize().GetHeight() - 60000 * CONVERSION_CONSTANT; #ifdef PODOFO_HAVE_JPEG_LIB PdfImage image( pDocument ); #endif // PODOFO_HAVE_JPEG_LIB PdfRect rect( 0, 0, 50000 * CONVERSION_CONSTANT, 50000 * CONVERSION_CONSTANT ); PdfRect rect1( 80000 * CONVERSION_CONSTANT, 3000 * CONVERSION_CONSTANT, 20000 * CONVERSION_CONSTANT, 20000 * CONVERSION_CONSTANT ); PdfRect rect2( 40000 * CONVERSION_CONSTANT, y, 50000 * CONVERSION_CONSTANT, 50000 * CONVERSION_CONSTANT ); PdfXObject xObj( rect, pDocument ); PdfPainter pnt; // XObject painter #ifdef PODOFO_HAVE_JPEG_LIB image.LoadFromFile( "resources/lena.jpg" ); #endif // PODOFO_HAVE_JPEG_LIB pnt.SetPage( &xObj ); // Draw onto the XObject pnt.SetFont( pDocument->CreateFont( "Comic Sans MS" ) ); pnt.GetFont()->SetFontSize( 8.0 ); pnt.SetStrokingColor( 1.0, 1.0, 1.0 ); pnt.SetColor( 1.0, 1.0, 0.0 ); pnt.Rectangle( 0, 0, xObj.GetPageSize().GetWidth(), xObj.GetPageSize().GetHeight() ); pnt.Fill(); pnt.SetColor( 0.0, 0.0, 0.0 ); pnt.Rectangle( 0, 1000 * CONVERSION_CONSTANT, 1000 * CONVERSION_CONSTANT, 1000 * CONVERSION_CONSTANT ); pnt.Stroke(); pnt.DrawText( 0, 1000 * CONVERSION_CONSTANT, "I am a XObject." ); pnt.FinishPage(); printf("Drawing on the page!\n"); // Draw onto the page #ifdef PODOFO_HAVE_JPEG_LIB /* pPainter->DrawImage( 40000 * CONVERSION_CONSTANT, y, &image, 0.3, 0.3 ); pPainter->DrawImage( 40000 * CONVERSION_CONSTANT, y - (100000 * CONVERSION_CONSTANT), &image, 0.2, 0.5 ); pPainter->DrawImage( 40000 * CONVERSION_CONSTANT, y - (200000 * CONVERSION_CONSTANT), &image, 0.3, 0.3 ); */ pPainter->DrawImage( 0.0, pPage->GetPageSize().GetHeight() - image.GetHeight(), &image ); #endif // PODOFO_HAVE_JPEG_LIB pPainter->DrawXObject( 120000 * CONVERSION_CONSTANT, y - (50000 * CONVERSION_CONSTANT), &xObj ); pPainter->Rectangle( 120000 * CONVERSION_CONSTANT, y - (50000 * CONVERSION_CONSTANT), 1000 * CONVERSION_CONSTANT, 1000 * CONVERSION_CONSTANT ); pPainter->Fill(); PdfAnnotation* pAnnot1 = pPage->CreateAnnotation( ePdfAnnotation_Widget, rect1 ); PdfAnnotation* pAnnot2 = pPage->CreateAnnotation( ePdfAnnotation_Link, rect2 ); PdfAnnotation* pAnnot3 = pPage->CreateAnnotation( ePdfAnnotation_Text, PdfRect( 20.0, 20.0, 20.0, 20.0 ) ); PdfAnnotation* pAnnot4 = pPage->CreateAnnotation( ePdfAnnotation_FreeText, PdfRect( 70.0, 20.0, 250.0, 50.0 ) ); PdfAnnotation* pAnnot5 = pPage->CreateAnnotation( ePdfAnnotation_Popup, PdfRect( 300.0, 20.0, 250.0, 50.0 ) ); pAnnot1->SetTitle( PdfString("Author: Dominik Seichter") ); pAnnot1->SetContents( PdfString("Hallo Welt!") ); pAnnot1->SetAppearanceStream( &xObj ); PdfAction action( ePdfAction_URI, pDocument ); action.SetURI( PdfString("http://podofo.sf.net") ); //pAnnot2->SetDestination( pPage ); pAnnot2->SetAction( action ); pAnnot2->SetFlags( ePdfAnnotationFlags_NoZoom ); pAnnot3->SetTitle( "A text annotation" ); pAnnot3->SetContents( "Lorum ipsum dolor..." ); pAnnot4->SetContents( "An annotation of type ePdfAnnotation_FreeText." ); pAnnot5->SetContents( "A popup annotation." ); pAnnot5->SetOpen( true ); } void EllipseTest( PdfPainter* pPainter, PdfPage* pPage, PdfDocument* pDocument ) { PdfAnnotation* pFileAnnotation; double dX = 10000 * CONVERSION_CONSTANT; double dY = pPage->GetPageSize().GetHeight() - 40000 * CONVERSION_CONSTANT; pPainter->SetStrokingColor( 0.0, 0.0, 0.0 ); pPainter->Ellipse( dX, dY, 20000 * CONVERSION_CONSTANT, 20000 * CONVERSION_CONSTANT ); pPainter->Stroke(); dY -= 30000 * CONVERSION_CONSTANT; pPainter->SetColor( 1.0, 0.0, 0.0 ); pPainter->Ellipse( dX, dY, 20000 * CONVERSION_CONSTANT, 20000 * CONVERSION_CONSTANT ); pPainter->Fill(); PdfFileSpec file( "resources/lena.jpg", true, pDocument ); pFileAnnotation = pPage->CreateAnnotation( ePdfAnnotation_FileAttachement, PdfRect( 300.0, 400.0, 250.0, 50.0 ) ); pFileAnnotation->SetContents( "A JPEG image of Lena" ); pFileAnnotation->SetFileAttachement( file ); } void XObjectTest( PdfPainter* pPainter, PdfPage* pPage, PdfDocument* pDocument ) { double x = 10000 * CONVERSION_CONSTANT; double y = pPage->GetPageSize().GetHeight() - 10000 * CONVERSION_CONSTANT; const double dWidth = 180000 * CONVERSION_CONSTANT; // 18cm const double dHeight = 270000 * CONVERSION_CONSTANT; // 27cm pPainter->SetColor( 1.0, 0.8, 0.8 ); pPainter->Rectangle( x, y - dHeight, dWidth, dHeight ); pPainter->Fill(); // Das funktioniert immer PdfXObject xObj1( "resources/Illust.pdf", 0, pDocument ); pPainter->DrawXObject( x + 90000 * CONVERSION_CONSTANT, y - dHeight, &xObj1 ); pPainter->SetColor( 1.0, 0.0, 0.0 ); pPainter->Rectangle( x + 90000 * CONVERSION_CONSTANT, y - dHeight, 1000 * CONVERSION_CONSTANT, 1000 * CONVERSION_CONSTANT ); pPainter->Fill(); // Test XObject in XObject PdfRect rectX( 0, 0, 50000 * CONVERSION_CONSTANT, 50000 * CONVERSION_CONSTANT ); PdfXObject xObj3( rectX, pDocument ); PdfXObject xObj4( rectX, pDocument ); // Draw text onto the XObject3 pPainter->SetPage( &xObj3 ); pPainter->SetColor( 0.0, 1.0, 0.0 ); pPainter->Rectangle( 0.0, 0.0, rectX.GetWidth(), rectX.GetHeight() ); pPainter->Fill(); pPainter->SetFont( pDocument->CreateFont( "Comic Sans MS" ) ); pPainter->SetColor( 0.0, 0.0, 0.0 ); pPainter->DrawText( 0, 1000 * CONVERSION_CONSTANT, "I am XObject 3." ); pPainter->FinishPage(); // Draw text and pdf onto the XObject4 pPainter->SetPage( &xObj4 ); pPainter->SetColor( 0.0, 1.0, 0.0 ); pPainter->Rectangle( 0.0, 0.0, rectX.GetWidth(), rectX.GetHeight() ); pPainter->Fill(); pPainter->SetFont( pDocument->CreateFont( "Comic Sans MS" ) ); pPainter->SetColor( 0.0, 0.0, 0.0 ); pPainter->DrawText( 0, 1000 * CONVERSION_CONSTANT, "I am XObject 4." ); PdfXObject xObj5( "resources/Illust.pdf", 0, pDocument ); pPainter->DrawXObject( 5000 * CONVERSION_CONSTANT, 5000 * CONVERSION_CONSTANT, &xObj5, 0.1, 0.1 ); pPainter->FinishPage(); // Switch back to page and draw Xobject 3+4 pPainter->SetPage( pPage ); pPainter->DrawXObject( 20000 * CONVERSION_CONSTANT, y - 60000 * CONVERSION_CONSTANT, &xObj3 ); pPainter->DrawXObject( 120000 * CONVERSION_CONSTANT, y - 60000 * CONVERSION_CONSTANT, &xObj4 ); } void MMTest( PdfPainterMM* pPainter, PdfPage* pPage, PdfDocument* pDocument ) { long lX = 10000; long lY = static_cast(pPage->GetPageSize().GetHeight()/CONVERSION_CONSTANT) - 40000; pPainter->SetStrokingColor( 0.0, 0.0, 0.0 ); pPainter->EllipseMM( lX, lY, 20000, 20000 ); pPainter->Stroke(); lY -= 30000; pPainter->SetColor( 1.0, 0.0, 0.0 ); pPainter->EllipseMM( lX, lY, 20000, 20000 ); pPainter->Fill(); lY -= 60000; // let's test out the opacity features PdfExtGState trans( pDocument ); trans.SetFillOpacity( 0.5 ); pPainter->SetExtGState( &trans ); pPainter->SetColor( 1.0, 0.0, 0.0 ); pPainter->EllipseMM( lX, lY, 20000, 20000 ); pPainter->Fill(); pPainter->SetColor( 0.0, 1.0, 0.0 ); pPainter->EllipseMM( lX+20000, lY, 20000, 20000 ); pPainter->Fill(); pPainter->SetColor( 0.0, 0.0, 1.0 ); pPainter->EllipseMM( lX+10000, lY-10000, 20000, 20000 ); pPainter->Fill(); } void TableTest( PdfPainter* pPainter, PdfPage* pPage, PdfDocument* pDocument ) { int i,z; double dX = 10000 * CONVERSION_CONSTANT; double dY = (pPage->GetPageSize().GetHeight() - 40000 * CONVERSION_CONSTANT); PdfFont* pFont = pDocument->CreateFont( "Comic Sans MS" ); pFont->SetFontSize( 12.0f ); pPainter->SetFont( pFont ); const int nCols = 3; const int nRows = 10; PdfSimpleTableModel model( nCols, nRows ); for(i=0;iGetPageSize().GetHeight()/2.0 - 30000 * CONVERSION_CONSTANT; dX = 2000.0 * CONVERSION_CONSTANT; const int nCols2 = 5; const int nRows2 = 4; PdfSimpleTableModel model2( nCols2, nRows2 ); model2.SetAlignment( ePdfAlignment_Center ); model2.SetBackgroundColor( PdfColor( 0.3 ) ); model2.SetBackgroundEnabled( true ); for(i=0;iGetPageSize().GetHeight() - 10000 * CONVERSION_CONSTANT; PdfFont* pFont; const double dWidth = 100000 * CONVERSION_CONSTANT; // 10cm const double dHeight = 50000 * CONVERSION_CONSTANT; // 5cm y -= dHeight; pFont = pDocument->CreateFont( "Arial" ); if( !pFont ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } pFont->SetFontSize( 48.0 ); pPainter->SetFont( pFont ); pPainter->SetStrokeWidth( 100 * CONVERSION_CONSTANT ); pPainter->SetStrokingColor( 0.0, 0.0, 0.0 ); pPainter->Rectangle( x, y, dWidth, dHeight ); pPainter->Stroke(); PdfString sMultiLine("PoDoFo is a library to work with the PDF file format and includes also a few tools. The name comes from the first three letters of PDF (Portable Document Format)."); pPainter->DrawMultiLineText( x, y, dWidth, dHeight, sMultiLine, ePdfAlignment_Left, ePdfVerticalAlignment_Top ); y = y - dHeight - dHeight / 2.0; pPainter->Rectangle( x, y, dWidth, dHeight ); pPainter->Stroke(); pFont->SetFontSize( 12.0 ); pPainter->DrawMultiLineText( x, y, dWidth, dHeight, sMultiLine, ePdfAlignment_Left, ePdfVerticalAlignment_Top ); y = y - dHeight - dHeight / 2.0; pPainter->Rectangle( x, y, dWidth, dHeight ); pPainter->Stroke(); pFont->SetFontSize( 16.0 ); pPainter->DrawMultiLineText( x, y, dWidth, dHeight, sMultiLine, ePdfAlignment_Left, ePdfVerticalAlignment_Center ); y = y - dHeight - dHeight / 2.0; pPainter->Rectangle( x, y, dWidth, dHeight ); pPainter->Stroke(); pFont->SetFontSize( 32.0 ); pPainter->DrawMultiLineText( x, y, dWidth, dHeight, PdfString("PoDoFo is spelled without a g."), ePdfAlignment_Left, ePdfVerticalAlignment_Bottom ); } void FontSubsetTest( PdfPainter* pPainter, PdfPage* pPage, PdfDocument* pDocument ) { double x = 10000 * CONVERSION_CONSTANT; double y = pPage->GetPageSize().GetHeight() - 10000 * CONVERSION_CONSTANT; PdfFont* pFont; const double dHeight = 50000 * CONVERSION_CONSTANT; // 5cm y -= dHeight; PdfEncoding* pEncoding = new PdfIdentityEncoding(); pFont = pDocument->CreateFontSubset( "Verdana", false, false, false, pEncoding ); if( !pFont ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } pFont->SetFontSize( 16.0 ); pPainter->DrawText(x, y, "Hello World!"); y -= dHeight; pFont->SetFontSize( 32.0 ); pPainter->DrawText(x, y, "Subsetting in action!"); } int main( int argc, char* argv[] ) { try { PdfMemDocument writer; //PdfStreamedDocument writer ( argv[1], ePdfVersion_1_5, &PdfEncrypt( "dominik", "owner" ) ); PdfPage* pPage; PdfPainter painter; PdfPainterMM painterMM; PdfOutlines* outlines; PdfOutlineItem* pRoot; if( argc != 2 ) { printf("Usage: CreationTest [output_filename]\n"); return 0; } printf("This test tests the PdfWriter and PdfDocument classes.\n"); printf("It creates a new PdfFile from scratch.\n"); printf("---\n"); printf("PoDoFo DataType Size Information:\n"); printf("---\n"); printf("sizeof variant=%lu\n", sizeof(PdfVariant) ); printf("sizeof object=%lu\n", sizeof(PdfObject) ); printf("sizeof reference=%lu\n", sizeof(PdfReference) ); printf("---\n\n"); outlines = writer.GetOutlines(); pRoot = outlines->CreateRoot("PoDoFo Test Document" ); pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); painter.SetPage( pPage ); pRoot->CreateChild( "Line Test", PdfDestination( pPage ) ); printf("Drawing the first page with various lines.\n"); TEST_SAFE_OP( LineTest( &painter, pPage, &writer ) ); pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_Letter ) ); painter.SetPage( pPage ); PdfString sLoremIpsum( pszLoremIpsum ); painter.DrawMultiLineText( 50.0, 50.0, pPage->GetMediaBox().GetWidth() - 100.0, pPage->GetMediaBox().GetHeight() - 100.0, sLoremIpsum ); painter.FinishPage(); pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_Letter ) ); painter.SetPage( pPage ); pRoot->Last()->CreateNext( "Rectangles Test", PdfDestination( pPage ) ); printf("Drawing the second page with various rectangle and triangles.\n"); TEST_SAFE_OP( RectTest( &painter, pPage, &writer ) ); pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); painter.SetPage( pPage ); pRoot->Last()->CreateNext( "Text Test", PdfDestination( pPage ) ); printf("Drawing some text.\n"); TEST_SAFE_OP( TextTest( &painter, pPage, &writer ) ); pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); painter.SetPage( pPage ); pRoot->Last()->CreateNext( "Image Test", PdfDestination( pPage ) ); printf("Drawing some images.\n"); TEST_SAFE_OP( ImageTest( &painter, pPage, &writer ) ); pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); painter.SetPage( pPage ); pRoot->Last()->CreateNext( "Circle Test", PdfDestination( pPage ) ); printf("Drawing some circles and ellipsis.\n"); TEST_SAFE_OP( EllipseTest( &painter, pPage, &writer ) ); painter.FinishPage(); printf("Drawing some XObject's.\n"); pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); painter.SetPage( pPage ); TEST_SAFE_OP( XObjectTest( &painter, pPage, &writer ) ); painter.FinishPage(); printf("Drawing using PdfTable.\n"); pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); painter.SetPage( pPage ); pRoot->Last()->CreateNext( "PdfTable Test", PdfDestination( pPage ) ); TEST_SAFE_OP( TableTest( &painter, pPage, &writer ) ); painter.FinishPage(); printf("Drawing using PdfPainterMM.\n"); pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); painterMM.SetPage( pPage ); pRoot->Last()->CreateNext( "MM Test", PdfDestination( pPage ) ); TEST_SAFE_OP( MMTest( &painterMM, pPage, &writer ) ); painterMM.FinishPage(); printf("Drawing using PdfPainter MultilineText.\n"); pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); painter.SetPage( pPage ); pRoot->Last()->CreateNext( "Large MultilineText Test", PdfDestination( pPage ) ); TEST_SAFE_OP( LargeMultiLineTextTest( &painter, pPage, &writer ) ); painter.FinishPage(); printf("Drawing using Font Subset.\n"); pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); painter.SetPage( pPage ); pRoot->Last()->CreateNext( "Font Subset Test", PdfDestination( pPage ) ); TEST_SAFE_OP( FontSubsetTest( &painter, pPage, &writer ) ); painter.FinishPage(); #if 0 /** Create a really large name tree to test the name tree implementation */ for( int zz=1;zz<500;zz++ ) { std::ostringstream oss; oss << "A" << zz; writer.GetNamesTree()->AddValue( "TestDict", PdfString( oss.str() ), PdfVariant( static_cast(zz) ) ); } writer.GetNamesTree()->AddValue( "TestDict", PdfString( "Berta" ), PdfVariant( 42L ) ); #endif printf("Setting document informations.\n\n"); // Setup the document information dictionary TEST_SAFE_OP( writer.GetInfo()->SetCreator ( PdfString("CreationTest - A simple test application") ) ); TEST_SAFE_OP( writer.GetInfo()->SetAuthor ( PdfString("Dominik Seichter") ) ); TEST_SAFE_OP( writer.GetInfo()->SetTitle ( PdfString("Test Document") ) ); //TEST_SAFE_OP( writer.GetInfo()->SetSubject ( PdfString("Testing the PDF Library") ) ); TEST_SAFE_OP( writer.GetInfo()->SetSubject ( PdfString(reinterpret_cast("「PoDoFoã€ã¯ä»Šã‹ã‚‰æ—¥æœ¬èªžã‚‚話ã›ã¾ã™ã€‚") ) ) ); TEST_SAFE_OP( writer.GetInfo()->SetKeywords( PdfString("Test;PDF;") ) ); //xTEST_SAFE_OP( writer.AttachFile( PdfFileSpec("../../../podofo/test/CreationTest/CreationTest.cpp", true, &writer ) ) ); TEST_SAFE_OP( writer.Write( argv[1] ) ); //TEST_SAFE_OP( writer.Close() ); #ifdef TEST_MEM_BUFFER // --- const char* pszMemFile = "./mem_out.pdf"; FILE* hFile; PdfRefCountedBuffer buffer; PdfOutputDevice device( &buffer ); printf("Writing document from a memory buffer to: %s\n", pszMemFile ); TEST_SAFE_OP( writer.Write( &device ) ); hFile = fopen( pszMemFile, "wb" ); if( !hFile ) { fprintf( stderr, "Cannot open file %s for writing.\n", pszMemFile ); return ePdfError_InvalidHandle; } long lBufferLen = device.GetLength(); printf("lBufferLen=%li\n", lBufferLen ); printf("Wrote=%i\n", static_cast(fwrite( buffer.GetBuffer(), lBufferLen, sizeof( char ), hFile )) ); fclose( hFile ); #endif } catch( PdfError & e ) { std::cerr << "Error: An error " << e.GetError() << " ocurred." << std::endl; e.PrintErrorMsg(); return e.GetError(); } return 0; } podofo-0.9.5/test/CreationTest/resources/0000775000175000017500000000000013044451156020263 5ustar dominikdominikpodofo-0.9.5/test/CreationTest/resources/Illust.pdf0000664000175000017500000063660610714372313022251 0ustar dominikdominik%PDF-1.4 %âãÏÓ 1 0 obj <> endobj 34 0 obj <>stream application/pdf Illust Adobe Illustrator CS3 2007-09-05T11:52:56+02:00 2007-09-05T11:52:56+02:00 2007-09-05T11:52:56+02:00 200 256 JPEG /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAADIAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq 7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq 7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq 7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXkv/OT+oX9h+VstxY3 MtpP9dtl9aB2jehLVHJSDhCvj7/GfnD/AKvuof8ASVP/AM14Uu/xn5w/6vuof9JU/wDzXirv8Z+c P+r7qH/SVP8A814q+pP+cSNW1TUvKetyajeT3kiX6qj3EjylR6KmgLk0wFD1Hzh5V1rWpbW40jXp 9EubVJUBjEskMnqsn97Cs0KPREdQT8S8uSlWAOBWPXv5befJbLSIrTz7dWl5pcTRvei3klM5ITgZ YnuTFJxKb+ssjMCfirviqqfIX5kzPaSXn5gSytbXUV06xafHbJIqGUPEywzKSjJIgCuWWqcirE7K ss8sabr2naWLfXNYOuah6ju199XitBwY1RBFFVQEG1aknFU2xV2KuxV2KuxV2KuxV2KuxV2KuxV2 KuxV2KuxV2KvHf8AnK3/AMlNL/zHW362whXxdhS7FXYq+sv+cOP+UP17/toL/wAmFwFBfQOBXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq82/5yC8oeYvNn5eSaR5ftPruoNdwSiD1 IovgQnkeUzRrtXxxCvmL/oWv86/+pc/6fbD/AKr4bS7/AKFr/Ov/AKlz/p9sP+q+Nq7/AKFr/Ov/ AKlz/p9sP+q+Nq+hf+cavIPm3yZ5b1az8y2H1C5urxZoI/Vhm5IIlWtYXkA3HfEoew4FdirsVdir sVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs VdirsVdirsVdirsVdirsVdirsVdirBLv86/IlhPFZ6pPPp+p3EssNrp0sDyTymKeS2qv1f1owryw sF5OPemKpiv5oeRyvNtSVF4hwSjk8Wthd1IUMV/dN+1TeoG+Ksmt7iK5t4riFuUMyLJG1CKqwqDQ 0I2PfFVTFXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FVO5tra6t5La5 iSe3mUpNDIodHRhRlZWqCCOoOKr0RERURQqKAFUCgAHQAYq3irsVdirsVdirsVdirsVdirsVdirs VdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsV dirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVd irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir/9k= uuid:CBF2C183945BDC1192F7ABDCFD1A3597 uuid:875c03d0-1825-4840-951a-7b833c396f5e uuid:CAF2C183945BDC1192F7ABDCFD1A3597 uuid:C8F2C183945BDC1192F7ABDCFD1A3597 EmbedByReference T:\d904\d4\TEST1.PDF Print 1 False False 110.000004 100.000001 Millimeters Times-Roman Times Roman Type 1 002.000 False TIR_____.PFB; TIR_____.PFM PBAAAA+Courier PBAAAA+Courier Unknown Version 2.007;PS 002.000;Core 1.0.38;makeotf.lib1.7.9032 False MyriadPro-Regular.otf Cyan Magenta Yellow Black Standard-Farbfeldgruppe 0 Weiß CMYK PROCESS 0.000000 0.000000 0.000000 0.000000 Schwarz CMYK PROCESS 0.000000 0.000000 0.000000 100.000000 CMYK Rot CMYK PROCESS 0.000000 100.000000 100.000000 0.000000 CMYK Gelb CMYK PROCESS 0.000000 0.000000 100.000000 0.000000 CMYK Grün CMYK PROCESS 100.000000 0.000000 100.000000 0.000000 CMYK Cyan CMYK PROCESS 100.000000 0.000000 0.000000 0.000000 CMYK Blau CMYK PROCESS 100.000000 100.000000 0.000000 0.000000 CMYK Magenta CMYK PROCESS 0.000000 100.000000 0.000000 0.000000 C=15 M=100 Y=90 K=10 CMYK PROCESS 14.999998 100.000000 90.000004 10.000002 C=0 M=90 Y=85 K=0 CMYK PROCESS 0.000000 90.000004 84.999996 0.000000 C=0 M=80 Y=95 K=0 CMYK PROCESS 0.000000 80.000001 94.999999 0.000000 C=0 M=50 Y=100 K=0 CMYK PROCESS 0.000000 50.000000 100.000000 0.000000 C=0 M=35 Y=85 K=0 CMYK PROCESS 0.000000 35.000002 84.999996 0.000000 C=5 M=0 Y=90 K=0 CMYK PROCESS 5.000001 0.000000 90.000004 0.000000 C=20 M=0 Y=100 K=0 CMYK PROCESS 19.999999 0.000000 100.000000 0.000000 C=50 M=0 Y=100 K=0 CMYK PROCESS 50.000000 0.000000 100.000000 0.000000 C=75 M=0 Y=100 K=0 CMYK PROCESS 75.000000 0.000000 100.000000 0.000000 C=85 M=10 Y=100 K=10 CMYK PROCESS 84.999996 10.000002 100.000000 10.000002 C=90 M=30 Y=95 K=30 CMYK PROCESS 90.000004 30.000001 94.999999 30.000001 C=75 M=0 Y=75 K=0 CMYK PROCESS 75.000000 0.000000 75.000000 0.000000 C=80 M=10 Y=45 K=0 CMYK PROCESS 80.000001 10.000002 44.999999 0.000000 C=70 M=15 Y=0 K=0 CMYK PROCESS 69.999999 14.999998 0.000000 0.000000 C=85 M=50 Y=0 K=0 CMYK PROCESS 84.999996 50.000000 0.000000 0.000000 C=100 M=95 Y=5 K=0 CMYK PROCESS 100.000000 94.999999 5.000001 0.000000 C=100 M=100 Y=25 K=25 CMYK PROCESS 100.000000 100.000000 25.000000 25.000000 C=75 M=100 Y=0 K=0 CMYK PROCESS 75.000000 100.000000 0.000000 0.000000 C=50 M=100 Y=0 K=0 CMYK PROCESS 50.000000 100.000000 0.000000 0.000000 C=35 M=100 Y=35 K=10 CMYK PROCESS 35.000002 100.000000 35.000002 10.000002 C=10 M=100 Y=50 K=0 CMYK PROCESS 10.000002 100.000000 50.000000 0.000000 C=0 M=95 Y=20 K=0 CMYK PROCESS 0.000000 94.999999 19.999999 0.000000 C=25 M=25 Y=40 K=0 CMYK PROCESS 25.000000 25.000000 39.999998 0.000000 C=40 M=45 Y=50 K=5 CMYK PROCESS 39.999998 44.999999 50.000000 5.000001 C=50 M=50 Y=60 K=25 CMYK PROCESS 50.000000 50.000000 60.000002 25.000000 C=55 M=60 Y=65 K=40 CMYK PROCESS 55.000001 60.000002 64.999998 39.999998 C=25 M=40 Y=65 K=0 CMYK PROCESS 25.000000 39.999998 64.999998 0.000000 C=30 M=50 Y=75 K=10 CMYK PROCESS 30.000001 50.000000 75.000000 10.000002 C=35 M=60 Y=80 K=25 CMYK PROCESS 35.000002 60.000002 80.000001 25.000000 C=40 M=65 Y=90 K=35 CMYK PROCESS 39.999998 64.999998 90.000004 35.000002 C=40 M=70 Y=100 K=50 CMYK PROCESS 39.999998 69.999999 100.000000 50.000000 C=50 M=70 Y=80 K=70 CMYK PROCESS 50.000000 69.999999 80.000001 69.999999 Druckfarben 1 C=0 M=30 Y=70 K=0 CMYK PROCESS 0.000000 30.000001 69.999999 0.000000 C=5 M=70 Y=90 K=0 CMYK PROCESS 5.000001 69.999999 90.000004 0.000000 C=5 M=90 Y=75 K=0 CMYK PROCESS 5.000001 90.000004 75.000000 0.000000 C=30 M=0 Y=95 K=0 CMYK PROCESS 30.000001 0.000000 94.999999 0.000000 C=60 M=5 Y=95 K=0 CMYK PROCESS 60.000002 5.000001 94.999999 0.000000 C=30 M=0 Y=10 K=0 CMYK PROCESS 30.000001 0.000000 10.000002 0.000000 C=60 M=10 Y=5 K=0 CMYK PROCESS 60.000002 10.000002 5.000001 0.000000 C=80 M=5 Y=10 K=0 CMYK PROCESS 80.000001 5.000001 10.000002 0.000000 Graustufen 1 K=100 GRAY PROCESS 255 K=90 GRAY PROCESS 229 K=80 GRAY PROCESS 203 K=70 GRAY PROCESS 178 K=60 GRAY PROCESS 152 K=50 GRAY PROCESS 127 K=40 GRAY PROCESS 101 K=30 GRAY PROCESS 76 K=20 GRAY PROCESS 50 K=10 GRAY PROCESS 25 K=5 GRAY PROCESS 12 Adobe PDF library 8.00 endstream endobj 2 0 obj <> endobj 5 0 obj <>/ArtBox[0.0 37.5566 311.811 283.465]/MediaBox[0.0 0.0 311.811 283.465]/Thumb 33 0 R/TrimBox[0.0 0.0 311.811 283.465]/Resources<>/ProcSet[/PDF/Text]/Properties<>>>/ExtGState<>>>/Type/Page/LastModified(D:20070905115214+02'00')>> endobj 27 0 obj <>stream H‰\ÐMKÄ@ à{~Å{l›Næ«3×®‹øÑÃâ€ÙC]ÔuŶ‚þ{g*."¹„ä!i®w_Ȧ_+tgkB ÁË)»"‹Ôœß(ì'1l=$jŽ:b…Å·ð–c°êè=ÏêPÚŒ¬~ ¹ãGê5I Iô¦!&²·ÆCÛÀÖFôJwUª[U µ¸êsÆÅáð1Íãn~ëûtI›DÛ5-;מLmGþù‚…•ÿ¬Q¬C›ËË ï‹Z¥ašŸŽû:=bÓç÷lé[€øB® endstream endobj 33 0 obj <>stream 8;Xp,Sc4.*)[TicNm'rog=k71E(m?92ulcQ)ic@)9*NFKPa\G.j>%(e)X;hR$jPE# UL4eo#64c/!.r#_l2~> endstream endobj 20 0 obj <> endobj 23 0 obj <> endobj 25 0 obj <> endobj 26 0 obj <> endobj 30 0 obj <>stream H‰4‘mLSgÇŸÛr{ Ö[äZMzõÞ»`æ+Ö"È4¾´ŠÍ\`.B·‘‰åEq-méÄ €¦C(©¨¡’e)q‘Ect·»K2’eˆˆ ñ%3J\²ž‡Á0š ÉÇDGØl²‚,Ö ºgúb[ Hÿ¼ëÞÍø™©}F‘%&Æår%õúE )x³ÞkÈ4±Ù±Q&;1Ë€: ´›ˆ–ù¯9n Ô (Üdx®û ™Î²CµœÅp×!Èü24|u„Ÿºð¥E$žxÁ%gÃYæOÏ]’¼5¿¢ø ›cØ:ÙëÃ+åSߦ>¿r( ‘Aw” sçpDõMá–Þ°¡§½'ð½Àõ–h·¿¹¹o®ÅÐWÕg켕$4V7Ž|'rý/ü#'>1ìN?²gcæÀäI¡¸…æ*ƒÎ6—ÓPã÷5ù®?rŠîk žïä~»Xlá‚îÒ ¨ ´µ‹\oz óì¸áÆDø÷‰^K‡0÷ÛW²v¥‚IáÆ¸A0á[znŒð;ìwH€ùàAùÓ‰û{ÿš#tIZQc ¿ÑþW„JÉ$ÄÄx†­íÆÃÝÄø#»ƒ­Ò@Sçã`Ì †%Y™g½`02ƒã endstream endobj 24 0 obj <> endobj 29 0 obj <>stream H‰‘kPwÅw É2­Ë”]Ý][ñ j±°Lg¨¨0U¤€Ÿåµ”Hh^Iyä (ÏDA UÐÒ"BKE©Ò±ãø™ÁÚÖi­uêô¿úçC÷ÃïÙsEüýEñø´ôƒ‡’6§r…¬"u§–rÁ±ìQCKÌ'aqúÒ÷Í”œ²ºøgÃh‡p/ç^ŧ»$‘µz×-‚o˜À€_¯ú¹é.QøP8?-ª‚ »Díìq?rbÞ$Š5)·ÕP%à2&ž3üªÕ ¦+èüã=À†‡øKpJ MúUm,(W‘¹Ò¾QÚŽ}Õü=ØQ—(Á¾_þ¿ñûŸm|'žM§};Áóg -ÆAwgñ黳’­)Õ@é@¥K·su· ¼¨°þKc]>ÝÕ”÷5Ùåpu»9–+Ž;J›UÛ…¸çpñ!Íam€³76Ûäi—%‰÷:ëÕüþ3Æâ +×[7s¤? nŸ$xS X-¬áÞSu¥±´ ã3rSFBJìdîõ<ï™:!ì×t(ò‰ä£ZncÉÜU=¥á,ÜÖŠá='ëj[H[ïHÉeòæÃá¹ky½‡½4î…ÈMang•§ƒ8뜼tYÚI‰c ãü’~tfVø4É: j°ÖWR¹i:› R©ªô„Én²[¨«pB´~¨èÊ7£#]Ty³°¼B£Ê'Ó­?öÑ`ðLl˜âÔ#o úyì™ÅÛð^1&9`6Ÿ9G€?aD)6c®SgxÔc'* Æ/)UQaY!™`¼î Á}¸® óšûÍX­¹§jÿ¶npÂu##Â(Ìnm»à˜p„ˆ}½xÕ ÊÔBa(Ÿ3@þ˜¼#©«nÑëµ±¦Àâ«é˜+µÙØ)¸¤¯Ä_>KZ½Þ[ˆFè°6Ë‹š¨¨2&n§JŠË¯69 º (¬"àl˜×Ù°Þ7fßäMËÁ+Éÿ ;^' endstream endobj 31 0 obj [/Indexed/DeviceRGB 255 32 0 R] endobj 32 0 obj <>stream 8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn 6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 6 0 obj <> endobj 7 0 obj <> endobj 8 0 obj <>stream %!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 13.0 %%AI8_CreatorVersion: 13.0.0 %%For: (rmi) () %%Title: (Illust.ai) %%CreationDate: 9/5/2007 11:51 AM %%BoundingBox: -70 37 543 830 %%HiResBoundingBox: -69.7129 37.5566 542.2871 829.5562 %%DocumentProcessColors: Cyan Magenta Yellow Black %%DocumentFiles:T:\d904\d4\TEST1.PDF %AI5_FileFormat 9.0 %AI12_BuildNumber: 409 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%CMYKProcessColor: 1 1 1 1 ([Passermarken]) %AI3_TemplateBox: 156.5 140.9648 156.5 140.9648 %AI3_TileBox: -141.6948 -279.1377 453.3252 562.7227 %AI3_DocumentPreview: None %AI5_ArtSize: 311.811 283.4646 %AI5_RulerUnits: 1 %AI9_ColorModel: 2 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 1 %AI9_OpenToView: -49 283.4648 3.17 1321 917 18 0 0 44 93 0 0 1 1 1 0 1 %AI5_OpenViewLayers: 7 %%PageOrigin:0 0 %AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 18 0 obj <>stream H‰œWÛVâÊ}?cœˆl›ÊM B{ÅÖöR$(IR±’´­ß³¿a?·þ±³’@„€ûAGHV­Ûœ5Wý…™ÁˆnõU$v¸Øÿ³õ˜ä Ýâ" dYŒôm › ‰ÉqÊÖ-dª¯°TTb ){›í/13¨I>z»ÄH]²T‘®kø+ ?c âXG}Ëc³È—¸Ò‰DeÜ;}°`…d›Õ¢â/,z¦}‹X“%ÉxzQê®­Œ¡k:~%²5\•¾˜è ]eÇð€˜[™W U)ë#f5Ùµ„Îa™*J\ÅŠµ¾µEõ ¿à»O-@glŸ]j¯!62ç2_ÃzšùƳ™¯aþ!óEà(º—Uƒ)T·Ì M€P36Íh›q[ŠŠ,ldž{ÉE¦¿8‡Tµg”Ú_b:ødºÄP¢:lTË¿ýF¥ Ât„|2™™s{:µ¨õ®S¹…gj_\ÒâN+1û…%í-P§–Ôb66-p¾‘Jq玺r¼oωDš/šor"•l Ô•ë`Ë68éX›eÒ;ð7gØBúÀ5àΩaSÇ¥ªçY§õUž#:çÄÑ]¿Ÿ '#€ ±7.Ï%¾SëK”ÉX뜀uÛzÇðF!:8‚…tDÅ®ÇïHÃ-vÊ9ëçãî5TÕvÅŠ²š sAT‘úD…gìc•[4KÀS’óaeC¦…Ù. ®¸>R‘.­©Úà)íätf[†mU©.»ª!CljB&è.©g6 f Ûlÿæ!¦º9»ƒ>³ÓA«Í!wé@Þ]Ýæ.çwUfáôÛÙ¦:é«n"'tCrð}`€ß€»6±`$1Ìñ¶¢þùÇ´õÁýÊ®¸®ë^qðÝÅÌš8^Œ»°êÌ–€¤–´3íу:S·¡K@hÂ9U‰ô¶>Ô¶œ¹Êy"bþ@ÀœÈ,«8fèmZó']Å]L/ê*,.~ð3E€êŒj<³^)]®KKW +gëÒ¥­é˜Í¬ ¬4„e¸:`§D—§Aƒ©µxY«–»¹Ò3añô‰”A¤ðÅŽ—í#«…Þ0 šCËʼ°èâŠLçš;%ãÇÞ~Ð.5Öé0i®‹OAÙ~b~°Ø|ÜwŸµ&pÓÎ)Õ§ÐAeŸùcv Œ¥´Ënˆa}ž5•éÒ;Ú¿Íjp`]š:âNÓuxZíéáþ5Á¯+./þŠ.#ZNµ=üñè¾4TàØi? "Lï&éý•’Ð…Ý!ïA§F¿•‚aàuT£c!]Fl]šÛ3;n‰ì{ËçF3#›©ÀÝÒ±ûÎþ„›Á¥3$ÖÙšÎLDîm­¯#¢®Ó~÷ ‹™ƒV÷ÍÀkàÔ¿‹†õÌÕ (1ŸsÿjªONwkãòa®KÄ&eÑÎÃ>kxt;úH¢Ö®bªá˜ƒl6tÅçTäN@¦søç­pᙳú®¿)Â÷p¹Á&gÕ9™`Îÿ€‰X¡°Îõ1Ñ¸Ž‰—%ƒ€û¬?èI8¤šä±+Ò‘{߉sט½bNâ\œCsµY×1¾O¾ržÓøó7p×¹ùÌá5÷^ƒ[Ô0Ï`tÀ¦q¯°ú=Î q®¡~dàdd,å´?ÿHCçÁõáüAVƒ?ÿS-÷°q–ùþŠ¥‘kà¥bë}ÅjÉ? `N¬oås·Ç–ø|/dnwc¼F[&ßèXÃh9²ëbf³'<«á„•d³¿ÐÛfîPÉ]_Üýä»Õøõò¨³vùûJqT¿¯ä͸c[v=r,+ÆíWý ôUTî{9A­¨7yEZÕaî6õ¡#OÛ¢”j½TŠGážç’6«ƒ OÛ/bCnl»Ï›|g7¤{IÜ Ù†0‡Ï‘¨T“ö/"Õaæ±Pä·ö¶£Â÷ØS´R _Õ«ØþV¾n††IB#ç‰DkJkè…N%(ÇÈæSž<4eAÝ: ï²èO›ou¶_œv*…æpÂd ×÷^—ÂZ´Ô.$rÚÏÉ妲Ç3©‘ŠŽò©‰KIlš×й\çz{I9Oª  §Ú¥Èn jî\ójøÑÚªTÅP¯;Ü7lwÙP9W¥Ñâµ|—O÷C÷®ß²¾%•³ßB,wÙ^öBwZUF;ÙÝ1A¯åV2uj‹ TÜ®oDo™&ë|xp½¸&&Ùÿ«‘qDËõâø©Ø«zöÕXíÉó–þ‘nƒo’Ñr¹K‹GƒÒØQ¯T,ÈÏß\4'ƒ¿3aßVBs’Âý4…T¤téXáŒûnCÝvƒže²·Ùg‰ïŠÏQQIœ¾Ô o ÙþÕEñD|,óÝ¡dñç›R›ï¦÷ ð¹û!X$ßÖnžŽìI—<ò~`ëÃhêí@³´TT:5Ùm)øE;Ñr¨ÐóPr­ºÖ_|·iÙŸ»9‡æLë}ôo؆ó®ëhÚKœðó­²/q=²mìT‡ÙËÛZ?Yü&bÆbI|^*L2ñ:2iGë˜l¦\ÎwŸêΖ=‹ç«€‡êAçE;åÏ„v½ª4’©Ó¾\¯ÊÚWIàp,¨ÙRoêדBäJ•˜$ëJçîÝyz'Ô8™ÖUÀùm öôÿi¯ÎíTµ-ü,ÆÞbAQc‹cÀ–èûŸµH1fß}Ç=÷C˜“Y¿Ùºa²f”ªëw­»)èi@õK‘êu¾9°½EOî©hPƒ5œUš§3P^—¢P߀šR4%L­ˆœ…Ø©…‰œ|‰¿ÂZ»îP¡èK£M&A ôJ*ÈvõsÄÉ'/k ³ùîG$Á6F½#Pãèèw†9£äíŠtQÒ® ð*|w„®(ÎÞähÀÇ-(­Üêz‡dÐ\“ÇñyŒÕêIˆ)k R‚óEi Ï *Û‹1ÇÊ~/o sÈ¢ðF-.–„\Q‘7»ÈÑàWšŒŸÓë©Ì×Ä.Tü ß²Ì`•ÌwjM9½zï³¶±°ï½’®V¤yš†ÿDÈçâ|òQ@5îhøºùYDHmW$m}„ËéX¨RFð Î’Û³?C¼'aø#5è „ÍÇgÞzl!;H[~Ü›¶%ˆÅ¦Þ<>Áp~‹DÁAàf5Þ¹`ŧ‹†Ë6+TÈrI3Ü„ŽÀ¸*è[hS½ƒj,K‡T£x!¹VôÑO2—á¼)Û‚ ð^H‡;F¼A¶Ó3sCYQ*ÁÏ+–7Œ;]Ûû ;ñVr©”@5Ëb(þmVM)¤Jx6¨A¬ÿm´9ö·€Ó@$”¾; Ý9§,oZÿ (”´¿Ró ‡œí"ÒÔ,P!œƒjº¡NKÁ²Fh±¤‘vGŽÎ]>ouÛkdçCàcÇí(òY:º€«n«O HA—¹w¤ÁÒŸ±"7ŸÅõÙ»GàcR¸Ü¢´±tG!ý—eĹ¡- lÀh¶]€FÞÀúmüfå¯C«H(¯m·]³nzvÏ6"}G+•Ç Œ‰ÏŒ9` öÈvÕ],²óÃ\b•Aã(2é´VõWçÀÄ\GkPc Λì/‰ó«aŠ©Ž'* Þj÷™÷9vÇòxž9ùÐ1blJ`ÔGÝGaš‡RƒÃƒ`× O~=ãòű$²ÍWGׇۥ(:K §z*/Äcj–o”/Ù5Ü|Ëv½>Û»¾„¨” ¹©ºÈþóý–é†í³ÏÐð:Q.l»Âu¬Uî€WuÓç”m}nw›M¾¸îwÙü´Þåë_‘…-ÃÀæj³W¶1”Ǧa}¿Výno¿€s×”p¬Ó„u²$þ|²üí½Eå!Òú³mƒWåï^rß™Œ —бäg°—ÉŸ¯°¿:ÁJ‡WþsvX¶-òŸÃyeÿ‰'‹êÁ¿+u$ ÂB/òùîæ ŒÛ똹9÷ôÙOQæ5/‚ÿÇAópÍ+Ç¿Ðܯ<”4q /9~— r†^€Å°¬|DG•䞦H3_îP¹N  ?!’ØÊû$rÚ:A €âŒlúpû†Ø71jó§[&@p·ë SÓöÍ´š7‡ÃTBÛ6*À¥MT\Ìi‚¯Žò*§…,…U³ÍG¹²'<}vݵ.dtßô£UÐLEг7‚QŠ=ñUƒý–0šØ{) ýV_yñ}ñŠÂñ¶ÀüÄ¡€ PŠù’“B~-Õ9¹ÃÞŒ-<ØmägåVo òáMÇ$ØÍùHåµÛª“’«³ÕNhà&Ï–Û‰)e¬y+S¥«ó9B <Äåã3ÕÐO´ÿ{ª\Ã!}='ähy°¼Ü5(y¦Ø½€ÓõÃãÞf{ÕÍ'È õ…1}aç ݰ-žjÊß7”fBýÕPó¾2”oa~N¯˜b?˜¬Y02‚åô—¢zë|²J9H=%N™ 0§·z5Í*Ø2¥½Å¡!\Oª  Æ›´ÅjU²SÚ_–qƉ¨Œ¡š_+ÃÙ¿Ên{¨’ÿTÆK`ï&b¸£E>7Æ¢ôh±:´Sä¶ÍW5ÿÖª¸5ø»‚T­"Z̶Ür%GsÒüãÒúOt7q†l}j@5³üE¦ä¢T}\·¦'´—ÐXAaóDwGdÜxÊ¥l®8–ð– Ç1ÅZÛÀ¦ ÊS¢ÏCN?¦ÏÕl9-x­sÙÑK¿FM³AWyü櫹ÿáN)¡Ä”ӵ׸M„“+h C3'8뼬ùA%g¼à‚¶ 2]ð´Äð¨se£ôÆ¡•j´6üæ@Ä\†…@Çok;ÔŠå)ÅO‹œ£œ…ÞŒHNˆ¶NŸ¼JÔu~Ùû iñUYýø´öŽ !wGOlU’S¾Ñ(%a‡F;&÷â¢VC"Év_îY†À P’8%²4‡ûÏ9þu©ÿ(Lï„A€fÿP^^K Y¾ßª}‡QÇ,ŠŠˆYhÇœuT´jk/öÙ÷4&tp«öbªhÏ×§Oú»Ž«Ÿ-HÖÜ[¡„ö]ª]>‹ŸGøÃ”·x|A¸ç6Ñb!¨ ðê1Cì†=.÷õ•£Ch˜ù9xÖþÖ0Ñ!$x—´§[÷Ë6ž­–¼ýH@Ÿi/VÙ0Ó#žEySGðô”^Ȇ“Ž6l9þÄló»M0h‰CÐ¥z*݇U\øo±Ù~iÂÅ49—6 ž|?/\óõô8@cݘLȽ”Mmù9]?4 ´²®xŒW«ÿU²fÙÿÌ´—¾AûÝý€ÚÈ(^!vÒú‚]P4¿Ãâs‘@ d¿u}“·æ¥”-±þÊ:ù:oÒ¤Oá=n ꈰÃM#»£3ç>±ˆÍZYõÒÁ‘Xi}l!ptgB|Âg½ê?˜Æ±¿™fåÇù’w„˜1ÒzÊÖú6ôaG7¦ÇåõN"­+fo¥¶•WUd˜7wL;œœDµJ•n\š¡¿&¢²Ò~£Ácö°ËÉKöØgUP‰'ë¹Ò¼h{ü.ß„S3nªˆ˜yn<ÖÉŽö€›Œ%+³÷:Lfö †t5Sî@¸7ѧ@³f(À?¾¢³A EÏ ä¸T6tÒ­êìðŽËih†¸0p‰x“p)Á7†U{íÔÏí˜í¶še¥yíÌæ].>)²#)Û’¥ ô´É^WLÜÙ!Yîh£®ÕE틲y·7…«Úæ(û|tÍ3‚™9ÛÍ99ãÒ4+ Ð,39^NÑ¡ñãah2-|?›LϘP©óÖy¯‡aÇ`Vt\ìÒq´‘çÂ9Åvþ€añfè[A84t#ˆÆ‡ÞTWÍû›°û‘@LhÂéTbÁv!@S‚vf0j ZOšt²š»ce ùÁ‰]$‡Ö—  ˜ÙË#´‘>d|Zqü??ÁLùÑy€ñYçB¦ë;ådLÆö6¬?]•Bš¬ö7òèr@]6Å®"¤æBC¦Oî–<üì6®£ùÑÎîìÖÄî—‘*¨€lÔÊB{ˆhh³9„iÌ•¤püb È]ƒšxªÌ ÊB§×9°ËÚ™y4î_~<¸¬!%§>!o2¤"ÉS0Ö€öÐàQ ÀD›Ðæ·²ËÖF­ÀE¦+í!L^LþÉç«Ý݈ /æ.LY¹vÑ¿Þnú‚6-7£òóøb¿Ùmœß· E‰N:*ÛÐޏFãÉòñ–ëy1ΤÌz6\£ Mù¤`À¤có6Q>þ=@·òà ¿™])ˆ«î{SL“5+7ë.PëLLÚ XÜÖÎs1eà ;ëæuþ]?&›•Ÿí5ûä"ßÿhœwŸ 7#ݦävoP ¤š—!z˜ïå^Z Yâ‚ÿîqX—Z´c†xÔy*L2©>»pAL_W+€CžTbÿM±ƒM×fH·‡!}$Á4Ø›ÚáZnc¬´Ëµi…^ºŒñ‚Y…2ÍU`(ºÚó)†#0hHnŠ'ÜìbÝ !á¦2I,âŽ=4ºûÝ£@½ˆsh˜‚O­ÞÅÐý¦]ó:`¶ás¸sÔù›lj§â0G¶>ú±Tù±kBEÑgó–%~¦°»›ñÑ0!UÄ:ï4§àÍ‚OHÚ`,Ø!át±¦{“ÇWHY¸ÐÇ î’qÛ€L´Y]xS¥D ºï§6Ñh@[†iu&½¿ñ =‰¼\Ƀêóú –d›¥E0Õt¿cMeÚwlÕVao"îRCZ^ÏÎh—ÿIÃÇQâËEKÁÐW^™~UŽçrоØÉyâþBre¥"±¯€t8›,klþ½¸-sÑseºøª²<ÖRÔÕdºðo•©r]èþ 4Îêæ°2±Qžìï6_²r®/fŠ:_ÌoïÐX–b#î0g•Ùe¿8œÑæô·ÁàˆY¬6yñ¯óýã?ÿ@Œ¯¾â_º‘“$*‚íùB·ìMGÆQo¦5 àoÉÒæFO!"Y‹‡j'ýC"œ‘Ï Ü3„_ÑVOM@·wÓ¯!oªN®-nU%,¾ÖPŒ£|;‹{¼¤ÐÎâ›Düx ÕuéÀˆ%ç®ZH+ÁvØ_hãt˜¡Âd÷¾—ÄÆ¼¢gáó+.Ž9UMO®µ2ãR )~䤗k笀H÷ ´Hfr¼œ!:ÙÀ9©ÁÏó{\Wsjåº_Ý9ÜýMáA¼«æ–BßBW†rä ±½»^ÔT5¤¡3·x{®¼Å+œÒ×÷[°F¦b¸Å·ÞÊŒéœ#|uôÄ=tŸÖIÇÄïí›KšeàdCδ•½ÆÆ¸ÊÐ(!”±‰CøWØásG—5î-¡µÔþŽ*à¢qEìR‚½ÎÖ\.øYððtaP´ÔAΓõ‡‹ÔÅ›,Žg0t*¡Ô‡OÔ¡:­¨©qää9â€y_©C²WýDm»i gNMZ~4[«[}£"Ì\K9ÓñÜOÞŒêM̈ä*i³µzåˆ9•èöpž!+c殕ßR߇p¢jFÅùåLüHu„ˆ.÷FÕ17ðµk~Èü©ÊÉSt„ò~Âç>~£Vη¸†ÕV`}Í4a™9å^Cû£Ø–~Èî¿¡%ÄÙßÄÌ©G1ÿF½'´&ËxÂö‰:S‡T°cN-sÛ‰¼”̨šíÈ öÉ]1:{æTÂÝõ&vͲ)ÕÊO"oTÀC[¨1¨¤Í¡"™ÔîçY6§ ßH‡9Š‹uÓÌ]\¨Q­¾:0‹}¥rý_þ¥x¬nÍ™õiˆzíøÈXíõªjôøN-JåÁÚÅ\o¾F#~ÏœJô”ÐÅ}-ú©’õB»3Ê”ZÙ-ÄÔ‚ÿtô=©(ÓŒà/Þ(ž.æÔBxXäùŒÅ”*Ké#0)?¸ûÃâ-|û/ëÕÚ–8DKAîZŠî‚".X@Q_pVA.ÿÿMÒ[’6¿ôQÒΙ™Ìœ9ÃFm$ƒ·“Qü˜‰Ú{*¬Tx7$p/:-y¨Må.Y,qPõÄÝÙïU™… ïæ^¾}â†; Ü6JÔ‡#åqüœ`£^ußçùЕŒP îÓSÄE]L‹Ñ¿<Ô¦ò¬7ÎY¨tmW ô7í V¸«ÕU2h¢¾h1ªy¹¸®¨ãÀ¦JNžüj«•ˆŠîu!úõ¤÷ÏjaEOžüb ›¨ó\œB ½¯5S¨*€\ÑQô«a'wyñ*iMžò†Î°®ÏRj1ªËêá[d’0é ÀhùräÅi¢ðûjQÓ»¨G¡@aP«ÔK‰B•2¥ë75ßN9¨¡a¸³EAŸ#`­Øm4È$ƒ€go 4ïLņ‰°Í‡”ɾpN·aI›|,­!½óB6šçôpÊ;]Šh¾sNäÐO®uãNjšlî JãLË vùþ¾¨4:Å,ïôÒ˜ÔX§F Ü—•¦t÷›÷¹®\ÿwÑ᎔›ò|Ã9ÊÊM/(YIc¼RnÏšQÞé¡Ò•¾RìÓIYm¥_æ)“¡kJ¯+ŒèŽË×û›,òNÊÝAîëÔHÚðJ¹;Ò˼Ï[Ê}ð×#ït¦<öïãœÓ‡_ÊãìU¶“¶ûBNyêk¼Ó3et4ÊqNG+5¯:§tÒÆQ5÷œir> ª¥ðS…wz£ÖÛK~Òþ[¨WóÌ;çóILÌêaöéáÓçíñÉæž}šY·¤HìòÊJXv¢5ò…?Rªvvjœ’D{ÿŸt’½œ±O³±‡ÄIæoÛ9¥“{Lœt°ÏËÉx'»ÖÚˆÝN—ÑÉm¢´X_LvZX†°åM˜–XË›µx¬VE5–Í\; Îï+ƒÛó{ý$~S*åRê¿r¹”®'À—7K“IŸCÿ ;šˆAµZYe¨»ü7$´@ºùû3öÌþíC€j_O¬X›Áô{á%Z1 ƒe(ß"¨{ÈD ­¤µ ]71ꆨ†TGÀ‡oñЉ´`£f}>j 2IsQ•Êm©Mj<\ š¯ß›cê³ j5™ÃP'á0ÔiðjO¬mTJr¶ÿÖ8¶P«ÿˆ ¢8jöæÀA]mŸÕ© 0–dXsT°q‚Õâš )TC$ù#ÃEE«îêÔX£Øá‚¹ßîóQ¡HáfŠ”‘ƒ £!€Û;WÌË&>úË,÷¼à{Çè=Œx¯fB&³±–ñžÁ™Æ‘ýEÆ^ ±&®lÿ)“ȰlvÁ¸SBÂÐà+¹NrW•íÇe ”p˜×%¥:ŸŸÐFÇö£ öÁð:•þÍ™CSþåa(„ðJïpqm" a€Gçp»¬ ·,ÀË¢ÉÕn ü™qãÐPÛé`ðòð\Õ×U,`è1ÈéS=d>äæÂH±XäìÄê°LädßÎa)ý6=Á(Ë¢r|²’ÆrË~ s ÷IÖeãa¦Tý4­ Çð¬o!ŒwâÑÃŒ°‰p"lIÜaßXA¢G‡{Æ ÞôºÃÑ6nùnìKm4ov‚\Ø7ÍÉ—ð' ,á|¹X“ÝSa¼ËÞ¬ùê`髾œâ"†4ª/åU ügŸ•z§Tm²ù~öR5ç +_K‚…R‹ÈKÁŽ—… ÉÁ¿RÅlØN, £Úd§o oèöÜñQ=z˜é«Jafúô‡žÄ#qn{›#¸¢Zoøk0¾dP ÝÊ´• Ÿ.c'Kvš«­*.|¬9µ6âbsê“®L×ó;_!±ÈT934v¹WëaJÈWužvcUÚ·r3âneºé¦ÍòÁ ÚX€˜Ö^Ö¢Ö¦ aÒÌT—; ø’ùm@×î« hæ¹ — m#@6e›¡¢œÚW2ÛRu¥ƹUø0ÝÏ.Ø= "$§7Q r)jú„;–àkqEy-§†œ0¯Û,uƺg)|Î~í\Ëü÷ÊyEYÄÕ_Þ¤P“Î%WiŠ%Ç”±âŠ^ò¤ªŽ"5ÿ¢ŠÅóœä•¯ÂKTÀ§Lé>wÉž¶G"Zož r}r®MO‘kœ¸ª ûâ ]õÒz>îP™ŽG]Ç”QÐ{X›M{Ž!kä€ñí˜ÁЖµ×ÈWÿ‡’Fª½}“öšÞÿ\Ò(vóçXVîŒ5N7§_Ôv›)õŸÖßTÎŽ³ÓrÕ¿5ÖÂÈÖºì™]B«¹s®¾™„4üT{ÖŨ^÷ZÐÃ\²bœÛü[ÓŽë ';”LͰã¨N:A£”À.a ^4=°úFäªF"[ã‰YÐ;Îxð'Zu~+-@,0i“pþ‹=³6§kg -/ZÌ Î¬!ð„%‘[§¹ÚÁÌòhvø`¬‹#´"fúן’‹²a1 ¯QfîZÄQ"nm‚ߤ’:Áû?F³ ‡ XÊÆWâ7‰ˆ@ÖñyÃw‹îÅË’ùf¥¢ç5^šU~¢´Þ2G8ko3ŠÿyÑü 6¢ê×h•¢h\óå§Ù¹kbh/ŸÍNäËivøEj·Ó?.ÙàÍ®y! ’QÖhù1`ma¡†¶Ò†'}—.« ÛÎáŒ5ûý¢Z5bßQ èá^n 8k(³4Fx§{·M¯\W ·;ÎE9“ûRDâš¶Ražf¸0=ãJ¤}+$zÊÚýH`,Œ´à@æX+ª—[’à=rÃKÌ!ŒÆ;7)Œ›*'A/k¡‚v¦W‚RÚ˜Éb¾µ¡d¶Vì†$.2oÂx(mée”ÙþÒgÜ òH ¹zä¡’í—ëô\Ä”ßѸ¬“*ù›}Sìbîéö,÷eÝ™†ö¼áU¼K¹çÛ9ù!™Í®xPAÙ}© ŽÆ¥Ó¾—jò1ƒ* ~™ DN>ϹDÈ\ >ü"=Ñ\Ùq•ÁoÑï¨ù݇tÿŽÆªòËâ´Úú`?[@yO@ÚÚã¶T÷Ê!|8‹[Ž k¾ºU¯°yT1†v-Yxs±¨»˜¡ø>îÀh,C‰‰KfY±Ú¡¤ÿAˆ´ÛZj±ºÄëà93ú†£}ÐÄóÜ…K¶‘L¤Ð”í‰r¨˜‚ãÇ‚qëGñ«ŽVBZ d0¤›²€9̤} SÀnÄX£Ø ¬6‡1ŠÝÀoù…v3W\*ÝŸ`·ÞÂa7sÅõ§ïikÞì†JÀ"87vë-öa7»=§ë¹¶7 €›;f’’_€†˜tânÅ,Êx»ƒÑÙž~ ‘t>w¬¤ß‰‚UHÍ…­lH‰€O¥õêsÉ`ÌG?ðd¸aµ¶ÉgÊtÓM§ßƒy=<ôpLå:FdÓ”­0*xgŽV¢}îÞ䯼ÖöísÇ1V“;,àɼdÒŽ|Ý&€á®LàB{âë,‡¦ûHæÛrp—ô‰²`o²”Oü²@K¡gŸQ“*Sê’Ô˜¿=­…vOI5p[ã®ÛªÜUeû1tâÇuÚ5áÛ›$”M&+§4l¬±/yÇZU ó¬1GM6™Â‡iíÖ«t+‘^‹> Sóì*6P€‚-"Ð (â'ê•ùýo’JQ©‰áOšåª>ûÌgﺮó¬m×Ëâ¤uÝÚ6¼#$¨f¹þ#hhÚgì_Pý·Oø¯š[}.³’ >ÒSr<À¯x¬4`v5®Ã`T˜Ï/ï>Ëßíá èy[¥3ïÕs©yY7®bK½PjæNºÅÇR·Y|4Σü9^*ä£ÿ ùX5¬=L±µß·Ói<—ž”¾»ù‰Æ§Okúݳ=‰ÝžþêñØEg5ŸŸ»zÑTíýµÎ´†ÒÕm,Nï3u²És7X'õHè¢qüÊþwwK4 ‰zôô»&*ÚÐ8Ýí `&ª»ôã¢ÆKÍü=õØã»ûßíÐ!qÉpÓÝj9rF ¾išÇF/2¡Å5…PM…“œî|Ö²jùÛ‘d·ŸDM?xmÔùê%墆γ? ’¦¨p=³ãUŸšîö¸¨ Ã?I ÀIž4›\T­6ú|㡎ø¨§ï;Nå 7nüí•9¨§ïo*;à¡ÞSu…÷Ž.výŸÙhöwY…ï @ï×”L¦uó;L3kÇëÿ‘ܘàÒêÛ¦žkáñ¦]̹ ‹uÁÿè×ûhJNÕKèhP<­®M¸Œ|}=üÒÞ+&‚ù¯‹‰#&á;™²7]›mïž› ·†^½Âc”3÷bèr|vmÑA+¡79 ¦U[k¥c¹ÝòsSå$Æ›>g4 7®ë®}Êgî4ìV*×nÞ Uàø“M Ú&Íqü=QÆïƒ Š¡!N•'S߬q{t«M}ÓRAî!·Aí¹QNü`¾½Oèznº•Ì?žÝì–*çÚ‰NÐÚ!)°Ñ Oe”Zeí< ãiQ¶•!c÷H¹ªáE¼I¤ûwK!YõP{Öì4bÕÚu0B9¿QåV¸(^4~†"Ä pƒ0,å»mp}˜‰cµ¦Á§Áu&>ZÒ¸Š‹ÕAáS¸[HŨ¢ŒÕ£šÍ×éR‰­R˜‰!V'ÈÍ{Æÿ¨ _¥*š*D{¶)³Ó¶±–7H¾üšœØÌÂLßÐ]££ÞqC¿&W²1F‚ <Ð\.YÕ¡{à–Ãg­àŸWƒQ×’ 3às'RìY¾hRŽc·IV˜O‹}NB`%aóÁŸffDÒ0 Ä•†$8Lð?ð« c9´€Ù–c¼•§ní'élâ×&PT‘ǧKÇ É©0ðýrhñ‘RÚ;2_'c2T›Á*ˆ.•Ô­‘›ç“„f“j »E­Ò­».ŸZ íÝ¿Ï3¼QFN Ï| 5´d”4_íÈ>ashl-z°þjÇlSÖ†ÞÃZü IK4iÉÃ%-µgÒðÅíFÝyVñ~Y½üQ¡ˆ<‹§)ÑÜ  ‘2wìÉ™>!–×TEÕÛ€c÷ e³aÍyB:ç=¸…=¸ÌIçÜâÕ<³£ËÅšÜòåšXn^Z⣯Q{¿*•Ûé½Y&×Læ;éÜ‚tqF¸:î~n: Ç4ÇSžŸ!¥Å!áÚøUfÎ_œS 3ù´øX*d]ÞÐà˜ºT›‘«¥Lõu­\¹¼æòŽxÚ×µêìÛyâñ4*mïT!ŸR¹vꛤª\ÿ÷šBipû ¸PZ©O¤¾nu§ŠKA擳¥ägM*§^ùdŠB[ÉüãÙÍn©šÚÛÂüàG‘E P|6ƒß=¸´Ÿ„±âóÁGƒOƒ›éøh8hIã h(.»¯œ ïœÂB:›¥¨öq[ÔAæ3ªG5Þy¿0ý™°ðtbìÕéÌ ¼¬²ÜÀÛŠÎÌØƒ²ƒO¡¡9GÚI¤c›DzZµ‰4Þi›JDºJi^G -àh 2æÌ½O¶ Ôt€IåZ'º¼ >³ ¢uZŨÖXÁÙGšÓñÎàâà¸]JÞ›êÆ”6êf—‚ÂãTHIJQÉ…–îVlÉ(bˆs-ßÑŽ¹q$†ØóÄ/ך“ަP§q)×Úöço³Ó`ÎûvZ&Òo[¡dÔ–†‚ªî í)0:H\a¢¡÷2[ mµ8¾-C÷²Ì³Uð‰e é)Ù/Àæ-ì4i)FOH‡Á í˜ÇæÞÔtÌZl6’3n6ß´dL­6è‘3 Σ4þ׆ËLÄDšVk'SÎì·'Û_Jx Ù_Œ%«Ò hŠ^#<ÖIä°®ëj¹<ï®QSÔÓŠgv¼ê£³f—¿I~"QÓ^õôþªA ¾išÇF e¿[)TsCã$¯þ§lÔt·ËGu—>â\Ôxé©â)*ɾq¬ýÊC PËñ …Š–<_|Üx¸¨®¾ç¸ÅËpXëµf)»´pt#Èô ãïêMé»;ψõì4êS÷Ý…KÁä|5ûˆc £Þ ¨Ö›0a?uc¹² .¬†}Ùš‹"·uíÁ轂½e«™‰PΪðº6¥)GqÌbBèÁ”£ñ³6?ðéj¦à„‘º5w°³ Ÿ`Wù×é ²Ž£)q{E'7Nªrc†O+–O°6üTÕu“ªºk«òá-ÀpKwï*”'tù)ÖIˆ2xüáÝ'¨'¿²!±OUWëªlxljC`ù®Ï:‰0*åÄió¨àlh©[ñƒÍMü½–î+¥ ilhJúô@˜ٯݰ¹qÌÕÉÖ^j™{6êÃ’–¨6åªÆå«€ Þ-÷V |è¾ß¨Êè3z†"Ä pƒKy³Õ—C[ñIƒë{äJC3E wnž %YðÐP\ìE OÉ’unR1êhòö1ŸÑÿY¯Ò®Ä‘(ú[Xd‘}im˜l0€ =.J» ´éf`PÙþÿTU*IUQ/U!~ NxË}Û½WÙéM›rð*Ì@n—þ±q†ƒ¦–'^Z[kf¼•V°5;LŠï"q‡/¼³Ö>Ò“âÖ»¹#Õ4yнÕÅ„’Ú×…5 «‹q`ûBËnbHêÚBnF+Á®ýÂiÞÜôs;±MJIi»Ã—E0ÍÜô=uâR4NÎZ½lWÓì4ÏÛÃsÙÆ]ÆH%nh£×6?gåqØŽšòÕ9ÿºQ]e‘ÉË(üç­ŒòÐÕ©½j)^<ÃVÜqÙiÒ°Ì0ÄÄNÝáÕ‰ ï~˜@©‰?WC~ý‹´•¸Ñe®óÊÁž5Ôš…× ói1ÈŠ\ µœ’uú±¦¤R¾@+|hÅO­4Êÿh»¥I÷×*èÌîå?tƒÆ†—#ä³¾;k·ó–dÄ:˜ú¶}sRÆ™›I©Ćz÷àC€ç¼ œó?âÓ¶ÑóÀÆyÐ*•ßÝ!Ô¦®œs›WËŦSJ\¥ÚÚ!·p¹­Zó˜Ø2Êjsf‚U©=xWÞÂu@®YlÜ”s ÀáRu„Hawü#ÂÀiDK­INÀgpJe?Ñ¢—È<¬à±ºv5¢Z=q¦äl”Œšó±(“Qú^¼ò\oü¯âqˆr<­7ˆrø¢Aç ÊáKqÎÎu(‡Tõêõ¥/¨\œE¡š*ŽºnäÍõüΉì4añ1uc¢TÝ#¬ß…ðpO¨\¯øÞ °| ¶WL¼ U/¨ŽüïO*£ÉTŠVæ9^2uEÉäx‡8Ì$íYŠVÃÚ3fiO9h‹®ƒ+ùoIQÖžÑãëõB/*NšûP.”\!8¹R}ðÏ%ù/vÃçÇò”¶¹ô˜¢.ó:y™WY¬Ö ËÞݹì{¥”ÿ_Þó«Sì ku&cdu¥ênùÛ.†¸QaóEf÷ŽÃ›¶€e6 ÉZ PD¸ñ4Ãrú†¼^½Ú úþÐä–M©Þ?yzp™NéøC_õ:fÇ“o ¨#z"#ß]qNZFÇÉÜ0ñÑã9Ðé#ç“K¸É Gz·ãáä„cêÙ¥.OÛ &ÄÓò}&U½$jϽRªµ‡ŒE¡ÇôÄë¹Ç#`ˆZ¶7‹’\c€Žõšdž'ä•Z¥ÙyÝßz_>rÖ”ÇϪ—9¥tW²PMzHÉš(ÔòÒ{hRÚ&Q®)J díA{ˉbk'›à†0÷3…ÒN«µ¯8„y?°!ÍÊZ@Ó>ƒ{†ãÊ(b(è(ZVxë®NÞîoÚ·Õ¥‡5žÈJc²MY;³Æ“м93Â-Ä¿e½'(÷o¤š&Ò‡Åäó83µ(OýE€­j-6æ˜hÞ¾ÉДՆ›Ì³8üÊ çýöBÄn§Ù‹˜ÙŸÆã¼%›}´N½—’ÈÝëÉÎ~?½MÕFO‡u2BB [+ô.‚oÁ»ËïýS[Fá•” Ì1ˆ•ÂacÖònMCÆÓºí+\™!5É×ÇFçz2†Òm#†9ƒóˆE˜ÇÎK·nWÿïkro‘ò©Ãô1'ÛGô›d…aÄ×ScÇóU݆E!jûÁçÍã€Ì£ÏÎãÀ{5©:Æ<ȹ^)O‹r ¯Ë°×vúez›‰ã©Ì+Îfõ-”…A·.â ×Õº_ ^C§O™ˆWûH#ÇfÅ|£ÅH6¾.¸Þ{Þ.ÞÀ÷,7ÔûòÙ¸ÿ[iòË”v=œ ”õãwŽÒo/‰9¦,ëD›¤µ]ÁËɹ| ¾âUe‚¨U:ÑÃlÎøs½+]µÎõc-6Ä—n]F Èc|†[þጧʘ°x2ŒÃbcÂ$ŒYìÃLBvQåZøHCEäÁž$ý–0z`Lx¥ Ø ˆ*˜hu%ÝÕeñl2CXú«ËÀá·Ují%#*‚azãMn½w5šñ8 ËF.lÉãÆJîðûÄ&W/ô.Àä˜eCó’ËD4˜{Þ¼ÊÆhå¸Hpm,¤ÛW u^1+/yo¢Â c줄AãKö¿6íÿ endstream endobj 19 0 obj <>stream H‰¬WYWêÌ}¿kݦ ¤xP ÌÈ  Q†#Š 2þÿ×ÝIH'¦“ ¾ô‚vUíšvƒò¤_8cò¡vBŽûÚ\¶7€À5Ú\fÀ¯EéI.!qO\µSqòmFò«G©àò‘pG˜ïâÿÿŸ?‘mŽ3 <éäDiXÐòà%pwÍeÎJú[P=óû•cÖŠ2ëÐÕc ŸšÈjŒË­d šm3ëà˽êô ™Ñ~p f»® ¼{S¼ðžž>`3âij+QЦ² ÍX )^ªŒÅ5ÂèMcû¨x0ÆfAý7ŒÌhà01¹ÿTXf’¥Iñð+Jx‰WÕ øeÒi܃̸H:‚2-–ÕSKäuâiˆT(hF˜¯¸ôwßRŠo±M,÷7Yµ“ÏAªÒ ^=T:8i ¾Cd:³¼Xƒö1¯»ÿÞ5”׈Ÿ泂Wä»"ŽGôxP ÍèeTBÜÉÀÇÕ¬–´fÇÂß %Ã/%ÜiÐ QŠ?MòòboHKaiÊ0ÊRÝðP“\bVI†îO{¾P„‚•O˜4­¤‡ê–îŽ;Ÿæ^Ý'LéÖõ!ƒæ4Zæ0+Öê”v[ <Ú³8‡ÐŒ‹4Ƴ½ûÆ)9T£ÁiÜ4œ¥"¶°&’eÊͱhb8·(ºpŒ6vh†-s*iâÄÇ–‡4ãØ=•4ãt;•´ØÓ>W³F;ø¤9F¬fuÁê¤ñ¸ö3ɲo¡•ñ[ÙT-ß]m¬ˆ-+ —E‹Ö*C )iÛ“Ö]aŒFÛûe´³Ê. Œe²b‹Ç´èØßoe4èÄëšj+ëî²~ê!3ª[3j'_+,}âkrÓ;äI‡tQ¬î‰‚¶¾v«5L©ÖϪQ,Æ­:·g© nЏ/ô‘a˜³½Z“VE­X#B:ô£:Æ¿z¨[–ÖŠŸÕ¸ï²V7§‹[}B8—Ú‡û0€ŽŽî *h£3`6uã p\Öµ ol㸕†vRr7 »o壳V4€k›ùÖvUhf¸9ž31‡ÝŽH£sƒv¼êtjC%ÈØ¼ô‚¦ˆ]У? ßÕüºfTóß-hãA“ê4A_Âþ´ŠHµýÄL£oŠÇ‡p‰ X–E¶{ÎR³©îýèØŽäLF­~|pÆ‚†ñ…Ž*TkšM{”Ü7î &~&/Ž Oo)c\ ]‡Îvýg:1¦Káqܧu{ñ&Á£“®ˆ!A¯ùè£A´6Vb%T'˜¬I£gánóõï°™S•ÖÁ–e6•a#ñÊ¡z.~ÑÑ ’–Rš¤ÕuŒE¥!4« xT¥!ÂÅ_¨´<"2è¶—¡[ ð©C£pŽ£Ó%o‚úÆPÄ…;„ôœxv%Šœi-zšQ„†Bú"$nký{óuÎÜA®ïrʨûq{¼ôC޹l~u­u¬%Ø| Ä7¥‚+Y¡´Ú€,\œg!~«›ÏR+{!m¸Z¯McD·¥Þêä-ƒöeÔÈÌÑò¡‰Gqˆ+­Å²4´ØÉÍ ¿óàÜœ¤aû]+aBQ+ͨg_((h°þ¸¬¾z[;ÈØ\#vpçÌv]A-$Ã<²¾x ¼]Cö K=ûÂ|Å¥µ¥ëFæ³Ð Té™°¹¥aÞžC‡~Ôšq°ÆÍ¨ ¨÷ã+».´>ª4ýÑ\u1Ó Íx¸­ihÇÝ)-ó* ‡ÞÓ¥z¿ç¢M(Ð è´~ÔPÔfÔï7?²îGÊa­ÙÑûÑ,ü©ª_6m*ÿ-Áwˆ:@¢ŸtôÁ‹=~a'’MÁf'æ‡4\-‹lâéÈ¿0Ó~(~¬+íÁ¤N?J¬ÕRý'W›á&žíÝ7ìG–’Û©%z"§:ûÐèD@b8·(ž6D MáhŽšøØòñî˜F'2^"c$Ÿ ªeD¬šÔ†š4ðš>âÔëfÆÕ¬–ýf[ä»"wý8ÚšúQyvhFuBÿ´a\;ÚL#¤i­ö9Éf*H—™i ñVlêZ‹Ô˜‹0Mhâ%7êiŸ«Ù“v8T´ÄŠŠ÷]Öê.Ú“"‚Œ¤ýùµ»'LhÏýM–2ÄúV›—4C”"ë¹,‹Æêp#°±\1)FøìÙr·X)FåŠKSÙæGJ›–ôES¦¬r( ãÑÍ\éqÒi^48(PÐ6>gQ£(m­Á+ÀT¢ í\\èÜ)›—MµN{t´;Îå© f“Q×¥Dc‰FY:ù¨`³)»B—nÁõ3pQ.v…¢f»ïë>£k7uM±ÂO…-#൛ ÊcÞ´=»)›ÆVpU2:æ^ÖŸeÎ_Æ’Zk•–I–} Å…ò¸•×™›1÷EîÌA$xà&Ûè+¯RªA©ÍP4Ûm¦ó~-쮪7âÅÃ]ŒÍx øWQA>+s÷­É–ñ¹ÃBö¹k­”Ñù}œ¨¹©ËÐ Yføù¢ÎDrƒúËså'éΟ9wù‘ÊQøJ% û _=‡p4·Žîv›õ¹«8{ йZ_ÿUA©yû){ŸÿL£ñz’Q f6—¾¸}BqÄÀ¿ Ú@ê¶ò[Õ‹¢š3ÞÔXÆ6 Ê-ø‰k?#‚Ó·ÉÄ.À„®nÐ Ø/.†ûm2¾ÂE}’®íÉ¡OU†ûHÔ¿«3áÆ:Ù\¨¥]Ü£IãÐõ‰á¼x™Ÿ"Škt}Yg¶Jß´VE)Ö¸€ŸîÖ"ÿö–Ÿz0kE@Xz¢øïq_òs@0*à¯hBÕO‹Yþ£â2éì}vᯜú5Œ(fÊõI=¡bÀy°“þ-7I œUÀÍçª.ßÔžà<Ø%UW3ç!ýC&Í/&¾|šÑÞå#ú»Xîo7«½¨ú ¨ÉÞn´Mñðâ&Íÿ„R:¬?ÓMã(åyâ²®•*QÈ9†»mÈA o(ö$/öðEG§_±œíÄ!í0Wàýûb°\©ˆÓ7.Šžñ˜"ñŸïañQ] ¯Ô‹<îÝÓ"§uÊúqгØ†ÚƒƒÖgÖíHRƒÐF_ò«§iv¬Ã|à†Ä{^0Tu–†Ôh5ÅÇN؈êœi4´‰«ê'mh¥÷¢3ˆ¡Eo¿‘Ž *…ù&·’3ƒÏ¼QÚq£t @§ÑÆZTÒzk¹ïŦûÜú¢?>~}ÀsÛ™ûü%ŒÍò†©pâŽ@ܸ¸XÛL ‚æ¾.7¥võ±.ÍZª÷‚ìnöš_‚*m$Ùa*Ñ{ô ä,t8¤„7жhŽŠë«`A?úí&ØT:âêæCÃΚ†xišŒd¦k“Q󧌗tæ+ꃛû0ŸŸ’NÌp ߢg:³÷Ôœà?‹ÅdË’ÑùYÆÙ!£â®Ø'u°ëѪ›8¤j“HÅqÚ_áð-@»€þY0?Còðݽ(œ¼m¶ÁÌÚRÀðúÅw“dæŠJ@…^¼ ×ÝR5X† ‰ªqâ ÏLm°%©»baUܸ6T¿i¼4¤›ãUi%P)l5®»-™Zq@o|ÚE–òádÚÃáÐÈq‘·>›K£ƒ¼0\¬o7;¸·Pç…åä¹c7ð”ÞkÉsžgeÃ@í¾v–u0VK€a;AÉWF p‰eëÛ•q-6ËßXNµêÁ`½™ÑÄ †Ã¥ì™ö´ß Fy°3ŒíÛ;SÀ¨ù• õó7;b󽿒1;üŽPVl.eÅý=G^ΖýÒlv8ª`üÍ¥]$c{¶ÿúœ!ÏÂiíµi¾:´ŽeI¶"wÌ·"¿uÔ8d®L][›®Ê­ºt°Û±™_êØnӤ⸎r{{áM¹ûá8°>9–ïŒÃœãp[Ý9–‹ƒcùrºôfsv=ût,{Çrí¦¾ËÍÉ9Òê‡SøÁa¹z¾²/‡××öåbá°d±vX²x9üª§™±Úc ýÈ!cã0ñá¸æÅþ¬$ O^êÍ)Ã!þ}Ã'd†=ÆŸ#sÆ»y†¿}x`üQÿ‰b 6ä!¼¹ëhÓÙ ;Öä¿Ä(7¨¼"uåì 8’tT`'EP—¢¸‡âuäˆAò5æ éT/¿ÿ ‚4¹Ÿ´ó§c¢9€öp[¥2oúOÉ@/È£ñK'Š5H}¢4$´0lÀ)²C}uèDñü?o(D·qNh–K ™­’5´è\»ãŸ «õ,ê·‘”^¼•äÜí” €ô¯åR^¬=¾Üÿ,\äo¨9+èåq¯EId]QQºó')X£øÞfI†½öKåB?#»b'(UŸ"'Ç2z3àÒ›#)&¶iÙ—x‡Ÿ¸UBð'qÉîÛç$`5 ×Ç3DyïÇa Ît ‘{Pí¨°d#Ò¢1*Hå½+(»™XIx½Ž+d~Ïd$¾ñ–•óîû& ‚ÄmZŒM‘i&ÍŽñökAŸ9¢¬ä*ñ¤6A2¾¥ »möPWüŠçd÷ü5“UáU•I‘ÖokuVcKÐ<èê.€Â=Ä“e&Ôa¬>r³ÍC $« Fx}8зðÊÇ9l=Ù•(Ö4S͇¶‘4ëZV™Úl@MÒ=am•éËE ®éj £ëZJ|_Boê[âŸS‚RKîDZ”bhQÇÑX—lGÊù}†Þs +ÈgzÈ‚®qÎàžÚ ßý PT”C?¢²LÁp0úC¸;¿¯­ÃëóëÇþÏ?þ!䪒ÔÿXíJ‡õº·þë¤ì–çíúãô#þCÈu Õj4¤¬—»ÕÀÍ#66©6"8Šå¯Š9£óÊS¬¼©\ߥ•'QM›»„‚-†•+)„=w †A—dØæ0Æð/¯°7 0Ü9ÞE„¤0~ñ–Ð,²ùkrMZTr>*GÃÃðv˜ôÏK»È½,®ì%7[(L§9þ³YËÖcÇt´’¼”vÃà xEeXR{¥T.µ¤¡´á'#½cß9¬»ä›”u‚o ?˜Ñü <~Æøz¹0ÓRáÙ¬Âð³UÝv_Å úÜ_1k†aŽýccÌša4þ©1fÍ0Ïÿسf˜þŸ1Ûž`Ù'´}°:Åtí‡Gx½þÛU?‚t=íÎFÉ´z 4<m߉dr\HðXáòA“ uóÐbȺ¬1Ъ4š ¦ %t­j+`¨¡¹ŸXOÙ§ÂK¸ÔÊÿ›ô*ëJ Âïžãˆ˜@HÒ!ìÊY½€(‹‚(‹$1`À¹ãËüö©êÎ&£sîÌÈ1'骮®®õ«Uú8í‹Lê_Š<©´ý2ç€(Ù‘?“Çüw‘}Å—žý³l©Ø禥§TcSìÍ[šUêù(2Æ€f=j>Xº:îÙÔïäǦ{f€†¥XëÐÚ(B“) ìm¸‰Ñ7°z7Bß°¡ßÅëXƇ´)xú:“ Î ã—qb; û €f5­ Àɦ·ÆY¯ÉnEWZËß Ö¾æQäõØBÈŸ²-Œ9§‡å0*Í;9×2í°l·=»W£n€zŠa¤)TFüÛmeÆZ! |’ñØ7!ãÅÃGl¥óŒÛs¡‚ˆ­5 JŒHí]Sj ÁžSUÙž¦áý sGâBÂà§¢°ý ¨P£†Ò^y`Ô1驨Ò0˜D4bv§ '6PÎR7õÒô¹¨Cz>¯ÎW³JbÁ‹'‡åR ^¢ðˆÔš‰Þе™-VàÅû ÕVˆ³Yç“a˜Î Zl,KÝ ¬§ßXx„ë*Óö…L T ÀÎΙo€ùÇ©'׿qYÙ€ºüV¡ºIò6QWùÌ0îõGºä¿Õ=d–-ëlÍŠ’×·j5ä PŒ@BÞÇ WEWÆ’÷ a´S±@E/Uîs±x87"€e‘ÔÆƒµdºŽ¿‘ØÚÃv§ÍÉ ·ÉŽù`ýãzÉ詺¸0x³,MxÀN`„ܼÝÂ| aøÁ|ö$ˆê?EFVüÒ"P±Þ¦…8C6-“ÒþÛèTÕj@˜æ³ Cêèmx‡§ÑS•jãôÊç‡üP4©aÀºLÛ5HNÃ1Á΋:öl ÇÔ¢ö•ÊÛ®{¥ûšG¿Ðh‡´£‘¦ cOAj/Ÿ‚811ÏQ¶‚ ¼p™¿¢U H˜iWk×&+OmÌ/œl>Ñ|ìwƪù•3ä/±ç ?w†ñÉMgª'ƒ vî¿à³+óÏz|%CüWJ oþ.#ö/"íYöo/¢|áPÂÏ'þƒÑöâQQ¤«~ò8˜ê—”’g¡P>@MEòµÈ_º¦¨zg±pggÕ%g€rXåˆO-3ž»rÔzQíb3!tå–uÂ|…*_»åYô8špŒÝãÚ†Y™?¿f°ÑÇÔI]éÔË6nÜ.Ù»`Ó¬ÓVáM¨G ›ÈÛÂ>³Qúɰ@çV TÐ ˆ4(r<‰OO§ ün õ«**æÔ%Dü„RèÑ%ЉÀGëÝ¥í ·?\‚â#ìõgÚ0 5ÏܵèÇù:ÅÜ¥Å|‚j›,Fð¥;Õ\*Ùz²‰>¿d(Š<ŽC®ðë(cyÜLÁë »BÕ“<_Çe‰qÍ“%t­ÐúIæõ6ý´åÎïFÄèÕ¨Üê>câõDJU…dÖ5LOrQ„`ZQWÝPEÌãBN¹ ~Š"Æ¢÷r~Ò“?“Çü‘ŠO$‘·§Ñ~ÎJæûÚe1õ ó4æUá®{ÇØa<©.ŸzA¦ oú³sû[ÑsšZ®Ÿaîß² WËw„EyÞ¶‡×òª¯ºà¶ü6£–%µ"Ì&.O¹N 3ðÁ`ñÙ§;!3Š4#Nlt76 ¤|-ðœÆ+òŽ—˜ì\Ì ™¼Ë¿*ÆoV¾ºÀðò“Wú áše¦zR8z°³ªD1ΕHG y9ØÑ1.,/Ål”Ö 8&ÌU¾ÿmZŒ6— Kî }»ÇçS‚7ìÚsfþ,êhÜmtÜ'ömöSQ.?]+°©©(‰Ç"×ñçÒùk¢yqo(°ç ãkmýgþð g/™TL½gü±+¯ço/†‰0$K]c÷¶¡,‰É¹±XšÍÙ»aŽýøá3•ሚæÔD>¸Ú„6ÆW ÓàˆÀ5M2‘‹Ö®¼œï–ksf½sYº6h5ûe.Ë1î pç8tR&À$Ã:5AM'‡ WÄÇà'*QÜà{L“g|íxß |ejžwüúo¿ÁÚONãZÜèAáôC Á&Bâ’–T4ŽdT)£¦SÜËáªJj&žðÖšÞššHI¢&qÍÝüé¢7FF“£¹Ñ 'W-Ãè›úoJ?g/Æ…©Ø ÝÝÚzwÀì†ýð Éñ7¸õûèj5›èÀêreôÞ7F–#‡#f†ábi¢hRЍ.O)’¢’Ä—VàF©„¦€ÆZšK'µã*ûÔà§€G{Ùû{=£hð„ÿ^¥Û#ÒU¹*Lñ¼ s¾zÓ <6 Œ”Ø\®Ãƒ?m=!´-? ´¢^ÞZš Ž??/Î!8;ëÝ yí°Ð8ùÂÜÑ€!•©ÃI%k½é­mò)ËÕlÁlü1¾2Ž=›çž®4êcØ`B¸­gÍàŠ‹íìwƒ›™&êdl€Ä-,c Þ2¸íÓú'®à&w$UÌð—'™} endstream endobj 9 0 obj <>stream %%BoundingBox: -70 37 543 830 %%HiResBoundingBox: -69.7129 37.5566 542.2871 829.5562 %AI7_Thumbnail: 100 128 8 %%BeginData: 2466 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF %FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF %FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF %FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFD8FFF527D527D527D %527D527D527D52527DFD04FFFD06A8FFFFA8A8FD46FF7D27F827F827F827 %F827F827F827F852FD04FF525252A827282752275227A8FD44FFA8F827F8 %27F827F827F827F827F82752FD05FFA8FD4EFF7D21F827F821F827F821F8 %27F821F852FD54FFA8F827F827F827F827F827F827F82752FD54FF7D27F8 %27F827F827F827F827F827F852FD54FFA8F827F827F827F827F827F827F8 %2752FD54FF7D27F821F827F821F827F821F827F852FD54FFA8F827F827F8 %27F827F827F827F82752FD54FF7D27F827F827F827F827F827F827F852FD %54FFA8F8FD0D2752FD56FFA8FFA8FFA8FFA8FFA8FFA8FFA8FDFCFFFDFCFF %FDB7FFA8A8FFA8FD60FF7D7D27527D7D7D537DFD62FFA8FDFCFFFDFCFFFD %FCFFFDFCFFFDFCFFFDFCFFFD3FFFFF %%EndData endstream endobj 10 0 obj <>stream H‰ÔW[oÛ8~ÿ }(Ð<ØIñf, $jÆ3“&hœÙí´ ƒ±˜XYòèÒNúë÷²µÈv»o³9H";¿sxD¾úËõÍLÍ‘yœŸ½z•¶ÖôM»<;XVÕÐõ­c½~{ PsZj)ÖÍ_mÛ•M½ð²Qš;û×í®¼^_8ƪì+ ¬ÑÛÜ”§P`š™„2¤!Ž" ´ 8P—N%i†º(뇤ùcÌxИ‚ø@?–om÷¥“sްÅ9¥Œ6žcÁQ °tìì²f3ìlÝ_·ÍÆv]ÚTMÛ-‚ôÉÔÁ¥y‰ ÞÙªj>Ie6S›¼©{Ð]•;ÛÍÞ6;SO¥o¬-lñm¼¬l·X->2Š?ñ‡•¾Y¡ùu–ƒ–ZÒµS w¦¤GT-^'CYo†ÝtãHz>Yûäo;Èàž=Ÿ¯—;`ÝØ¾h Wzùîçéš¡hzýþÚt…˜í£­ÿyqp¾²»}åñØ"Êæ4@q4—,_½ õ±(Fs&Ao†¹œ#ÂyS2'Š e˜sŒùÁè¹öci?-‚7MmX¨¶¿)?ÃÚBsP€™Ç,fùÛ¡²ím]:¼‘çÉ’˦°Õ"ÀÏ~òÊx$<¡ç¿•il ÕTCï;ZDGÀþ‹y²í$ÈÕÞÖ«æWŸï,–ǼD@暘`H÷ | 8$9„D>,:¸v~œ—£Ê«k¨ÝU[>”õ☠_ÿЖÅsA9ÄøÇ/b.&¿òø{ÈVÞ÷¶>&Í”^NZ#š_Þ¸¨º.Òfç*ÑùÍg!>´KÕ<¤Ï/^.†ýùÙûó3"Ã߇¦·x¬l YøÐš6@X„zhÀ#šhܙΆ÷P¤²¹ÅÝȃ=W…yx°íáÈÃMÙB›ÜWöpoÛ~Û ©‹ðfcÚ¦`wxß•½ïÃ+ IGߎþü3@ºíO!½êñeÝ ÀíC[¦Û†vçÿõ°ñlS°°n€³î« £qcâI×u%ì¾+JÛŠ» ìöfp°8Ü mkëͼ°ð®m`»ÝØ´ˆ‰ð¨nšýÓÁg[ÜÛ]Y—5˜sþåÆTuÓ‡Û§ýÖÖa ¥è`i¶wfãÒX¡Há†-X]Øjº@+›6ì·­µ§7³zîèSz^±ú{o[”UeÀlÇ“$´3Ýf¨|FB8áïƒiÁÆ=nMu?Æ80»I*ßàJÕ¤šjÄWV¯ÜB¥ÃôB¨½y¨½1xÑs}²[ŽZË1Är¢³<éè~¾ñÁÍÕhp5\M ®Æœ®Nv»¡êË}õ^u•ë‰Ûã‚nGãÛ‰ñíÉêÝ(\m›ºÅ×Z­ ÍØ×c&Öf mNNŒ‡ÃØps„ÃŽævônŸÁ•=Ù•£V9j•“åIÇõ°Õ›cNÍÄ 9¨œìŠòcé#Ãh:Œ‘†/òN6O£¸÷`<Ùçg+=ŽBúÓzÕÁ‡`2ÿÉÚ]o÷‰_ëÉ7õËïëûp* §zãØ]ývî=Â;ú9«§ýñk㣭!ü5`Þûmôfïeb}] ü¡m†ý²¾oÎÏ^G¤kÓoá˜#£ƒóÎÈSn –›íPÃaböLªþó®)† 4~)?ÚÙ p Ú_ü—(7O»»¦*»Ý)Æ”3>Ûïq´j¡Ù`éWwÿ²›Þy»Û›¡³õäqv3”ýwy»v–¶¾ªGÚ¡Û«¦©NY^n6í˺³ÕW@$ÐSîƒë{Süé‚Áá?rÞþ¯ÂÀ  ½ìý«óãÚÖÖ°U7ßUïÔÀvû~[n^Êøçg¹}1ó£ÂýIþwÛ>~¶ÃÃwí‚o—"ßìíçÒT/ýRö§˜Ù{8ù?WjäþøðN&_Ï’?€;PW±ÇÖqÜîÛÁ\ÇÝ—Pû6ð{ýÉùwæ¶³ýç:Ò©3ȽÁÿ0*S›6ð‚c€é‚¥;i˜Ç¾üìLåG³±ý?fÎçl9Yuƒ{:šg³om$õTã‡Ö}Rë~áFpma´±Êm#1^â‡Iáϸ=?Ëó\çYžæI®r™‹œç,§yœ“ç(t®µÎtª­´ÔBsÍ4Õ±&k¤£,Ït–ei–d*“\š2ž±ŒfqF2œ¡,JóT§Yš¦IªR™Š”§,¥iœ’§(’<ÑI–¤I’¨D&"á Kh'$Á Jઠr¥U¦R•(¥¤Š+¦¨ŠQX!É\j™ÉT&RI)…ä’I*cI$–HF"Zd"‰PB ÈQpÁ±  $"žsÍ3žò„+.¹àœ3NyÌ ÇñˆåL³Œ¥,aŠI&gŒQ¸²†b#Í©¦MiB•TPN¥î‡SD£8uœÅiœÄ*†;dÌáfEã8&1ŽáÆIr¢IFR’E$ 'ŒPB0ËαÆNq‚–X`ŽÜ1ð#ƒ?´÷9&˜a*ÌL‡‰)1¶5 L Ó£¶)mõ‰©™.)ãÛ®ér7e_ÛënëÎL(±Š³ªL­ÂôÊL±¤çØÎT§ÕHÏ_" 81 G&" ñ4Ð4†*M#+7K´HÓMh­ÓÛå'qkÌÌ4ž™ÊÓYíÚlhviV›•Õòjš9ˆyb€¶œÕs ÿ:?>ÜñÃ/øŠUÏp¼2q¼òÉ[(¯XF„Ö š;œ;ž@Ñ-òb‹85ÓbŒÑ…xÒØª-žR‹$ß m[ì,Qs]c¥6„ç5:ø!ˆ§52×a%¶¤Ø›jË*K«+XÀ*Ëíº²„‰æ ‘,0ž aGôF·´CìD°ZâT@šOÁæ€oº•3éˆÅHÂo ð&BÎ6¨b,/ß´ª™EÏ,ŠfÑ4‹ªYt ” uÍ¢lš¶YÔÍãêp³¨œEç,JgÑ:‹Ú)7ޱê¯Ðr³Ô,Òü* ‰-…Ëšð3k„ài×fíBÓ×è/Ó)³À^Ë‹‚Q23Ú†“™6ÑFW ˜Åfre6ftnY-y™Û°Ç¢\±«hTHÍ´‰Æ@Þ_™ûóÿBTr Bü@ˆØ¨HO:8BŒø)”B‹‘ĸ’Éq!=ª2O?Y'ÖŸ3eŠ#WĈSðenŒÊŒ­"j•¼q4÷ï›ÕÜb˜ÑÝ´×~æ%ÃŒ­þ¼bÓ]»!æÇgv½kÃ]Ãn®Uï–Õ»Vnf|^5Ÿ[ºk±ÛŠDU¤óƒ ·(6(ÜÂp‡ÃVgö@|ŽÄçP MÛej¹ uÛˆ8åSé/òèéÑ_‘ scD®ÌXšE&ydVD²ed^E&Ì͹:ck,rÙ#»cF6"ë (p® Ä$ÜÀÖZŃ0É›Á  & `ÔrÍ8 ²y."Å3PU¡/@ΊUƒËSq¸EÖ#¡"`µ 2€Å#4ËŒà°Ð0IŒ ôUÀw†GàxFhYl¢¿‚AX^¼ ~ίÀútq\À÷Háe ´¢, (# Ōж(i© äV˜áˆv¹SýÉœ“2.3öÙ ë¥r£j\Á?ÙñiðgãË)Û³¥7Ó¼ÖSçsuy[uËÛ¼9KMØÌu¯—Γ¤ƒ¼ÌDíàÎ?§íÂ^îó‘·Å/ñ×»lî…Vn‹7Zñ·¹-Îó<¡¶_ça¾Ìå1£´D Úãj`¯yš¦qº®ò@ÅJ* T€* (T4) B@e€Š•*´üTöãïÓÙÏ56*õ^eßÖØÏöQ]¯Úl˜Úº+뮫›ª~‹ ÅMîuIšQúIÊ[Ò Q*×K‘ÜÆhnöÄ´CDu×µ®Î.Q{Ó¯ _w3|Ý1|ï–··Ø¡dbÆû%õ£íÕïø†?zÌ{IxldÉ'ÞZîÞYn”è×î,áÅâÜ 3ÒðXš_+Ì7Êò¶(£D³,rQ¾ 2pörIöË^38-Ç8Ž“RXΣê{Þ"ô¾R9Ó…³É|WÎ)³ŠÍ27’Ñð RöK¿WÍMUŸ(2…€HJ9pôw¥,) Ä®˜‘"ÁR(ˆT-¯·…DÑ)D:TÊE„Ȉ‘RbBlÄŒ–ÂÂñF)ò"è„÷½MŠJÁqÑãdú›D~ˆM˜‘2ÄRŠˆñ$w›tSŠ_©3l•ÒŒxKqß–í{½š(‰¢2D¨ÐHg“r8Èš;>’Ÿ~zz÷þ»oOß·¦SIÐ[ÍG‚ÞÉü7\@þßtZfüm™üºêÈÿ µy4ÿ‘>7…Ï'IHž&~^•>o?[tCþ¼$€nK ˆ Ç‡ƒ ¢ÚÈ ½ÚK¡­Zår»K¢.ŠYÔ„ÒM…ÑØâLÄQmÜ´½¤RúFDYâ(‚Å ¥ðL9Ûr}ûäñáóŸøÌë³/Þ}øðÝÏO@þ¿<ýøáý/ÿ‚+¨ßº'w¶.ž,n£)ðz+n–Û©$îï¾ùEÕüå'Uí¢ëžúú¿ÇßGë¿OáôÇÓ×1§o¥ý«/åy›n™ý½´í_ø‡ÞÔ^ªMûÙµí†>égü©m´l³+rhøëôãoó [÷ɬû¤ÆHöœ³ÌcÏ)z¯_ Ušb±öÄ.•Ûå臔ÄÉÕÓ_ÛÊI#Pê¥SìØÉÂd|÷qA/isò ðCqA|uÊ1F|„8Èxº¶A^fF«c*žÁÅGY#{ñå3–÷ˆÖ–¶˜½cŸ }›“úúLѼKÒ®vBE™ÂFkø"hæÒwÁ SÅø¤[W¼ø IüŠJ"~ yyN×k£¯ƒÝÙƒæ§T°ì˜ÄÑgú6¯c²g—‚|…W½ü_d²)ß”2}Èø6Äc—S•Fk;¡zYv 8^ø ›"íºsþŒ BbcµAúä¹¾€m¿ÆÄ9"êVÎRn¸h/_θõ8vÊ¡…ž[ï×A˜m»7K¿duQB¹Ùr‚Ë=ÕÆÈysà©:› ]Y¯øëD!ÚKÚˆ_ŠãÑGÙ ø)ÓGnAG0¦H§Í$(­tM ÁìCÿ8\¶˜ŸP"Ú)°S­Y_d°IYkú b  _g5óâ‰K‚a²&Ó·Á‡ˆ™6AÞ„sÅšÄ8< ŽŒÚ/>Ïl‰Ÿ˜ ;Ë‚ªœÃÉQრ„-â6qZø"¬ÞK'›*™œ˜Vµ>7¶¤5# B¸ÎZÓŒÌñ‚TP?ÒÏ{ë =:¬ZŽŠî Æ*‘JÖ}@°,\=Ç6õEPvô½©ôc* :„2ÍòO Hˆx@ 4:¿2P\ë:áHÔ=¥Ñég3À#²#åÎ@ñmH;¢­¤Ð(¾âûx``”TM+¥‹ôÍžœ7wÂW¨7ÒJ#÷°1Püê:eRÚ=e•Átrëlg |ט؈F¹3>v¥30Jž¦=cgÂÂ@x.›Î@øÁÕјLí „ÑÝ¡¡ŒÝ3mPâye |DBg .Ÿ{¢Ñ'VŠoLY!ß©–_ˆ&[sY(>Žze ø©ÔÿÒ]/¹šÜ6€·ÒClIÔ33ž™ñ #nÀ±£3ÈîsY"K‚3º ïÿ*õÕÑi`í›?þ»­âüimSçüi/Wçu6¹”?Öɾ"øã‰j­ìüñE–U?–ÃbdèÇ˲\?]³:]?Ô=çyê‡æLÖTýP/<Ì\¿Ê ŠQ뇞,f>ãe7tU?”£[æ ýÐ\UªëW'Ö5u×µHm'h¶'™)¨u…6¨{)ýäÍñ¸ªü¡F Î_åÏœóäÍRfø‡ïÛ?”x¬ÌÓ?6‹©¤þ±Î6êk^òá›ÈUîêÖ,›©¬EÆé›ÅÒ¦ú÷úúDz?Cèþé·ÛaDýc= ZõÏÞ4Nÿ´iAEýÓ/²]§þqYVî§\ÐŒÑØþñÖr=¶¸õÕþüqªdÈæ¯Ò].åß!Ãæ›?Ô:œ?ÖÒ«óÇñn}œüU>üÚpþtO¤åüi×ÉŸ6¥:†Ïtþ'銘¤üi]²óǺ¡‚%=‡l.×O_²"²®ýŠ€hö%Óõc-5" j|X;øcOrD@Ôu–ˆ€ü*WîUñÈ÷¬P?cœP{5" ëÚ#j]®Ȧ”ˆ€¬ÛŠÈ—ÓyÕ|¾muéfD@Ô¸ïW”Å5æ?" p—ÊÑ–i ª%#"`åoêWD³ðláâjWˆš»ï4ûwõ0«¼ZD@Ô«õ+VܾnÔ Äí­°>#r˜¿y°51ì){d)óŠ€l6‰ÈÚ˜4÷Yê0û ÖD=g$@Ö}\ Í6"¾>DD™Ê•«žÜ"ê‹j$@­åJ€ÚL‘õ‹V$@~hiWärÖ ÷×ärTZº gj$O€Bz% G0Í+êœÎH€¬ûŠÈá^éJ€¢ÀH€º#j$@­Û•µÙ#²ž) ÖãL€ìõ Pë uë”· µ›@4‹„¼Måe f|¬Û@4‹ýl3÷º—$«öÓ@ÌG¯/Ó3[Û@ÔÒn¹U{ˆ×”ö2uº ä玗éA}˜žûp˜ž5Ürû——øÐ*·øQ5½ äÒå—¼ÒyÈuœ/q/ª¼ ä>í—˜3ÜŠm Fu¤0u-ë2ÍΣÅ6õ|âš(òMJù4½RÊpQcÂ@þ®Ë@4…¿ DÝFQ÷Õ.Ñœ+b àÌ‚eß²ù2ÍÙÃ@­sveŸ¥Þ²ùœ`AÔ¥ä@uJ‚|ÓJàëCˆ Ki‚¢'·@P_4A­û… 6%dÝJ ÈKÄž<äzŽêÍ/1+SnaR’@õ‚œÁ|#˜Ÿ$»ÌÌ(/³½ùD0Û'8‚g¼d=oósë6‚ù9¹m)TºÌ<¸½d=_¢žë,‚¸³NÙk½9‚¬«rEu¶Ô¢)bÿÊ>L½ýcó9Áª¨[³l¦þ±§lK›êßëCèËþ ¡û§ßn‡õõ0hÕ?{Ó8ýÓ¦õO¿ÈvúÇeY¹ŸþqA³sÕ?ÞZ®Çö·¾Ú¿ƒ?N• Ùüº›ªó§CȰùæO'µçµôêüq¼['…¿6œ?Ýi9Zçuò§M©ÎŸá3?ÅIúÁŸ"f )Z—ìü±.FèÅ_ÆÀ’žÃ?6—ë§/YY×~E@4û’éú±–5>¬ü±'9" ê:KD@þ?•+fîUñÈ÷¬P?cœP{5" ëÚ#j]®Ȧ”ˆ€¬ÛŠÈ—ÓyÕ|¾muéfD@Ô¸ïWÌ "" jÌDÀÌ]*gDoXJ¤¨–Œˆ€yà7õ+¢Yx¶Ø¢®«FDÍÝwˆ6QwQÕ"¢^­_0OÄS ¤j êR%" j‘Ã@4l•@”#e€,e^Í&Y“*`Þg©·€hî¬ ÈzÎH€¬û¸ ›mD|}d™Ê•³žÜ"ê‹j$@­åJ€ÚL‘õ‹V$@~hiWärÖ ÷×ärTZº gj$O€™ôJ$@Ž`šWÔ9‘Y÷ ýҕ³>#ꎨ‘µnWÔfÈz¦H€Z3²×{$@­[$@Ö­ÿQœØú|ˆf‘prW<(AÌ8vÂ:D³tK:áØ¦å¢Îµb‡õZº#8t¶ÄD-­¶AnÕîâ%¥™gj ë$ù0K¶ƒ¦å²~6S8t Å äî/¶ÅÔ@|è62 ÄE"®ˆÈ•ã6ßBXN'¾uZ˜R'vš¤ár›r_¾ „[˜Ù¾\øÜÔ²#¢Ê2ïAü=lñ×Z ˆ+IùB€”2A\}™/ñÿ¹n Œô@ëÞ_âÞ¬v#,VäÀŒÀº;‚(G¾äÁ¦¿ds(¸S‡‚Ù°¦ f¯ä—‚¨SºÄ›Vz)¢ f>ÅnõèöR//Y÷[A6å¥ êV^ êθLœ®P7–׿Äýr!ˆYJ2óF¸®np*‚œÁ|8™cór'Ê7pê[ëi ŸÅbžHpF-n ëyÈÞ>À’@î")‘éo'Om=R ë'@+¨ç²/ºÄ}—¹ú9 ý±HLÌMc WlŠ7ƒ˜ªþ\2ˆ:Ù*=b«= _Ò”QzH˜8_ËhT Ñèº`‡…i3È€iÍî 2Ó: d3sGn “­lv oÇ4+ÃÂd‹R¶l˜UCü}´yrˆk²Œ6õ‹¨1wƒˆ—óÌý;&e~Ú&‘׬{.Ħ…tg.Äkqí Á]XÎ%Ï+‚k‘ƒÝS¯."6ƒà,w’ˆM…Ø×œÄ¢ •Ä‚õÆ#é$± ¼ŒW.,L–R•DÁ¯œ3Ÿ$ .r¶'âg FêY+šˆsMªö yØI5»‰¨í±û˜¨,駉ÂS­Í–šˆ£[««šˆïY§‰hYâ&Š`Ê6QxʵƒE˜ÈodzÖM”MÊc¢¾iÈi"›^”D~O7"•D¬ÊÊýË™ó)V+#r!Vå‰o¯\øM‘! q’á"r[Zó4‘“Z8E4Ä2Í£"V§õ!ód‘û±¥º‹Ü¹¦î0jƒOăFveÖé6¾YRyˤÛÉÒu¤qºx›G6ðÔ[î#Ãî>~r¿ýî÷/?|þôåóo¿~üý¿þÌÞWºË1P_øöÇ/¿þõŸ¾úþûï>}úÏ¿þþÛ—|í×þ¤¯üîõ’þøïŸ¾ÿå§_ÿñ·_~þËû5ý¿¯ùõe¯YNDáWÙ’•ËvùGdð$ ö "!!àí©sÊ.Ûw$D°B«Ù™SÝ}»¯oÕçÏú×?þ¶Þõ;üþìä³[åŸ_þåÙþõWü«ýô›ßþôË_ðÏú+ÜoÀ?ŸNñiÌn™ï€š¶cÁœoïCòYмø°Zäuª!ý-gzÁ~rÄ{žèG¶Æò#·1_ðû0Î…!u`üÌ®Á}Ö¤öÉ3Ç9©Oþ‚Ü…óñ&÷]±·ðq{Füà=׬ŽÀ=ñæ>´Ç›“ØÛßFû¬ª öëI*Éb=nö‚=Ö¢ù}Øc½j©{0Æh°ç3©úÂ[]] {>l™{YþÀ£hf°ÇŒ§y`í_Ø+Fû€=¸c&¼a*%?~Ø£˜]K {¢«¶€=ñVê {‡y\°G.¥¿°G1û‰°çEr0b›ù…=¿½FînÚ„½¨¿°gñ¢=¿¨ÚcY~À=Ñ*=p+®õ îqkþò¡=ÖäÂ=–°¤¸gª¼´g§Ö°G6Úëñì´õõ|êÚƒôlo%‚Þó|9Ïb9˜¿àCÊN¥='ÄÊQ`æ,xäì篋øßÿÿßÐÝžþTöÇkøj<›ðiŸgŽà[OûC¸ŸêoÃ×V«^†o$s~ ?k± ý2üœ4õq¾i#ã1|{‘O3D?ãäY/ÑÏëäóˆ~NÝ?´=¿ÍE‚íùMSù ±‰ÕÛó‡kBx¾ ‡3nÍ/¶Éõqi¾¦„ãÁ¥ùÖÆmþ ùÚÝœ ~[ˆBnÉ7Œ÷äSo.ÉoÉ•xiþé4Z\šŸmG½-¦µ£]–ßÄ÷ï%ù*#õ[òí¾äÉŽŽíøMàÛñGíÇÕËñk®%°÷M³þàø8 ÝŽOÅçí~_Ko—á7á1õþ˜žÃ)ËðM,´ÃWëéù5|´•\†oÞí· ß>4Æ×ð5gŸÄ¥øZ—&-Å_dž㳷Žãg‘ZnÇïEêŽoíÑ.ÉMsP(Ypü–|ÏÛŠ?³úöºß¶µ1嫸8p:£·â[[ë¼ú~ò*¾^vHZro„€}ä?hÜr?F‡üVÀõóÿúÿÿ[RÞêÏ)Éëä­ü<óØÛbAý(9"úèRòŠ¢lAO#¹˜¢Ñ,™k Û„Ü‹9I¹åº9Ñ<—ln¿…Ürn¹»Ûb[N³Œ0òf@ÀÜJ õcŒ+9šRõ/öê«æJ.>'¡ä6O­Áv'·bÎ=¤û¤Á¥Ûd?æR®§|¤\üZ!娂?Jn“4[É1Dm%·±“0Ä­äVäoÂV½•ܲ÷£äöbIîž »êå8y£†_z 'ÇCIy†“#7­áäx†f·“ó!qη“óéË'G·”z>D'G‘°/b}§õH¹ef¹¥œ“Ëú9r4su6»Ž×É1ØÐ¶“cÌJ›áäœÔ~>D'·¢IV '·lŠ ÛÉ-ò©=NŽbó¢”ã݇„RnÛÕ+å(¦Nn±fŸ>:¹åÒÚy:9ŠeŠDÖûÛÉ-K½¸àOÎn3÷NŽ<ýüJ'œzùH9ŠpÈ-å|“÷(åÈÖ‡øÏ`þõq‹©1ky)‹IÒy(kyh ÊZÔ\?”µ©›Þ7>f­& ʰ{ý`óÛå`›ý(³özò|a<˜õ°V ;µˆ`̃ZS?¨k›ŽZËuäj­X|öµ Œ–ÃZûuÒäÃZq³ Öbáj>¬5º¨×/ÖšVT‘ÃZ›&ѬÅ7BeÖ¥`-îmq”°ÅÌCuØbÑÆZ4ŽŠyV¡¯%lñ~þÌMZä$%HËžvòÒ¢‘ÚºW–#5´Ñ_ÐbtÍw´˜ÿt8‹ÈCïÍYuŽà,³ÓœE¾2‡³V´óL Î"ϘEìå¥,jÍŸ))—X”EN£½”å—·”Å›0*›²ü¯hP–µ–ƒ²ü"íAY\³È Y¬¦Šdq½Y[@÷©­¼”Å u'")Û6ò7eÑ€ØsÊ¢Kk@ÖR×q +±8d…'Ö`,†Á®3Yʇ±²žÚf,²_Ø‹Ö+ÄaYb‘EbeÝç±jß,¾ÒÁ>ÔŠ¯:Ù‡œU7û¿#——}(–ÙûÔ>~‰{~ɧ¸Vð!ÂÖ7ø«ç>ÅxúfNðáMeò1—|¬¥à³l—Ðòò‚En |¸HÒàCÖörw©E‚{\´س˜§¼Ô³ïqAÏbS=Å`ÎúBOç­гœ‡%¡g¹Ö\_èYqë ¡gy¬v$÷´™§”~sÏJ>µ‹{–ƒÐ˜"ËeÙñáž÷¶EîYæ1tƒÏrOÁ´šmL=¸§ýçTÛ ð!úrµ9[pÙOäžeɾ»î¡ØD‚{–M:f€Yò|ɇbò§Êᎋ,ò!×Q_òñëý„Æ5DV?}‘|þ¡ùµàã÷¬‘øp‡\º›|¶tÖž3ÈÇÇêÐ"ùÐ+³å—|ÖUæ©äÓê¿ÉÇ.¬å%;ÕÏ¡ìûK´úxÓù¢¯uû8I‚}ÌÎíÃ>s ö1·@É”ÇË>"ÌyDö1K ö!§ÅƇ}ÕÚU»>ìCz½Ø‡ÜêØìC,Ò^öY±tž6ÆHâ|ý,ææÛࡊâ§âϲ4òð|ðW1¥¾ËxS9ðÇìÈ9üã•ç þ!Á?äÜëË?Åg’üC®UƒÈÓEð÷´ÈJråÊ! åVÜ"­8pƒ›–çT V ©ŸI­ˆ©Þ´¸éFZ¶Mµ¿´âö4"°[¬™–‹–›€VÑ^{ÐrIƒ€–Û"â! {Õ´lm”ƒ€uÝüüphż¬—´\FËÀºÏG7Q\ªÖ}ÆZDæýÞ´¢¦¤@ä^r Ys~ˆbõçJÆEñM£üz@¾ÉFD ó:èl²¦5È/ª3ˆ×±Ð± K—É@>×2‚è•¢ú2]¥Î+2°n /² KÈV-y3ѯK¢»»–VÔYs À™䈤ú"E™@f¿2HBåü2W– dN=ˆ\eþÈÀb ;{}hµ!¾ðd rª}3Ynyˆ¢Œ±h©©›ˆ˜Z}hEÕåú` rê%ˆœ=Œ©ï·d Þ$î‰d óêà` ¯ìÇ$2в["7?ó¢ÈÍa1™g¹Å@\´¸âFK.Á@®œhÙ~V~X¦!Ú‹d eÛMC:Ú‹@+vvðb e{îõ00aÛ‡)œÍ˜l±æA`²;õ³CÌ~2lÕv˜®É@{}|(&lnŽŽ@üîý& оnôüA }ÁpësÚä&8¿øB^Ä!gŒÃ@‚æa ¬#íÃ@+ÖTñ³ŠâÑdù0Њß«3p_d3ÐrîíÃ@|½£œx“‘œrÎ<Á@Ô4â‹Öè‘v‹ú! ­gw¯râ©:¼H@´J×úM5µ y<‚€ìÁ¢/Ù¨E6g@ËIT^¢ãK•@ y3K âü>dQF Yó¿Y¯›žKn" Àå]N$”¸üU6¬eƒX€ÙFdDF EÃbþ=çTÙåë!6(šè=¾Ý}oûãq94 ڃ׉—ZömÊdKÈ[@AEÔõmVo…Pˆ$i<Ä´o>š\ÃXs´±úvø`r@äÚõˆÜ=¿ÈEê»­ˆ‹šÖ ³ô€|ò” ²Ÿ„Ü?ÄÔûÿäÓ%üãÒ/züKì‹öðï¹duÿÄG5üÃ\µÃÆå¼™³ÿs°– Wè£,xàlùø—ƒ6ó¹—Ë¿’£b3ÿ‡m& À‚>,9¿ˆ¦ÜÊ ‘¥M Ë›K@4Ö\GˆÜÓ*ú( 2pë·€…S­—°`:±-`Ù§˜WÙ(#‡€e…–€ÌÕGúÈFÔr ™‹Ô[@6fY0²dö¹z´ooáŸ]âÇ$óÏoi—ÖV{øÇ<ª„ì•1ë- û3yYeÚ¸–`F§T}ˆ¾/Ž•¸1ÞræùPØÍ5ä¤ðòÎÄ5‘‹fy%Mݺ D®¹œû*_hÔî…£ˆ<«– 0wèÖëM Á¢È5µ2WïÊC Û©-zùf2€hCÝÛ@æ™KȬRnÙØ}\ ÀxÈ9õq hßî')›çv‘Ÿ’Œ@Ëë̳ ´6/6Œ@æ¼V ä3óÌ7ìÏêe•hãê|™œ+­öÛ@Î*­3 Ìth“0ëM gjÍe˜ƒ- '÷¬åRJhÜŒZv¾€¶l€k §g hZ‡^ÈÜ}2-/ /¥A±6/Ùfð™KqˆèÒþØT|0±„‘ºªnþs»õCJ7 ý˜s›¡sõ|ô®P üxMé=ð³œÆŸ=x”ÐO¸„Sý˜‡/¢£ÕW£éLJ¤uº¢~ÌÍ Â£_s¹júY¯ùÌôCžvÎxÕO:j‰¡¡ri¥…~Âõé'Æ£Uk ýl†Ÿ(&S’?4îjÍôCn¶“,ýU¤¾ê‡¦YŠ„~È£Œúñó¥áÑOjµø!æ±ê=â‡ ×Æ{j-ðCÆëõÀOöùå?6N­¡ŸìCÐÒyd?ìþØØ|/4þ„G4éÁ³¤~óÇÆäküÅC̵ç›?ûúšƒ?»ÈÏHƟߤÖVFðÇÜK þøŠ}ô›?4–áE•ñg›sðÇÉ2˼ùCcÇÊø“ñòϦa–Û?ÎÕ!}û‡˜¥‘S)zÈIßr å1nm夺?šO©ßÚ“’„€ÌiJh9•ÏÄ„mMïmZJ «Ÿ%à`ué{Ù1p|™T¥-‘DýØK±TzõŠð ˆFZ ¨$Is ˆ¼¸A®Sßk A\£ëÔ`2'§ë ÈŸæ† rr) AäÜúAµ!‚ÊÝO5DÆ1¢Ý’š³dÇIÏ &+<Árb´‚ÀÓA.RuЂ“'›ÜÁÉ>àäÆ:àd¹æe¢!8ÑY RG0aEK¹L(ò<¦¶!˜8±ëÁ„jÍëFW0a€{; &¼hëêD/ù\AÁy¯¶£ aúCA|¼¿]Af¯ß\AäîÛÝ‹‚ÂÊW‚<§I; "·Ô ¢±&= î‡l…ç—‚üv?I9‚¼æ”€~K» d[éÇ@|m*r ÄçiÔ‡èÏìe•ÈqÍIÃ@ÌÈô0³ªU i¯Šœ„vlz%3Çž± ,ÜZ#³[íL÷J vÀ™ý#ÞŠ yôyÈu“ÜZ#Ðj‡@•Ö5Dc]‡^ È8f ‡•õs1[g÷ 0aQæ>O˜øÊÕ¿“&V˜¹<D«  ª‹A¬Ž†Å\·ƒÈøÙþ#„XcX\.ºIˆ†Ô8¼›B4`JÎq[È劃I q™´â¥ªqÈÙt½jC,¥âÀzmxÈóâceãq‡VÈI¸ˆßi{Ìb1ÉÁ¹XDH.¡b¦à騈¤Ü*B›Qr ˆ¾·¾Q,än>Pĸz™´P,¶ÐJ èÇšz£È³Po=PÜg£e"ÏOö¶¯&¼ÈH§2äÁÍœY&S Þ&²qí£6Éâ!ËÄÂCŸ_ŠhLå¥2äEê+ÄT´›\ÉP‘mÙ×¢õr5S–Џ´ª¶[Eüˆ®/•!Gu}^¢[ŠÔGe­ø~QÑùT†Éíf3µ/”9}gn:ÂEð,yL¹aĬ/ný’‘©³m22Tõ¦1ùðå°Ñ`š%ldžÚõ!nã¯Á#F§BL,êÌŸùÕ׿~üöÃß>~ø×Ï?üúéí·l{÷õo_}÷ñ×?ÿýíÝw?ýðËûoþùþçÿôÃÇŸ~ÿío¿±kþð_¯ùó§_Þ¯«~Çÿñß_ìw¾?û÷ý'ÏøëGþÕßÞ}ñöý_ùç¿ý“?î øß?ÎÝ)î5Ôó˜ .;Û°ؘ•»rÅòf¶]E³´MKyh„¹Y É<«ÝÄ ÉȱØ÷zö­áÐéÉ´‰úNËÝ3üóþîmMãc Èµ¦•‹=®6 øŽ†IŒÆÜÕ~—`³·,âß‘ü;¤õóð+S!S¸Ó«ULÜäÏÀA‹YY¬î{0Ù&ÛÐé½Ví¢Â-µ¥ˆE›»ûãUßmb6,㎦ÜÖ°`˜ñ«W \]4rëäEÖñÜO1}¡¾Ý£´eßcû¹”ÕÊ>û"Ó Ç{æH}øÀ»u{ϼ¨v±7¹gï;ì›”›_»ˆ=ybµÙEOVniû%éþ&jf}¥¼¦tµ{šudŒ¯÷w¹¢Wn ÌRí×L`jÙ^yŒrnb£&f'r#Ä}¿˜yFåìrnj¹ØMpÙnÚ±z‰¹¯yØ7®öõjóŒ 3Â8›»3î±/2Áâ®.’T§‘/ŽJÏs“ ë1ËÙsæö4¹Ó‡®éÿ²û›ÿ»Ý¬|PÞ<¤e9Ôæ‘y´~¤BXÒbÙÍ©GZdÌÃ#­ ú²ë-ËqèŽú ÄsÿU ¤àùêSJÚŽ1\ćZ4bS’ZÁî¦I­}^<'µâG×ðV°³&·ˆZ?Ü¢Xfr‹ŽF\n-·U?ÜŠ¿ÙàÐ`_oíÇÉ·öØ„üz‹±³p½5wмÞV["é­-(ÁøoÑö=^oÑñ)æßñÍܵT¼_°¶¿à¢y[Ö]p-÷Ð]ÚÔõj‹V ­ýÕ¹ˆ†¶lK\ßÔ-Í-´eg´[¶S«¾Ø¢ ³ÓÄÅ\IkñkQì{…µÌ¾×ÑZd>í¯µV´Ã†µÈ>›H-¢û˜Ò¢6|s¦´?—ð“©å²Æ+-o>Æ•ßÁióJËÿñ½<¥e[Û‘–7r§nÇ9&-³cò8´h¿7ö›-¦ fô#-&Ô3¤—ý+-&`ëi1K[Bkqö•Њ&^hqHêé,CÑtYô㬜·vœ_]á,pÒ³P¬ödÙïëÌŠŸ þgÓXV}ýCQ}Øérí=üã:­úú‡¢îþÙ‚ÙÙg"ÕY_ý°¦æ üÑØ_ü›çÀLßÔ‰¾£+õcÖ?ÖÊü¸økü—ß'ñCqº¼Ä(ôø!÷ñÚ‡‡ì*aÇ­]ú°ú·¼òYàøìïè}|¼™?e‡_ÄÉ{àãR=%àãPÔö‡ñbSxàòÃÙíÚ‡÷":_ûð¾qÔ½öá}§¹–8ÝNóöaž–¡aßë?¬òi4±ÎŠw–°KyìÀyµ×>Ôöa³!íÃÒ>]pÚ‡â û€„z Iü±výP,*¡ßÏE¨eYíÕ·ýê‡ØK ýüö«‹#ðã}|Õ?<áô£[êYvÙW?¾VÀuôノúêÇ!=ôë¤x„~œ…M_ý8SýHJþðnÄ{"òÇ×í=SòljÑvøÇQž9aïJ^ÿX¬ãúÇ8‚?ÚT×ësè³hø‡\ޝÍ.ÛgýCñ4Úôy´þ!«7üé_ÃÏ];üC‡šZ¾ó?DQ†–eÌ"/ÏA`ÃRõÝ–â;Ó{7È\Ûk /ì]" DVYa rí5Eq i rk= DÞÞ&‚x$êzäài(hq¨Ÿ“A+.¼Ìë å½»„ƒ ët­×A+6Á Å Z¶½u¾ ZÑ»µÃ`[6V»ƒ–ô« Õúô-Œ ZnËg<×”åqTL­8›ïTÐò®Þòq´mëÕgw2hÅÚ¦\-ê5l÷°ôë ŠÞò‘Áv\‡AäÓž&ƒVìÅ{12ˆ<] J†Ük}D±ù®I.Bq§5×Ë oï{äwö ™}“MYì-ä:ˆÏm5¿b<õlæ ß«®psE{Ĭê}‡ƒí¢|ä,Ôù:È©ª5Dv¤É ¦÷ìú2hž[ ‰ÎîÁ —Hi/ƒ,ʾ 2ú…é ªõu–2—"·sÍ×AµùºýtšZq‰<DÆkºâŸN›™¢(k…ƒ–Gß5D.£½Z±÷QÃAäâÇ:ˆ\=‡ƒŠµêû.ÄwÄÛ8:Èì³8ä…÷ -ÛŠ›á òð¥ƒ(vW˜"¯ÖÂA\T}›IñœZ5äài½ZܳÔ×Aݦ´é eÛTƒAÅ:]ãeЊ“³ø8hÙvü–ì±ãã`9Ûu°ØXíd°Øú<x:XŒ”6ÒÁh»ƒöùú2(Ö¹ù Âöó%2(FܬÅFÌÛ?2h‡—:$ÄaÆò‡AœxÖJy"Úé Ø“x«úã [Ñt§5ïôÜAû|Wù8hÅU5Ì‹¸ƒ–ëqû>ÃA|gtPâäóã Š½¦ƒ¸‘¯>wб´áœEBA¼U¡ ¦ Ïs¿ bRí>CA¥É+äÔþ*ȉª "oïÈ å"ÞA%ƒ˜òêg 2Hs¼C"ƒ\!E_Y”udôA!ƒ$ê£ ¯ë,QAæÒCAäu”ü((ÖùQЊ§v]P"hQ¼-ÿAÐæ}_’ÚÚØ«'‚–[_mAíÞAËmÌDÐòðœb¥ú®ëÚwº÷qŽ ²Œ‚¸ð–DвhÜÀâ«þ5°ÄÁÑ Äê×™ZžÞþhI]¯:?”Ñ@‰výÇ@ùk{÷4PlGmšb‘~ZA­öÝ^ÓÀš¼Á@˶Áî×@+zßv ´¼¸ŸUíIk}´bÅ.‚–¥ïZÖƒb*hÅVÛ -âÍ´lÂWA+î:ô*¨6Ã%¥‚z4¿ ¢(ÞeRA½ç¢£ òiUSA§7eTPñÓýü@‘UÚ« ŠÕ÷M*øs*ˆìS5äÝû5ßX; ôÿè¯,¶"/'„bTÖn¯‚βûUïUÁjcÒæA›TÚ%¼ _1 ëþ hûT©-´¬Þæ9‚â?êEÐvÀ©-9k&‚È{|”óÞ‚rÎaA%í£ .Tv*h¹î "Ÿk¾ V›®ÓOª© ŠÛGž "/ÝÁ òi5“A+êž;DÖÕ‚AËuõñ2ˆ¢ö ZŒÔeŸÏÁ`ÅZõM— â¶·qdÙçp2È ïP±— "7¿O2ˆ¢úÄ&ƒÈCG0ˆ'Þ&ƒxl‘ rìj» Zm·—A+Úð¶`°Ú_i5¬X¥óã §ñqв7ÂA˶î×ÁÚ¼o; V{ܽj0hYg•—A+vüªË å‹6UÅ»9Ým0hÅÉÅ|´l“@ƒÁj³`Œö2hEûP.ƒ[é "7ÊdÅž½ c•Py}´š5À=DÞÞåAä)ú"ˆâþ\„"—±^y÷¶/ƒüÎZÁ ³ÏÜdEï9È rõÅGqÍêg¬dÃÙ¶^ù^ë1W:ÞÆ¯ƒ˜U³íp°é`“°Î—AÌÔV5Dö“$ÄìÞÞ>¥‚(Šj(Hr¼?¢‚Ì»¿ rÙ‚L>&D@}[A^ÇU"‚ÈcÏ@ù ù"(6þÒ÷‹ Ч&‚ÈUk hÙµKQÂ"¿ZsÎ ¹öW@«Y7C@äÚwˆÜ<‡€Ò¹>.€øŠzG™Ëzäu—†€‚UŒU{D^}½¢8‡„€¸Hñ“DîÞ¦€xJÚzäÀùq ƒcq/?½¥€bÃ8× “ƒ,ÑY_³®µÐòÅ &{‘@+zÏv´Ü¹™-O‘ö hÅ­*! å¥k‡€øüˆ˜ʲeÕ@‹uyßG-nëЊ£ô~´h?j€r3¿¢¸½Á¤€rODG@Ëët©I ŠÝ÷C(8®ùÑ"K/(ß4IàÏEH rõ%·oõÈï, ýæK ‹º‚@äá‚@<¢QòhE]k^ùbÑÑ1Y¶î—@+iÊùÈiXå5suÉ-WÑDÐrQ/‚˜õ½Ž@ä¸Dy­A®œ¢WAh†‚ªŒWA^¨H(ˆ\¶„‚Ì皯‚6_{ŸŸVЊSýá¨àB T²\h4ýw§ƒë¯Ì)ýëeÓ«ÙMá¿r—‰„ˆ¿?`• bR@d;JF$B ‹ù÷TUÛí×GƒØ h¢[ýûÛÝ«ƒƒ»Y‡såÒʲ†BÑ1T!j¬qÆ Â®Ú+Y¬vç „xÄLÇ!u0|rÞa©.²–ƒÑR „V_ ìº ’ƒ°óìÝAž¢Þ $BOBî]liƒùš†¹ÂW1l"@zšƒuÚ j„“]NjÂÉ|ÂÉûu>œà¤i[v‘ œØ«SaÀÙÅüa@ÿ„Á±m €Ýr·„§‘Ç!aÀ-Øê!aÀk{0À/š÷ #z¿R Õд ÙÙ~ ©c>$„^Fõ…„‘¸²g3Ÿg$„®¡>Hˆ` ýðLb$Œlc äÛKtò‘cmD}p0xmÈñp¿«£b;í•qçÊBÝD®N"«*?maøí±;™„êž^1ˆLE÷3ƒƒV %Çà`’×rc—àL6H$s€ Ç õhóÆ ë&p‰A!¨ Q¡Äƒ¢Iq Rr¾MÁ!kP>AA$ë¬1öƒe™Ú MÆ:ñ‘zööð‰3$3eB$#ãmC™éüâË_>|ýãw~ü×Oï~ùøöÆ>ûòó·/¾ùðË?ýíí³o~x÷óû¯þñþ§ïÿôîÿÿúó·_é™?ü×gþüñç÷ë©ßòü÷}踢ß~4¿¾ç_íí³Ïß¾ý+ÿü·ýòÇýÿûû|tƒB^i°ÿܱŠíf%LYPÞ¨Ô" !Í\ûnÉ <-lãŠÉER#©™e¨J÷8»Åàtù/%êÀJêfµÒl»AŸ‰ÝçÏ´ }à˜¤Aè¶O1¤0c¼¨qÝS×:íahJÑ|•ÌHW=3 )²P¢Û¢ÆTÃÇ H1Ó¾VÛ3®ùÌÛ –&&|ÐFµGÊKhÕRçVØ+­C,O2c¸”!µë@ ä'êHªï!º»,Øç.Ûg¯¡FGSõ{-ÛàGìPÓL‰ýtiQ ,€$uKI“àªê¼$X 'JMšdé WúЂÌÑîПi«pÌйu Ò×%&”m7p))è\‘Bš¸0ExFuÚ -G˜}ëQ‡-@× xPÓP³Oe²F>¨¦¬Am²…:“tä>e³$DCT΋€N%jÂò©A5%ržq êJtL~ÑØ°x{Ѫ:švnËÄ‘B÷¢ ôfÕ6Ï;9,3žà£m‘a›²¶»õ;g˜©ÑiJ'ÓìΨSÎ9Ìý?¸ýÕÿÛ ugó ,‚,ëMYÈQÛ¡l¤¯-Ê¢ê¦eŽQFâP6Ò@–³ˆÑ‹:f#/¶|0‹ßƒéÌFk\7k#ïÔƒZÊœnÔ2úA-¦aÓP ]Fz 6Z):jI™škñm±Åk±hA|³–;WÒa-¨Ãëÿfmüb<¬E9Å:µ-Ùg¾²±ž™{ÆZÈÍQÁ¶el`ª7lýhê[è꤅h=›´ŽY«“–:Ä줅ž‹¼‡´ ž¿µâ¤ml ¦ƒžnÐ"ˆZhš©ÅY*šù‹³ ’§›³ÒFCq–Z«}å,‚hz²s–ÚRI˜¥48Ê2Öì^e_¦ e)Ãh7eõîÖœ²|(†ê”Õ oÊ*Ø’SV/ªÝ)ËI$²ÜÌ£C¶±?àe³ Ë4a xQ–ùÔˆ¤lÛÈß”MVŒ7e™£å@²Ã:dÙ†µø€,‚±ƲB>Œ¥ŽùÁظNm36[±$S¾K‚¥zKëA,t³)ˆeÃǯ¿ØÇ`¶m'û(S­Î>u´)ßìc0ÏæìCg9¿¤J=]äcïÙ»ƒ’~~ƒº˜>à«,Q»Ð >>“Ç!Ÿt¾À§Ph>hLP|ÔzAÝ |œ$Ôä࣮íæ—Xstîi׊c2ÍxS1­pA8½ÊÊdi¾@ý­× §vÖ¥ ÇNµØ[ôØš.3(è±5Ís8÷Ø•ÆÜoîUò®ç[ÕM蹺·åŽ÷ØÃ…–{»Üàcÿ“­h0C)î©Ýmsƒr”›{ŒÍÙœ{ÒÖ[ˆ{Ð1Ùåv¸Ç`‹Ñ¹Wy–Kš½íE>CŽN¾—IH>Êb_wȧ··ê䣮Ö{‰|6hÞäS°9øôžUrWØ­_;äÃÎᣦ“OçjÔù˜+“4}%’ >µnòUa¸9ù”ƒ%ßäSžæé胮±6G´öùB¾–éìS=˜û¤c¼Ù§`jÎ>éæè˜Ò¸Ø'‚Ä>icªØGoö1•k¯7û”Á6öQ¶2œ}ÔÙ|þa‚¹Û‰Š}Ôѽ«1µÖ.ú1­°«õÕìc„?êaúàOd°›–øã3ÝL›1Œ:•‹š×Ì¡øGãpþQ§^nþ1{wþmrlþQO3‚€\Ñ4Ã%jëò! «^­Ì+!F ÙÈÁ³Fg ½q\ dÅÆ¶¨z5º ÚŒØorÖK³…`—u,ªîòM@q/Ý ÈÓ¡:™!‹ˆ‡€ÌÔR›Ùž–Õ‹VWèÔÊ@[éѨ‚ni#°ìé• ½„À²›¬…@j-øÖª#º[£P–u©5¥ »0…À—Iº•w}ÜÔÛëpê!kŒ„@éÕä8¬Å¨•é äï¨ä›¢KÈÎ@lÎ@-µÖ›Ú$ãX6•ƒ¹ß T¢æä ¤¶yÍ?ñ¼k¾ÈLŸ%9œYª»ŒÓ(]³3P€Jéb &ŽÝ(º3Ъk~‚³NkIÑvž ¤ ¥;9f¹ËÃ@ãÎÀÌO™ÉHZ¹ˆX­Ëî“Ô¡gg u2}˜™vç’|&š¥Woj^ë“Ä@h”[wR7kzÔí°H=JqrÒlžð0«ÌvmˆÚ:ógb ôì!Ý ÌÈ¡fA1:çê̬ÒÑ."Ö•ÁÆ@H\ôå00ðnmwlÆÀ€š`¹òÂÀ€ùK; ×b ~Oþ‡í:Kr†az£.‘Úﱇ²\ó vÚqdê™2LlšE áí÷|(4,¨šôE aA4õ‰@œX\Ý7ÇŒ¤zÈSÎZÇÀ8íc añõª{ˆb+õÈšà”øûvûˆâòz < ]/«—üvé"ù! %íœwŽ,v?ò‹ž­â'ö€XÎYìÈÇ*½B@¶Êìí=„¬áñJ£k¿Œ6­–2ï¶’@äbÝnÙðµYÞh4 cƒ”zE½•ƒÀÈZ• 0|ºŒë>'^ ¹ôy=B~4ìß1?š6ÁO@ã–9"š¦ñ€hû®ç)±5öê@äÖ× ¶ÓÖ˜/‘›îE"å€Ü¨zã€øL×'™mÜòºÛ€È:ÅÈ?Ä2ÆÇ¿‚ûøÇ­_çñyj&|ù‡9õÒ’\8 gòÍZ4u¾ü3tæîÇ?Ã3Ó-M¼ýs ÅŽxüó¤-üCÆ‹ußþ¡ø›×Â?äÕ5Ò€µ¢EÝoQô^wˆl}Ϲ> QÄ_) ò(ÏÐG‘Û¸Dq»‹°6ü1w÷;ƼdÑtëï,ôÈÜô €,Î=SÀʃšN ! sµv È¢?Ó6|]„2Žy_ÞÓ¿øˆIáŸþ¥ßþE±ôy5Kÿ¸(k·[@.gÙ=Œ[€ŽEió ±A-üaüОÁéï¨âíˆ\5Þ @4woý Þ~³¶ ¹y ³^ /íyn?--"ûÞG@f]ó# £]§Ž§G@·Vž2®º“@ægÂ<¢X÷ÜI s]- DöÕÇE kõ™úÙ.È8áö$/ʇ@çVÕ —ò¶æ· 0òÓÁ?ãº;dì:Ìmô›@«Ú:du$¼7ÓHxä6ëI`¬œf³ y´ÝnQÄê¶$Э'Î=:oQkÑÂ2¼4oÖuˆâ3¯E?yÇBéô"×évˆbßu%ÈÉ5÷òxÆ×C Šshp ‘w›5 tÞåh7(‚EK‘[éõG cT‡@û™#j| ™×@Ô0øöyKÍyZ½dqXO_!€Œe¬[Àøò¶“ÀøÎHA`ä缓FQÃFÈìÏÎ#¼¨ë`uär¶]“Àx°ò+ d¯t>Ž·lª_e ÐI`´ Ï›@öióš2Ï–²·w«·€,b{¤€Á£0òî·€±k€µ(`èôã:Ï¡—2=ÀÈ7€ÖùÐö ‹1 @F¯ž"KºÃKU3øCsÎäÙû¥J˜ÝfêÇ캓й)ý¬Çüø‘ªá-ð‹\Ö…_\vÕÔϸ…‹§~ÌK»èèÇâ–úñ"å9^Q?æ®ðèÇߨ5y…~±lšÌB?ä'·~nâ¤øè‡\{í©ŸqƒN¿ôCmNv„ôC|` ü ÷ÔŠÝø¡ø›ÕB?äo‘G?äiÖnýPܵZꇼêÚ©ÿþhxô3>¾–ø!úzæ=âgl¾nüPÄ–é‰2~ßøág¿Ì?·fÿÐÏ~§ G?äå:§þXìzÆ}¨CðÇleÜü±Xô¾ þ^!!ŒmøÍ_|{óä/>¤MüéŸæÍ_ëJþ˜G­ÉâXãæźÖLþâɺ'l–]÷ÍŸ=OãáÏ~?þEºÝþ±S—ôÙ­‘K­ó=ß}$€Áð#ëµpŒSj (f <•q *–2—m)`d]ó# Ÿ@ŸŸÅÉ–\~ÊçKÝö1vNëi Ýš:õ†h…Ñ4&‚¨Á¾ž¢‡âö"ë„ûF{Uï["ˆhÜxd.²+äe—ú<äF.‚2Dö>>F?oO'ßÂ7Dç.IB™žrålx"ˆßéKsÎA«hKû?ŒgTG"Èf™Å.Ùu%7}[‰àæ{u&ÀÍaMcb ¸±RáèÁòWºÕ‚“‚ïƒ`9`‚¾h|}!XðC47JÁ‚6ý(X@G æD|RÐpàk=ŒCÌø(È“Ïô£ ³æ7)ˆ<ô¶{)h}çQç4Ñ)‘{éQleÏEBAãÙåƒ ¿¼ÙAŸ9# þ¥ d±Žc ¾¶T;âïE›èe –ÓWOù`Ùl?7t~ DSõf?Iï´™²ãÐô&÷€CÏJ§YrcÇîM ^€ÛõOA -œH™×Ø7Ü6ѪP?Ò§òQ¢ÖžC/ a\»¦€+Æ‚öѬ»›Í›À‚MécçX85}g X8czý(ˆªa jÉ öG/ü9ˆn]wšb—õº…zHˆBÁKi%…( +÷º-ä– Ò ñ)ëµzrÈëìýñũЯžæðÞDBÂKÄÂW…Ïš$¢€ï5âÂÕ·Ý&Rˆ?åA‘KYöœ©"xs}³X0gÌmg6Dù´3b۾߳!º¹ËÙð§áÛ3žÅ5Ægé¢c ÇJýæÃ¢cἦŠNÁËQÑÃ=»Ut<‘ꉢã}Ø—'Š•Ü튕ÛoÌD™XèEkÚ"C£D±þý´Lxq endstream endobj 11 0 obj <>stream H‰¬—Mëe· Æ÷…~‡»)L ÜX’%Ûí*/J-$¥Ù•„fh›†0]äÛ÷‘t¬sý‡ÒM 3™ç¹~9–¥Ÿí>Úxôñd]ó!Ͼ–’k]o~ù‹_ýUž*³-7»LE#£6{èe­s¥6žw§ÙÚ sµþxdôå’UBNÒ^}štvsñÑhžÏ&‹²Óœ®IYªóR7?{£Î=©ø’úñûhL»S³1±îõ”¹ìÁO&êâÚ_IÏ>„ºë¾ˆ³=yI·0u  MSŽ1üÿ„$|4Ï~õiÏi«õ¤eò€^¬c†A“a BÐÈfMw7šsEH¾#6j>f =[íÖîÛDZX¦fÚðÑ¡'¶Êõfn˜ÍÇgW/ÿ¨™éˆÉæäIa ^nŒÕWŒkˆAöûÿõñ'?}øüý7Þÿ뇯úùñ÷Þ}òÑãã/>üôþ‡¿=Þ}ñý×?~÷é?¾ûáÛ?}ýáûßþÑã×ÑæÿµÍ—?ÿøÝÕê·þ—ÿùs|è+ˆ?_ýœÿúÖÿew=¾ú‹ÿóßùËwÿïïwïV½ Ûèˆ}C€ÿ¹-Et{{.CºîØ5פ!IÈåT²Œ¹ùö#ÁaTŽËÈ{HßVèÈFH–» ­¦E¸F®JhK-†þ,;…nŸEê»Ñž$<´Äx°ë5‰"…ea-´¢‰„n–“4L=µÝ_Ö–WÚzFþ{#6—:cý45}îTõ‰qx2gÌz4BÅX#ô•¹»ÓliŽ9#‘–Ðb¨ÃÑžÌC7½VS*&Âí‡ì„¶Ã$ú`~®>«K6òB¨Zk1Q° Z¤Ç˜Ú.8ÀSµ #oÓ=‚â¥6–kcŽ1¢Øv§Á#"×@ƒ^͆F¢ †?3,m÷vØ o`Ÿ¡ÅƈP@Ý[†2>`wêÜb_Õó×5õØ#,¬‡ŽCO¶»Ó¤Ø¤1Á*hÕ3U3´HhDøîÊFÚ!ëè±q½°)®íJCÛdéG” ësE#Ä{w‘ëëeIN#¯‡µ8'ʲ›cÄËRE w§Hv˜CÐØwVU\/ç=v¾çϱi;XF´™-3ˆÄkcPÖÈò"†ŽcàÎÕ#!àÞÀ>ݲøL-~împõÑ¡aÆ©EÑ6<å* ˜ßbç|™6ûEŸ„c¦®’aðÿ¬(&ñÉ ‡d4NM+™Å"»ÿÅíOÿïÜ6DvL9) oéº)Kž”V”…Tîo(Kž£( ÙÝ”ÅÞÌÑß`¦çma–ü\“³ø½¥~Á¬aõ›µyZ¨u)üµn¶q£Z›‰ZJ"¨¥ë6µQëù¤R¬ÅÇ‘ÑÖbÙÓµ¹Î7k)‰t²–qº`ùÅZTŽb­9 –¬…‰ªšÅZèâ¨ÃÖ§ë [˜ø¬Q°…Ö"-„ ™iáÍ¥Z¤uÝüÎv‘z]ä½Ik‹µ^¤…æ¾ ´øp>@ %º ´Ð£Ýœu‰r<9ëf\‰/ΆÎs.8ë:ûÊY˜“Iг®W/̺rRÖ=)Êî!6e]·i'ecr³¢¬7¢¦EÙè´è lxÆEÙ˜HGQÖǼ@Rõ`*QAÖüЭ ëi¢&'e=¡F1(kù›²ž€8sOÊz–ö‚,ÔÐyCóùSã„,/б^ Mnƺ&yÃXÊ]+ÆR^Œ‹±Î&yƒXgëX×9q"Ú®1_«=¯ø¯ìsO2èÁ>׬ºÙÙËÉ>7eÙfŸ¢(îû¥+|’&¶´Àç2®óø\÷Ô7øÔë3OóŸ7’y“/´œà ¯YChϵ#矛~$lðù MyƒÏ¥ÚÉ=_$sŽˆZ/ìAò¢“zð|‰z¦: zê…¹ú =UàÁFA:2iCºwî'ô`îÛ`@zÊšÅ=5LÆÁ=x,Ú‹{ÐÑQFÐr]oîÁìÔÍ=hóôhçÎ¥QÜÓL´Uàs=ûÉ=÷Ö²â^h™Å=hâ<Ünî¹é™¶¹KÇ*ð¹&^'ùÜlùœ òíA6ù\÷ÙOòÅôùD ò¹Ö|~ù²Ó:Èžøbž¬¹Ÿ¯Ð#w¡³•7¶ _lkB+Èç¹²ŒOò!«pOÕ"Ÿ†­ÈYØå$_dj>D53SI­Ð-¢ëDŸg¼öUì‹‚hTì ܾÙ&[±/´úM׾‹}.…ìdL¹Ñ’–ý Ùò¼éç&åó!ðM6´ðçz¦¾ñ×½Ló˜ üy£1¹ð:o¥7ÿb䵊®…fñÏ5~òÏMÊ¢ þ¹î]7ÿ\®¼Þô%]` Fèä& ´ùCæ@ ̉+B/à¤ؽHç<³“!‹nŽ@hªãD Ì}M ö‰X-.B‹ÊA@X:ú(BÇj7¡í"âM@˜£çÙ„^<¹Øá÷ w!ãZ„–i\ì×ûè` ›I¯@`¿ÞXýj{ ¦¶¦…@×C¸èZ™OºÙY {@ŸiŽy"0¦×YŒFù6 †¾Þ9ëeES{10&ê«è¿Çþ¾2Ðã)y£ ƾÊ,z®ˆêÉ@Ï*M^ûòÅÀÈB'#U…7]æ¸ d7îÞ'aêê\ â,-F‰´~"0LZ…ÀÐ9r²ÏÅ|20F¦Q ÝF1Ðu¿}e ×Ýý` ç7e܃®‘³›Þ%®–¯ t“æÜ „4Í‹Z0Ðudå+½®ôºì[Ö>YŠ®9õÍ@æ ôF”÷Ä``hæ“1r¾“ ƒF1еå£çf ›~ÜÿOúGyoÆÊ®k_ÔHóÃÕÞ0°Õ•-Ø«u#ÐëŽ×É@ßón7[ñ:ˆßç["—¼Ž Èv»Y».ƒO¢¨fÞú¨D6ºèï— ä ý‘3çÍÀx­›^ÞyÔ½0for3Ð_h Îd ~_Losæ›'x R „çÞ0ЧÏwT2Ðå)H÷“gÝKƒ—oúDY{É@,Qßáy¯Jú®&¼‚€¾Ð‘ÛpÐC¶?¼eþ`ÀYŒ= ‰*´ èrõYô½#¥‘é œ|½îwËlÉïaÒ,†Î½ ¡Þ0¾^¼NÀÐM‹€Q]!ú˜6N Æo’_ €PÔæ¢»æfÑteMý‡õºé¹ä&¢üWÞeFBÄ®ò'¬²A,@ ˆlGdDF@ˆ¢a‘Ï9Uvùº#Ä&Š&3U·»ïmÛõ¸ì".¾¾ˆLoò@Ä¥õ âæñ €\¾Ý:€ü½ׯºä“g>"ö£û‡0µöð?uzIº,}_*æW¤·„/þá5¬îÎbîV·™ë¿ÿ°æzÑ +ôѪ°ðäø'‡6ú‡¸4_nÇ?$wÃfþ!Õ——¨Šêvµ@ä¤úr2çº6EVb] ‘,²*‚"niño¿J©[»DnJÓP †Ì5ub.™ÌCB@]G¡- ãâ}d²Ï*jRB@Æ6á¯2)¹‡€û![@ƾT€öí5ü³Küœdþù-õòÏr¥…ŒGÉáGeÌr ÈáLÞV™€6¯z Jéñ¡:VàÆxÈE(ó àKR@ü¥ÞÞ9€XݵÔ€€®k9қрŒg{˜}ÞÀìç¯@åòúþê"–9€Œ×C_¬ÖÞÚ% sÓÇÝdrUõ2Ã@1 ƒ@[„Òo¹R‹è&¡M@.îYôɬš7£†€;ßG@+› …¥€æÓ³´­C/dL¼6€/ _ÌÝP€ÌY¼d,*@„.Ýá)õ¹$[ï=øc,õÖ9´n=ôc,u†~Œ‹ÇG¿Ìí¯ÑÖ?‹½;=øÙƒ‡†~™%œ$ôc<¼ŠŽ~Lv/GÓI~¼¢~ ë>:lýø–‹UÓφÍ`¦âÉsÆ¥_nè%FýkÕúeÖg—[?${/%ôC¼a#~¹Ãó”oüÜÍš­Ä•ÉÖ1V~¹ôCnªæÐñÐ1C?~¾4<úåf­~e´ø!lã¹–j üãõZà—×ùåÂÉÙKè—×!hë‡xˆvLVß ¿Ì¹È-øcœS»ùc2¥üí‡lþ—&7öõE‚?»ÈIÆŸßÔ/þ,§#øcÜTƒ?¾bíæIÞT6±"ÁËÔyó‡dËŽ•ñ—7ÆË?[†’oÿ¸VGnÛ?„’õˆ8©ö@.ú*-4oú -ãÐ*'ièõЀJíО”rÈ8ÍZ¼ú* –k­ýn‘ëª%ì}R´€ƒÍ¥oeÇÀµÛ}“¤s_§^ˆRÁ •A$qJ¨ ê«Õ. â}À=²P}³5qM_ÇCqjùF¾Î A²õG AÄRÛÁn[ƒ‚5ÒûF!ŽõF"pò7‚9E ˆÅ ò xÉ£Ö@ÀòÚî 'O6ÒÁIßF 8¹±ÎG8Ù­­6‘NÖ•CêbÌjÖA°Ìƒ` ±AÌÃê__äê8 b‚¥Õ£ VA©íV‹«xËç bAŽR‚v†iY>Þ® cïß\AÄÍw»3;ß~ä9Íét×T "YüÜã ®‡„‚¬àö@ßîG)GלÐo©· ‚0_›4ñyåa ‹ÊÛ*3ó*Þ ™X+ªýa ç«ä öö܃@.Bžš.±pì›ÀÁ6À­5±>»é^ Äúœâ÷RŒG›7¬›äÖ&P=R¨TòM ’ez) Ãá± 8¬-(?£_³¿z˜P“Òæé; â“ILч‚ÈftAe3ˆ™®(æR­’ç¼!Äú¨:S ‘HØ‘FPˆÖä·…¬WœL$4Äe¹ª7«Æ!4çÓCf{•ð‹Í{ ™¨ÄKÄĽBº‰H Ç;!ž«2óm"H|—"‡2M—ÔTäKwŒòÍ"ǵÏ|zCêôô†,*íÞ‡u`½7|!ÏšC Îù¸›Cëãr¸(Å6‚EùµÚ ¼²(h DCE!á騈d¾U¼‡J (û:$PTz7o#Æ6i£ˆc ÖœŠ~¬)7Š< 5×ÕP\g£m"ÏOö¶¯&*º¦‘NgȃÙ&âó1=>&2™Öƒ&î‡l•g?¿‘LúÒò¢îb*ÚM®d¨Èœx1šŠˆ‹™²TTI¯·ŠÊÅõÒrVWÓç!†E݃—ÎZii§34¢åt†xÓ,õf¿¢-”É"Â)µp¥žex3v`Ä»¨[¿dä ¯C¬ÉÈx¤Òo“OŸ„&“;g62ž½=úCÜÆ_5‚G&†ŒÓ!&¶ eÊÏ€üü‹?}õñoŸ>þûû÷?þôöæ>ûâÝÛç_úñã÷ûìëïÞÿðáË~øþÛ?½ÿôÝï¿z÷ö+»æÿóš?ÿôÇuÕoù?þù‹ýÌ7àg¾ùÉcüë[þ«½}öî훿òŸÿñOþ¸/àÿ8w§¸»¡,XŠFeýkç*{$3ða\Xݨµ&ÝâÌSŸbƒŸk®ÔÆcÕÄ6ÏØH\¤ÍnâzäÇ,Ó}OžÝ“ ‹’qáá `œ-n+ÆìÿÎïaØj¶ßåí§`¢dÅì©ÀQEÉÇwðb&Ó´ß•±×3¶Êcœü;Эœ—Áž™L–±“D]¨ø3:ùC p}ì{P¥“É&sú¨»¨`7DˆmËB€u¾6Z2són´ëR“×Rç¦Ææ •€MkuÐ`ÂX¯Â‹l๟b0}»§Ï:ãß½Py˜è·n]Ÿ»mÄ8ÎØ3qÝí=е6{Òd[ß³Ê_Ën¼óM}Xì´³oê¶e¶:¼f¢Ö,LxpLjʰ7VRî÷`.ØÙPñ×a®Z·›lA\’åH/7á{#9³=¹°–9IlÛÛ+ã±óŸ›FöÙ¦ˆk…6ûxcQ¹Z°QÇMUÔnÒQì¦ýûÆÍס5 ñMlK¸Xůq¶”5î±/²í+îiÍëŸú­ÂÃéËÆ…¯Êœ» àˆ²mÑÂÝÑf¶òPð`¹³á²OmÎöjN“¬ÎVˆC‰GT¯‘ÉÞ ßƒò¬/k•C¥ïdA\+øAï¹Àk³Ï{-3nª½z’3lE‘ÌÛ,ÎW}aÁgNÙ+.~lT¬e2žÔG¡‰nà˜›¤uݤâqÃ~ÂXT:,­ÿc÷—¿¸Ý uч>¤Í^£!mfoÑŽ´ˆ«”‡´™[|?Ò"FÛ~¤EÙŽ^Ô"i Ȧ6ssÓC->O+jó:¸no³õÁ-C•·L¦~¸e»I#6·Ù»Ê›ÛìmdpKh¸†··øq¹å‡·ÄAõx˱¬ÛÛì}åí-¾µä|¼Å¯Ìÿåm#ÿåº%†` _ ‘àþÛ™„Xý9y}íVùIJ×[ã’åüÛÞ"K\ø£]}Á5ö¥ø‚\dMmlÈ|µ5®+ÕÔ–¹TIm‘×Ö÷jkX±fýh‹ØúJlñÃÛ‹-ŠX¦+±EöÞw[ËÈCÜc-‹ºfZë9ö:·–ÙßößZqô‘´–9f“SË>^iY³Øœ]Ú¿[¸Ì|±GZ¸Ù‘–×Ô¢)­ÿOìåWZ/rkÛÒúƒÂ)—–÷Üš$´Måä h§î7ZN5y¥å„6RZ;ìi9»~¤å,íZÄ¡óBËØÕ´(V½Îr1¹Î2Wù8[÷WÛÎÖ˜é,q’³T¬ée–9žÌ"[Üòìbêl¯,J »ûÇÜTÓ?䲚¼þ±(ËÒ?ÅØÝ>“©öê‡"ÍÁ‘Žü˜ûÎ?åMÝñã52¯~žåÅÏkÅ?dÜB?æϹø±8B^Ç7)Ú?fµ×>¾¤JMû|Üú¡©­úʇš¿á†ÑTg§\›«¿ð©âÙHøýÔuàCî½õ>£)Üð!OY3íSC»"ãµÅ&ÚÓ>ätšk YvŸ|íC±“c¢ÎyñCåÓh¢†Íi¤}:bùü˜gícm-Kû<ËLûk‹îÚÇ¢Õšö!£ûX‰smëÕÅ"5õû»‰ëÇÜgõóÇ›ýµôÔ/þg½úyÑ?Î^uÄo8âèvõÃÐÙbçúùg%\[?ΕEPÿõìˆiê§=Æõèç³°Ë«ŸÏÔ8’:ÈZ£'rþE¢gºüqÊ3ÿ|ADOäþy®õõϋ͎-ùs›Ú|ýsÅ$÷Ïs•ô¹l_ÿ:f«}ýcq7Úî³õ™þ1K4ü×?eÌ•þ1×€ÚDnfö Èb£„ˆ\mhÈv.ÕØm@^3¢ws=·þè7Ž.Ñ d.Ým sý5Å:FÈÜ»¦Ì+‹ _ÉuÝúàI*ˆhçÃË Š³I‘×âØv®Ó9_Qäü8 "áœAdì­ãeÅèÖ6ƒ}b¬VK‘…/ô¯ j:úH‘}&‘m«xDqôب âj»å£‚}aþ2ˆbë£&ƒÈ2­%ƒý–þd1Z>g°Ÿ×fÙ_øŸAµD/æk‰yHK™µµ—A{ìšÎàßMœA>iŽù2è×yôkÖH=Ç&{ô¢ötЈ¸ƒü;Vóë ”ï·ôïÊÝ`;ȹ"ª¯ƒœUª+ìåí ÏB¯ƒ>U¥¥ƒÌ´3Èé=T^QÄBlÉ £³4ô%RúË ë: zŒûìs£Z{ôבz.#dîqσ‚ùºâtzDqÖyw¹ô‘òŸv›yd±Î™"›®–2믃(ªîÆŸ2—8†¸ƒÌmçã p­Æ¾ëòšmœ;èyÏâtÐo¼f:ˆŒ%7ÒAf‹]YÔPØdž½§ƒ¼©Doxä{J“tÐOÚqqÒ^eAé(F¾¸©&ƒÂu:íeÅá³x;ˆ¼l·î`ákËîÜŽƒcµ.ƒ¸×jëã üóþä8X.Úî êóË`ÅrÔž âo׃•ó°}¬è£û qxiV/ƒ<ÌÄ@þ1ÈÏœ×A?­ë /ŽýîÏA{‘ë OkR¯ƒ¼Y«QœM®ƒ÷&á 'Á°ƒ|¼Žt×,»Ö<ùü9È¢¶ë ´WŸ;ˆWÔ‚föW[A~U© §Êà×øW“jéHÅMž© ÏAÑWAŸ¨RSAæ’3ˆ\jtP—ANyé5ts¢Cr}…yôb‡A1(± “¨‚~ß`Éô\4dž[É‚uõ(ˆân‡CÁÊ.è"ˆX£-ÿCó^g½bm¬©Aä®óƒ ÔŠ½$,1AdÛ9äJ]7Ä5}\ È\íƒ o¼êE94a b1ûH>l]¹úe\‘Gô†â5]×c ‡®YX÷óñ·µôˆÿ].‚\¤ŸV?ji»¶äÍ ähXY¯2ïÛ¶\|¾Ÿlù¤µA~õ=FŽ ?¨®‘r’l¯‚œ¬­Ï£ ç{ÙÍôõ`ö*ÈåÖLRA.G I]A9GšY¬Ñfº‚rÎE[Aæ_ú*È∦,NV<´µž 2Kí¯‚,¶Ø7]Á¿›¸‚Ì1U/‚þt=ú1ìn`ü‡¾z±[èr!n C·ú« dz,= úw•‹ ^«öñA³XëEð€|ä$lëƒ 6ªÒúEY¢Í ñ=µëALŒ!ý"Èi>ÇEyÙÁº¿ÛF°îs˜Ü“ˆÿêGAÞ¨¬« ²¯Á£ sÜó£`ÃmGœT¯‚,®yWyÊJ™w«ylü,c%ƒÌ2{2ˆŒ1°—Ae÷ÿdÇ]Mù÷²óa°q­Æ¦ë òV´qΠç=‡“A¿ñJµ¬d¹Çs.ƒí¾d6±d?®öþ2È×®á3èc×úaÑúê/ƒ(bx{2Ø0koÉ`ã*Qì>·ƒÈÖwïÇ‹‘±ÃÎ×A½oÛ 6×= "ËhõeE]2“AäD›‹ Ùv#{DqøbW’ 6ƒpÖ_Q5DîE%dî1”—Aõö‚[M™çAÔÐk"ȼš$‚Ìcï,‰ ‹V5ü»‰#È\l¾ úÓû: ú5s&ƒžcæ^½=‡3ÈÜöâ#ƒ¼g‹3ÖeãÙ—ý»¶•r®h·×AΪÑW:ØédÐ'a/ƒœ©½I2È'IW³{Eûtd±Š¤‚NNôG® ç¥¯‚¾lAO1&Ž õmý>¡’#Èlk$‚ž7’/‚Uñóu½²¸{aG™³á ˆÚ]YÚ›¾ˆlc7„„¹é+ jèáF ÈÜt¥€Ì}ç#`å2 /‘èáœÏe¾ú}§¤€•«¸´yê|dqXMy“²OZY£1¼ò-5v7ЮÎ# âšqz»VCK1G ˆ,ÊÁßV.ÑÑ^Q£÷yãæÖÓK}D1z¶- ²úf²DÆû+ ŠK¤¦€ÈÑEnù÷-â°N4mýˆÔæîû 2l›/€(ZQM‘ñ~–Ös˜ùŦ Xωh ˆ<[œY/,jì‡N`åq­ZÈ\‹½²XbÓtÿnâ2wk/þøÞ~M€ìÆÿŒ—@/ÊL™-qùŠÍô%E™sýò£ßr²,Y/(Zí’Öò6Чa«¯œ«³ZˆÜª\‘‹Èxä¬×f‰ “~8‚žç|ô•Sä(TÐ…*ö*è7*5d.«¦‚žãž1_UǧD1:ö­àd Tn+8ÙhÆï¾Nh1ª¦ƒÈuèL±\¬Gkx!D'M±ÆLGK‘Ïi7!äb=×!Ä%Ñtl™Kðu!ä}gLu‡k¹„–áõ²éÝ즡øWù/;šæÍN«VÝ  D·ÑPªjXôÛsŽ8O.ElP59~nîKbÿ| {€°[ƒ(ÂÎ6Ø{€3…Ü $’»o!÷.kÙ D¾–ávç€pÀU ‘!ˆôh€uÚj„“SNÑá$ãF€p²¿Î‡œ4mne{µ`ê L(\ L° äÿa:Ø6&xþånñ0‚„xÉ¢rHˆ6Ñ ñ€æÖÏI˜YÔrHh>HÈ=óývRçzH­Þò^H˜yÌý3[–CBhIò !‚-õCÂs'!÷C äÓ[ò’c}…<8È`ÕÃA<6Õ|8ˆß“×Ñ Ó6ƒ<×’zp¹8=88|ƒ6‰ßž{`IhÓÓ+‘©˜~F`pÐ ”ñ`ÏM"’ÕŽã2‰fçr°›`mf¡›„£y ±8˜6 9žñ3@™o2âäF-Œ]QF 0VÖï|€±rC´QHº`ô§Ý`ä`¤ŽXã”9LÙç¾r‘8ÒqˆâŒ5‹‹ø}Lׇ‹ ®^j\|¹‰q±r¶ñ,:`D0ÕãyM÷ÔsçÁ5NÊCF‹—£‘º-®ñI­w¹Éˆkµ‡ÈS]æÏ"v¥’ —CÄqUZŠí Óå8DlYö™î y¡‹Ë†FèY˜m›ÌØ2Ü•8"Eëæ½Ñ‘,Z­Ñ‘z$“_Ù|449ëŒÔ³ëÃ'b_j"°ÝŒL´ m–_€äç_üôé«ùôñŸ?|ûÓÏo¿fì³/Þ½}þõ§Ÿ>þð׷ϾþþÛ?|ù÷?|÷‡o?}ÿÛ¯Þ½ýÊ®ùݽæ?ÿøa]õþþd/ú®ØŸo~v}ÇéÛgïÞ¾ù3ÿù/ÿå÷ûþ÷·³:Åj…BAr¡„ÿ±c‚$APÙ¡©~¤f-QÃHPKÛŒ@°*êÁF§BÍÔ§Õ1!)óˆ%I¼¢ðv%ễ£Vט×~#¹K{OûÆŸéA!™j Ú\n<ƒyŠ *Þ^ Ø«¦Sòg¤a÷”Öη )dS‚Þ3“IÌ[Ôh}çcP¦¸_Õ7ŒÜU´Oh×´åî^4’­AÛb脾ÿÖÙÕàÐÊž Ð*&ʸ€x/HÛr´Î3 àÓ´¿{‰u.YÅÝLŸ=Â8 ªˆé)û9æEíN…&ºi¶3OÓÙ¨ŠÝDÛF‚ý‡_ŒsåE…fÁ ½uà´ ß©ûI KÛ¶  ‚F±Ù"¶È–šoµ¼¬i%Ù™ë©s³ó±”ë‹®Ô½Ÿ5#Û9£Š…׈€<÷Š—¦æÊ¼Ð9c‘”j‹Œ„/7éþnºòO´ç´nùe¨¢Û,‡qÔkQ·gŸEª^³ª?Ç Ÿ}`eŸb•¶Ý[¸ôeEQÁɶ;s›¡ûÏlhþ³ÙN†b­UIN^’+72yq »2µu€“£Índk©«Ú"+?&¶¨ýžé$ö"Ÿ`ÐŒ”UC²RžìC¦³iôTƒŸ>“Ò¹cÛ2˜XÆ¥êÛ°žñËY¤ôa¦‹i˜ÇiºÔê€C&ÿfùg¶¢*àj„Í°ÐÈ¡CXh)íAXÝôÔqÂBô¢hGo7b³§w 6³«ÕƒXüž\¿ 6ûÔº9›ÙPf)ky`–ÁÔfé3™ŽYhîY+kc–”‘z8‹—Ëšœ¥±ãnÎrëZ9œ¥‰ËåÁÙÂÏ͇³(¨,38«¤ÁÔà¬Òk1óœ³ÁP‚Vùw‘´J+Zz€Z‚²Úë¸)«´C"AYê”kPz.êÊ*Œ–j ÊB—6²xñrCATè È*.KÅÉíb,ƒ2G0Ö´£ÐKm_ûÂXe†äŒ¥ö4²¤t2Â2¦Þް/·èöfƒÎÿ"¬=Y5Ë‹r’ ¬-šù&¬µaí9Òƒ°jϿ˭”œ°Ê¹€mf–IÂýºËLêNCV7î7a™xì¶a™í²#ë°¿4?‹`–ÃWVAª‡¯Ô¹>øš×™m¾æ5¿m¾’JõÆ+éUäà•:ËÁkö[ý'^Ù”G¹¹Ç`õm7îQ‘àtš¥ÞÜc°N î ÒöøJªÒËE=ÄèÏ7ô(iä7ô¨›ë=a…z7'ôxM‡z¦ë =‹% èAãУ#ßÐcÐúÁ‚o’¤ô¨Eoæñ¥æ`žm[ äAò/â!fŸ¸€'|EÌ“U=›yÐ2ÆtOc‰RæIŸšÎ =ÊÑnæ16§óLû@ãÎÅ›Z01Í9˜ »1zԹ̛z ¦šƒz/7éöjƒÚM={¶JPZ|Ü2êù¢ySÏ‚гÇxµôø}ÝG´C=ì›N:µE=;U'–Q™2IÒWê!àOeSO ÁÔ³ìkõ¦žeh=hÉ¢=èZeÞØcªK›Á=«÷@Æ=Ó9ßܳ`Ñàži ì”ʸ¸gôr÷L;O{Ôɹøà^Ã7K—›{ š±^Ü£Ö6‚{ÔÕ þႵû‘÷¨³óÙÈ]Tõ"cÙ'CtVCõp}Ð×X¨Þf‰>^ÓÝ«úL—v³Ïnì®ÐØG]óöQ—Þnö1˜{öQ·&Á>êéðÀŸ4Ýlülïê¡´ÚóŠ?GI5ø=§äà_c™Ú,º®ïï¹= PA6âÝ´ßøCp»3Ã_xéYÐUêM?Ĥ·ôƒn#IÐZ ýìM4è=˲x¤_› [o7þ,­çÀtZ6þÚ‹^ùÇ £Ëð×öhµðGmü‚?Ä$% üQw ÔRÊ?›÷IÃßËMº¿ÚèãÆŸ=[FàÏ.òYÈðgzÍ5? J þÙsÚ þñwTñÍ?îfM5øgÇZGð™REnþ1ÄYEþµ ãÅ?˾ÚoþYŠÖü£öûþ˜Ö]ê?e¶ø3ØL üYmxW8ø³`ž?ÓRƒ§R.þÙsþ™N=øGÝÖ=oþUdëô)ôðÁ‘Û™w©SëÁ?.Z¶òðÁŸ@D0ä[Gȇº†ˆ¨AFÈMD“•¡ˆ]Ä“ED|P‘‡¼»Ùú­#ä¡®fÏ:B|(_úìAª\šw„ÂsÚ!’/¦z"Ú´U ‰Ð3Õ>œ‰@sLcÆŠH÷lœ_T$ƒ–s©G0W¸±ìð’sQL2ȉ‹Ô*°;1Š/5 Œ4vgxîe¦/Àñ«¯?~úæýŸÞÿïÃÛŸ_þÊØ«¯_¿|õý§ï?üüòêû_Þþþî�ûðÓ?ß~úåÛo^¿üEÏ|÷Ÿù×çßß­§þÆÿñß¿õ¢/øýûá³iüõÿj/¯^¿üðþù‡ýòëþ÷ë|tC ”åMx@ÿ½BµÉòŸºðhѰU“hdñ˜j?®1¹ù>òR}»Ç©™ü•Uw A‰[—75Ž€ZWu[~Áv»Içbïav&nÇtÖ|¹©QïÈij\óô °”Cæ§¿ß —A”#båñ!üF/”l]®G/„»Æ‡ H5O¦Óž= èq‹Ñæô±¡ Ç²)Ú¥%´j©ó2 ²(¹\B0O3D9` µñC' ØkL™!ù][êÖëj÷l¡FsÖ²‰X­MµÄ‰AƒÍ¡g¦F\sÌyÁ.ãÕˆ–‡f`c |ééMHCÛ˜v6ÜacƽâÙ@çÖ5æ­Q—P–ù¼ *‰ßਚ¹Äb‡DëD­OƦÒö aVW €®µh¥1°5)³gìƒjÊÊ»ÀkÖ'éì©»t³ÚúÏÞŠ‡¶xrZ¯¶Î€WÛŠ‚\m½ÄVjÛÁ꯶^ôÃÎLm=IÉmÇÐ\íå¶c"õ¿ýpëÙÒZ}´ùXëµ¹ÌÒZä"-­õ¼¶½×Ú®¾´»¦µž«®¤Ö£ÿáõ¥Ö‹Þ¤+©í8í\iqv{¤EÑÖLi™c«£´Èüµ¿Òvœ«¤¥´ÈKZÄÐñ:‹Zo-ÍKlg‘Ë쯳¼yïé,>$þ”³üÒ’ÇYÖzMgy#élç¬þ2‹§i"ÉlÇ ÛÍf뇋ÇY¬¨&ÒÙ~Ð?Îbª}œÅ2ÕdÖÓ°y™ÅA¬Ë‡Y/Š]eÑ ¥]e‘¥}”•ýÖŽ²ÈqáPVÌ‹,«v‘E޲óö5?z Öâ~¨µØ¨r5;úy,«¶W?ÛêG?ó¶¸3&RõµÏ‹sŒ¤#ý¡YwNú :éÇڼö1·—>ÖJOú<û%,éCžS^úP䦰éÃEŠÕC¢õW>üHk’òñ©iÂç±.yÝóâfÏc7›Éž¡3—¾ì™Ÿ5¹r7{žëÜS%Øó¬ZõeÏ,'B²g¸ãš)Ÿ¹DÒÆ#ŸáDhšòyN¤ÑG™öÜœòÙ9knù 2ÍKŸçQ>C¦×|k)Ÿù‹Ò¾’>䩯|¨­ÕS>æ6S>ÏRc»ò¡ØER>Ï>x¬¤YêzíC±Ä™ŠöåE¶}ȸãcoß-íC¶8ƒÑ¾øÒzìc­'}¼Ïn:Ї_ÈG÷kŸ?º¾bjãrå{[Û>,–ÕëkŸ/+ŸU-í3BÜÓ>.Cm¯}\ªq~M¬'~ž[‹éâ‡%oºR?vD‘Ô9ä¾ú±X{êÇÜ?ÚTç««-õcV©rÙ:>ú©/Wöè‡Ú±©r×yôClÒ_ý¼ØF¼Oè‡(«¥žk­ðú‡¢Ä‚z–>,Dž;'€ŠF–âCcÖ9&Ó+ ¯"Dn2S@ä:ôE‰®¤€ÈªvD\1 ^ñ“6­$®]=wžf~Ttci© çµLRAE—Îù*èE•žz<¾AϾ¯ŽA/žQ*–Ôª‰ çfí1ÐK6t¤žùÑc ç¾M¼zqhì4Ðóª{܃êÍ©ñ¸/‚^¬:$ôÜf¯‰ žSÒ¯‚(†_DPÏIk#ˆÌü‹ ­K‘G«‰ ²¿ÑAµZ"˜ÙâNsÌAÞÞf"Èʼn2ÇáÆ~¿3MSAÞHW*ˆÿ÷V~Äm1UQA¾Xl[A,–fö*ˆee!ÔCòV˰WA®ÕV‚ˆq]"ˆå=¬½zÑ–ÖDä,KÙ#E_Y”•2Ç•© ªõUW–‘ 2—‘ "k\ôU°ùO^C½6%즂ÈEÇQ_á|ù« Š2çQÐc·Ö¨ réú*èE³=ñCAäç*ˆ\wN:5ö\*ˆIÌŠTy¯áTWŽ¡” zö†© ríUEn[Aä©zÄ5[Œ…WAüÎV[*ÈGF=¯Qê«`[nt© gßPÁ†.ýEЋƒKx+èÙ7{½ ì¯ý£`ɱ-,þ¬ÖE°øDQ׫`ñæÓ~,Wl*èÿ?¿Н%Ó‹ øSv (îÛ¨ÅÛ*&¿@ÐO-µËE§˜x’?â¨3çUG¡uü±Ûý(èE-í*ˆsZÐ |ô⌃O(x.r\¬Äíã âCqP %Ï=öûØ âF»ù¨ ÿDûèÏsÄlⵂ¯m ÖÊ0} ĪZqУ"Ï4‹°Ùk Wj“c âÒ™6Ü0Ƨ‹ –|SI)Nœa‰ [$¿²(3d¶š’¨¼ð>÷Â@æbi òÜF¾Š¿Ã>^½¶á0P0%‚?k~ôeoñ6I wÆšv ô¬±%þèí´bÒ=k—@Ï}çK ú4vÜ Ð?dC/È1¦þˆ+/¹zŽóPèmö Xü—DO†€hþ6R@#ÆÂýgnZC@<¸8…€¾XyâxWjÙP|Ñi»¢E?c`«ÞV¯€5q£€ž}s]¯€^ È㙹ß„,¹nòHk'™Vz PÀ+(=ç‰@•NªÁ@'Ðzµô“Z)å` uòÓ¥}Ñ“XÔlœ6ªþmbà¤ÿIa'¦w³MA Ãû$)È™ÃfP3=/ŸäÁ6³À Æv%0}_s7YªÞo…AŒ×ÝA¤N=ŸäÂ:» ƒ|)y¤ ƒÐØþ 5‡ì€cÜÔÇ{Ùn ’ i”À w.÷ä¹ÏžO "ƒò4 "ë@žd•GÚÆàâõ¦ôÀà"áf`p±·®¸èØÜ* ƒ {u¡Ô1˜°g¹žL0 žºŽÁ´™- &øý ðƒ EPçæ`Âd·ÙÎÁ„·þÂÁ„ÃpÛçÌÌHÛÔM¦¿p×ßpç u®›ƒÐÝÞƒƒ™öwlò¶æðtB›·…l~ùqÞ‹Ü̼ü`O÷‹¬cc¶ ô)vR±Ú7ñXY„›‚ø=9QÄ~·V¢ ¶ð]/ "YÀ¦ "­Ìïz‚ ÿy™…º:=!ˆTÅÝgÞœt¥‘ÞC÷º'Á¶U|Ž Hâ ï>‚ õìë„ '9mA!È6ùWºnªA›7 1rº9§œAû%‘­Ë²{@0¡*K_Û &º æ§I &ºÌR_8ˆh†j7Q†rnABðân 6 QeØtï½b! Mi w'­yÒ‹o+ÁC ˷ǹÐZ¯Ddtø4UM߉ ¨Ì&&v‹â:Aø¼m±n-+ŸT$"’¾åÂ"·2-g©¸>ô±ú:Á˜à4Tj·?D‹U½ÞþeÛëxñ‡`uĺ?ÜÐsƒ¬/wµƒ(/—ƒŒ»èžZ`,ŸñlN0xˆRƒ‹…O›‹ø˜Ì' œ\-Å‚¦h³+³o½`±ÂBÊ*]XÄeIW‹~¹i'y#êXañ¾!]Tä-JŸû¤bŧϴÝ!¯o"ÍEEü>—·ðMEÓuëàQÅ"+/6~‹ÝX¬|Ó‡;ä á%".j’sÒs .B7Qåâ"> )`'+÷ùáy¬2~·;ĶT'ÂÂWµõíé²Ý!²0;ÁˆTí– ÆÄš±1ƒŒt.Ó ÙF#Ò¾:í/6’D×UVl¤ž©ŽÉ¯…&'èH½Fñˆ‰ )6 Ì2·KLt |»_ òó/~þøÕýøÃ¿~üðó§·_3öî‹÷oŸýñç~üÛÛ»¯¿ÿðÓw_þ㻿ýã‡ßÿî«÷o¿Ò˜ßÿ×1úôÓwרßðüóg½çð§?ß|r}Ëõ·wïß¾ù ÿùoÿå÷þ÷÷=;Åì+Te9ZÅÎþóŽY—ᩆS£n¬oÂ@¡ÎUf=ÿ:,kO23¹¢J©•útDC“”Ã='¯¡`ÂIr {tµ¥ƒ3ÔHÝßú ï+ü‘t!õkóÁ¨.z»•® R/˲4ˆ˜ÀËè$©“žPj`AôºÄ\RöAø Ž`TlåP;G_ÆÚ÷©|ÁHË·L; DB÷œe˜¸÷”™²7ë>´cÊJ”°1]{Z¢ýöÞãg°°ò³9ˆ»În:§æ€ù²ì/s´Í?o&C®¯Ë×ÓØAã>cºP¹×¤ ÷Ò‹®&shPë™X Ù ²sW`pg‹IƒpÄgÃLhÐB©qPc“å³T¦¶AÃ';Ev U‡Ì®}pRW·nI{9u†÷¤Vä|Ð>ºÊM‡¤Ú§æ7ã(G.Iho<ØÁ&mÖ†N?s û›n ½ÅE§0Á8©‰Y{ôŠêº{ʑēO&«ì5Þƒ™š¿iËkeÓØ!Úô–œ7mQMèAÛN>OÚ"ˆ—˜A[苤ŽÛ^Q2ÅNÜvzR˜ý·Ð¬…èƒÔx²Á¹Ì‚µÔ)×`-ôrö>XÛ\IoÁZèÒV o^NÔ"ˆ"]Zhú©›´”¤ÓAZmÍ ­´:“–šŸ{A\|j–ZÙä ¥œe¬«5;g÷ÎYê4ûÉY=¼÷à,ådÁYMR+ßœU rsVrJ‰³\ÓY²1ËÝ´œoÌv^h‚/Ì2O¬×“³Ì¨ÑGp¶_ÌÎ2±'g™¦mcrØÜ˜åU¬çÌ"˜mS–Õê¦,u®/”Í~j7e)}]§,ÑT_ K†Û¥öç:d¡ûµä Yk`Ñ,'ý¬¾í¢u1 úA§UêI?I½›~†ÊØ“ªŒr²Aý>Jšú}ÔMúFŸ±DÕÐ}QçfŸt=ѧXê>h,a>ê©§<ÐÇàu}\$Y ôQ[?ÉÇO´šoòiÓZ€²¬|p!~Þ=Èn6{ÆÂ\íÄžj¹Àt™r•Ž=èÖJ;±‡  á=è Zù¬#Íë8ɇ`©Ö‚|Ð¥|ÐÕ=òƒ|6"í&´aÍ@ôH/&1´¦ä³tè+ÐG=ÛI>Æ8ö&ŸtA>è\ÔßäcV?È ç±}Ô|°ÁTs°o/âì£Æ¿NöéñÝ‚}ÔüûfŸOZûë>=ÇkNèã¿´möaëú¢ksöé\[b“e§Oö!­`U-Øgâpö) [=Ù§Tõ˨àmÙýà]«û¥ ?¦¼µôSE¸ý¤s>é§`é7ý${ÀOd*ó¤Ÿæ8RKçô£NNÇúµÎ‡ØI?e²/úQ÷6ƒ~ÔÕÍþ¦‚uÌô£ÎŽiñZÇxðÁì×:÷a@ê)}°±RÕi€1äÛ€Ò¥Ô²rˆN@êŠÊ½ H]F; È Þ<HÝš©—Ìàü ²õB v®nB÷ª›á† b„f ‹tΓ‚¶Ü‚ß‚Ðh«ã„`îÔn6>q•€ tÅ÷ DÌFÁ@è†> „îÎÄMÍÁ½ŠÛ=1°Jm´‚\C‚Ðuöl×5é  ƒn÷Áv]µnRó‹"hI6Ì!H=j R[)'lê™Á½ˆCOšcžÔãm5h€ ´ßt‚ŠY êAŽ•G-Ÿä†ÖTo ê`ñR7™,Õì¤ ÓÊlÛE䛂JÃ:N *Wk R;¢A¦7ü÷ AQÊ% (ä, ªFR;!¨`^7%}aQP„*夠Î#((FPº]kžüÛõš-9xG÷ˆøÀýolª@±Í™SLwrÛÈTlØçÒ« Š&±ò® 3¶m*È/íó*È¢˜¥‚Êí»j*È\F{D±÷=ôSAæâGP¹z> ªÅßtä'ÄG¸Pгïáý²ËRAd4ÜL™‡ßæGA»  2[k© /ª>þ(È_©U‚¾rZSAå—K}TÜ`x-DÆû4T6©Aå‚ô• "ãeß®‚…¯×ñQ°ÄÔ– bKŠ`á’®‚ØîMRÁrÈÞ âÿí‹ ú†œ¢ùF|(DsÚ¬Ó¢O~A[ê‹ 1¾’¿ò¬cvô³Ðº –ßßv¿ ¢ˆÖ¹ òœ¦rÄÿ¯*QDÿ_ó"[Aá*Ž‚¼}ŸWA~h« ä¡ç*ÈZ¯WAÞ(z/”¿3´¤XÏÉÙjÈÇ|¹Ü+“®þÈ]µúLÕA¶4Ð7¡ö×@ß©*i óŠéÈD.ÓÓE[^›$‚.NLGŽ ·HÑA/Š=Æ¢8‚ÔÇ@¿n ä=ì¹ô4ÙÂȯøÍ:æÇ@}> g K ¢ÄHþC «›\±NËú%¹uûˆÅ[ñ& ‘Ñ%yxNÙ¨þÆÝrù}†Û2ËøÈË.¹"ûQf ˆXÆøÈç8Öͯó ˆ<}.ü?’¶¹nu\±+‹ŸÞ~”¿††½ ¾ÛôÈýŒZq¾éõ Xn! 2Þ­ëEŸÙŽ€ÈÆ‡{TÅ4QëK еëJ‘¥¯™"køc Š­6K‘G‰ÁÏ DžlÆÇ@±öšjû+Ã! ufY1Ã@Ý'¢c só'ýc ‹Óç±0Py\«- dÆ?^Y¬þÖ ïEÂ@fߨ?úÝ{ 豕ÆWú# ×ÚH™-q¹*¶Úk ׳¬~ ô«—ÀŠ5ióC v•v¹n“@îº>â5Uj»"kŒxA îØ[ÿˆÛNm—@‚có(áÅK Äs;JœÁ’@ú$íc /TÖ5«±Ö5y_ó5°b¿Î8£^Y\±òn ³éJ™÷˜yDQ×\‰ ³ZK‘«õñ"È¢îÙŸ"ã¨ÛAþñ|¬lUá‚üÆò.ôì;øA¿ìJ1&‚ÌÍïòƒ ‹êÛ:d:Aþiâcá‚üÑ"ý è W["ˆ<°²‚¨am["X±Í!g"XÙ¢ó£ Š{ø(ˆ àF*ˆŒ—«½ ¢È™í X;VÊj"ˆ¬³Ê‹ Š}©%‚È›ì@yÄûƒ Š“|D^mj"X|íEE´¨$‚È­tM™›¯å‚,ö;z¬’2Û‡@Ô:Ûúȼª&ÌSô%Å!= ¼ ™Ë°×@¿{[‰ È,ô‡žDÐk1o8‚Ì5ZÏä5kœ®.‚\϶ô è6s¹Y:aýUÛj¶• V:ô]Xç‹ ·j«š2ÇÒ äî^1:]YÕ4ÐÁ‰ÙÈ ô¼úk ÷Mè)ÖÄ tž¾c _'LòfÆ´”z"?JÇDÔ×K ‹>o™«Ö$9¬»²¤S@äAø€Ìµ¿þ¡† n¦̵¯ô¹y>þ »t&ü€úüüy.öòçW5Mÿ„MŒ?ûøÇŒyèõÅ9$ýãEJœ±Ü?æîCáü”uûç«&–þ!/ósÛõO–Çfú‡¬ÜMÇ?aÎúú‡"{(ýCÚ‚?™½ÈËŠ>¯ÿ;ß$Ç?ä‰iáõÅ¥*éŸð’¶Ò?þxøãŸà·”–ü!V‹™ÏùC†löò‡"V¨'Èø#ù“}ŒyøcqùtþÉ> ÿ­úiõ@»¿ @±èæ ³”ñÈbñWfx/2·Q_ýö­&€þ!÷8Œ/Í@¯©%€Ì#üpù‡@ÕlýÉbœ?r·,]/€(išÊÖøèû°Ê+ 7«ÉH‘«è%"Í—@îú^Gèà„N g³—@o¢ÇÀðg¦îS¯~¡"i sY’zÞ×| Ćí}~Æ@v¤ÆsP¹c qÈŒ¿û*hØjÞM[Ad™ÝRA6RÛca2ˆ"v^OÑdK‘ ²%ã¤{d¯úû6dOsâ8 2Çë‡A^Õ|£ƒlåâVƒ„ ƒÓ_5œ|Ι "ã4Ñ_‰B™õ0È…“Q“Aòg>ê\ …ùu‚A|ðŒdM:´7u$ƒ‹ÂY2¸øj]Ÿ)ÍX|T ±Æ›ÒÍ žAý0ˆGÌ3Q2XÚ›ÁBÿÚ‡Al&¶r:ˆýŽO_ÑXƒè¬æcßvíg­_ý(3>òüãë½d½"áý:ÈÆ·yäiMúu·ø8(Üëó:˜Ù 0y÷&—A~æŽñ•þ*ÈšŽ« n[T®‚D*ºèGA¬gµ~䃭e¦‚ø é£ V¨ï¿aÅpݦÌD»'§A#AÍAã Pk"ˆç9÷¡î"ˆ‚X"HqE"ÈŒzdã”à–:@ý"È^)M^QÄ % d´¥i ùdÐþc Ø,2_q+©cÝI°p jqWg°pЬúqU‰§½!ä×ÑÒ-%äכğz)Ä5:Û!-D¡ø^:¢€}¹ìGC¶,Ž'5=ÄgÄÛå€È«¬õ‘Õé_ ñ‡„.‡D:?þ˜Xø¶¨~r QÀœ÷3âÂZ—¼*ÒˆÂ_²YäJ–å–†‹Ø c®±¹©¦_jχxâOï|ˆ®:?ó!®¨Cî|˜èíªóY¼¢r’2V,â°„±n¦+†ˆªéb¥â庈ÿ“r\ü7uz» endstream endobj 12 0 obj <>stream H‰¬—K %·…÷ü‡» Ø®Uª‡¤då± „,b‡x†ñ›ÄÌxáŸsJÝR÷ïÂ03÷œÖ[UŸ¤Ç»ßþæwÿªÏÖµ>úÓÄJ<ês„wjµòÐgéøA=Jè#ëè³v‹ÆJ>ðQŸVµ+t¸¢1è(à»g%kálih,Ô ÛÃ%%<Ƴ4©«Žk/¦4v ÏŒºª˜C{©5¬ÆªÔKé0­zë݈uÓÔÕ•Ú½àûY©¨U˜^, 5eË­™É¬ÔÙhï­­:µHÁ"µÁ2V­S׈\k-¿›âÿ£R‰ÖÛCä)Õ±ÞUÄ”R«"XLº¢‘Y¿‡ZdQññ)=¼¦.Ø4yecÐEÆÑQyöàZ¡÷¡è‘룻: ,tB£s›Ê3TºFº1XÌ7 :šŒÔ½XÞªžÕlî#'ë ¥¼`ÐY¨Š§-²Y+ªÏŽZTŽIGå ­÷ÚeCâ¿6lÌv+Ö-ëý‰ÿ|òéO>ÿö݇oøþíO¿<þ@ï£O?~|òŇŸ¾ýþß¾øæíïßü÷ý÷_ÿíí‡oþüùÇßg™¿üj™/ùñýQêü‡ÿ‘}Ècþýê—©ñëkþŠÇG?¾úç*9¶þy–üëYþ³[+«µ@h" ‘Š™‹ßž¤•(þ ¶èÐá¢-µ¨@{oýؼ`"²Þ”e´e™ŒxhÆg=Òö¬"£±ŒŽ†£Æ¦@# <ëH¤žû÷Ù¬Dm‰ÂïÎx~ö&e–G¾A7ëÅw'Ψ~ÆèuV´qû© :L&‘g¥2:£¬i9c©”Z Êì¨b€« ²–íé~,fŒˆ/ÚDh„hµ#…Îj½¤ëÉžãËÉæ†ôhHéZŽÅdŒ£^cÔ"± ¿å-@êÊòÒ™gñaÊRµ6îGCþFÉnæbÁP5fKÕ¦çêÁu6†<&¤—$SÑ›UɆ¢fúDo»V«M˜æ!mØCliØÃÚ9mÀ•I7ëIXš\³î 8 N4•‚ ¡¶BÌ!p¸™g-«…;\{©- ‰ånYmSsî¹ôQ4{†aÙ²;É‚y! (U)±ucÏknqŸstÖ“‰HÄ:uOž —ÑYcä9ö1Ʊ«í¨Óc%WÈ„3uÄRvL”ž5\–!<1[w‰U©ˆ´<Ür‰±Hî<¸š(²!`ù™·£ˆ»Ç3 Z4 ³#Yd<‚4¼CÖØRm#3Ìfšý3Î=øY8úUÇ›§™‘Ù!¬ÄSCÍÔ;ÆÓT.ú‹qá35Gg®¹ Îèøl-áÔ¬ÔÙ2²6 1¨«j/ôH_‡:²nH•váö›7Ÿ¾{÷ówÿáÃ[–=ÑþæÿŽÿ¤ò œež˜ Πˆ gh äΤ_FÙ„3áWdÙðköBg˜×¦³ð€ÔMg|/©¯t&E†mD l߈¦Öú‚hš<æODC{âö@´d8¾ ¦fË¢ùÃu3¥·È£ÑâdÿÁh®Õ £Á)Þ$^)›È…ÑXñ±¤ÇˆFÃmÀ_~H¡T¿C:x¹­mC†oBChùBh¸€šoBÓ(¢›Ð0ÆDö&tî‚a›Ð0ª hè$ïÐp‘Ú#ŒY,/hŸ)ye½ñ™¦¾øœ:1:ùLÍißø ³WÑÅgêa'ž©šÞéL/rs'w “ÎÔ%Ïô ³ïˆ“Î,#ųÎ;ÓŒºèœy[tf›@Î\NYp¾9,œ*z§3£ª%I'ã8+†ù¹Ò™Áj ÎPÍû†3|¾­®p†)¾Ù̬(ºÙL-úÂf™›¶ØL²ÙLLé š¹5ùð8ÐL-¾Ñ ÙæDó¾o»al½ÞIHSsÝ' ©«û"!tUï$¤©#N:r£/RÕVï„Ég׉AJæÃ‰AjK}Á 3UG]d!í¶0˜ZïL/_T“‚Ðh©;Ÿ'W ÒäqR>Ï R{Ü ÈIºÊ‚`.›mB×!/„ÉI.BölЙŸÃ^èþ,ŒàòÀ¯Úç­t†Yö{! Ìã2yF×Ñ7=0lm/„‹µ A'²'aè¼goÂCYÝ„á½_(£•×[*LœVmCÐÛ3sठunö‚ôR'Sç[eBZjžyÒÄ›aAW—qR’›|à ͒Û;1¸Û˜¤¶ŠƒÙ{¾øƒ”^lapÖw ¦‹‚ÙÏ̾¤ 'Øò=xÁ –.ðXÌíM‚M 2^Ðzà B —]_ô„r, f,šÞ1˜«ãä ¤‹Çâ ´2{odä»ÂÌŒ" „©Eî L³ÆaêXLHÕ~aâ,É4A˜ZtºLP¾€Ð²¸HßAH“·ô„ÔȱBjÍç„0µåž&)%=Q Š; iJ¾C& ¡%r4“…Ô=õ……ÆŒí±XÈBDÕÉÂÔùŠºÀ0[cÁZ¥/R×fwÒ”lyÂÚÌ ©G^7 9¥IÙIÃ\;½àFðItç!ÜÎlZ@„1puÜ@4æj¾p¯@„k؉ÂÏéÂÀ)Ûî<„y\ÝZÇbºy)ù‚C˜ÈŸ¶q#K/ˆÉÇCxÍ<6aŒšwÀ‡60™f/<„[ñ¦Ý<„¡=êâ¡O®i&Ê&íx¶<¤æÌo<„éXÝÅCê–¯‰ä!¥×zç!MË ž<ÜmL²#dŇٻ÷“‡Y&ŸO“‡©óésáašn ˆÙ‘D~GVßÈÕ¼kM æþj_@d¼O7 2´<á5hžO f,j»1#Vë DÊlwòQ޻󦫋‡ Ÿá‹‡™+yL\x˜¦ŒÅÃÔ® ˆ «Zï@Ì–¥- ¦.m‘Ú²ÑW *‚väÓõD˜]ré'©¸ ˆ¬4/ž Ò”ÞO B†çn‘º„ÝÓ=ŸˆÔ¥é"uM}¢2e»- ²´X@L=Ãx1[ÎGÔ"4r®- RG>‰.@¤ÉÓâ"5cü"Õ¼-n ržZu1×./naŒVê uØé@„vóP™«=^x·1” ¿ãä·  OÛxb9¯q'Ñaòä!aUÇ+ BÔâIJø}%ú ±=/•'±N1 <ÄBöV_y8÷àÂCìd Ù<ä;'±uå!Õûb>–Æ"£ä x"L+ºÈ—\Rt‘P«òD˜=7ø¼×K‹]ÇàyÀÿá%íz?œ‘„=pì 9XBRÇVbµÒÂøßg­Uuv:(Ó`l÷Þ÷ܺ§^_íš ZDüÆr<È_×]k€Ègt‹š úãRt‘Ɉü¡± ˆxƒ|á½­ª¸&‡œ]I68är©9íreõ\Ã(›q¨•óΡÖkô‡ {jæ!bç³ß=äÊÉ›‡²‡_žj«¸¸{¨¤oæ¡bÊðPV]8TÃòip¨Øeãq\^9ÄšB//"ÉÙ8ô¬‹–†½*õ³†X¬Y3:4Äöè-/ 'g ±â»®SCÄI/35D\Ÿ5ÔnjKCÇk_2öå¢![î~iˆXwœ‰!·^) ±K»ž’€X†ˆ«ªÅ†èæPvbÈ‘SÕv`ˆoó.rÁ¿jð„!Þ¬¦xÒõZF Ú†á`nbˆŽÚ¾cˆä,â&†H4ž,¦aÄÒŒ!\4DV“h"ás¯KC$âàqqˆ\ ©-‘(NÕàä ýçÙJ\Ætçpa3ã¼íl2é[0ã¼22Nšò‡L¢0#/tºZˆC†Ñ§C&ƒ¦xp¸Ú2.u×P?ž õ„nRÃñ¼c¨d*†!ã–¼aÈAi=ír@ ®Á¡æ7. ñ‹>Õ‹†XYQrM 'ͦ!—"—û¦!FÈñé!¨ÂojˆQÏ)_4ÄÔ`Ä–†¤‡ouhÈXgÄYC?¦Í4ôãŠf’*Ÿ.²%ׇˆCï‹CÆjôÊaàÈé{âÉ®¡2n±›‡ŒGñyòI ÖFÕpÃCÄØþe÷ɨÁð±o%›‡üÜ)>y¸ek1ù¥^šy¨x,âå¡ZîÆ!C ŸyÈEøî!“Q+{xȸÄbòí¼ŠÅå!»í}65t*Ú¦‡H îÅCd1Àiy°Ú±ì—‡;µ^AD6q-;~êÊ œµmÉQÄMC)ËC$b þâ!²¹Ç¶ "ô57;fÔ,g‘Ä"›ˆØg%×`""n˜¹]DîÙÒLDDä†vbsˆˆ8är±ê¤&båyÈÍ5EDÜ9Ùg ƒ«ÁDäÐù–ˆX±`Á_Dl¨0š˜"BT–ˆÜ«UÂEì¼ü`‰¹[§um‰ØyÒöKmØYÁ©‚œ"v –D5Ñ>æø*"BÞ—–ˆÎŸ"â£QÝžDtØQ*)ñi(ùD">J¹\It¨!s<‘ˆÑD'‰ºë” ‰¼ iä'‰ŒUÚM‚gÕD]$ò>'G‰³Ë‘Ldì ÑÚ˜$zÞp."òÇuÝ"ò‘UŽoä ˆLƲ@ÄϺèˆøÜiCAÄH\DÎ/áëL]@ÄÒÊÉ›‡„¸újr)òbµyØæ€MkÁ;<Ä*¯¼õmâ@ìAßÒa2n¬ÏrqÉÊ¢¼<¤Un\d—‡Hâîb2l=‡MÅBú‡X±=«¼={ˆUîCé«>t*¢èX}†xY_ºêw‘ˆ-’KJÙLDB›yG{-G¬QS ‡ª‹Ü¾êìæ"w.®-Ádt¼»6Ý^l?s±‘ÙšƒÙˆ­ÍÊ>ŽLdû®#²YÅýÁ#¥•âô‘†d±/Jt¢.!¡C©½ô ‘ø\{r8r±YOE#ÖbÑllE#Æ–³c¦~GÕà{L—ªQ¥_F†ñúF$§Å•+‘Ü–!.!Ew'!ñÄô›Ü»1, ±òKna _¿‰]¦ŠCÖrç6K!Å`@ŽÛOÚ¤ %r^¡yÍb¿7ã(˜½íö"s&ø”Æí<29ŽÖÁ#›ÀÌñ¸!}D Ì|ä3UÈRߘ' ™ Ú”HúE^ éW­yÊi0 9¹£œ#òѧKŸb*«b×aUŒX‰>ä]HLNáXM!ök3"1¥>4âÉHÌ|û’ j­ª‘ PXw&±ÌŒÈ¥Ó ’±˜ØŒD;|£fJ2¡5v0éXB$ù5œ|cN~þìÃã—ïÞ<¾ûùáõ‡ßn_0÷û®ã\®OoŸ¿|üðîá‡Û“çÏŸ½yóñý‹Ÿ_óÙ§·ßëÉg§G^þøú—ûç?Ý?¼ýËëÇ¿þòxæ›ÿùÌw¿ýr?ŸúÿÃÿª.Ý´Íñï«ßFŒ¿Þò¯r{òôöêûùäWøÿ³¯ã?¾R{÷fâùýïfê‹Û“ïïÂo¾ÿøÄO?ûÝëÞ°(YSÅÒ±ò1á%pê*ëãz+wz«?âï!ûë-ÝþtûÛßÝíígÌ¿z1¯[»ïÏÉÙøí[õjÿÅ=y|ýÛOµ©äÃx›?Õ€)΢3RU;:²ÿïÿë[ýs¼Õ‹cùÏ7sæÛ¯¨‚»˜CS°Q]WA;Ü \)XÍ%ˆWˆÛR¸NÎØx&á`g²¦Î¯öz+ [–·lÆÌ8ŠåYàG—ãÇÁe¥Ù8Ü äG­u«°1¡‚Ì(£Bš{¿˜2º‹ªþV2Þ •iNwÉ1yügþ.$˜§ùKi…·Æ¼ì=M<¿ØýÙÓiq¯´®&H‘¹Ï]ÅCØÜñèjÂ!†ÊÛºšðӬ̷®&)º£«ˆùzGOS†H}ë)î¨U¬¯±Ý±Ä;ºÊ]œ¥ÙÕ7ÖU·N¨·®z8¥ZWq xëªÄÛºŠ‡bvþè*–b´®úz‡Á{WÇ4YO}ÇJ@9wtÕc¡€î­§øm”Ùzêø]ÅWQÄÔø‰¾66 Ê1“®¤ÑÕÊ‹!ºyëÄÛW~ aF–ÙTóØâБÅ\a¥cb®ÐÑàæÌá¥ÚIg0W*š$‹4˜+ØVçݙâ¼` Å~wü%â ëp­'qeîµb¿aWÛa® $¯èF>^:l£r'€ci¢n!¡KŸOêiwÐãRr¹}ðëÁSQœT=ÀÌ!7@(S€ç¾à%-vG|%ínå‹/B}ñ»{¸¶‡.¿z$ F,‘|Öé ¹Pz6|LAŽ' Q/LeX,^{×4SMâ›UôŸõ¦»®í|Ðùèlë%‚¸¿&8˜3¶!ª;2q(Mà¶·Fw`¿"@¢Ä…3™6^§½Çbƒ£ÛäùD¹ÁbS ì赇’‚ ­'"9ŠˆàFŸ™¢¦aš¶… ¾¸Åèå_*yØÓ‰€„S„ý¢¦Z¬­I9µú8àTf/>޶sÑñÉcÄÕ >,Ýï·ù(u4¡ˆâ4l‘k3ÖzoŽúánŠ¢f¥5%¬ëk½ ÒÔÆT%•mn¦-°"Ò‘æjãy „V%Š4<æÐ·Ú-DBYf‰=À;J:ò´[3E`*E„~£v¼àìV¶ûˆÐK»bƒhüz}m F|àZ•w-rœaÇÐnáþ¡Å]¹\zkŠPvApI:‹Û#¯£¸¶Ç…—ª‹«Ãº®¸Šœn‘80©Ÿ•W•À:­sÅ5–Âõç­„ÑZ· 'KG¼®š¸:ÓÈ^’ÌT(˜(\²0R­uÎÖÑÎ2ÔÑÆM}‹• l”­^=Ñ®oÕwãWÓð酠ݲæØºgÖ)ÆLvi©M5x¬”ŽÝãÓudfèqRe›'Îd_¯:3zëàD ÖÕŸVæ’ˆZ9—¤àØROÝ0ñÓ³ÆÚÕFðH†cƒ˜kÕû¡3·Î~œEÓü¦3«~\•玟{cOߎ+¥ïâŽ×ööÄ zeµG`©c»sì˜è«àpH5‡ t¦ƒ³Iò3¬sÏMr¦8ã`üÖ¶ö†à’ñ'Öçæõ›:½Œi06h·â_9ê代cÔ½”7¨M”m¡²¥cg¸³®c,::êÃoeƒ¥Á±WÏäl dlm_;›"À:].” Ƥ½»­®¡àcí8ªš2gËjE Í+# wEïÆÔáû¢©)‹®š)å³Äb›^¼"ˆLÕ46øgZj«–ªÀkV«NQMÙÍc«·#HODXóZ ÖP»÷„!uÇö.6ÜÏÂGÓMNh2ß§Zê¶ °²ª?úEÜLi\XJŸ…÷Ñ·+°%7ÝUúJ;iWÛŠn7z%ê+Ÿ u*6}Í`LnÔdùacl^""4šÁ fËqe0LýŠ€Ò¾¥}ƒcl(7Ú˼ßoV ;+zNõÍÐÓmÄ)Ú¥7ÌÇ.ÚzÏýJÞÒslcæü³‰Kã¿6¸Â]qoõ*·4õ½æ#Ä®jÓÆ6U4óøºx½Ÿ'Û,+ª¿ÖC@Øš4Qþèõ’U:m…P°AÆ>CÛ©Th‰çjò]ÁÖ-¥ÇbŒ‰Á¶çx€µ §r0†"'‚ØUö”¤+¹äÓ”~Œ^oÚaœ!Ú#$7w/ò´må8”{w8§¸ƒžzµCç Iñuš`|Ò÷9F×Ýf‰ ¥fF„±"1h.s€6« ¯lWýdÝòÅ•X…³Ró#Ô}‘Š÷t4x­š¢0xIV´’™µ±]ºÀp7:,,„ô+G’ó`ï;ší^”`=ÓÙÚ"K=néu^]Ò°D6Ææ µª¯…y˜ì”Ì”" Õ[}û9¨J‘Þ¹s$ˆFÐ%AžÍ•Þ$ 0X9çª i6˜L³Ó» ´‡c»*Ú@NÕÆ`rü†S ‰Ø@6(2#³%–‘ñ³^u±AW©¹î¾ 0wÕš]ÉC¼ªX` ·`9@, ÷¬{GØú¹Š*"ݧ¨@ªLmißñû ìQ;öˆÎãDèCi]Ûn÷KkÊõ.“™|„°*á‘ÏÕ™‹².§‹Œ9‰ø”=ˆû$ÆI4tko¢¬[îtÎñÁ~W£²}uÁ½eœ­í±rxùp¥S´ŸS úæ­‡ªËc\ø)æZvÓX²Žá±¬*ƒÚÎ5åq3ØÑWr¿Õ²,(lƒ9–­;ZMüThøkŽG¹vsç2•ÅíŽsÅyu÷€=©ÖÓG/#ÀÜu¨tŠðiù5Ÿ¥Y}ù¿„WÛj\×|7èöKÀ>³î—GÛä!Á!!`G"„`$\šÇŽÉߟª¾ìÙšÙcÇÄÈ¥5=kuWWW3‰† ç>âv^m¸<‹ ¶–àÂYÔ¤Z3o” ÏC‡w:úOl¡ú‚ÇVMÅ–³µ²âðíó€Gµ¼&8[ï0?² õnØ!¨âv²_%+dÁ@ªæºv¶Ög :D‹-‚›èE ¼{ûB(¢®>nd)X²·Dlk2GÁa·/bfRÒS™¥©ÀìÍŒ«‘&‹OÔ½#nÜVLA¯TFÒm¡Ïí"»®vÄþZ‚׎×2ò‘…G8O?>†®cmÉ85¡½c¾çí:I°m¦@ìè5\俤AåV—8׎x-Ž7ɵ€ëÚ´Sòbg·‚WÏS(eúá|$A^v¯à·ã†¢7«ø´‡_£ìNl™B_Ø’¼^n%j^·–´F}|…[¹Ý›«'syúl¹þùìç¯^|;~ûæp÷òýÇ¿ÿøñ݇÷¼ÿýÏÃcüé›ÃáÝÃýÝ"ðüÙUX^\= Ëõ§«'ùC\‚ü¹þ—ÿú?ýìÓR–ï—_~ Ë>qý6hÇFöùÎlõ‘™V¼ëˆ¿~Œ§¼de¸†Ø¶Ÿ>ØÅ~À_HÚ+‰ÿ'.ö?9¡‚òà#h¸¿ð (\Àl ç@E i CÓL‚)>ŸX4–ôpGGRÛÔäaÄ+3&Ü"tJ#F¤á8[—Í¥¡Âãx1 ñ†öà–€ šÚ„øÙIA8èObö€ +ž³Ê–Jt±Æ„ÂéGd¦O ËÏ£/ M Œ÷åš§¹Rö3­ø¯!­À@4®%3tN2žs±Òìbc86½G²„ÑN•b—(¥Èƒamd Kja6…ÓÄ9ѨцÞ9«ÏØ”/7z˜:8‹áLª¾¹Ñàä%¹;ÈÅ 9YÁ1M¢%q½Õ¦wË£h6O÷vMÇ9ËÀ& ¢ŒÑ29¢S´/lIÀ1$}.Þ÷3ñÊ#ˆi”ÇE1ÓòŽ9м˜îESª Ѝ…N`*lî×}b"ˆü ×'7<€³ƒç† ½õÙ8D,ÑêŒm²a%¤T.Æç]m$‘µºZÎ KíÊS´™Ù-1 µ!ŒJ»2-‚¤Uì_:ËÔ¬’#ëÔÙ&¾Þúñ¼Ðª/EϤÚ°ˆÍ×Zºq$ZX, ¥ËªVGþiöQíðTLÃõË:þëAb6ÁI‘iµ¥½èçñk¬JË.{o}&H5ø‹R¥£1=©ñÃe6œ1çÆ ×9ÍöyN^ãô×_k‘÷c·….õÛnsî´ñ…¬]Jñn1Nëö¹Ÿñá­¦˜k ɤìJ*úÌä C¶ñ +‚·NK;uÑÞP6QqUýÂØù̈:Ÿg6vÎfßî¼3ß. â>RìgnE'gÁf#CŸ€gÅ7›$ÔçÊšbô9]‘¿Ò´UfÝ" e£r¬Õ’÷Ô_ô›«'syúl¹þùìç¯^|;~ûæp÷òýÇ¿ÿøñ݇÷¼ÿýÏÃcüé›ÃáÝÃýÝ"ð|IÏ®ÂòRµ\R‹I§.®ÿ忾ÃOû´”åûå—_Ãr‡O\ÿ$t¤˜CP|[tÐÕ M '^ñ×'xhëµçÈæ³¸÷ä^?PPUB"³ ªÄ.¡wÝ‚FÁÊ´ÞÅ´íìPÙ!¯{V°õ8—G·X{q-Ùܺ«Ê­¯éaTÅ}æðKÒØbŸÜ‰hQ t*ùeÓhƒ"¹8ÉÚë)§¬=òž 8G{ŠOkT/Nõ{XÕ ýÿ…Å’¶o¸x©y–9ÊZHã§ZKŤ-+àQ+þ³ÇáS3Ê.#±Ÿ6¶ÛªâÖ‡ÚSkÅkô£ŒfȤ>•ñbX-¤õlõ÷3F}Æa÷»«×%lœL“Æ ì{Ïóð*½þ  ÛÜÕô଱’ )§DĨ‡Q4}îѾTŠžû0á𜨱hkmõ;+Ÿ—ÞôõshK¡¼°$\0n€ß©Z_‡×@K%«µ} Â½oœÌ=¹˜µ¬°ãÚXº[aÛš ¶½ñA¤‘¤à™ú¹Çgg¤åAÑËBû 6î]Gô7>}½— þmM”«^ÀФ™MÛÐoT܇‘á±Æ%üû´ õ ¯IsñáÆÐa™..c—ƒý–?,á~<î÷°FÌЦ†[,~ë'o^»ónF">yRs˜Ã°„ {Ò0V0b~†ÎP‹‡­à 19'ÏsCr¤;ã€Ê Áž77ÂþZÉd.¸#‰XËëp{e·yH¶ª,d›ÚôÙ`÷,„o…ÙÌhŽ¥Ê ßŸ}&4ÄŒK—¹÷ªò…Ö ÉØé‡/ôrµØZçPÑ^UsƵfp—D$Ü74Ñù9¼æ¶]Ú‰_¨bѽþ;èh”O-.qUöÒzAØ¢yþÿði;Ò"°x™¶4ÿwÚJ¯ïÃÐ"íq˜Z‘´Åw;Îë¹…š?§Õ;5Ý8Å ÞNm©5W\v†~þúû}—Ý]YkàŽ$>¨QÂÚ¯~C­ ç:5?™º&¤^?𪻃۶/Ö®€¥IêÒÁžÌÑåú`YCeáf5Ã8¶þaÝüV>ß Ÿ·"%²E‡Æ²Z ða¼c%¨5bKÖo¨×Ç¢•…ŠšUR‡’â‹iÞ#»JtþŸÔ_sJ”/ Zp™…7\÷ÜÒ ‡üëymY¼`få‰d)ü Çá5ãÃ\áPÐ Ûü„Ö^…ï(l>D2 ¢E¼Ò ˜°ùš`¥¢îÏ–^Y(ù_Ùۓ׆g}Ó³µ1ȃåbÄ{¹µd«m/ó»³mN® b/ƒ H®¯ ºøÀº[“‡à¹ÅµPz>aÁí°DŒ×áMö¸½ ”Örù¹ßÓ½Ý 6OÛÜù€2ø~ÃæµúÆeªäÓ –qT‘vÁ}L?‡…JuH¡"€µ,ûÕ¸¡ÃäöøŠeÉÝX•¶®õA;Âù®_xW fx«}|ªÄvž¦â^ÅŠ‰‹("¼¤ú_kBÁ„~/»û³÷+É’Àˆ£ØÐ°jiþœë7|ÞìzÃØ¯P_Âãue틟•Ÿ˜v-9W–¦ÿì5Ó{v d¿À\7•ˆew]»;‹jru‘ñŸcï 5LB¼‹úì!Þhï C$fql™#~®é ý­‘¢µølÃð”~}Ep$EDæ¯äÃSd¡&w$Diiê¢*àê÷|¹33ؽ‹sR¡8,Í-{!=aõoßpx›eD|*¥³oêX,ØJÜ–±–Âçá¨>{"}`9«×ÅÑ÷Ãíž]Ë«Ðl);ËJ­;Ôãµ-’•“‡Ç´¥/> °øìÀ%û†ÃYJ&´Ï»µQóaeY 2a÷¯øÏ?ÿA¿þ­3[}UÁ7ç ìÊD]Ö–¹† ¦ îfê}¼£ZBÛHŸÌô»:\¼»ï_еIg޷ΪTw# ]‡«>hߕɪñ€>?Hx‡øÁYG†Ã[S-}TCø³By¢‘ƒ¹J÷Âøl%Œ©‘㛵¹¯­Ëió†açc—JMÀÊ a$fÝÍ(.¸¿oÔ” }}9$nVé;ÏœiO«Ñ®z ØJø–YyOΉ½"Wóìœ9zïÈu[§Ã—™#¾X{8zOeÄ”Zºø“a –à";fmä,ÑÖ3÷³•zÁxƒd‡Ý‡ÍUæÃr´hÉ,]Ï ‡oU3Xb‘âîpÌí«þöšÒæIˆ(,dYBe¶Îòˆ êawa¯TH[6ͯjFrvL;6,. ê¢vÙKúëæûÓjBI(œßÕ›(àŸ¬ééz¾ZOÐöbÞU²ßìêꪩØ9Å ©%¹ðSœû^o¬Z/½Mn%ëû€IoÍï â£Ao½Å¶F YÝj}ÄϹ¼àÜ7~ –Z>U’¼Á¨ô,ˆÞ}#Àd¯MÃ"Ië·Ðäˆä±HÑÆÝŠ›ª¼™o €Ê˽%9Ì¥6ÂlD«Ûëå±­fÇâ”=4̸m’ç”%òf~‹¤åxÁ=˜cE½“úe ŽFï@Fmn³yqqÅ ;ÄK ñÉ”NZ<=—ÏØíÐu‰ŸË5Ûµ3f­¹©¿%f/~Ò °·±q(‹.Ñä1ò†7~Áˆ$º÷ÕuØŠ³pÜ …~àã+œc³k'E‘•Rã µŽvØqŠ•Ûó(‚€Âð;³Ó Jã EM>‡OlsH\ÐŒ|—o"Ôg¬Ã>8:MÓõß}Ýp8’6òç¨Dæäü´²ÛrÁ?ÛçE‚®Ã6õ¼Já€t¼¡¸ùÞ>ïpìW¹d̈$ÔP{ýÀe‚ö ‡·’gÇ\ÞítW]Ëf· ¼ìxn m¡`Ù²e_&Û^´¼¥¥ØRJ Ù¥_ì^¤ ¡ÿ¾#KãsžwS6,›ÁŽ,K3#ß=kŒšj4»'@i[Xï‡ñá¼¶´=ƒÝ§ãòÂG˜Ñ_Å‚ëél2LõðÁ—íDû–û­–:ŸB‹Faƒ±çô,§¾T˵¬5Íåtoša¹] 31¬1äEk&¸ÛeËD]à %0âÚyx´s8» àÔ;xF­hXÓë°//ƒv¨—´%Œç͵õ-#$?¹¡s˜çí²ŽÁ,ÔQoà·\Ëzî#O‡'lh~%ù ”5Ú8¤|•CÞCR÷ý¿~Š·|$×¹&Bª ºñ‘S$±KXè«nÁòë“ .Pb´Î^¸Â¿òpºš¥'!™-Ï™©^ûš åï{ãÆG—.!ª$ïž n-]®>ÁVÞMÎÎ8âsþ3)çÔ›à‘&ˆÄzuxÐIz×z<Þ[Ònâváûí2ìŠ[äÃüäK\„u¸ë}ê`Oбlæõ¯í²+Êb-{¡»ÖÁ á:/Ä‘±Ý‹Ï_gË4šI‚-·$<sÛx;es›¿ÁZK†V¡ÎÁÚ;ù]ºñÖ…gmM¾´ibp>=ÏÁýò÷Š$Kž]}WÒ±S³Ò”¡™Àvýž–Œ÷BÜlK¾×ÍE`χ—¨:ˆ£|øZåDv§:²â*"¬ð§JQ‚Kåó»ÁäÅxë´÷pÃ8²ÚÖ©‘=²õ=#€²Î-ÂûؘXMD8]³‹€¢tF°<;èœ-AìvÙ‘]¡8` \eÌÒž €ºV‚ÛËCcÙè¾Qœ˜6>Åä ‰}1bÌŒ¹XÆÔJ ýÈðÆûàÄPÖ9×LàxÉ «1åÖö(¿Ë P°ju0,ü‰j& rBu²lÞµ‚¼ñ\Wàñô½ Œ‘]o… °-z%¼k ³ä)$Êç+OÕÌb•QE¯×þ®ò¼EŸÁQàEÍ«¸¯!~ãjíŒ`È|°¼®¨Z/·pòµ.¾_­.‹ cïs¥N°&¦T¢þ¼¸”¼„ê9Ü»´×F%ga¾ô 0ç4N|oyxIV1Ó–ó©yuäò—\¬B¾$@eÿ×mœy2sóŠDøìcæáÑͨMÄqTÆ=Â*•xr@÷BŒ ;µ±6Ð׌`ÈhðvûÌ#ÀäNÒd€c±ûµ½"ô¥|K­G§f^­ .+±ÉF…KϹ@VÊîXdeÀïIô©C½²:-^ÈÁ‹Õñn×ïÛbŸö¬pÝÆ'Ñ|™ë–VF.켊ðp=TÑRæaƒ+`)çnóå’ü¢£­ÁÓaÈUJˆ©§°fn8\ÚzÖ&»Kl­Ö¯«ð™ûšqex)¼bÍÂlFÎÙ«nF€˜6æ€e$rè>O¯+Ù#Ç‹#3B‡Ö-¹4 0+gàMjy·`T¾l?IÙ?¸:ÍÊP¦†áãáÄ#Ûekn™ ™õÙØ8Þú2QgóÚUß;`¤ì;^€VôÐFÖûä!Éq =¯Æ—ëØDòp%swpXDPߨ?@ªz$O¨±€Ah„a”2FzëZØ÷ð‘Éq ޳˜’¥œQÕ-'þ·É¤êž€§õ+³À â»8†)ÀYHõ˜”q˜Æ+»hv)ÿ(“Y¡Ki·nïª-•Jê†,Ah?# ‚õHÓ@¡¯·VwB|!®&v³mÎJÅÙ• F‚Up=‘{‘þêpØhàðk‚`¦IËuõ/Kð†„mp5!hk?ñôŽi¬úäåfÙ€kx« æ2¥¦ësº; ·hŠÎª'øn\bâŸÚ38Þ“ƒ¸éëŠ831´ ÁVó[0žvE}æSLw¼Ö#"r 8Àž³-¡ÖNÎB†\PÔx8·?¡ktL4Öyl#püž¸KN‚]ù5)ÁÔ JiýаW˜'ã:Û1àv5ÀŠ¥7A7ó¡…ºG¾%sp+9y¸2€,!Vζ |»Ž¸„»3õ°7ê8¢-Ê7ÍßëqH@k4¤B-†`³š`÷‡ÎýH)"8£¿×fY‡-ošVžŸ³Á›|2òஹ¯ËætmSeÍcÛE„ªâƸRóñ},6€é ÄâtŸ`eC׋N=µäÞÛ%— –7Ý;@¼:çÇÊí2Gç ‡,x„Îåmõð|;‚&ï­ËBßÜöÜ’}Èã˜z C|"ÌtåþøÜ»n–­µºæÙ½–3B7ïêxŸ÷Ñ °ÃÖes9Êa nN=®xí ñQ¡i¹©¯^ãÀÎ$'òÔ3Zu19YËýJ šžGnãÁw‚ƒ1ƒÐ&*x5ëè ^S¸{*#̳P!‡|ûåO×4€zưºcËël @óì4ÒCoQôå;§sSgp¼Ú žXÒõ]Sè p4ëœr‹°¨7ÒŸ«|†ÝLl‹­Óôp½ã}Fމh½Ýi=À=ÒÙ óDpÒ\ÔÇ®ÄAQޢĎä`ãIÕY¯mÙMé8¥e{«K)5¯ñ%ƒY;)Xç‰dm°8Yå§Î°xàu6ƒÜ-j•ůŰ´I‚ˆña,¶Ù&žâ( _£çåZèAt¯KN€[}r(ú)$GØSšJ&H¼Ø'y„ÇaYŠi8*ËÀËJú4 SP…S|SSÇ×¹õRhÇíH.›!ÜLl^·pgOé 1ô°ÃòÊè—qr £­vÌÕÎAÎ,æÐ‹‘Iæ0‚—´~»…bëÊ„§’'ÉE~ «œ€vìÙ‚8Ì‘}2%Ô ”BIÆÖ— l _m­+ÀíL!V$ýòq³•ó†­gq°1ž2€×•·›PÓëñ©]®ÜÔŸÜ•f7 &½EVc›”T_€»£p±ñ´Én«ÓÂ2s,ø^On—šYœaÁ"²C–óÖR'ðóÙ—OnTÛî¸É4g\ëðã¼Z­WÜ˨R1<‰!vIòÿè®–,ÛV8%EAiW7ç?žâ¸3oUã­•/®‡DD}i7éÒ€ʳGªZÏ ™l•§‹z8?«ÇR \RWÝÀAš¯ŽªûôNm×¢j%]x ßÛ.DeJOæà…ÐdËá69h5¥Ñc C$¸L~þÛ”Fœr¿3[aM@aßSçPâ¡–ê‹0‡þéTpÛq'FØáó¼BšÿsSOtP‡'âŤqg`?°»¡Ž M/{oä ¥wmûÖ‚PÚîÆ[˜¦¿hTÃ[ÆæyxÓò'çÛáSÌ{ϧ)ûƒz.Ü^¬Õ;†‘:Ó×&¸ æ!óÁ†7/ šnèêê3À«Bsìõ"\én¿&õ÷ImÝ} mOcÊ#ÁM0½±ãÿƒ€£:2OÈ4ƒäé97VÙvƒœÓq—’¹ë÷™…MŒ]âò5Îá;Ò1pŒÖX> ýÒx >çj»oótþ”wåû%k•k™]Û•YÃÈÁ@ê™·]àþØÙ§ßݼÚDÍC+8hË\·Ð9gz±{m "›‚ž¬qT.v÷ÏVÙ´7¬_i.Ü,Lj² 1ç)Œ:ѵÄG÷¨üs”ùmyd•n |vËÙUÂóQß6üQ˪ÀçÂHš€]8L¸®±³¸á¸$ïÔ<ºÃk´þæ,A3’íLî'‡K¾øÜðOƒ¸(ÜšŸzà,»ƒX8Šy0f; ›¢Îù¦øúlÔCåW§7Ö&/(¨°`Hpn€o¹(çDë§¾G»÷m¥·˜"ýn «a&|¥c4´vO¨‹¯çøt©¹ )Ðn s — רZ¯9Í›lоž\,~nk¤‚†·:îóòjs™æÃ+‡éÌÃZ ÿ‘f'M;#òîqóÒ"A3Vüа.Mä¾[z`CúÈ =ph"–Ï-:ÂS´öGGPÆ 0Y`rýDŽ·*ïZî´¨ùµ07â^íKlÛ° )ó0ìö% ls#pBFys?ѶJüZ¿1#·èåJxŽSD3ï'7T»po°Žl’˜ÏEçqkK§×¯å–3Y³§íýÚR]·~]áÜ«y~ý{+4”³fî%î3@Ó¨è¦Ó‹vò‡myôI÷i·ž}‹žÕÏ´'vVXÔ†æ•ÇÀµì‡.#tˆÁ›¨‘+à[úDÎt[ ¶9ÒÐBÉ€~n¢ X›+þßïÍìÕÇ®.€§x~=„ùTÊÍM%Ò trƒîVtÓ`&fÆÔ"ˆ5,©.Âçn{•Ð(áSdz^„é³ÞqXÎhár´@S3•üïÒ:Éð!>ó¾p ^é1há,è$öÉwð¸=¨°&¹.À‹Æ;p©ÏÝ{È:ƒfl\§{* RèëÅK0š³}ß—JD‘™J=¦û΂6ö¬Õ¿¿Ÿñÿöô¢ð¡©¥y—à™) 4ð"ܱ ‘±šÄØZÚ[Û_PÒ­Q5{JìñzXEÀÒ:ËÎ"Œö¨nrAƒ>/•ä›…¹«ïc¶ÛÁ÷Á'!3“xŽÇ•æqiT-Õ%(³i‘² Alª_.çà‹è{µçjBbàsë*œnN1ÂÎí˜ÆW×-¢¸.Þ~ìÜ"qrÕsÎoÜ-X/Áð]5j©õ<êBuc¨;Ú¯l_…UÅ×&!/®eñ«Û=BwÎÄuø©îë;ÂAã,F‹ˆ¶$³Ã·ÇÛ7Z–׎–ÇöZÕo4äžÇ¾T#Þ)Û¿³HñûhòÃ'÷ÎÈ^MÐÔB醟 †- ðÓíù x."Ü ‘#µÒÉÕ6ßÏsVgƒî`<}‘ž\3ò ýOóØœºC)q™¼o p/ïð#Y½w½x9ïß±ñ5æj©½&RPx{ýÀî’¤@&›^o'ïH9óE¸þ²y·»ñ5 «È°òÚð/¦Ïö'‡ÖÑ÷uxB›NIâßšJVscLÅå£èTîÕÁ‰®ÞŸn0|´à«µì5[RàN-íŸò]\ìFú˜A„ó‰.ð@­Ü¾ä† —¡eøw3(î°6.´?@Á’£%/‚Ì UEÚÓf¶D¨ût~pUjcä®ÖÑ-©=Èäø@„F¯ï¹}˜‹kýÿÜ428§ü™GVÆj/UCî®PŸÃ/nK°bzOô+sêûwcCyE^^!irMê0ñÀ§4¥–‡ÕvK¼>7³òá0¶º«~RªKrK·ÝÂv=pB¸„í7h* ÅþŒ‰×nÓãm<‹¸ [ÚÃê]˜ v¸èí2›™öÌ=b¢WTÿ0“Éæ¶KçilÃÃÒýfv‚Ýpu|ƒÂÆ1/ÂÐ’1¡ŽfP†ùÀÞôô­—‡Ö€îÕ5ËE2Z¥;xµ˜â»Ÿ,·+Å<•q‹’Ó£ýŽàò‘š·oåh+}v&VÍ`àÞúïzr#¶êÆax·;Х䜙ïó¤Ö>m5üÝÎfq*bÛŸÁû00ñxDafb€¦K³ubñvG›#`lé/Û—‡Jðî…vQÍùÒ>o?ËŸ3ÁuØ> U³«6–ÞØ,$ûá^à£ó]‚Ü),Q‘O a³ŠG÷F¾Wÿ¬y»ØYßuþ2à‰æ]EǺ°éçtÔ3W‰•Ùu¼&šØ¼ßêð€jè…c'k& ìkp÷cQãóó1…)÷ ÑΤ"˜ö^ ¡D)<ìÏqõþÖ_niœ­÷b@„q¹Üæ1w˜ yÎ>5iì2½#Û1ð\pþ§`,ÃÖÉš‹õ4ýzšsäÚJúñû·;7}jš”:œ%l?ÐéÌìè9X$FéÍetØ›£º×®\ƒ«Å£tàs¨¯¼pø2vÙ.{T%·Rò¦=¸ZlV]ì*ÚÁ˜úìºÄžÍ ® &> ÿ?og8ƒ˜Ö!Åê,[j`覿[Òqךu‘Ûϱº1½œ­>7½_w”Ô¹ÚPÖa¢ÃÚ;÷»‹ _IÖÏ&å׋.pë±YA˜n¥=kp=ç‰6޵ú"ÓÄÅ7UEuáý÷(³9€IÎ'ö¸á{Ñ?å$f’­ª¶Í`*kÔ®ô$ן‡‘×åXuQý¼´.Fun_¸ÊÀc(@™}’Ï'ÂŒ.ôËqãÃç轟 i+„}ìm¸¤‘ðÈÔ o_Z ºžA¿žÊAŸŽrœ>Gæ·4ï§53:ðêßÜ•¬êžØ¼ .Á„öŒâb¶Ôúš,A{ÈzÞ‘†Åׯ¤jÝé¢Еú~Ѽc‚9Y{k­µ€ñ¼hÕ«ƒ¥}Jwp€§5ÞúäQ%Óš/›ø<ðpt¡ DŸû££^q¥ jÿ"Èìúö:ÿ€¤è<ùh#ÃÏE‹cm8ù-Ü¥M¬³/M¼1CÌ\$ž›?AKžW“ËËEWZÏ|ϲ-·…KÈý¸Ö¹þKw¹µØuQø]0ÿá¼’@ «ïýh+yH˜p„`Œ¤\™yplLþ}V]Vïž3# Búܧvuu]V†í+‹l =q³EžO:[·ÜÈ®HÜ…¼8Klãemn˨¬’X†”Û¨,Õ`[k—å« {)”sDeÝùz£Ã»?dñ*ñÃËë"ëäO‘í¥L'€&òÂúÿ¬‡+Ó <¿ÈDI+OA[D͘Û:ƒé–•ï/Ú´qˆ±^™VÕn'øB+áƒiް rˆoš§·pÀ–G(º±}.Y7]~ÒV¥°¬d„Y+É-§Å}VïR¼Ù–Y#n)R°v Ë[MX—æñÄÛ×Ziîš["(3NêFð"‹ÜÆhÀÜ"˜ Ú ÞH•ƒÃ«çƒgW3ùYãpèB…ÙgrÂ^”Mc[×Ú ¼õIž…¹ Þˆø2hpòʱU¨å•£-Ù‡·åì*P-,ïý©¥$Q΀+Ùr¥A+…Ê(|‹}4UôV¡"=ÀPSyDš -‚0>f<]oÞâGv]zƒõž"Ž(3¹ H¢V|HhU.o,!\pÆR¡'U²„…ÌÝF¿‹cR%»Úk ©2ÏT™†çÁ½öÛÍâdá["5·Lmá0‡ ç³d`Qà˜óH>µ>´©Ñrò³xßÎKø†X1wX[]_)qãÏÒÌ8´F×Tþ½t¤¤Ùé°Ö^èBß®©8î|¢¥ÝÀ`r¬P—1‡‚]".Ç5<ï1Ž”Í-díÂTGÍ*„ô©eçSÞÀ‹¥«ÌuØUÄ8T!pŒÁBnrY²"WNËëÞQåÈTciµ]Üi»ÉÔXCE‡!fW¡…£ª–äËBjTZ¢› àD›lLÊ6–´±äï£ã×-L•˜só¶âp«WZû «…Ìœž”€àH‚A`½DáðxÌ܃v¸Õ9ËÀëÑæÌ3÷EÝTL‡ÛÉÕ©Ø“>ê¶°¹Øðuˆ‚epk! y¯Ó_ =/Î2äùúH'@¾ê®î—/­ó…tþ9”ZCÞ¤±ÍÊÕµ‡†³²™ç?àµb•k1É8yµŠ·D¥ºÂ v¢ùén§z0åX lM0Vû` ^`h±Vê²xÎÅ<ÍÙót`+=â eÇßë"Ñ£cØrØU/·8›Š'I¯G’•´¯Ö ‚Ê2 1n#ÙWª_Œ;hCÙP¢=ÇÓLá‘““rê» ì(¨åÎ$)Õ¨C-/¦™ïsa‡ÌIÒÑs%AÑ]G!:†¹¼›n2eîTok cµì¥p®~*.·0wÛð2¨UŠ ”ÇÍkâcÚ8'>HM+‡m´Aº\½Un%Þ½xÀGè@þ•Ã[3E!ê`,‘Èì-i çÓl…XÑŽ*l­^U«š úcX¨j—ž2̇ÚT³SDwOëª54ζ0²¶â"~¥ÜY+|ûËû¿ûúŠ>±w ]ðžˆer¹2‰ y\W4ëJq²ØÔ)Z=[¢)ï6¢À±GÖ8œ'õœWø.¼§sxˆåò¸ˆw×§Í}aQ^]ºë«¹–)âª:`ÛpNÊcµí*à-6¿IÝfZ4`·Ö¨[‡ÙâpóÕHÙzpw‡ëzˆž_IO›Þîé–)<-Œ#_²mh ÇÞš^[~Ü­;"!ØøQìT9çÐê¾÷VUj% ~;aÚ1­”‚ʵúãss„Yéíö¦ ïïb³Ó õ|x‚Çn?é]k+ 6†=‚‡ö9.ï .ãôYx¿9è‰ ¿7}¸ÜÓ$ZqEO›‹„”­Û¼qõ¤©ãPº©~ sã>¢‡[ja!ù¾–5µl€Ö”êíM¶{²8Öôî½±š•c_ n*Ôarh‚?Ø„þ¥Ù›. ³'^E‡7º\üÒjµHX•:ëeáεÈH“Ã5ÏÈlk†Oä˜%’Xæqs_+õ|BÁ=~ÁÎþÄL¨‡ÁŸh—x"Yn©ì0×*ì sâá–­Õr§…F] ³åW4 oúðžî L™j½Ò4þÓæËoš|Še:/úËÇ/Øñ|ûð7¿ûíó§o~øé¿ÿüÓ÷?þøù‡ç ß|þÇ¿ž_ò_|ûüüýÓçO7Ã7ð[ûåCº}ýð.Ý>üüðî'ý‹Ü’ý÷áú¯ßãoÿûùVo¸ýõoéö ¿øðgŸ‘&õJʤÃyÉÁïxêFÒ‚›‰7Ðñkxþ+x&·ß¨CÄè7ŒŸŠ?P2éö~-Â&åLër)¼jc †­<‹Ï@dd8j½}¤…™fðRJœ]âÓwpT$•B=Î\ûõûÞyÖ·*ƒ²JhvSõáV§Ø¨©² —“¿8\t¼.v@Ôïö!T^v u¬®È^4oÈ>t|„(v(PIõÕÓŠ*Ö†w ¶ØÎòpX"Á}j|äïû.×Ä€áØ–ecGª¶órÀ°p©•‡e®Ĩ+˜ugB›×ﯞ.1škLáktö"'Üfïùî°J¼Ī°î øêN^L¨:Ì[$BžäBp[0ù}x$.Z‚-"à,6Øl¯+û%:ÖÜ¢¥åO9)·5ŽCå'ãuŽdø0ï 8$ÍÈœU2·°j¡%„v(3¼%êZ,A™ÉK ¦š½L!ðÙ™5F…ÈÁjó…0 èfÆ.°#G–É88:æ`ÓåÉÇ-}ƒ#húpn•£d…½¹`2¿Ö|Ë/b´DM£oØêu+æàõû‹ï¯#Û;7ÛeëÑÄ— —9A{þ{híè‚û Öän»'4:.¶ØóÖ g·…àºUDÃ2@i—“d1³1ܯ¸fYw‡ÃbJ®Ÿ÷²¶Æö½ùÃ'-·?‹µd,•§–n¯ý€Wì‹©œó0¦P³nxšÅµÜm5Ü!£4‚£˜\4ª~K+`÷©Y_K9 ûu„¤þê°‰ŸxªÚî!f\¹,7ÏP/·*Þ4ž‰«šà Â&¦fÏÈðtÏÙçìKˆ†¹;ýÇî³øY BîFEj〩÷³VÊËà —h1^mL¾„ 'ÓäÅášä7ƦCV|X©œ0,ÂûÃkƒØ3$®¶z8*jñýdÏñi b« `î™Á‰]p?Eõ~zÖ}©dyPc·“úàx€ÿ·8*: endstream endobj 13 0 obj <>stream H‰t—]«^Ç …ï þïM¡ t3i>t™œö¢Å¥¥H(¥ÛýľH‡þû®I³gï×!Á?Ö™=3’ÖÒ4~üº§Ì‡&îÎ9T…&”C²ìðíëWƒ×ƒ —[p?ª–,·¦7XñáXaqNG&²àr´Â2 ã_Ë`Of¿OzÔT¯¡ÔIÚlMª)_aÖ£Km±ÀÎ+åy cÕ¢Ù UÕì‡VlõÜÂâ5‹MK¥ÁÚѪT‡9׺A_ µò=¸àv]E. ¨Äïž´¶Þ¶—éTxƒëÛ’˜oÁíÈ5gƒ­Kv(bt¸.0im·`=2“8ÌZ"Ð £"ÙQé(½Ì`F5ˆÕ!RG¶ad¾i@Vƒ)7ÞVà27L¸Ëy øI¹ÍÚL‡SÀ’É`ûz±À[nÎ =ÞÎëÖ [ƒ”2³8ÎÖ-h™×F±.x›U‹àT©Dp1HÙäµÇõž|žüPÊÕΛ“÷]=z·Îuè+´£7)·`= Í Ï;-å ‘lÍ«Â7Žr£mžZPŽ^{Ž=䀥 4_B(jŸÉ Fe°ø)ªÌl{`hÆ®kšå·'Ô^k¶lâJ7(·" ^4Nõ`íSjF‡°„ÖÐh…¾=Ëá3ÁÙS< äÙ0˜u–¥‘ݰt À$Ú-õ9­J=!”e­PàÉ7#¼YZÔéÔÃO!MøXꋦîm(ª.Úµö·¬¦äHW=»[©ëÙR¹„–ŽÂŸÁ¹ôþgUŸ{rŽV²=H¡üYÊ&ÑÁ‘úQâ&GJâ-±ÃÚSÞ ¯ÐêOÁ0"75:¤&}‚:´tRO ›,ö9ø)›©Àípšê§çàžyp5­Ç= ¬qióÈççJ!WÉÄñ¹TÙƒSªQé“] ç¸ù•ó1T’L|·6÷þ¦¦'„.BFB%7^pŠZ› (ù*`vîpé [»íÁ°JÝÜ´=1To*tNÂÁ±T)1õ%”³»[˜Åù)‡Kf§r F?Ô9¢Çpu‡+oíâ¥HŒÄ¥Åx6ſճCÚR1ÚÔ¼19…ÊÆX÷íðŠÎøtçõ,_ØO#EzP¨ê3½O¾WÇJn³cðlÓDz\î°]ryòm-ÑóØ‚O¹Rj\d¯SžÉt¯8ƒÇ°ô‹Ä¬rƒ8¤æ|\ÁÑèìy+ñØAmªºg¢bËôç€ëuCÕ.m {ò Ó¨KÌÍWкŠ˜ÅâU…¾ÌEkl)u]£%ÅÐ:²“Úœì`Dá–HHÕ†ƒ»ËÌ¥ösÿÁñ4Ädü¸,›P–ÙÞÃrÏ\þ3ÿv ;Å45Ó¿+DCÐæ€Nñìí"Ä:ýzÈQèë|vœp‰qks{0DŠ«sIõ Né[µè|¿²B·úUt®=àíô윯,]•®{œÏÐk0L߯@xo»AÏÙZ!øè4çbȳpG&²†Kh"ÙàªGìÁbi™Ÿcq½:!ƒ­mí7\ÂRÆ`®—X ÌÞ#«ŠðÔ&(D6s—: þj³0SbÒõ>ã|¼)†×½ îV3,WZ%îawnè&•ŒÁÞpº(Û xßGcà#bãOÌØ³ŽÊYÓÔÍ¿¿~•¿1åch ¹FÛ<>Üù9½ÎA¶†9øg1«aÓ º¦a§y k°øÛC¢¯:L€Ì¦ãé6, ÛU«þE[“:¬dzH¥ð߯ sº} Ne­`O“1+6Z+àxk>ÏÚáypUñ'ìtƒsä˜ùGÂ×)´ÜV.kJØ.¶ÚdúÙ,X–Æ?¢´šÅ #D$hç„×àRòyeÎ8bÊÞ¡_Q‰ŠÛƒa:b¦ƒ2´>5–̆ÛrT!jâÍ >mŒКLAä¨þ!ø¯Ñsl,ÙnÑ­Ö`ƒQ‹!ÊŸX—Î\ðü¨ÁÒm¸Ã?Û¸?^Œ)ù]ÕÞ¢AÇuUòØÒóã~¯‚ü=Á™„3?°Ûl­ö\[ùyRNqÚb´‘lÃQÖg–îpå§)?ãBiÁ1<9äU€HfŽI=îrŽ6"Šúé/ó|_|ýúþÿÅ—¿ëûíÇw_}ÿãÿù§ï~øáý÷~õþÿúxå¿üúãÇï>¼÷˜øþh¿z_Õùæ§×¯~?Ð#Íÿ¾ùßøÛïñÓ¿Á~zÈã¿ü5=Þá7¾ù3Ž{Ç£ Ï§ C÷j±+Þùt|HŸé+ÿ Šß~ó3«‚cû_Ìíý Ô°gÁÊØàì÷NmQ Cù>çbéBCÂPŒ¡ó¼›R¥;Dýu¶~¼ñ‚gw¨•èhRXm½åœ7ø6Ž$õ3Á8¡û~zbIÝ5/#c‡úùª.* R°)t×Aròî>„Ù r,PQ•OPƲk…“³ø-ˆ½B'$,‡èìnÞZõ+À­Å]~t–AjlsÑ^Ãì›Kÿ¥°0ÀŒ©q•LíSÁç;È2Ô’ 60‡ Õ'¢\9v¯ÛƒÇã)êXÕS„—fmû9ößıKÒf Û£kBL(¼Á·±®û9¸s“§e{טÙRY9Òa™Ý7ìU­Q%ãd‘yLÒMeƒ¶€"\ø¬Ð`0¹êFÆŒ¬©Çï.ˆhÆZŽ:1˜Éž–ý×ó’à-8Óð`±:ÄÄJ1Œ·È€B,»¶‡?¬Bq¢n{S_ÆgÇLsÙ€ëø¹ês0d*_—ÅV›€+qÛ[ðš"0 wåê3›?¬ð2Û*±çÌÆËo&Lµz`KÝkY¨” ú ņÚkð,›•õñèë’Ï^?yõe˲ªÜ`Uý¦Q«–Eõ.XXÌ•˜Ìíz©Ö=råB¼(j™OTɵI;äµ*ã¹sÖcTÙÌi¿Vop˜sËôp‘PŸ§àêOÄŸs&]+l<Ù­˜ÔupÚ»ËgÒdð+̹fraSyãZpQ¸@D—sÁÿÏw™ÜhvëP8'`CÔ¬uo;·î^ü>œ$J·àE…üy%ŠÃá@d-,hÜ•žæ¸ÆÞúBsÄÜàmg^Íñ‚¼õ©"½`›D_؇:–W¼vþ…<Ì‘Ùà-÷z›"õª—ÚB„mõq^<õpð¡AÀ©¦Å–«.[!ŠÛƒ,trµµ¬7à_'çÞ WÇöpx£=Ÿã#÷@š!Íw{ÑјGÚ°ØBæ×”±j6gÍÐæôW[ÕH›¢×g·&¤A{JTͯqc(ÌuçôäÇS¸úMù¹yЪ.pø{Yq8ÕÞ°:ÂÅì÷ý}(µÀÿæÿå'ãŸáúùd׳áþ­®é\7*¬ÔGóD+²Ð±3=¯Ÿ©—;À€ÝZçy À…Zù¼/·1–¡Y—w¸ÙÚ c#¹¸åµÂF©Ä¹"kËL² 9üã;Ö|Œ!©ÔXì|0óùðßO«b.°å'ð/¡(ZÚ›F„U±U·ÂJþ2_X—Õàñ¥ÚçL«Ê*!ÁömР=ÂdU5cTût³útzqà>ÜãÛr~±^ÖƒZM:´ Ì$*1&~¦fn/4Ýb!ÀþÚE}áj%sÔoMMFH.Þ—öÚ˜=L;ƒ»ÉO–/\Â-œc²–äzò‘/cXá€Ú{f³Ü¢ Ú1ïªNi—;਽h8_ÝÆ[Yqåó…œL½{YŽ9$ê…cV-ŸÑå…KÆcÏ 9ÈÿPõ™² Yìå·ª¶›Â»X³¹–ÛñýU³Uû°Î’14rŠðzc>}ã¢}žaF  ¶e9Ò3”À/÷K²ãYªS#K´â/ϵçwÔËò+oã¹±ì`$‹‹Àš†‹ÚvâÅm‹÷¢¹ÎÞVžÓWH ÐtŸ·1v z½V\Ü^œ5H±ûz w¿‚uVX_ÓôyЀoc±+”Ô5-fÝÿÎçæ²'Wï‹ùZ€5ŸöSŽÁòúþ“W3=¦ƒÍán ­×uóÈXÙž²¥¶ˆ0ä½RŽQ5ä½%5CCø›OâÔ5bÏÈT ñ¬CÇ`ß;Î3åu<Ž?÷0T‚«Ên‹@Àœ.v9Aëš83ý÷U»ˆ±ý­¬0˜r¯ÔñŒ^ëaÙÂ,8œ%º±¬‹˨¾ìÉ–d@B¶œúØÎT8øŽÄ}ÒDaÅ’d°¨¨ux)Õú1&,[*ëûI›‹Ï>½í"“‹x¯XÆEäpT{ûm¼1jHê™àë׎¥Ò䝸ï¸Á>·@5žzsãᢖøèÖbÄ,ÅÁçP‹Íº?Î@Ót¾ì¡z‹´h0·,ǘ§ì˜þ9nZ7Dÿ¬äžXOËÕÁ]V¡,€2±KÅÏþïÆËö.ÿl¶k–¥¬OÝ5бӜÚy1åòÌ1íz;û-`)²²:4ÜM }Œ±1ºM¥Ó!¢&õãÁ8¢×W/v K(<Ê4]È¿k’#Üí`nHdñ>uÃÁ—×’6ÏúŒ;Í WÝ58cäçsG´ŠF|>xíö`œy•[ö¹Ôó ¹CÕ“: ÇlÇê&XEºÞçZȽƒ[òŠO,ð„ ÏtM=‡»ˆýjÁ˜wÆibÍ¥à\ç)ª“o·¸oOõWÚ‹^à˜0¾*ÖÛ© ÁZŽ–û½)ñ>kÚôl5¼Ñv²Wëv‰ÈÖJû›c*cµ ëÐA¶€"ÊÞÓ¥÷%F–lŠÆG¶/ þ>eø*pwdÒi±6M‘jR;ºÐT˜àMê5‹Ð²£ÚórÞlŽy÷œžÖßÓª|.yËäÙŸú´¥³Ò¸;ƒ±}TâcÊâ‰ü]gþé¥~T«I^€†ï¬– hSÒ|®5”{0‰Ô»wVâ ¤z'îMÍÎÐVz -†ê `V1£›- ÉT»Üœ?…µ‹d+ãL©;Á±TåÉÆÎ…yPµ—NU9£Ö˹ƒsTO_dÆ2t޲ÜC.%Âí!5*1ŸkØçòÕnÖª†Í§Ú—ÿ¼þŸ0Gøçx ŸŒ„?Ÿì{.Üsöþ\ŽgYwÆSÓÅáŠx¯¹Œ[™ý~Нw»¸½±œkÒ €K÷”;sÒYùNšâ!¾ éðI^Ã1Ñ·HŠ%±›ñ]?)£¹çò£÷LIÿP–)íjx¬Åû\ÈkB*¡3£Aën"‚Qòt›bl–q5¦î.ùnyâµ–;Î O#}°6]ÙF„·g=ë·—Ëšê›hÌÚØGN@±MäÍ6ÑÚÇXRHŸ—’^‚g—è9¾ÆŸ{€|^ÒžJ6%"0·fËyi ±8h‡whŠ>ökœ‹l{T>P~³=^Gën¼t"©H\ƒÔKˆC©©h@ûò[ð 1=Ukñàôlu"¾¶,@ÆI´¦À:\%ËQì]½õÃö[f“Ç42¤ã|à‘‰vI È¢&QŸ u“ˆJUø*®-\©¦½ ॖ/îÒšaé¦u»æ|+(váÕŠÍåýUÁ¾D·†‹ûŠ!°Ì$З£J©ÅÍE: âßcœ]3.¯e·HÙljÀ} Éã`ƒÃkhiI«?ÞzçéØ¿Zµ-p$Êw+äµ¶Ù¯¶å¸m$úî*ÿƒ^\•lY1$˜<ébk]ë[•’쾩¨HÃ5EÎrH[òÏìÇìmh Çñëx©‘™J¹ì3 };}:ÞÍènnp¸[.}ÎjÖPSæn1ôvVÛ@¶P}ãFø( { | ö3wC‹Ãƒ)v¶u”Ú8P­4‰µÝãÀö ”Å=ãº*Ààˆ8r^Ðæ[&'ŽŸ¢1Ç÷rWeT¯±Eql›È(î7  ñ± vðñ ÂÚiøª ædÛĬ’B{ƈƒ½V‚™Õo¶´lØ5n£ë'vA 2 |ÜЭ#aF€!ab Œ@d´7´xF [v»­YO{­©—›#Ϙؚ3`«hä¶Þð²ÌjŒd“¸¹¡Ãп¡Å b4†s‘aTK÷;–ØÜ€óÕ3–ZÁ |˜#„7‘ôðn Ö8Å!̵Z¬qįÅð|¤ëwM[nÐ Âa ÃÃãgi½mMu+Rü:©Ðõ~Æ×S®«JJü¨hœvT\ƒþžD½,°f&´Æº×5‡šk¥ù-2+nÅ“Fs[‰Œ4¦zRGNnÁ0PCn@'¢g ›R³˜pv@ˆ¬”=¶8±ìàZ«’„éH”ÄYrHº#7è+¾nØiÅ©AʈˆÞ6qlq¨)÷'yäahð(ö@Ì%ŒlÉ®1(j:}mh%¤Bgh¹ÕT3â´H’Ï©Y^`ŽÓ@ºé#mÎØæ2°7xÆ@¶\bÐt}ìJÈ×%º¦Ž]íE°•tlššÆ”wÁ ­¨ÕôþÔÇ"Ã6Ž.qÜjñ$˜¹”‚”Ú¬GV|Ÿ¸'ˆÀn?*"´ÄV¬-,ò”xƒƒðœújnmV5Ë5° t÷:ÓÂó¸glb‹«ç¶Î=×'¼¡Áµ¶d4FjàT <§±UâR¯JŒy`CnPôqÏþ4æ" [`Ä)k ²Åx ˆ:(4|CDmñ#ؼ!äNx{ÆîÁZ8FÎ J¥6‘Œ„-Ï&¯ˆ»ûm‹A )kÖËŽݾ@/PFÍûsÃMA"AúÆP¥Dàn¢žjAx–$‘_ÒˆCБ‰1CE–7á±!ýM§©eЖ<Ä™‚Jœ¡Œ³ jv`~‚-ÑâT÷LºWE(¨ØÐE’[ÊáVg`~â‡5Óu/»züˆœM! Aà–DHÉM֜ƌ€ÉŒwADí>`àêÊVÀk)M"Ñ3’;v€.¨W?J"wC‹OpælIŒ,Cx#(d€œº*¶8†IÑ`ŒÛ‘°qj´”°‰od6dÊ”…u+dvG„YKì–騚8œAšxˆCEß îŽ_Þ|rJ¤èGnÛÐCÀtgä6cxC‹C Ò>8´¼iÒË(B"¢˜qÎvNÜ  ²C‹‹8јs†ÝN·Aï>.CÂúׯ´}¸6>@ªâž1ð«0:ë.-±š…ÔÇ›kÍ:ãÉP“‰·3ÛjqÔ3nÛ¤L°h[Êvœ^j!‚¨þT!öZ}Õ¢TxøA惋ö†àsÆŸc<ñnˆ·ÞF‰k,ƒkr:ý   ¹¥¨Ô¹Ûc ‡âMgh9ÈPƒ’µ r¾ñæF”o * è` Û¹ðêðE—yW(ˆy°V ƒ?A /8äø¤›6bg(¦ |1^ ¢È”*ápÁO1mÜ;ïòðÆ¢[(èEF*¤r+2D 8ÊzÆZÀ2õNô<áVvxvSIäOBØÏµIï×îISê0ÌCé7âMo»–h-ëä†ëoÂôJà3>pË-c3Í;Ó=BêâÈ^kÏi:Éã‘"àþ$zŸ’=žõÀ){8î)C†\OCëCE©â øÞ g¬¡Écvì‚ -B&Ü >Þ¼AE»€†,ÂJ míh/œÞ68,88t³‹’'ҳЂ‚P̺¡ßçEGˆËP0ç2•n“p¹ôA©•C‡Ãî ø"ÔZ[×BjHËM»„‘d=c|ܰ½“÷°%ö.܈ ÐëŽ x¥„oÍȼ)îqÛ)íÈÚn+;\þòÛãGðÿ“£—òây¾<.ëÍê]RUªÌ *4zñ¦Èß•i^¥ùõá!âÇê:Íý_?z³6¿Qb<ÿýìEšÁU=kþ~ð3üë¯_½)–Êüý4]Ti‘'åÝŽŸ~9øáö&ËáÇCx`™^Ö•Úüxð Ê2éÛ,Vi¶,Un,ØÁ³—yÕþ¨ÿ¨îÖÊüøÃÑË‹£Ëku•%‹U¥þ–ä•zVç‹•D~A"“Û''ó–Œv÷ùíºÈÕÿân{rOפCFà¿Áû4>stream H‰ì—Qo7Çß ô;èå€hbI‰/Åéɲ`#¸È.¢\з€âÎJL¸¤Â%«ŸíÞ+Å»v›qšŽ¨F’=cñ·3üÏ„Ûôþõýw£Þ7…66ƒ'Â{§æÁCùcï§ï¿;9sNÜ‘K¥3¦ŠöN^ûÃí_~³‚ê‡? ú?öNþc”ŒßÅßlíȵÐajBq-½Xo?ùK)FuFÍ_=´tϬ.çV[7ÝßÑôäefƒ“p¦WKqt—p¬ƒsÑàR»‡ÏÑd¥Ï&°Vb{,<_;‹ù¶]ŠP–J˜me“¼njÉTîÛ|/fަ‰´eC›åŒà³ Òuž—àÿjmäTš8I½ ûÈTÄâÜ«mn—€£Î_q×”R 9äƒì긔]Þ:<Ùm»Ñ/V¶T’Ô‘ݶ¥¤ãÒ$¬%ƒ§x/òhõù¯Üqî_spÊáá¾±w<´ê{1'T¾ÎþšÏŸÂB6ìõñ\Û·ðvûÿ’€×LbV¡‹`äë$åçxðé‹^¿÷÷jÁËÇ<¬üÝDpŒêÀoº|0þ¦ŒÖ#Éûð ß”’)œÙà$üU¶³FŒÞ~µT’PÄŽ½´]Å!_W»5 ì œðÖáÉn3˜­Ò“RyHRG¦àp¦õãîõ§JÑ”–³‡«.ؾ[ÖÉ\‚óJ{Œ8™@ÞźÌÞ^^T9‡Ø¹g/ßýûÿ]j;U:7ë~U×Tyò¼ÿ4Í 7ŒH§x¢<Ñ Ñ`@(Ò'•ù%kΆFé¿%¨Å’0-÷ñ\pvþ¤Û`²xαíè¶{âc=a3m%%êMZ±¦€Qak¿s¦WK["«%ž(µmrð´c/l²‰LÂ=ÝÇs±eJ ÷0 o“SëVK«íb“ä:9?:1<> Ä×èQ%ðQ©×kptHPõD4ðÉs4R¶Á#mcÙŠ„ﻯÐuNa¸Îó|’¢;!½ÐWV•x ¯Ó±Eúüa<݇Ÿ¼É¨AÈ‘=B•Ró~ÆÎ¼òr‰,«ð7JÁ¶’¸POÑŒ&×QwÖÄfaŸ`ä碄 IÕwÒ˜GÛ›àæAÇ£@’ãmþìQý_ýñE*¥Ðë± g+,µ©F±U¦#¶Ý†C>¨×h¦›ó¥0ô 4Hoð~&íšvó`Úû™Ìól¢Ê• 0~*VIµBÄ_wsœÛÚóã›× ’ȼ&T)µ¹Öïí¿z÷­Gô+¨ {Î>žY)Ï­¶nº—šôTrŽßF“‘‚:¦"%ø*¥&%ø=­ôÙÖJlEXnZYHµ8´[š;€ß:ìIS–”Öø7TGsÕ_èObÓ¡ûíööÂÑú»N`›•x¸9,(Š´ ?ü››;[ú±Šæ¢:Å—+ „¯ fƒÂ¯A–°Y>"Õ‚ŠæY¦¼ZV¼Û .Fc PÊP-<±‘é•Ñq˜Rh9ßÂCÞfp!âK³žû3\U,è’¶ÓX·#aTQ÷c÷^ô­ö³KÊR 3Ö•X§· Iü˜MfA;ºýìÉÏxÓ°!x† ¡ï¾bå䧮󼟤(äNH/ô•U%Þ!Ôéhs·ÿ0žîêQ„<Ù#Té+4‚É{ϼòr‰,«ð7JCÇÙ¤l%q¡úhHŠë(¨×h¦›ó¥0ô 4Hoð~&íšvó`Úû™Ìól¢Ê• 0~*VIµBÄ_wsœûÚóã›× ’ȼ&T)µ¹Öïí¿vÿ þèý ªG¢³gVÊs«­›î¥&=•”øM-)!¨c*R‚¯RjR‚ßÓJŸM`­ÄöX„妕Ŭ—"”¥f¬ƒûZ¹Àp¤¬6ô«ÉYÙ)¸lßg’S`þX—ƒ¬‹x,Ë“þù§à<Òƒàdyoë2{{yQ墸Ÿ½|÷‹º]®èwø¹^ùÊC6”§ýÞ)~‘©‹úš²Ë4R¸íü=H?¶Ádñ¨c{C䱞L¼KBjÑ¡õ»ƒÂ®òž4éi¾nú“Øt”³½sxáhKGÀØÇÃÍaA®»p¶uŠ@–UK’« f£ê FÃ~opÿî÷âŸQ|ŽÿŽâzhÞê‘ Rûx.je2ÈUÔH¼È8XðJa)\ ñZH<¥È2åU—ö6!o3¸5@)C´èª| ±‘ÃY®´"`J¡åÔfÈÛ .D¤½ks€« ]ÏvëÂ&Œ*êfì^•ͦÍu—ÞÝEâ\If68 gzµx6‚‹á´0¤‚E'4ÍyVñ\p/Ðd¥Ï&°Vb{,<_;‹U4r¸¡,•0㺢Ǯ‰Ü/i‹•-£«¼'á{V 䥫¥’„)5rîh(»'¼%¬·Ìr¾oÕ$ÕãA-飉><Çmc ˆ‡¡ôGNXêñdêþQÜæîS]„z=#Ôë‘pÊ/ ð§ñ8”q‡<Óñü€¡ÎYá)¸l_-ªÂßôœ'PÚbo=™@ÞźÌÞ^^T9‡Ø¸g/ßý¢n@—+ú]Ǭh¶nÖýª .ñ=í÷NñÖ­.êëígc/d#…‹ÑÎ߃ôcL:¶7DÞëÉÄ»$¤Z¿;(ì(ïI“^f´ú“Øt”³íç½p4C_'°mbx¸9,(ÃuÎf} dY ˜Ã*˜UGÃ~oØÑÔ¸z$Ó>ž‹T™ rej}+~B)f#… 4A ‰§Y¦¼êÒÛ&äm£±†(e(‚]•o!6r¸ µ2 :z¯)…–S› o3¸‘–®YÌý®*t=Ûi¬Kš0ª¨›±{=:4k6×]jxwÿ@ˆs ™Ùà$œéÕRàÙÎ…Ó¶ ÝcÐ4·YÅsÁ½@“•>›ÀZ‰í±ð|í,VÑÈáR„²TŒ늦§™ÊóPâçv*òAÓÄDtƒZ¬Ô¤cZÛOh<­KžH«-a¸›Ç¶½ 9‹Þ`¯ZI‡Ï¸kîskJ/ ¡kï%r±žâ'_py\‰mg!'ß¡ …íÚk›#ViCu4Wý…þ$6ø­)ÞO/Mžë.À>n ÊTÝ…³©Ô)ž,ë2-m Œó¥§£…0£hˆ`¤L¦v´VVƒ9ÈFÖ ³À_Çê±ã]5ù÷ñ\¯ C®ŒòÓ´á'”*7R¸@ãtœ hJ‘eÊ«.!nBÞfp1k€R†"hÑUùb#‡ R+¿ºD/ §ñ[xÈÛ >D¼ooVtŠ«Š]ÔvÒ6ýÙàKd½“.£Šº#;NýåÒðÌÈŸûøRý¦Šà—„"í¸zòŸx8ÐñÛCáñ)¬ý—ÃDUKÒ«íDµá·;Hµµ½ÚiA’W"z*¼|Qì0§.W ã tסc5i¯2AÓ6™*žÏ-eh6Ê´ú?ûeÔÓ6Ãñ¯ÂË'(°iRŸ(ݪI0&UÚ+º&NspÍE—; ûô»$íH@ãlr®ë ùûüÿ»Ëø4ï¶A£VÎdÞDνE l?‹ ¿À·~®‹fPŸeÆÐÕMÑ_Jo _ƒû˜‰T¯¡-j+ºuºê$•Â¥6šk„º늲©­0´UÝ&páá°¤¨ì&œï ãÉÒÑèr5Á\T²HåR— ¯A)}?ö> ÆwR+°c/½cmD±Ä?ÇæÇÀ·êòoã?d²h a§”.wRølT©¼òãÏÂ4•V†qï.ü›ÁÅXxåÃ&‰[yÅ u¾‡ØÉá‚T²?e¼ÓK.ýŸð|ˆxßíè¶Š º©ý4¤múÙè%²ƒÃB!WíDª~¹5|]C7K®ºn‡êX6åÿ‚?VÄo¹r6'ŒÞ6‹î3”ÿ­. ×Ia}ULes^lF4ü¸Þ«ùæL»Ø¬¸(_úöÖ¼r„÷N˜N§ÿ6w9E»Óšx.ƹv&3Uæ‚пcJ9-=J—`„ YŒ.ÙcóF;׫RW2R¯ÐNà̈2—ÉÎí¼¨Þžâ‰êX6„' „öˆFœ7†ý)d±»Kž0„„Í~˸ØS™e® \vQJ¡W'„^ð #m¾KØî{1Žeîu8¢Ètï0bb‚wŠDˆ«§„¹r”‹úµã]c ÄPµ?įsÎî^‚YBýYQÝ}×*8+Ê‚ p8…ì`ìû2ÿ5ûÖä qhϾ_Ï“ÜÿS(® ƒ›†ù› ®µ«7؉vEêkœè4ZÛ^k+üãì%!_éÐ&a®IàL•¹Ø¹kd¡\@N#6¹s×!«l:…;)ê²ð|ý,f š WUR“¶£o2ÃÅXÞ×)š( lâ.QÑš@´f”Ä,«ÀÖïÆ@J[óo؈œ»âª!þO‘7ôz§o’¡õ©õ\3#Ê\&ûíÏÆÏF¼ÿüÙøqô隆 ûŒ²OB"˜3Fo6:=Â#ÝËÔæx¬M8Ú -¹Ì ¶lÏæ@7؉vEêëœèÀ´=[ž>ÖVxÜ^R‡¶g[ƒðmáíéË•þ`0wá endstream endobj 15 0 obj <>stream H‰ìW]oÔX}”ÿà$&ÎýþXž’aaÙ]ÂìV£Qät;ÄඃÛòï÷Ô½î¤í^X9™m%ju—ï½®SuêTÝYÙå’Ÿvwî7ù¼+ÛÉþ˪˜ÔÓü¸mŠêMrÿÓ¬¬ðs>ªlW?L®Öã×þëgÿ<Âãä/øþ¨˜´E]eÍ%ý|x}@ÖâÄÓ®ÍçqÓAÓdŸ¯™œå´É«°B$ûO«vÕƒöò¢÷×|ÛÕ×ÈæíôQþ¡ÈÈ­áøVwýô}Pø· $ûkœåO²n>/²ê°ìš7¯_òýÛ)%[§Ñña +6HSQGA7ÑôÓpD´ö ºÜÑåxˆê³³yÞRÝ4ùô ¼8ÏCüES+žÄß«CÜ6‘ùŽ\ÿ’3fŽŸåÍ›œâ{'›ÁqÝ5“üI“]œ“mŠ>óôÇ{1¦EÙæF–ýGùYòy9~õäqØsæàéÉq‹‰p>9NÛézôaÑhòôm>i뮚ÂÇÃzͨòEr±¶/Í•Mkô¶ñà¬É&mVÕÅ<­¸}h˜®^6 À‰ØŒßCeyDšOøŸîþ±A–¾c–ZU·E»ÌÎÃòE™o E+›Æ‚ÊÙ`U7{áù° Æå=cAd©Œñ4›ç›ü}—W“ m»£¥Égõ‡á-½´Ü¨ó–ãq +?f—kx»*XmÖl¦XqÃ] ùYSÏ6H\X=.=Ë®gõ¼·¶‹²Í›õì?ÊÏ’‡ˆÊñ«'ÞÛxí;xzò*o>Íi^vÕ›9¼6¦ëc6hߌeM{\Fty'}èÓx€8ÛÒÇbÚž‡Õ/¿ÐÎóâÍy;ÛbýXàêÓ·ù¤=¬»j ?ë5lûB<±¶‡»²i`ºm:Û.σÃb7 ÒÕ«Fƒ7X“Ï»rº/Ö®ªÛ¢¬Ÿ%€ó°üEQæ°|eÓXPÝ`ŒU7{>i³›@\Þ3ZM™ ò4›ç›ü}‡ÂÝ`FølÛÈCó¿Šn$-ÛËèö2º½ŒþY.£Ã…z{½Å€¶—Ñíet{½E:{ÖdÃË£º˜o¯£Ûëè(oÅuTý\G‡cÜÞFÇ—Îímt{ÝÞFÐmôÞÁSÎNþZM¯n¥Á¦ÉtrTW¿à”ííõöÃüMQ-?ÙÝ9ºXœ_ÎNë¾–Y—'‡e‡·î²ä`w‡%¯?îîtáŸ%èã9>Rá–2ä=øõ†ÿ _èïõ%ýú;¾½Ås©lò1Qɳä÷?X2Åû^ã„=Ç”I™2q«Ôx%“Y° ‘2o,ÙeÊœL`ã&µJ جLµ4PÛ$„q˜€ü@úûJ÷ÂÛ$ÑÀTl’ó(„¾oJ ýd²= 7ÒÙØ(˜ák®ê‡G¸Qôú@ÄŠh]г”XÅu˜¨¨Cù Å ª 9XÀò4&I´nÍå" Ðo"Ï¡Öý4"0¾zêúdô,Jÿ—þ¶»ó[¨Í- ‡/iƼ;ÝÝ1Ëc¡!™qzF Æš“΄ÙŒE×öªW N s¶h´Ì{Ó§°ç›ƒ’­%¥ŒÀ <ÖDÐÔ¥F Îk‹Bß FQ–Úªxj¨k2Š(ÅpÁƬ ßÇ?L~n|ÃU0:ÌÄGd²¯áÅL¤Ra#rM3„ãq€ $‰ !):N4肆1ʤU©0Mó8ËÆú3–…Ö#ãÀó£Q"•˜ LL%#Êõ©¤î¥úÅ ´Ž»Ð^¨ôÝUŠYh„»ê„4VE µ½"ôƒ” „É|4¢2YL:IÈEùÚËmG¯êÂ÷‘x‡ÿÉÜ„u>\b‹D„DDNH,E2ö|@ö8ÄoOUW÷Þc ‘þKŒ—÷ì½V¯îª¯l¶{_C®l¯°Ã/g#z¨Ï*µøl»w:Ž&xiÔ0¶ƒv{íkÈÌgšø}:œ,“µ-`NRÕ5@뺋‹°qú ¢5²/Â8[¨8OÇê¯UMƒòï#¤9Ýá]½Ë®;RÌ,ÅÅÀºSs@ç0FÇÎFVI5ä¶E~!O¤= ¼ž<µ±Yfmî ­µ“*n™T¸¾®~ʶ•' ÁYV¤Sĺ„y;P@ f”!!`‚Õ(yg×À¸uÕõ >ÅËVÕ܋Ө:7ÓŠðx¾L˜ÌaI2w˜éfžÃýu&K”•ù­¤(ˆýÆØC¢U)Íu§ œ·J¹ÞWO×¾醣Ôu'e…!a˜Ìi1TéªàW¶E)Êbå¸jô®!µE[nóFëQàHEëc9¤cï­ 1TtTw_¸˜ÕAÚCÂ],›<œ›R“…ËøÜ>‡ÊÙ™#’{”jžvÙÝ–@”»ú0(˜N£šU|o«“éälY÷>™"@Ÿ–ÓQ‚ËÏ6$Þðúªòµ¨èñ»uùÂßšl¢šÄnèïjÖ_èiizõ“t®@g÷CÂñá-´PDp¤U&âDïf ÔEO¢Y›ôÏ&á:ýë²éÿ®…¹ v®*Š‚øÑ¥¼"vTÈ'1s9‰"›cf2D˜ uVŒÀùé:ÛrÑDú `~xŒë€GÌE™1ÛðAŽ|øÿ_WÍ/ïðjº|A0-›°82:“¢Éw#T&!½‡·ÀsJ¶,åH²*mÆÔ8ƒ‹‚Ôx£>쀫€­³P,W éN;ÂY®Uø$XÈëÞ‘ëRÍâúnLmÓ†RMtŠª»Ês² È*ƒrQÛoÙžÚÖNCs]RÏ~µ˜–¢yÌ6ÄÝ'È“êS–Ú¯ L¥Qœª“a‹%ä¡  >íTîÖºo-M½a²BºýdžÅ°ÙžU00eÍÑ¿t•læÝpâ]š[ÍÖk;1pÙU4$ÓÖÍ¡y³5?>âÁÕ £àXàKŠRئ­aت±14éN …â®wmgßb]x k^Þêa¦8#Xüdz¯ÅÔ"a­¼ëå?Ç›Jm‚ߢQ /¾Ö’P…~Vwˆqå³½…à]é2Æ™¨ L_† F2_Su »’;›lju³R¢KåÁ¢Å6«om‡@”¢û²úúÊQóFÚtŸ‘$Ëdè€A >^cª{R;@¬ÆVã@¸á`^^¼ÃÙ¥7ŸÈê€ËÜà=//„¬h„:Cà°‹K´ïÑuŒ³óK䝯þuÏÎaÏôKŸX¼a.ÝÚ8bNb¡¶íÇ+—ù{Å' ¢Ó±²Í›‰µN*sW½¤¯oV"¤@tÇ5;…9š$§—ŠÜ Ÿìs;'ÛðV¯r±xú¬&*Ž)¶žý–¶”Ÿ‹ØX7Æçж•Ž%”9ÃðV3u›†`¾]ŸŠŽ½è ðpR—hÜ ô6¨I”Ý=n$Õ®™Û’>Mk=î"_¶ÞTçØ»°HÍn~S“R(é)ªnpÆÆØ„ör±è]=¢±ÊÒŒBAØ‘-°>¶(6¾–OEÁE› h_ò⊻CaŽ# šõ*¸<ëy¥p‘È6º7ÙÔ–‚tŒ{:à.ù0»*¥nB0å m$.4ð‘ÊÙÛ׋B›'¡büÝ¢s3$!“¤Ê¤Éíû4G 9Þ1—TÊ+Ö×)P"†šé%o¾¶”¼º$§D!šD_ìýðÒÒÙ6TM;¾÷1NátoÌY†%•³ó*òPŠ’ÅÞTÚët…ºâæ{;ž•ààª[u°ªâM,6¹÷ñ)û ]ƒ¡Ònz˜—é† )Mdö ¬qKüÑæË£ÙûHƒšÿëjÜþ†PõP5ÈS˜@UT}ε.¬bÚR%•R?…Uø›‹ qŽ>üÚ`^Ý=Л‹¹Yèÿž¯€’'q›­l—àÅ {Ì CxÂ,È÷hƒGä`e·¨6Š;½‘‰;*¤h/ç£å÷Êæ,·$÷Sf3ëÝux2íÛÐ’¢‰G@BïØlnK8xG} u‰)ÓMQwúp(©(¡ÊO±ß_`FwÌD›$þ½3tP̧±ó8ÖÑp„>½bI$XǶ–‰­\ÇÒ6¹ÅçZÙÓÅÒ)†DÔ\˜dmÍt¾asµ‡\CC§×¶É{p䬥©ðtÝvk`é4æj·Êq5¨Âzb‡h°ì@A¬@˜Ö³÷ •ÑU â”k¤æ<vh©]»üzޏ)r0¢”ê_gA%ðñÔJÿ<Ø9+«òd`ýàªnJËÄLžO6%g;ò¹i5zÆr¢ØŽ–««ò¼’zð#ùA¼À£_åØO#ò\£YÙ?5tÉCy:&u§;ò iÄ y|ÝM ÈÀ3º¡uûÕËŒ÷Nc<34b¦““— ß·ƒÑ2æ©™­ŸÃæšæ!¿sJN‡t ˜‹Ê„m @1bGag&#¡¥Ù}±.‰Ó@HeGüb =PTçÀ…²p£ãDhìlØï¯êãŸBŸêìõÝ=8©} À£SE®Zå/?øÍ¾Üûèòèïïýüó_È—?{q{¹÷Ég¹þùñííÍ«o¾ùöõí+{û_ß~ã_(ï?ùé¿ùêöÎ3éòñý—/Ÿ½ûЋÇ_?»ùý›oŸÞ¼~w³Çî>Äãé«O_<ýËÛç_¿| ÷±‘±tïþ³Çon^]þöò››g}.Ÿ¬ý`ˆõ“?éòé ‚Ù¹0w4[X@Ò-Çg°hÿ=zË¿ý?ýk?\ÚåO—ü3]žâ#Ê3¦¥BÑ[Õ¹UK;fû«éª[jw‹™%©;îôÌnFs¦™½*ªÉò¶ùìP<— ä“>,göÏGò|*”¦î–=Á…&ÎðÀ¾ÓòwƒØb]}ž»kòõÖGö7T8Eöˇk58Ìw_0¦™ $ª•-ãX«ý³§ -õ¾"Y`uÑš´>dfå0ïÆèÒfྈ„0ª³[€·O0ŠïÆ6´Xzð”©<®ÍrË“y‡.Îë{§5D-fF1ÉL–˜bS½Ï#ÌbvlHîøGÁ¶$éÞ½dW5ûÒ¢ ƃ_h°?Z AÙ³&:ô»2è²,[•AR,bÚz/j&ö@ ²mZ‚Ôâo-%š±ã÷“*‘µ;,ެf[¶Ìª'‹ƒ4P¤ç¸ÌŽÛVô"‰ùU /f­žÑ²Ó5ñYÁ‚l­‘òP—f…ç òlîž jk»‹¡ZYo{Ä2§Îü•9ÑÓ3wwŒÍJ¢P•Àw€ÂpíuDtN¡{׃Ïb¤TdÛEáoŒâ)a:Ì%œL“†E8±í+Ñæš‡ ¨Ä=DO³5Š>“ÉúÜ¢© 8…ùOeÉhÑ”bZ’‹jMøZ¿x©0öúªã,¤·ë0RäÜ w0òF÷ÉÞ){ä>ãõ ²Ã,†$8¼zÞ£TîÞï´4ãw¦æ~õFÞòÐþ‡Ëm&ëkp62tÂdó9ÐËSNM• üÜÿrVs÷Úá¸xVêGÒË%GÂWé Ø)Qum s‰f×ÀÜ5A2¨Ìn»ƒa£¥bêA? ΙÚ|Û®ƒÚ¿c6öõð‹HæéKoª“Q#e`{ûF€«Ûì¬vÜB\€ÿa„p jÞ_öˆbÀ$€¾!|¢hÁûa_çÀûœšbå‡ÿåéš1‰'bÀÑ­çoÀ2*‡|;Ì8ÚiÂÛ98†Êé7RÒk–å ÂUθړSgó,ËÄë[žËðÂÒpœv³¶Ù)†Óf­Ä$˜ähvc“סµãßú£à;®TUº•èuuo}hJçop(–†­pZÜç¡— ;UD^¯Õyo£–#ß‰ëØ‘X!8z-3FÝïËÂ’m—+±òc¸KÐÀÇÛRú*Ða½ÒüËcMð]À-ý7þ1Óÿ@¿«¨ÏëéÓjú¸–>¯¤ÏëèÓ*ú¼†>¯ Ïëçóêù¼vþõë ñÏ͆(†wl«¾èŸù³tæ¡îÝ÷»tY0ÎöÒÿ'µ×ª5:Œÿye¿¾ðŽÔOc¤Ùe?ºXã—ûn‡mwÙ© %ýõs_¯Dv'^vŒ w'’¥í‘ýÛdÔ¡ÇNŠŸy#€ ±x×6Æ !âGð&7â|÷Û=Üí!)&±Í‹«·çŪ޵¶)/ä×õ÷Ê9"9“øà¸ëÎ]W!èÇ÷ýÌ@1!IÇJÎñi£+3W»Ô`ÓuIfî¶V7]§¬ÔO;w“Ã_í0ÓY‚° Z=wn…Ã`d=¼ðƒŒ¯È€úžÖO·åï’a§œ!NO“†ˆq‘ïS³¼°ÍÍÄ fÿ*¸ƒì_§º¸µðÈG Ö¿fWÎ+g%K¢†×Z• ˜ÓBt0]<œY«ÃAï6+špíPå~‡ôcvÉ]"`üœ®B=˜]b1.jgOA×Zièñ²1tnîÎ*#„U¥ˆ°›zΔ¾rFXþÌ~ÁâçÐ4®ä|$â¢f0‰šû†ÏY `¯gë–ó'Ä©UÇa€Œ€;¥è#Ï€‘¦®AûfÇœ­î¬¹ß¦c¬Ü¶GE@¢Ê`œò”í ÊV~Ñ €{óNÚ(ž•“DCí02üª"£Õ±ó#²äTêa[MKfÝ™é¨qÃ@kòs¶²ˆpëvê‰î¥µ¢”xä›gУ¬sqAy)?gÒë‘1ÅUØqOáÝëîa´÷€^](ÅÕ7#²0‚'‡U¢Ý\1–›˜ETETëÕéè Öfõ¼4)5¹¡åÊåŒYm++ûëŸ3u@Û1:vÍ„¤@w®l7p92˜“ÝS…°ÊÃ’Ý?'xîñÕàÇlþ'ÝÄÇR’$vÍAÜ’™ƒ­ÀÎðSFç¤ÞIL-‰"Ê%pi怚\Ó%aÎu= Ȇç$î´™_sŠÁ^P`+Šç„A –›ùW¡×Rª~ -»§(cWX`ÜIâ[ýô'B“EF>Ö ïÆê¥Á*¹38éó=3½'¹ ›ÆÌ@x ØKqjÑ;q€Ÿkk0ÿqkÙõ'Ñ›òE×Û¨¼Mô”±ús›(ºÉ†KY¼zU%3l"_TLÈ{ÌWNÈ<¥¯›ï¨\»ÓMfë³'¿"ú.F‡bíf+¦°¡Ž£Dúˆ¶áãÐÈJ‰$9ËȺ%}ؤ¾Ní Þ¡›@]ž„ƒþd)–…vg\Ù÷¦šáŽIù­F˜¢½ZŸnîÁ'¼§I9aÑR~Ĥ7uâh·u¢-ÌZ±o“3$n ·ô–hàM —;§aØŒâ‰+½>5=‘:`,Æ 'cÕV3CXMçòqw\Î3A“²fEÓœh3uz¶CjµÎY¾1Fp=ùèäÌð]ºH£®-±ÇÀh=ñÆ 4«Åïg)Ù\dd°Û¨©ÊýœüøsYueBßTŒt$h8ZMeONá‘ÎÈ{€Û6†;Øî©‹L勆åèÎâDg]œó`‹GP6ª3vEˆÎͰ«D¼ûÜn=Ðß8Z>¨OPzØæ‚Ó(®CŒö‰ó«¦ª©»äMpBªcë) zlMœç”èsÙ0ÆØ©7š‰a&D¯€ùQY\)òàŸÏyµ_Œ5ÆEE†8äXu ó/bÎ͵g½FIy­7Þ¤£ºñ¶í¸óçý9ì‘~FërmÏSoÙëvDgð7;úºÞ#‹)…ŒZOê¨ÔX$ƒð†‡—É }[9,ž+c½¿z?UÈ—y­A}]CÁ Vapð ʲX·WGÅ%ïºÉdÅymæ ãÈbI«¨zZðp¸ýɼ×Lv—¶²?™#KÜšO | ÷,¬ácåx]u8¹Ä çauÃyýiGrªí™ÙcS]†U;ÜÕ} ÝWó‹ús§ >^¾™"<ž½sY¯‚ƒ1Â^É2£ÜµÓc=ìNX4Ï9å·°ßk€(JSîypruñ:ÕÔèâRnÌÜá”+úéè·°ñ@Á¸´,YHgoú²j«F4±@vYm6Th«Hoœ/lÒQۯ±µÏt>|mû|¯h˜õ¤Ãˆú¹¨ù¼ÀeûrކmDöor м¦Õ²p9mÞôƒ>.Z°eà&÷Édœ®íz !c<º„ç_©£ª«!¶ÄÕÞ² d’D±GG^˜h+‚9ŸÔmÜ&AÔ“À Ñ@)¾<Ñ|ï3# ºUÓBÛ'­Å¦Ø”\ÙåeŠ8ÒL=úéwé}FZúú2wŒrJœ9BÄõT䇠÷-7B²¿‹'Rbc'3Gç ðòk0ºE NÞ¿,Åh€)‚x(”Àä¯ÔµßÅ¿c‹)>] ß8ABÃ8R”>ˆ~@Œ4`d—ä³i‚,#8FÏP¯ùy­¼ÔÂz\÷yõÑõ³d]š›.])œ¹‰õ³—eK A•Vñ‰lõ»ÌYCÔÞ„Ò˜¬ÈÆ^1Âɼ ‹H²u¶¸:HYHÂþâÔÁ†Hû×z‘ò2x¡qÐAã­µû|—{üÙÏz”»VÏçë-ÛŸ¯\R¢Oª7¨—ϺGRG1xÂÿL@ö½Ÿª°%FpÞUÛ”‹uç£BÔ´á\Yi‡DÒÌîæÓ`Œ1QÅÝž½!gêaöߥ¯¾q6çÚeaÜáZîi$ööÊÈ;Ûwè)¼N<¾KøðÅ™…=ßÈç'J:NÇ=·eB·MÅuoWߥ³áA–c%>×vtGGÛDLñ×IÔA6 + ï°1µ¸ŽÛ¨Å-ïør_é} ÅöD@ëoyàNåçzá!¶€³ÊÂõìþL!®¯Å›ˆöñ]úZˆ"­üê‰;Æw7˜Ó’ezFF¼¶Æ þKï¶ÈK}\o‚>lžÉ-XÖ™Ìf«ûÀ-la毖*>sÅ@1*ùOÖ;Êgÿñªé­ëÆ¡{þw :ˆ>(JjWŽã.Zw$ j (ŒÔÎ4îÄváÚ0òïçP"%½:Ä‹ë÷Îå£(‰<<$U=Õ¡{\ ¼sTÃ%ºà1k Ö®¨ëñ5¬O¹5q#Æ¥³ÍÕ,vŽ“‰“ »bm:©MËÆÖ¶Ï:îk¾Ýß«ÛÓƒíô—¯ûüôðâæ÷÷ÛáíÝËëWïî>lÏoïÿþ°ý|sóñ`ó›ÛІO_íï=qä"(Ó£!8°ð÷n÷Ï÷78=ÃÇÉùR™3‡Ÿ‡à3:ŠÏø˜@gϰê‹Ëó»Ë›ëw·Ÿ¶oÛž½¹»½¼þcëµpÞ_œIlÛ7bòI‰v,“’ ø(¶Ò“2Nèšç£ôBPœ©’zÈ}"@,™Œ*:„`,‚oqk#M¿Ó #·QÉ‹ éUá1 r* R{¨ cR<ë܉ Uöǧ ]^ʶ´~‡OQô€záÕ¸RŸíÄØõ³ÅÂZ„^¦R°fÔˆ·v‰µ( ð$)è»Ç•µØ(evn2A§8¨ÆÜ´u «ØµÃn¨Sní`J1O©ù,;iµz/‰Ün{ÝþýŸ„ý±àõÃþ“³µ,wùåø±î•˜È4ðaç'=ü£½ÁÆ((ÕeFËkoÞÈã­<ê, Ã¿ÚS§-XסÕÚ'ùö>ý ìa£í§í×ßÜv±w¯mB|Þ—‚ûRhÿnëÞëê_UÒðãÉfÞ–SWqÜ¢u"Á3µ§B ¾ëçÄH]BÍM¼â¾-K4ÚqÉñéªVW“ì‡Pj©¹8G3)·Ï®x´SXH¿›±Ô¢±x$žº¬õj+DÁئ˜u¶1QpŸêt¬† .àv"˜±EÙ®º &£WÁKò†ëþíOWÈ&}µ4RÁ³E\òÓ£õlµÂYtNµ‹àÎh©W­ÝΑyÀÔPÍxˆ"à]¶íê!b¶,ɲ(õI`#…TÏ¡“wÇýP©,SdÐ[\'ž]5?‘Êb?ò§iÒªÆkNâƒeƒËCã§ÃçV„(µ½§>ÙÄ´†Ñ/¿p6’å#{JΖ=2_Œœg.V†¢ý;˜¤»>%×(Ù9§ºæe–Ù¼Yä¨>B¬–š”\¶ºI–Ädkq™^‰#=Ä…¨õ€ùÕB#Lb¶¹Q¸˜&ìx8MÇÉ)„èÒtœª·xuTm§cLJµÓÁÔg Zòâ=Õ=øHÁ2ˆ²QÇà*Ñô–°Ð{3«pdÁjÒ[™™`ÍcxmŸ $гöÖ^2¤Š:‰1èÁ“òR±T–šN¬¦±ÄÅoβ¨ïޤ~ô|¨XÁ,²6Шg’=ë‚¥êö­*Ò½’TU =ÈJ8guL™ ¡b¡%h>«º uRCTÇ{ë]1)HulZba3žŽå"õšªËAd´=£ÆYA™BÔRøzxE’õrm2oR²Mk1‹–ìt ¢Ïçe×¥®óÎØu1GÖBH’¦ÿŽäàs× ð¸ÎAW„Ö jL)©Ì|Õî™Xæ”ÃL–X9¹>H¦h_… ±¬}¥d=‡âcZÒ¸8Ü`1Z… ê¶p—´B従Zm™2*)h^Vïpà"{UVª‰…9JLkgŽI?Z·µWÒ.µÖ.ATÔ¬!¬W„öîIcÀ4³æ ]q4€±¨çDÅ@—œzŽqá'"¹ÃÐãæØaܵqËÃe•“Œ;Û†¥†Ð&—éÙuQ€(âŽçÕ¾J .æD `2Ë–2GÃÐÔîq~É­±ÄàãôPJ²Ã0"ÈœmwÞ<@MÚùPÊ‹‡ƒáÞbÀ8—ôÐ’&+Àâ4_MÖQjk¡Š9òfKÑÀh">Ê´7CðvÀìbš\œ…– š|øIµŽý…`'”ÊÉ Ñ<–kô ®gŠî#“6¹¤–èca¹ºÌ8O‚]qæ‘mÞN3û™Æä uéÃpâ;ö]4¼ðh掫î/eg2eZfš!Cg8+=^ç(<ó‘ØÊ—ªÓ£g?XbÖ›Ò›ŽGáˆàP¦(£Âh€ìGb ™ì-â&´GhÙ[1•l{LdQˆÖ6õl¹\ºÉa“\‚©L+»,*ßt–qñPЮª˜º¦Ø¥®I ’ Å£!vc§’au‚Ÿ‡m”È?rÀÝç,’zˆ‹gg«Q¬iUø–Ëä†ç\FýgëÅ[šD†ÓònZÔd”@ÅäÙê.DO먖FWóUÁúJV%šmrˆ[µØ(^'ò_ÛkôJ,ó6èYl<[<(É(+ÑHBàH3í°¡ú×>¤wâÅdZ…¡ª€êŠUЬÕ@7õ*uÛqZ#i’¿{.ÎôF;0Ýc0ϰQ Qý¢bš¦QÇ%LÇMuÇ5¥Ϧ³jLÃwõj òµýÅ<À’—­d6‰4<$Ì©^OéPlU×ÕèÊ¡é0s™±w‹’mVÝ>ÄÜŽMš¸·e2c2ç4åpI¬ž‰çP<›M”ëôŒÑKq z-É:¿a9N†¹`ޝ’Z3R¤a)SR›†‚è,)«“X‹)Q›§o¡Å§ãÒнʟ2ÉéPœʘ#vBãJ:µ™FhM+vûldäth­Ë6mC8z‘êäÍvdåF,:Ƶ\+%uSb¶9€’9t}$©15†RôÓsðÞìmZCŠr±‘Ñ„9Àh“(3ùéÙçmEϳ|ê¯íÎc±ù’¼qRž±-É€â2 ψ†ã…:áb3_ÊÞ–Câ♋ͮz «1ÔCÇCÆ1‡qš¼cÇL2>.c‡Ôtæ$/foöÅBöyƒŒ ‹…É-ž½ EÄ€¸CÄÅìËrüÈ><œf³É‰žsüÇ\vU—ððµ] Ü:sò‘õt$³„×Þ•+ŽìjÊÃ9yòûîêíþ^Ýžl§¿|Ý秇7¿¿ßoï^^¿zw÷a{~{ÿ÷‡íç›››ß܆{:}µ¿÷€#tÞá"û{·ûçûT.ˆ3etv®˜*@pøyxp¾Gñùó±èìV}qy~wysýîöÓö­`Û³7w·—×l=°³Îû‹3‰í`ûFL¾“Çîv=½ØßcÃîŦ=Üöºý¿ !¨ rÂ!1@ùøæ°?v¼~Ør¦â):­– zïJL”ºcŸs…ôoí VPV€ Ãm{óFoå1âuÛá_í)Ó‡¬kgݶñI¾ý€O{Øhûiûõ7·]ìÿýªéÕò6¢ûHü‡gƒ¤ŠØž±=nWä†.Ú´D´Q‘ª ¥64*EüûŽÏÏËåRÚnËâåÞóÎ=çãŒ~÷itݽ›œ»Éµßžç¾±ÓèÇG"ô£ó”•sçL᣽¬JÕ._òØ9ŠõMíµü’'–A—ÑÖW…{GH>µÎ¦âÞ@UãmUZÓ ¹÷ѾÖF”|s½<ñ*8#i­fúUÓãÝÉK1è¡9U_'ÆÅ”Áá^ž½v¯“…,:†Ü“Ñà^öž W¡õè¢"ûùÆ3hÆÞ®ÙÇ.5pJ–ͤû‹å„þ©ùÇ–Md‹ÚÜA¤S[Xdí u ^ß ÈB®8…I_æÐôån"€®uÅâp΢½zÕb^Œ=I.Õ¢‚òSœÖ®K“ì-Rþ5©«%I¾ŸÊðÊ û©{÷Ô$0«@>¤‚ÛfƒÅ–¤¬¯UéTÛf.¥[bc„,\Ñp¢r`v$ϲîEÉGLI.HjU÷»’ÄqVØ`0çf§• ¨¢ ÐT‰Î;*BA³)í& K'ñ2×ñPÐFŠŒ˜e˜wígmam‡ø@x°ÞµŒÃj —§Ž\¶ûùKa7¶ŠUw ®¸”x÷ŒEàqÚ9¤«Uhm ÔýÎÁ˜ác Îư]±hÚøE¦ örGVMizus0¼#±ºWpäk¶}@A[kÌÒ™9'$=ÙÌ™óQ½7è$²ãÒH+ž¤îg‹|®Ãµ?©fíÞý9›±®gxÒÙLò™âž…׃zÍä5–:‘©+ìÉÖ„çËäÌ$LÁá-_/u†È™«to“Ì’‘ʹ`¹UíÔƒá^xd͈مÄG^ÄGŽŸÏl©Ñ)c_­N.\±«p«†V¬Bèì2ç²í*<¼újÁN’¼;ñÛGÂÔÍ9ùª’P$Uå 5oÉТdo^f³;™.ω0̹¢Ïa.¨rá+Þ-zucíäÈcÒ:{{½m`ÈD&¯rór Su$»Z¹;?À@aÀIv\*Fp§Â ñr‚šèsáDyô¿ÅÐJÝÌŸKÌ®1F;¤·%tÏ) ° é©Dæ7jytˆMIðY; -d€ÖOœãÏ™U¸t>>FÛ|— YGÆì¡×¨`·›Á6»‚næÜþsNf›ºÛjϰ¤ ”;rõT»µU$öÈäÆ%!%˜ØiÁUmWÛ¹FQóèЬ¸q AO%_¿0lÅÁ–/vÙtœ‡ÂŸûç]ÝÄdãçì¦r‘ÂYpž4çm cÚÌÖ§ä‹â°¢™Ì-0KEúh·÷îÅï,¸³ê9ø\)ïÂMT¢FMÅ‹“@)8•¤‚ Áç¬oZBj æ´û*†(c*õ°À,±©Œã8ËöíÜ ,þ 4 '¦$¸\Ä¥2jf*3žm½ƒ–UtÖ¡3ÐH9”¢»Ö ’ðlLO×›©ÆÆ C¯až÷á9LiCïÈØ\3T_£¢§êv†‘HPéÁe¡ žÄÆG!ôÌœ0Îu×°$RâÒ$ºÆ³Ÿ¦nl¨³;ƒÑÓ™Ñ.¨d4œ2\Uèxµi5ü86°Ìu3At7Û»X;¦8†«òÄæZ«/¹°ð9èÝ1iPø!3y®‚F­¬|`Ô0z¡rwì©UËà€šç0ë ¢Áö±©„Ø´&Rý9Ôtq°ÀƒÙ›œ7çæNHÛ¼[«ò‘€3ðZ¹oœ †Ò°—ÊàÉȈE…ЍžáÄÁ.7yÙ¹®b¾ÌÁå’N5džƒ¹¸P˹øbéQ×¾k–’Mêµ¼w'•ˆ=›±Ng â²'Ãk/7\—š·ÈŠ_]"Î@+‹ù…[CíάrÌhvu­S&Üeu£zfÿÎ%Yêi ܄ܷË( ) –s:xYl¼‡öÇ+0K%“×›Ê,óâTV¯¶/(sŽ«Kç0ü¢è41¼ ³`/´É.=enCxŠÏ‚^8ãÒ­‡¾:…¿y·+\ñÌöÚÚÆ+áÞ$hã­Uì—Esc<µô’7sm ŠßÛ’q½­À©¬C…$ Á."sRí¹X»‘Ìh˜Íýºל‹ìëPŠS-#Ã¥àqÙ™ 5ª·x팂”™yFmË væ´ç¢® ˜N'HÚ‘ý©²-˜Sê4¼GKQÍÉn)š¢4¢”=H.½!z”ì‰áàÚuÿ²¾Éhˆ^þùƳãì‰sÍ~S•õ¶K®Í©ú| Ç Aùõ ö‹êÛ[Ÿãó;Ç£?|ÚÏŸß{úòÏß÷^½~ðâ›ï^ÿp|ùêÍO?¿ùòïwŽ|¤CSëÑ7·>»8iUê¼×ZÕ¿L—ÿòúF¦ôÚîwîÔ¹ÖtCMúçå«¢…zE_^µûí~šÐã/ôÔ¯ž=yýìå‹ï^½;~>±ã‹ß½~õìÅ_åØãÓïŸ>ž¾Ý9~6M~1?.¯“ÔÑGOo}Ö€½™Øý˜]¥ISL[gš Dæo‰ÆñãÈ*šð« †&¨&Ésà*…ÏJ’5娮/f§øç2îš–ëÁÕbj4m‚¨q“b äb`aí}OÀ ÂÃðl©ª°0ˆu¯9Þ-Síf:Ž.¶Í((´äžœîŽa¯SXÛ®Ý"ÛÖ;îÚd»†'g>Ý~üf~¤ãáùßGÂùëePd¦åÛ[·ß\|ó‰á]æÿ[€ÁñI!^ÆŸd§þïÃ|ûñOóãÛùáYŽ{ÿ8?çÇ£·–Ò³"Ïd7û•þô7ÅÞ|üæøãŸÒñô–~÷ðÿ‰ýo"þâ ç›ÿ°OäV,CÍv8³ŠnszTˆÍ‰÷åËô»ø’ÆGÀüJ’½Áà‹F³F$òsÏñ¸ñœD<Ž>IˆVëxó÷Î»Š®´çIÿr»¢¯ ž<â­.ì÷­t¢ØS–Ê›Šhm5ŠïÅcâ½[:¤´µ‚*k‹=#£Ï•ÌÚäÄ'6ª›Y•á0œ%8nˆ²gÇɧøÉ³$êûžwv£3¥­Âõ@PÀ<7 ÷üT<+ é¡3šÃ£o<{†ôÒXGzEz [æ¤ÁÈœH§ÆÈìÍ+Ï BUÏÞÄ£C³3às5û@^'¾ž/²^Ñðymóq 6/!ã9eèðA)âJöS0|tÀî=tÔ’÷S耧 ‚qË †Ü «<ÜåZ7Áõ’°ìÔµö®¨ý׫tÄz((9iŽäNè³-ðL°ê¦O´ë‘ ï"Þ¡“˜±v2p÷gu²n†Fb>ôÚý.Š'ôÅÞR7’Êj`®½‚AÕæf®âÆeGCñÄ85¸ÇlÆ7è]¬rx?õ ã®óަö ã¥,g$6A™ÂÓêýÑŠ4@¢<»NaÌׂU‹Ø;/fYĈr¡Ê!åšOèÙ,ië0‡ÏÙa`+F[fܯv9à8n C{ ®ÌÒ0[¸œÕþÅ~ÕôÚaÑ}¤ü‡»©ÔHðê±Ç_°JÓtV-‘ŠJÓÒIPHUõßsæËöM^ vôI¹ïeì;¶gæœ9sॺtnFΑ~ð]ƒ§¥€ˆ·Q)9¶"Íè4«Ågø¨ÈÄú~ÉQ)£òA=h3ì=8S§ Ï‹èhCZìi‘´=óbÑäPÏó„£{àÙ‚,Æá¸—Õ¨ÇÁrÑâÞ²·¥2ÆIóÈÄâ¢udÏ« Q\.·Õ†…ÉvöÒW>ŽÎ—òy’çy?r›û¶½×hÙè½ÛÎ-GË>¥ÅûK=ü0-;¥x(s‹Ë¤º*¯z >ê«·vË[j~Ëc™ ùû ÑÈWezm ÜÏ7Dq,y ãì^Pcm= ²ªÆå¹–T‚$©7æ°ÖC!ÙA|<.oÞÅÇÕº51 ê ßÜòbÎVW(Š¿¢•Ö ‡=÷3͸¿s—£isŠÐq©Ëy‰à/2“‚‹žX®1O´Æ: Žú ¦äãÄ<ÃN3ó¢´èäÔGÔÎn‡‡ EµhU…Û$ˆgw@WAJ+üÔû‘Õ=QY·Hy9½.chÂÇ!K´¨õDÄÖQBx ²O­ó)"ó²_ÉYZçI|{0µ£#BÅCò᥵t6ÖVBdPž3:]Šb¤—`Q‹„n|¦äšÆ.;ØÛJ¶Èêmï+Ì ‡)D‰úñVÞ¢ed(TMŠâ˜‡ ‡=6çSU¦¹ìõ Òìùíòm`˜é1Écó¢ØÃ˹Yf<ÃFp ŒÔ©„tƒÎ¤ØYûÖR€B8î©nÏèÏÅÖW¿Ëôà«…æ÷Ò2FýU)©­Þj4¬z4Ø)”h“9ÂŒ¼®Ý÷[¸h•^]˜BËV:ua Õˆ!Ý*p—Ä—à—>kÆŽñ-ÔÁØö‚cRÙŽûX=Y&›ÏQz³×ÈÕ ´†®Üù½HlæÝ”a÷Î.OçNfïqem_î¡wÖ›ú[¹­îÎqQìëéçDS¤´õ€I=3[ åJk>˜½×05†\*`2-aŒö´@æº9ßÒÛÅœÃý¡/DŠÏ P‡bÿn‘šKw,A³^žoû‡ýÑ;öoW[1¸zþUÏõ~sõÕÝ;óòá½Ëã?þwxÿéË¿|{¹ÿêõg/>ÿúõ÷—_ýð¯ï/xùò÷.tItŒÇŸß½óAâ% ÕƒŸ‘ʧéú‡l%%ÆØÕvTLç6`”¾ž?É©ñƒòñƒö°=LbzòNýäÙ7¯Ÿ½|ñõ«Ÿ.¿Ûå£/_¿zö⯻ؽηOŸÈÝî]~![~-×ÏI¸èã§wï´ÿ‘í½¾?xòÃ-éò™þîÑÓ“”8‡փÒÁÿ þï²¹ã‚6aP mjÙØ #ÛQ8ƒ›öuü©óÛ(,`¶VS24šæ¿¦ôœzùÆ}d= ŸŠsŠ›&DKåÉôFF‹ÄAs•CÔVø z£2ª´è%HÆIí•n*æ÷:X cÁ¸´¹%ù ×Fî£øvÜÙôl¹h}3øi´kÖª¸›V–Ç%¨íá±Ðe1æ’,l²"‘áqt_i6Ìe¹e3j_3#Qw#¦È ØMÿpŨÙ⃕¶`ÌÖ½`Sí…‚²x; äLÇ3Î\·óçAlFªSY9wÓˆjÌ2ÕéÆXŒÀ15ß>¤ÔP+Hi5 —'Baz ¥Ù<óŽ¢{$+ßYÑ©Ñ,å¾ µZLºH¬ÐÆV¡Nè6­'¬Ôì„lÖKNp+Üjó`uºË´ÂC²¸ÝÆF&ùõú…šIî)*ZßT¬K/¨¤+ˆ¾'‡…dÕ¢²¯×æc¶>$N¬©¬&S£j5¦1ôr¹ ™PÛöA‚KÕ¹¢Ä­T.¨íƒÈqÖœ¡˜¶CÇ .T'GŸî™´L`X-ï„æäÆbÊWËD“²|ðÍhV@Þ‹VUÂû ‰0R·%„4fq¼ç¼GÔ»L¶#ÑlÈŽlï¼…›¦EŒ'ÊWúª¡É5Œ.2űçŠpÏi§e9Žzyè䚌„ÆÒž(yŽ£&òš>Øo)‹,JGrs6ňЭšŠhA+ô1Mrx¡+l>}“â¿0´ŒÎJñ£ n|¢6úíFN›6î …³9 ¾BÕ¯«OãŽáµ.’åÒÙCG˜xXCµ·H_Õo²…=^EÞbÈ Š`“t 9ݶ²A1½ÉòEu*ÎÍféHCGX”ÿù¾¢ësV„âl“·–Í•"ßœ%›Þy“#Ø¿[DÕjÍGGÍPNL^mR‡¶A³œ+(öžéN(<ï\*%fÈQ…Œ,ãÄ `–•1ðÚ‘7ëD¸«QÙØp3;:ˆè¸ÅDš§7üë¾=Ù RÊH¢·b„¸НàQ ¬äŽK›Î-\g€IÐqD4·ØŽšFE¢œm’@.ЗcêÆ\™U×,åÀɆQ­%N=;×Bjô£Ì7_ÊÇWò1·hJ—ûÿôßöëñ²DjªÒúÉþÿüý7X¼ðåw—?ý9]žÞÕ/}ñ3Â~FØÿ=Â~ÿ¾ äÝíi ;d8õ8_}¾W ^§¯Hï~´W*¬D»Ô«•7¼miéHMÑ\Eö??š8ëÚc™É=¶Bã\¡šüe¤éí»×ŽÂt}èƒ7®¤X0ùZ0žw"£ñ/wpÌÙŒ`=s1Y‚WS^X:+„s¬€‡ÆÛÛWÅ8rŒ ЛžN2­dŸ—f7å è½G`jT£áî¬5íGb¥ÔÅ’ÈwsÎ~k¦F¬†;ÑvÁ7”ÿ ˆ'f'ÝŽ ëTè‡ÝZ„fZG"CÈQÝ* ³ûPÒ3#÷QlÊ•}º.iY!l·Á­H$ý/mF£äÆî¶ j‰ ”eÖ[.ê‘Ä"S¡[Ô+™ºD×2t>0TE8rÞ[Šè%áo3êôª;G¼} |‰Ý^;7U‰ÝÎá7”NÜ8»Í50Vàʽƒã¶w4R×ðŽÙÑ··sM§Ñ«™cØ~Y> `zó#k7€!uFÂVøRè!MúQ{XQàÛö"HzÏ~d¥IÇ<Žùx‹tÆuN&‰„'J$]û›{îCÅÑò!åR£øˆªC‘jU¿~sëG‡]\ÞRS‹Žjd·3$Z:]‚I ‰Ýpÿàýk+ŠÞò¡ bBuí) g- |èªOÔä‰QëtH› yò°*WÓ8‡ÚÒ°`äÞØ5½:ò< þ ï$ʬ×hÉ”Œ€’Ê3izƒ]E2i†;¸ B vy•š(ºUÑÜ æÜ8§’PÒ…þÃV ¯«­@N?" ˜‘x„cHÇi:³—YN‰ºkôYÿÍv•%Árƒ°å•ÁËÞýÏÂíIåWîa¼€–V¦ö…ç+p§9B|jk_?5—‹05>T{Æ{5§–N°^ƒ¿ŸæVõ­áîµjtùt pqÜ ¦ú£ød¼1½,zlò@$“O³Fa Vî¼ûþ«™Ü3=‚Ší#¿Ðº†ÍLpJ’›àákƒ }æÝWvžIî@ì².Ø´jðn¡EºÆ{·ËMˆ Z| ¡ÿØð¦|ãn^bëüé“>O­¬g0?¸BwNÙÇGçH¸YGƒ`;mO#ŽàqK¢ƒ¶fhŽG4ÍYÕ48™®úzˆ+j“+ë|ûˈÅV0ý:Ò3Á M5Á"Ýá5_Ž—ü]˜³K¼Æ±^-‡5f—QÒ)›ûðìùJ\ø1ì4ÄèŸH¡êæ)ŽxÅ£jAðâîþICS·`h؛ђ0 D2 ô› íäpÅõwy8mz{ ÚÄÓø|6l­s²K QX’ãv}¤y(R6k%YÃ/%S(Úi¤|Ú­ 6ÍòÍݾ’Žëdfùû­tØaÚÙ–FÊàüFÚ%'Üœ$¿©%dssðV‡'ÔÊ{®× ÚbY٘ᘪN²0±ãÛix´£¹s/ñHŽ:ãí‘+½Oá#&è ’à äÌœó!¯!”º£»j„`áU ÞJy`âÞÐH&UË'ö'‡Bà:4ëh•¯Rv-lÚ1 `‡R´s ô|øÔPÕ+¤ãaÐ:-]‡1wü²÷×Zzæ¬]#pT Œ‰ Pû-±ê2æJ@Py¡zÖO´ý×oŒ·ê¡ÀxÛv>xŸóèxÏ:%÷‘æÛóÔÛŽºéÓCQüü\õ鋆>[o;I¯8Ö•Æ­Ð' mÅ#~©{·Ö§F=ôT_K¹².õà>kl˜?|:T82ëQý˜ÉtÕNG9“>½¯ÜY:bpi[ÝX<êf®T“ÊÔVª›¹ Šôt‡q~ɱS¶úC‹¥ý:spQƒÄÕOɦ™½”6ºZ êþ4Ü á’ÿ+6mÀƒi„2P—o A¥ dú#-~Ådµ0Ë^x§5ïDá¿a×ablM¸wiUÐÜ W‰ŽG"°P&˜®3ÈÚêÚg †|&EP1o $ ኌûùÿ±Í_ÅÃÿœðVXzI°¥©„]IÂFÇõ|DI£ü¯Ž1§ endstream endobj 16 0 obj <>stream H‰¬W[XG ~GÊ8/• NçâñŒÛ§t ½¨ UQÛhvQHõßóylŸ3'Y„@äa³kÏùÆãËgûæÁ¯>xö›‘¨ì$µo£–²Á}{rjr¢æš–ø¢)"¦é²¹ˆ‡‹X¤¸°r®~®KÝn¡ö}$ɪÉ{)ëñŠkа «^a{ƒ £´1 hJËn_æšûJÇçÍ5ÄYV Uʦ©#SÃ{É0ûüF…mÏ™æª=Y…´§”š ©årZTwC‡&Çs5àº×Ôúæ'{aiŒÒˆL3ˆì8|š‹Ûѹ³ ;o£½À}'4484­øñ2,Ж޶ã¤cdN‹iÇ™iGƒÏìx; ö½¤4s‡?Æ4Nö$åŒPæQÐÔ´ÆTH{Ò§#Þ VaELàJ»š:ߢš$gf<(±Æ¡òÎ-“%cYTak7³Sߥu=IiÎEN3¹(ã·b§”nÂÆÕ„ V} ©{>1 )¥¹FÑÃÀç–<¿Aö´Qˆ%Ï+‘\Å2vpMSˆ0¤ÚV ‘ãlšBt&94}ÌБ&¤L?¦±÷&Õ…¹t¶ÂdvôÚ–÷”|Ópëåt.–YÌ ¢IîÇÛÌ8Ø~ ËŽÂŸïG¸ {  |ÖºkŸÅM¯YLC­M'àÊ4:™Éä²ZeÊeÔäÌ ä§Ôæx&Ž'ó8„ÍŠGO¦š]˜VŒ¼÷dΕ_‰X‘=’ £7ÍBš5¿Š²ÃšŸ½»O౓k é½zPQÈ‘ýTÍ[(ü–g%gxS&"…X1t`&ó ´Õ½áó.¦Aƪ¡FlÊKÁ€â„=Û[x>Ùk£' 4ê<çÑM8+dô—àÙ ±Ê“TëörѯMM:‹A5µ{µJžÙª2³tÊjÞî¿ÜH§ c¨¸Ñ›T~Þ=5ä¤PJžW¡äîBKÁ÷ÁÏ»ÿ¨?dûðáöôOÿËß>z~÷ýÛ£W¯¿¼ýê»×?mŸ¾zóÏŸ¶?ÜÝýüpË[ÚêØž~¥'?H”*8£Í$ðúoÓõ_6 ¼ ùqGjubaîTÒ(Ÿé¦~zÃùqšÂpóg/~xýâîö»W¿l«lûè›×¯^Üþu3ãžM“~|þLí{¸ýZ|¢?î{Z‚ÉOŸëo|jÔ‡lý>DF×?ÔPÙH|—ŒX[±F2“²³˜$9†sêäåƒQÌÉÝfÑó1§ h¨-C}tk(Øî „ÖÔ¡Á”Q«Ç,Ó¬Ùï¯Zµ#:±t9ÐüJ“ò1¨Œn}-®2ÎY(&‚ê}¾w ê®UÓ€‹Í³tÛLTŒ‰‚•zÍm#ƒÝCù8Í–^ñÜdE•táèTbý5Õ½;ÍÏ©ç@Ðæ5œ›ÄX=§qšÇÍ,çÅ A˜ç4ˆãÕ'Ó(NÏ…œZá˜ÒBÈè‡70úÙ¤¨e‚ZÅ;Ø@‚@[háÔW>¼ÇE 1aÒNjQiœ=cfË>"›Ñ6†3RgëpàÀ9xÎ\¢Ô‹ÓÆ”¾¤ù¤Š/ôGF=ÝÞÝnYrFÚ¾œÿ! •èt¶SnE߯_ Ìþ÷sºÆÄ3g24î†È¿<55[Þ%$µ¼kJ§*ÔÉÊY_Ž21àsaœŒêôjѾè\ˆ/K•™4Z½”çLˆAéLüÍÚW ÁÔÀÝc¥Ðd¼££í×@ eCY:û×0 9FOÝ_Ò)¯äI#ÐÝ ÑeN(ù2‹VnÅ„QÈâ6\HeyÉ‘ÔÐ|xóó‘ ¿hG“OðÛLò%í†T?.”(ŽCèåÞÙp’‰\x!”3K•PΡI.̹ù61_0…ÚµŽ¸jjßJ¸d륬h5^;6*4>žó-„­Õs`{?óžíïÍñ#m_ÿ§Tþ½€ú탠ínÛDÕ`àöÈiƬ‡±Ãj1é ýshð@*e©Å©ùæ¾æš¶Gÿðÿí¿§o{µ»Îvõ‹ýý;üþ7Hßn´}¾ýùÛ´=0?úúì2ÿ/s¿¸:ïÍI@ÍdcS· |yŸñ>GCÕtö†‘ÑÃ.š+Ú`B'oÐIr¹l²²i´:VÈQØ!שkjªk°Ý̤^®Àt7¸n÷Þ{ó®YƒH‡ÑÕ*nUFÒ:¶Óì§uepaö£¦oN %r‚»,Õ˜bG?Œ¼Xqµ±ê㆘NÒVÍh94ãÔßÿæÉ;ÈAW_&]Õô°¹¤–WHFI»Ï3xöÑSBHÆ·›ƒF–8¾l4ÐJ%\à®-pQ‹lÃ4áÂ^ŽDSá^¬=˜&/+'4,ų Y5=I U—oŽ›+¦ }Y›@õ–È•¤ÛbÙŒvϽØ1ÃMŠ¥QWc,9÷ÀÐzXòkôù%e¬õÁ<¢€É†=›Ò€9²—Zø½É5{K‰ àKYV®ŽSªD SK=ê¬E²SÜÿ-ÈÄ•‚^ê…^HŠ£Äx8…=!G±·’ÃUÜVð–ƒNJMmo6{ªFS(<S†„§:çHàÑ/èèå.:£¥Å´"HY¬XR"÷Û •È-êA9Ó!i[¤3´5ßà¾Õ›£cóì …›¥‡¨®5zux¶àRÂÜê@Ø5<”rÖem\꿱®£^°{{]öNÒso7Pº [ ûz«r¢ë:ÖýÚ!þPl]Ͳƒ“Sæ»BîT!øü€h1'ªFW´'§ÂÐàI©ž¸[Ö³v]_Éò|ZmÐãk÷d ®N|€°§âØ€]¨‚ŸTÎ_ÐA®óƒ·Æ£cƒ=Š^ç[#Cs¿¼ˆ_9Gøåýí°PçzCÇįaè6­¸ÙK€¸¿ógñã±˜Ž½g¯yDžØÍæÖËšBRØ]Þ’-*š=Þ­1(w[Å´7îþ¹¶KŠ#«¡gŽf“жa[›@6”™=K¥ÏW]GˆT9ûlçóº2Ì 6ád˜•ª¼¶Å*íJÈbCŽÏ;ÒÝŒkÀ0:dr;°w]è{ß{´*ëpôF#„©%GוuO-Ö^ ÿKCM»H˜Ž¸8Ô}´eÄp;NºsËZÑ“°¥¾ƒÞ«3—;äa‹“3n ¥µ«sÿ°Ó·Ú‘ëŠ1F ÇùBÈÜã•900Ƨ¨õ F©%49ìÀÚÜ}Í“‘܎,‰VŒèG2[±Ëå8M5„5–‹ª;êjFgsªmuöHa`Ãä~ÑhMäxi)á­6!E™ð¿X¯¾¿n"ú úî R#¡Ô3ÛcxJ·á?mÕ‚ˆ„PUH¡f…TQ¿}Ç×s|Ç¿ EBäa³;ã{<¶çÏ96x¶}{¦àñgõó4ñ15Þ¦øJ›ƒ¼=ec,o±)GO­+ wÛèJq!¹oÝ`è}à4ÙÆéѺ¨AªÝOZZù¹V6‰¡wI(Ϻ+ã‘À)e.=ùSTZýCróÐO6ÁWi ã=EW Ê2VZ);†@€¨„ÈOzl„rSf´Š –ÁñÁ‰[6ÝšSãUnãQÀgQ˜m( ð%Z+ó†¡6ðBS‰|IñÐ{J[sfE˜²Èunëf¸ÀÖWû x1Æ»ŠÐ#ˆb]ã¼$AšÍ1òÆþkÂŽ’{Ùµr]ÒBoº:EÃüQBv²ÄÇçAþ%„¾Ï°Ñ š‡°llŒ*j“3É.Ëš*Kë13&SsŠ68áÕqÒÎõV‘§!<|Pgò6”L™ø°¿*–¬‹GÂ`M M®HHOóXú´æN›Ç§™ÏñèQPA¼Å™FMÎVzvÒhÆÞaL‘ËäÕÓ#{D§Ü˜èšÀcÎëóó2Ðm“N?:ù’ƒ+Gð“sMð^Êæiàr=—µC'_n'Ímµm‡jla”§Dä·ei¢n<«s2§Á`s4ý‡å”6æ|®œßp¾ñàALV•詚k@srZ°…\\Kut©Qfš§úi=¢›t°?•‘sW”¶e-°%8×Ê{Ϊ©<¸š‘\-ÍrW0_h»jýæœ#x㲸¶÷ÞfŸ\€h¢¡KÉÜX»¸vÒ¡ÆB€'7ß(C´°$ çÄñ!ø¬Ço2A«sÚ®DYMÒm-ÅÁ47()Z’ÒTEWxgcûre_nÌ”":áèGK᪲fÌÍ1jŠèĉ°/ÕXd}…©ìSߌYý¨"„^Ö®·1©÷ yДÂc.ª %ZaKËp9oèU+‚±`#z5v2=Ü3ú’äµ¼\½ ×.CÖn} Wv²ÛØôj%|£ÚZn M^F–´¡Sb%›p½iåŠot{ËNÕ:y‰£«YžâÝæoרl©ûfd˜Çëà!ØcÞ>úbú†|*¶nWù:xvBûÛÿøÍù‡ñ£>9^üñùûÃg/þòÍñìÍÛÏî?ÿúí·ÇÇo¾ÿ÷·Çï¾{rБ{ן•?³vb×(Ù?“¿Jû?šëvõy“fŒ¢vÓ>Ö2Oþ„í%îòÇwõy}žNãG¶ó'¯þúöÕÃý×o~8~1lÇG_¾}óêþïÇ î«3¤o^~5â{rü|,ùåøñ¾£% ùÅËñ[½<.uˆÇIE×½WëûɧÙ9s¿»¸$Ë,Î:Ê´MϧãYp÷÷uÆ.߯éøâü϶´¢IÖˆ6%K[^öW²¢úÍ\`îw oJN^ÕÔ²ïÝ÷î&,MSØš»Z!,¥É™lsJÅÑlŽc9;3F„Ic–Ü Î~'6tWD½"Ì ÛM{”¦³rÕ°Ãëè!€õ¨+}sÛŸÁ‰NúMýy®é6%,sÅs0»àêMKXìbO§z+S-•ý1Ì“7‰i/O ƒøiÊ0.¶l2U*ŒcþF[Øcéqvšƒ‹¿BÚx±yòì`e2´àiªˆ´æì{7šüÁ€J¯n4ê³jS5T•=/RÕ ÝH2&1N–-[ÜÈ.4­“æ¢H¸R#:só¸ÆåôXºº'g>0#ÓÊͲ.÷Þ÷ÄFò›"Š•§þ¸£&»ªïÈSA ɃEì^p-y´¹8®5!p%]@«= ‚QцX;mèÚ3ÐcÏ k† ­+˫갵[%lXêö 4˜ö\}%³¬å^ãc*N²•€y”ãC„øD‘§+»L †æ8=]ƽzG=öÞÈëˆxhˆÕmƒ¼ßýtãpOË‚”k«ÚY‘ËäÊŒ. }e@J( éÑAÄÇC¯^bóηL=ÍÛÍv òw Òƒ^ÊÆëÛš%B¾Ü$.y4'îNFq¶áS^u˜šl$Ü$'¾ÉàÛFîG]èY%‡°#ÅW¼Ýy]½h[ ¶] ‰NÞ(ÊScŒ-,ŒrQç¼]KÃ(žžzðœÏï)Ó²«+Ók Bd¥– Œ¶ÉTΘ :f¿«<é«F CË¥ÕϤoª-a¢¥%òʨvc¡‹œÔ]àÔUŠ£Ÿ¹‚¡”AdÏãaS’-ƒVgie-·ÎÑ‚ÏÖ Ô³ÁμaPÎNñ¨®‚ë “º'? ??€‘·Q©Ü}Ëĺ ö–Y´ lÅXe]ÅÓÆMNŒÊ%¢Ï~± Uh㱟,~êCk×"›xG¯¦”¾¡÷òkZ@º„Ÿ•;ŒÞ…Í8Æh@7‚Ô°œåø)àÚqÄL1*Óº£¯§°*8cGë´Qå"wdbä«S[«­»xª…î+ 9|²˜Ø R¾S^Ë9!M$Ë®áÊÖ¬­ix€ygT6~ ÎÎÛ$¦ÇçTÁj]ÆJÉŸÑÆþ¢ØíÁ^=MŠÑ,\˜$ûSIo´¥ˆ¬Åz“Þ¤ØU뮂åùB÷žfF¹)/«^7t-H+›+½¯Ó+No¬±—L±¼S.7˜ÃÝš‡X–;ò51#v²wÞšGªôtõTT΄¹vVË4’î ¨wl)¤1ÂSËø‹tàØ¥ ]-ðœ‡,;8AU öáËûÊÃÖœUvVjÀÈ=Q(×`e¤çÙÈ6OzÜ„í^°¼‰À˜;Ê¥•´¾Ê¶;DzaÐÍTÆêQùƒëŒž²¢'l¡åø 6>~8£ÓR=0µã#L•÷fÉõƒhíhÁÀXQAg v¥>ÜÎl#3¡Aq_\ŵO¼¾¶4Ê„•T"¸dPýê*P¬Ïê²atíñéØ6á"“€LÏ  !<­Ð[Öʨ¾µ?Þ<ãJÐCm‡ÆŽS¬p`ìвÚ2.ÕjÙôá`Zâ¡zÓ)ëlqg]FF£›l¢ºBѱ/Vn¼J7ÀSŠ´è†ð,+?ju½ìÔ< bDwÛ·Ë¢·ǶyÖ¤c0Gã4—cûD%$jŒ¨º—3*@ãH— %1h BÖaÀ{U 5ëLZ9y7[luïè è~vzÑm©èzæC^†YÖ½(Ëì›§mLÝ h—u^7‚'Ó–Æzf×Ié´2—Ås¿Uºò`Ìr?:¬xp6hÕÖÎT††u;O[¬+E×BÌ;%ÔÅô¹•(EÖü°]i˜0‡^Âv¥aÁº²Eák¥uu°¤®¦^¿«ÖMKF0Îgš ë£wV“¾å¾QE™Üç“f¥µ>ùÎfò©|sûÀœüò%¿ož^¼xe/¯î=¿zcî]¾÷Æü|qñöÀ8c Jòä‘<ùµ%‹îÛÀðá»þ¹¦A™ùù8Q ‰¸0'¬Õ€¿ïÑîGáÞó±­Â»8ùþÙË«³‹ÝóËkóÈÌÝ'W—g»×¦9÷¬ºôêô™øw`¾‘G¾—}W³pùäT¾ñ¦é»H°ºÊ ¿qP#íâhÙ¼UFhÇ‚—¦ù¯|88·»ØP=å};ÿaýO01‹FÀ°~Y~Yù³›íÙz¶ •àÜù¦ÁjPÍmŠ7!(lj (÷—>žÐ@­ñŒpÔ.ìSsö]˜ïBOˆÂËÍÈV׸¬Tª‹{Ÿ¹Ö‡Ç M“û¶aðæ K“{ìÕtÁé·q®·r§ÏìòrÔyîã¿ îÚ>KÃ|¸õO ?#Ðïö„5‡ÿëÿ·ÿN>Lù„¨-wÝ~ÿˆï@úÁùÉüú›5§·êKÿ)úÏÊÅnùýîÏÁǾG§àÁ9ÌëH¿F‰íMjÞÉ]xQ¬Æ–‘&êl{Ž Ý8«p?«¬‡•Ìg5Èš@¤Í%'­Œ§ÝtŠ‹^&àíÙ)ÔƒZse½çòÎzO ߨZ< ô|Öš÷à“ïÜ4‰´çž|i6BÛ¡™×5ѤԋÈÚ¶v@Úï»09톺ÖvachUCz.‡8[c.]Cy¹JòmÕÝó M˜˜KµÖ(üÇ·HTúýjSôNµ!M†T˜ÕºleÓ-*ÿëÑËK‡ÐT³ÆZJe)P—¨‘©W™-¤UB®¥Ç¤ý >š*((FÌÆ «Tó¢‘wo/Øœi_Uå–ãîj¡E#èþÎM hÌ¡[«t}¯¦»j`R}Û’DA(^16 œ.Ñ»9IØž4I!èãìHm8î²He¸ãlb_õ:NI3!,nÖÄ­ËËÚ?^›5sT‡\ Š;‚ŠMX‹° ±§möqpÓ¤œÇ,°¹? ]¸Í¸gr÷#Å4Ý «x›Ø¦n(RPCÕzLQm€wÏÖcû92ÐX*ª ¬nõÇ™6áÀÃHKN៎ÙDslbÝv(kù9§ |ÖÖöASŽX(”¡JÔøuA-O:ݽ‚\ô¹g®æ°×iÔ}ˆ´”#† èÑK:–îvL]Ⱦö’…£¹aôHbÖy”Ò«Sf\ä½žÆ R Û 4!y-  ¥ 塞Í6(kýx}Áà.Ä Ã÷Øçˆ¬L‚×úÉ‘ÀÂ8*ªIІdõÈÚˆj}@¤›[_4vÀ.6[§Â¶·ŠX/sËvTX%/ÆS¤ /訣s†ÃÉëÀ@v~£“cÍ©“žÇ¨ô›3j!¹Á+| ©Ö¯þÃTVO…bn¨9kRTb€ù>kˆ½ƒe •ÍúNˆ‹5rCã¬^œˆÕ-GmÆ>ä— LÌ{oýGVCÑ&+ új5 e£¸•;f´Åz-žAÄ!,©× x!‹h¾«p²ƒ ±.-ž“ÊãÂY ›”ÍMOP*zhŒ“-¹õJŠ_IÂÕg?—ãKè·áÀiqÜ‘j|ZÓ›tD¡°²J q4¥ uÒ†›HáÜX¢ÜZ.ÅZZÎõE5®x¨LÁ¥¬µx²1w•S&7 ¹šSÃ#d õÝ„»2;âRZr½­t. _¬ÆsŠC¨Éác!¡AGž×ZD×èÃ9(½ÉN‡†åD+õCsƒX»qªÄjÑ(V:^æ,è–^É/¶˜G|ì:´9(™q¾ VË0(ZÖZu˜ô EK Ó6Ïe "¢?k’ö ö˜ECN PµÖÉëhóÈ›ò6WœNY–hôq¿²Z[†&®+Ž-Éï+r:•#ŸglÚZ_Mµu’â„.iÙ ´l×é“1ÍM£Æ“³u0m^N˹ˆvw”d¿é”•gÅÝj•F)»™;F†qKÐ8eÄ,›NÒ¸@ÚnEIÛ¼‚ôÂL­²êèVfÊÊtã%ÈÍ‚CzÕ±ˆÈ4o„•SÙHžM¬T +]˜§,ÍåÝ !èêEcÕð´´»÷{Y„(¼³0YŠR0Õ¦ù}‚ǾX@ &mÎgMΓæÁ'ßYMnL¥3²óIóiÞµ¾³™|*ÅÜ>0'¿|ÉïÛ‡§/^™ÃË«‡»Gϯޘ{—ïß½1?_\¼=0ÎXƒuòHžüÚ’ÿÃ_¶á»þ¹¦±–°@òqB¥%âÂhEo«ß[¦£pïˆùØVá]œ|ÿìåÕÙÅîùåµùNdæî“«Ë³ÝkÓœ{V]zuúLü;0ßÈ#ßËǾ«Y¸|r*ßxÓè1JM8Û÷ÜX¡Æ6â½âN Ѐ¿¦­Í¹yTtaë g?Fµ\Ðör•Y;J¡N1"ØõÖ»<òÀ§8»Ç[³• ä°ŽÌzy/{R½ÛɇCäw;ãJøûà~¡f;ƒšôé§Ê¡çzËôá¿}v¼;}r}þââ­ î½z}¶SÑí]>wpËšÃ[_áü·¾z¿þ³æ!>@,Eãã,Èš?E!U_½¾–_?âÛ}0d~2¿þfÍ)Ìž<¾õÕ·à‰#+Ò‚§ÚÍ@ ‚”/…TÇ'(‘Љ¸C>@¥«0¶á•±§r!I/«Q ™8Þ!_·XçdšTxu‹Sª¸a‘ÜÜù­ gÅ‚w á¥Òæ‚yêëª}C'NæZ3f“ï,Yà¤3pŸXژ΂­u 8ºÃ®•cñ—ô,ÌŠcÍBr°W½ÒÚFÿp\’‡eú'åè›ï¸¯»“3žl — ‘Y‰µÝÄlfñÁ‡öZóäO‚c‘†Í‘l(±ù(Ö+“įî ¶|m }ªã1÷ymœl¡¹ÆÁÞ‘t‹‡èV¶T¸¶O@&o#ݨ&°ìö¶'4?ÕXij­/H;Q“øVBãW¨íü ç'tu³ y•[ðõÿ“^.;–EýÿÃ0-åû1D5’‘‘BL $&­–ÿž;"ϽmjR:²TîŠÎŽ“+–.@Ú3Áó<¤å’ml*9|K ¶¥‰·Ùî᪑ÉÜ–.FŒP7]ŒŒÔ{ï˾ßVãåfìäOÅKá4rlÆE¼‹V‡NO0»ÃìçÉ­¿ÊAFë¤z¹Däµ9¯’HÜ]Wh.²çM«¸±ä±üÅiš¶a¬á-„R¸<Ì/é¾¼˜{ØÙÙ=ÿüÊ×Ú–ž³†ž/qwÐ"z¦ˆ{Ó}ñº{.²m$ÄLJ? ³‡ƒµ5õDT}@ªÀCÖ½ŒŒ·ÂUË[KÑ”“}•bÌýE0ì¾TÖòþ£KH´yµèý`Mïªá˜Fµà‹©¼ªô†.]Àˆ²ìa·º²‡¹“!E§Ð÷ÝHÅL|ÅvxÓ›‘œd!™åwS®î!m_eo]ËÜw‰r¨AUd†Ž›'ŠX³¯šöÜTõòÌè3[?ç"ý±ú$ëܬõáC݆¨~Ö :óêšV?¾Œž/6оøXûAÿ#Ú6AšMÊ?ý½Y­fP˯ßÙH¦:yÃ(> f'Œ¹Ñûiéoõ\ÔåÕ]†IKÌv@ÝCêÍÂåŸméä;Ôÿ–±ù¦éZÁZ'Køš/ƒ>*¢Ö_-¬~²g©<ú._l6ÕªOÒiŠ1²ÕþT]Öü¶}¶5XHØQL¬úå€_›uš OzHafúCP«Ü¥ô¹ZÚ$´Qµ¥é<¤ph©Þ(—Õg;— ‡Cë‹ÃÇÒbsDCÖ¢X}bÀEßL*ªÅÔ‹Ìa¬„e²ß/¤¤ÚÒ°ûÙ¨RŠì¦mÞëÒ÷C”Èê6}ú‘IJhN¯˜–k¤ÜSÐŒQÓþZô¨Ga#å@ùöª1(úPcÕ”èHROhf ïH>KR@:ë­—„§‰®åU\ w 23“p广u‘iW3Ú'–§d"PëzIµÓk:#¤5µöš/!%#ª>‘VW#20võKCSÉ%Üœ-'ÖjÌ’„'jh-y¾ñG*š×ŠHuœÊ?I?Úž9h¡$½Ü^6)ïó L='%ž=àÔ‚5ÊöÕ…{¤¦°Ò-1hÕÑÊ35LÓéÞyo{Ç=R¯!Òh[¹‚BY¢rëÛWüÒ„ŠÜuNf¶¿R#^øªËt‘Ær$„R\-iZP k»ì5ö{øX´KëPFÆC7–"bDÇöXÇÇv\$RÔðŒWò7Ô|¯Õ®”)fãmž`C Å/ja–}pþÊÇ ŠYOÒdzoG#Š•x.×äãIŸUìz5FKIÎŽ¢Ï_Îq“ %˜´!+z%u*ÀåÚ =Ã÷ñ—§÷‘}&1ôKՃ耥x¡åºôI .”¶¬¤k¿=¶_AÚUÆta](Þ cŸº‡ÁHòÕƒH­™¯ŒÙœ)¿ŒäɉJa4gþHwéé40ÝÝïӯ͞ÐI„îAZWä 5çrÖ¬žÆ5J}¾%Çüœ?ýɛƦd›¾ŽœmG6Ø8>Jt§–a¹ yt-Ï›=ë¯ç8‘ZJ%}ÑÆ]ÑË‘rJ" ArAÄu½Ô*.`í0ÕuMŠ”ÜV· ?à(dŧ–:>Ò³©fB‡C²ß£¤—›.ýŠÒ~ó?ÛíÇ…OéñÛÿê§ýøé«x*=ò#鿟~±ß~ÇŸþ…íë£=þðøÛßÓãŸßñw?8·}„RŸ©ûu¢n"Ô}€ºO÷áé6:ݧO`Ó' é>2ݦ۸t–>…JŸ¥OaÒ}HºHŸ¤OáÑ}8ºF÷Áè>} Š>…D÷è>݇¡û(t„>…A·!è>Ý ?Šn¾ãü‰äûAË7~ðôôø·$Sú.[ÕEç?Ç.UÑw˜óñ½Û QR1™Ý²çF|Ä¥¤ðn\¥ÇIµÊûñÀt*¡ª&n¤eÔŽênÿïnxøÙ ›kV§‚A.εûžt´RÆQsnÓ›ÓŒ}O7*ñïÇCô­Õs¶|û[èd #ù.žù0áÁ.›‚yÔ‘ñ¹ìC}ºHøŠ×ö!}GÔùÞËó$ð¹ÆdÇ4}/ ‘±Œ•6ë~y³µ¸‡Ý×qET—ªþƒ \7CÕ*3$º6_3Æ›Õ_Ìq“áïÏùÌu;c2”‘F§ów{|èøúæ´jœ&áñE¬Žãf¥3ヘÑ­Y¼ÉÀjž¤!1Sü‹ÈZq& =‚ÄSf ×úañ¯ùŒ·;gÃI3N0øx “íÀŠÃêÒnkÀ½ÏhYñ¡§´¼Ÿ)ˆzë57æ­‘@ˆ[#c©>l_hçü†ƒâöÜË9̘±;´ ¯cäàvã()?=¤¢§YevxvDS‚N9Ƴ•¶ ¾ _ÞÏDF²Û+‹SŽ„âa"à6ÛÒ)#sûÅs¦>@ØZÁ¼#›£„·:ÚÓ<|öÐÀòÑ%VFX:€QÍÑ!ÏzŒˆP ž°Á 4İW1¶6[v¯Òc7¢ÅůÐVnÇš6E¶ud—yŒ£9Ò¥Yv—FÞ˜Æxñ°†ƒÊº2o|&Øso[Ùg“é/7¨]Íy"V·÷,‘é~-Q¥®eæþR Û§ó(b[uGE÷ZJQiúÌ«_ì¶%6ŽÓ‚v8ÕPÖ3ë0¶íÝ“l(—§‡ƒ‘üT¹Õñ.±ÕylJ‰êYŽ‘­á¾°ùa@ ¯ÇTCHŽmÌ9TæÊ”05²ÅyxÝЭ‡öµyP+A ¶Œìå· ¨WLÅZÒƒßbÉËÆWccoM(öeçFø§}…XƒÁsã¸Â€Y/3MÙâl°iA²ê8´8“î…±£‡‡qŠ {­Gì—+ŽW[Ÿ.»]v­——=‘¬°wÜ?íCxevëË^çŒ;Žx8E6èf,fœ=04™a,eõÀìrµ'ví©ØmöauÄ ¶žZ.cÉ#@UÄlÚë¢êOçt{{­pr ~Ršyå¤äv½?ŒEÈ@Å—êzoéÈuwžÏ+¬ìÐÅ'nk£ÅP®Ë7·bã«^Îz1€EÁ²"’lÉõ„ü¡LPÙʡӒz©”e»†BMŒ¤u/5-qÖO÷"àã ¤eûØ4¸4 7cw¶öM36Júº»˜d#¬q^Ô/­˜³“‡*¤­ØŽL{”ä7˜Y)*r5z¸mŽ('ä/Œd5{9iézR¯ëjî—0sxM ^«RÞØK-T÷0ÆUNÆÈU)²%-•ó9vÙx»{€‡V‹ÛR®×+l­±~"½5ž<§ #CnDp:êÆôl "¹öÅËAŒ°¯¹"¼ê32ÝÚ:qØû™ÌY%I¶äÈ{Ù-ûy=ÛwAÌÞ´ñï·UwìJeô;)N;ö˜bc1Ïž}î±½®(ÔÙdLÿ£ºÊŽ%¹q +ãÀlð>|ÿíÙ<VëG!¥øÐ,ȃ?Üófjo®ö´ðpó¾ãöÈñoÅjÈ&ŒöíJÙgÅ®Œ–Û*­ på¶î³æ·­°dÓg±Ä¡D\×áuÅ´,·¼ÑhXcIo?7MKÈÕOÛrç´Gå]ËŒwðÒß®U ’&nò1üîÈ™>-Á[cúÅn_…:¿ËùN Ÿ ^y3.ÛÏp·î½º\Ç‘î3ësóÓZ‹“‡&øUY†Z !÷S¼x(ª¬ÉÑ’BEæÞõï%ûÂïÿâ#ê¬ ñï}ûÔdO3^[Þ˜CŠõI¾.#äPå1~­2…ÂGÿ‘áQBþ¦”çZΟ²÷Ñž§ÜmU;ŸB† ß&Z3–©í’ÞéLm36i—tÑ9¯`™ûü_ç»I;I{ådpÀS7÷¸vÌ#ÝZX_jpgô½ÀkL,@“×+×w8«…N±Ôç ib×Î #‡Òl§d&ÂzFÙŸ4ÊŒµDj¥¿­aÀò«QegÍœ´‰¸Šý¾`G몽EÛè¶›Çä݂ۇ<¨üÓzxÓ«,Ëx<è~Á!⩲@Qî€åÃi`yS®ò𹙓ʈˆ0Ý òM$ŽøD#q…¶ÜÛÛ âGÞŸøzÙÉ+píÞ_Å’°o³Ù"yª0 ×'Ä–¸·‹8NVŸØëMfÓûn.'Î˵?ü”çë¹Kèf_-p—½á·êœ´…«Ù0!Ÿ³ã€nç¼î„9åQ¬Û±9Gv S´W>óìÕJvN­¢èuB!QËãdâ’7Ÿ¶þ*LŽåŽPŽdQ¶ÓÅõe¢^ø3ß‹‹ƒ Qx¿™Ó¤Qåòþ“Çx²Ë£3¼Õç&­öoµUÝw5Ǩ]ÌÜ2#ívÑ…\ô áåF»Zœ­mÆß—‹¶Öü÷Àa·ñ5jÚÞŒù ø²ua‰"šQƒus\ BˆÆw3«¦p&²‰7Y«Öïïæ°ñÖ­žóá»–ëvôY~o¸”: sÏ;¾meðì~ÖõcYÊr¸XW:!̹A˜–ûvyMwÁr uÑ’Ú,…ƒ(0³0ÅðšÔíœcÝL˃­Ié¡B{?N¾¶ö ÖÈÔA„×Έ3Û7m¢=îWú ]97—Æ^yC ¦n€) Ô=ÊôOÁ˜ä¶&36©»ak_×µµéN g¦ÜÂôónp85È4^¨Æ(¹HW«q©øÚãßê—îöÆ&ÎÒâïGøn¬>àâíjÝñ0_\8äFùYxŠB?Ez¥ë/ÓÍü,³%Hö²YÑÄ-péy¼›3¸ÅÃø³a/È“Wqa’»ëý*¬ÒÄ«;hÞ¦…;Ìh#Ö»+}.°U}¸êG¾ÄÅ”?LÛçrˆÃ/oõù6ár„ÄÇÈ¥;xþ#åæ$ñ—Ö$gø3ZW¶zý›¿‡nhˆŒ)pÉâ¿Ä1bÛ¸t àÑbîïžTaåßÃçÆ'ÓÓ‡·fóysá{®ÀÏ(çÃWÓ¬3Ω‰c2"?b¶öJÒü†]4ýàpÔ4õr‡Qpì£&8—‰¯‘+ò3é9Ų j%Ÿ»N¹=ðØÒ ·á`áZ΋„zØÃd§®Ú‚çGíî4XîŠ@è=å[8EÜ…^¡‰|¯¹ú#4Ï,){~,wóP®‚˜d|V<±£@çu°¼1³[¯ÇÔL/^0®€Ïßß#%­Rǧ[º£[³‰+™¹SÙ;/æ+‘Â)ð”åôx}`~ RËiD Ѓº‘KÃyÉ \ $‘¥`Frû€Ÿ!Oüô8 alµ,º[ŠÛªe|7¸Õ‹ºßöâºõÈ{` @ …!Éoàë½³¶p¸ ü1‰)r=ß­ÑäþÃIœ±·ßÿàÙ†ÛLi)Ü´ÍœÀ^-Nëwy×mâ.ÃUˆAË.{Ü~€÷ÙÝ mÝ °EVgç‘{ãìgøJz{€ƒ]ÀcWK$j­’#Õ¹’´ŽÔu'p4ÃjX¶öˆIñˆ<(ki5Ðß2«Àêò^nÎZ?ÆöËaà›²‹2@(üµ"ãåè)* ‰åª|QZgßmÒE8`=îÖ~áFß mì%Aô`×`˘t­6\‚¦ ›.ôư—qO€×*O©a¢Œ Ó7Õ ŸVzÆb§ÁófY¨ÂÜu³?°‰c–p^ ñ'.V=¬ŸPà+à¯5ÙË·u…µ|ÐÌ© '{5w8%—¬jaðÞðä:x(xçæÉÞ³Ýx4U ¿ÂÔ\íþ3˜“íéÛ/ ®££­xK4fE¤Á)¡ãŒoèØ{qפÊz5>·ZTøÇ_‹ÅØìC£ôaâk\ÞOCÉæšÄA x,ƒüÿf|òNÍ.ÐSš9rQz eãΚ¯?Òo6~]Ê¡î{t £ÃlpÙ›CvhèþžŠ)BsÒ¥°–* ý“´=ON¨±e»FÆŠ1­,Öå/©œu&SÂkíªÊ˜’5Ý4$Íyjæ¦ã‰ÄÅf¹éëà ûiÆÄN¿xäR°Ðˆ/Ùœ;Ä´ì÷ímîÐè`0Gm‡Œ¢_aÅš›pN»óH0ñáþÄG[¨ŸÃ ÔÑMj29q¡°ŠÇ>ug*="Ú 8¯(c$KËï}€SX’­/Ãâ†#-;µ³cLj6w˜ÈyÛÉ·¤f­igŠSñ‚‘Þ°¬Oàéí›[ÝæŒ™®x,ôåX ¹<ŒÔ8Ë Ç© #x˜ÚÂoY¡}Ÿkœö´ך¦§¦½&ñ­`Ùkr/ñ¾Sw‡ ‹îzºÁ )°_'Ðcq‹Ä&ˆßú)7®‹­Þ6ÔGøt_ ÇVÕòU@«‹´©ÑÃÞ]£AQTkÙ­Ðçisæ¿ÇÜ-naØ] [ëË«o.Jƒè@A-B\È—ÄÚ ÝŒš3{3_M®*ÌÌtd9ÄÒw& ë.úq—³œp ¨ô¸ÐJ¤MÓ®-sñ…ñÁKJƒÑ]d§¨LZ‘aÍÔ_|2^ ÒÝ®ò5œ2ìmó…ñËoÊpý9¶·¸ÁgÆsž#±™,ÍÆ¿Føt˜1%pmG8Ô)Ð` ŒµìJÝn Àn¸šHYwÝŒÒ$‹Nï]³ïÀ;8ÝJ ·‚­o;‰¡pu ¼QK%îZ÷Šï©/Í,&×%[õ±‚˜†¦ÁPàû«¬ ÏÂëDÈD[Ô_ŠßÑPÃûNä°,+°µ^“àÃ{ g¸ÞÍ+ß}$› ŠuÏ6“?ʹ8W†hQkysy+ŠÀ‘öºƒ,Ü= 5a-åQÓôÑ}›³nû‘£¼-N~JQypšlc—5΀ÛÎ=ÏPyà1™– j° 1J³ûH3ٵÈ÷D2RVópƒiWié`Dæ':{I™õl&ÉÕk¶t;'lAìàX…:F¬¸u`ØY#RJj»²5—<*'dË•HD,ò]ú':¬n¼#9ýˆÎØßÿƒŸÛV5d…–u<à]NññPÏi¥H…ÞÔÐ9HyÚ@{©ýŸ“/ç®5>¼®™rð¹?x-‰£;/qS1×Ýab|xŸ‘•ikLJ£ÿºk»œ¯x}ä¤,¸Êh°Ÿžò*ÇøjÛ¶š¯ÖG}Q|<<årÛC#0ê7LãÙqýpô~Û)”:ÝtUÑÝá>/V•ìsìÜlÓgφFYÂŽ¾”s­a)²èjx—ø1f[–­¥\×·PŽ¥ŒkýJ…ñp\"~ÎÅ L‹I-µüú€sÉû—mîÏ  -2ÙÈeü=¼;3"÷{7áíáÑ?¼M9&ÐÖ }%خӠ÷ ³!@8‡0ÖþXGxïÇhþ=|Š!ˆSþ?œþ_8èümŸÄ!Ïy{Œ;$öÃA6-y8­ êª PSa°8–ø=¸ž×^Å17RÃ24-ö жÅ×L ôbùçûi‘ýÞ¤áEWË34˜šœy4Ðrùu ÏÒ8jzðDÛÏÉà³H¼*y-KÍ8·9´¤(H_´mN)nËn†§:ÇfŠ ÍêPD/Óa Hý¹A£HÈqhî„âs˜@&ŽDÌu}ëym¹!Öa,Qôyfê=Zr<¸ÛÑ•ûnd<íjQÙ˜˜£ O:ÅB§Zp²´N±‹Il˜$öøR,”³I§X·ë,ÙfÍã °à­ÌÇÐc7É¡qñbþ’q#ˆ±;áÔ¼m\W±Ø­ñÎl¢Ä—[` y‚EË?k]³²h•ãû{xàm¸ÝlV#­ÿàMDœû%Bêb\î>ëF¦žyŒÓåy;xIƆGêK|½ÁýëIû|Ÿê0«Î01ȳ§íkï‰Õ~i^#â¶B«Ç Ç“Ò<ГÀý­ùx8„4ñ™=hÏö«)y%¼]®ñæÔ¾­ÅC.C\˜…VO#V‚0Åœ•Æ#Þ\S:G[- üvÀÙdÃÚr$4¸«Ø VòçýÙÉ@ËvO[ÇÁªº·£ÂgˆÍ³s%îsv»¾sç¼6´U™.ø¾9ìU õ4ík'ŒÈÒ@<ê,7oM6¯ÅM@ÄñÒݸÄ*qrÞI[ØáÞp¦Vã/a‡û¼ø½& —/ƵŒ¢GQJÙy’µÓ8½ìÄ)ˆï^âsÎïçÞHSöp4tV ¦ç·±CÅy,WzQ€(¶ü0¸­¿bMÂ>]ZýèÆèT5ðÅx`ݦÒ§rwXÌ›Ëô6jh ™C½4xØLA"PPûé%|9T à=Î}GôØ^3ÙiŸliH|;i|Öv²@—ŽÐ‹ÐqyÏÆþŸ­¦Ä7Ï5vØdsM0A˜¯¥—4ìýs¶iÅ,‚¸èZ¹ím4äiÑ Ïë±®šN­ÚõÚ(‹iÏRoÔ¥ïÜAË ÏuZÛpÑ¢IÁ¼» ÈCÅ¿©£ßÃ讣¯a”d ¢fKŽPC· ÎkqìS^>©ÓîDrqÓç`•÷´§¸ºMÙk þkàH,¹xùãRG ú5‚¸ÏÖÍ‚¶äY0ã iP¬ªz `­òe80J¦ÚTºy•äTž‰#>¦ˆ]¹O›yà:íÑÏõâ,N 9Þgì7.À×tN`«îÛª¨póÌÁ+]ó¡²ç×B ‡ÄÚi¸\Ü݃½®Õ•U÷ƒöÒÒ*¥y¥Ò &Ë÷^™ÐÕÌÈ{Hû„¡ü'y¥ ¬Ì‘õ+p_+UðØãܽ‘£µ§›¯h¨·oVñNÚaÃKÔLFJ¹ƒ;Q‚ ˆ1²vä0Sî€JM9òÍ2nrì`Y3€èÛ¢vgÿ‹ªÜDhè’³²¾Z 'Í#wØ)êîŒo:2x¡cmj÷AŸv|’í궇¯'MAŒR™í@4ÐQáA¡¸iˆn<&Û>ç-ÛÆÙBÔœŒªÅqÙF$˜d –#»5ÓAåíxà°ýºÅÆLM8l%¬öI­’ߊ·ˆ¬ë™'ÌÎÌ#TfÚ´Ú““ zÃC4øBñmÐvMû¹/‡åËÑŽ¦]•{ ›ÑÁQ]5ÁÝ”…:½ïWßrëÛ)·eÝSXÏ:5Þo¯£é¼LXk|;ŒÕ’{¬ˆ~¡!m¿žnKth“)-ôkV„¯e¾¦]¯{0–Sl*“t«¡6Iî­Þ®¬*Z¡åN #2TÍ2hOirŒ˜¿´œ×;Ayú´ýÆ Ó3Ó=ß~!L0¸î=ðkÖ9³í^m“O-raåww[%f€ÈŽè(§Êþ»ÛºšÒx£ôUë,RdüËx•µÈu\áwÁü‡~1XpUÝZ“'YV ‰”E!aKŠ­`Í€,Ûèßç[Nu÷"Ä0súvÝSgù–ê¢ÕIS†`÷#hÖº ½"~%]òÊŒúQ9ïF·8üí9>s(ÐpŒW"m.+Jï²ÔlÚ±cÄ!"šž/h Wç`_HŽ`·ŽwªÌå8Ì QšÁ¶øF%½ÄîÄ ¢ÑÇû”¡D< »ÌJ‡ÁAAûÑœÞßn¬Ó§OÏÿñÿýþé£Wwß¼>=z÷þËÛ¯¾~ÿÝéów?þðÝé¯wwß?<åS:ožuóà“T15%å„Ð-¿O÷ÿet)p„O°Ë˜Í¾:€²$|½|/YŸ?îOú“ÄЋÏðÖ/Þ¼|ÿæîöëwN¿eìôÙ³÷ïÞÜ~{rb/”ÎëW/˜ÛÃÓoøÈïøãþu}þêæAß±O^ FгwUàÞЙ·ñ ZºÒŒ:/Ò-‚‡p°Ytöþ§x¼d[Y—R¥¤³¤ ï‘dô¬3h9BÚê @@^B s±H‚¢Æœ´ÃìPª4ŸlÙHYL/÷tšze%JHäd@y!QâÒxas€ÔÕQs>Ö*cE“t w_„É¡bEúˆ]–ôßç)Gœ€ÚI,ëlX‘Îg…°F’èËâÿ|°iØ\îÌ”F™µI¶l¤£sVÍ‘Gz­eoº5b¸N ö"Ð2¸l ET°²ÓHà*|%ßë+ˆÀ.Pj0‚0©‡ø¶²Ê¥¤Da½{WÉÔyÖ³‰ vú/\=¤C!°Ë$`n*`÷§}AÚ(*¼£t).u?d/11•@‰ ذ-ÌÄ·K‘p/H0Ý*hYÔ;¤#¬jº:˜IFt‚ dȹJ8½ÑXX^•¤‚¨t½Ükx˜9CeB1œ@‡rOAZòW; )§Ý_1Ýòò<ßäàÓs‹˜i{-Û<2`—q®4EpÓ"B¬ÃIÃ&Ë P™¬ë®5ÅjÒ‹ŠÌN®vùÑ}Çý8 ¢zöàHQÀ"Ý~’øQ×È¡±¯´éèõ|!ØX,Ù›už.ÊR¿Ž€uÛ_Q"ÞVË¥5àÍáÓ3}ÓZ‘Gj’{è°­œ‹²Eú½[ÒçV[ÐË û–¡_V˜À†­ ýBÝXÓÜbrÕШªöã8ƒ’+ÉûP%¦´e_)mÕ"Òg¬C½D¥$n_î30óíÑ_Ê¿ÄÝÜ`Š#ÅÉZàVPQë#gì¢PV ëÉ*~.KQbˆa«‡0yŸHÈøzdKìs›ÍÒ‡ý8!H FÛ+V2‰*K-£@à¿_NïÙœ%Vl@Z³™Õ åcꕤ%aPÆî 9ëEKBñDñÍ`Aë,l07˜ðá+ˆ[|dœ¨'}B¦Q86åÕ‚*Z–pàÆ¦¼¯€YÃÅÅ~æCJéÝÁžÍMÄêÒªï '·À¸VéGBG0,\#îS‡I”7§ v´11ŸÖ«M'`ôC£3áÈ!“ â,©·œ›sì0šÔ‚»Ò î!$+"vâèÁ0Wu@U°c‡ñ´Õc…ŠèbQ.]>†Å Ðü(%²¥jð ៰ ï‡É;#àqðÅ–j 4]Ô1ÀÁeé‰ú$“6æIZSÐR™¤”$Ø *+@ú3ߣ[øâ£ÃZÃÛʱDTh}kª*$3ìCðL UÈ{[PØäkC£ z=¬1(6l£…VGÚCùìç-áˆí-y²án«&[ À{X“r(ٛʫ-JœG^1¬å¸zeù2‡¼Ö9Ø¢Ãs%£ÍH§1—8Oƒ‚…êIll0ß}7©o '´òù˜ûZî‘´Š›4g™nÒbm|@-þKñ½‰¥‡é†±]ˆŸ |qêÛE‚-ꈷõC› n±…E G›®G2¥ËQ0Ìì°9eì•ß°E˜ûeÎPž­*ìÿÜs†]&iŒ @ÍT*e8LÚÉãP¦†˜œ,W‡ÛDà†y‡˜˜n†ÆWfqæ• .A‘fÚ¿{ÒþÄÍ9yB¢kñHj¨ÿR£­BO„–lÃ9½L)ëyÓÌ¿Ý(ª‰ÑêË«NS?+]5Y}í¥™µîõGK7s¤> IŸÙ*wÒ Ev˜Ëªë¡ ÇPáu°ð±rÒÌup;Zq’êpN®ð›"<<”(‰]:ly`\Ær&]®Gà Ò=¢ž¡Œ´ kÛÂö–MÄH˜ü-U©å2X˜],ø¯ÙÒØ’|ävÚ‹f/K÷5ƒrîÅ´”Ö¼^ ˆõ.AºV>ç©•t×íàY„œhñ)Äf bà<؆áʃøuFNH–í=¤§Þ‘ 5Û¸¿T9èúœdP…Ôà"ç;½NßÚ"ž£x°F@ålÞ”<8®G€ê1ʦ†ÑP‰¤†¿Í.^ï&GÍ ê¤ bk  X²a—ôê¦p ã’ž ”C­Å}Åg<¦zJî¡xÇR˜È|ØïÍËRƒ1+õàå4×4Ú‚ Úqýî ´ÐGŠ·Á*ŠG `èÀ—§¡ƒ8´´ô¸oiâª#‚Í‹ür_°$Ügø>)k7Ñ ÓjÃ'È0]ÒËÛGÐ1¶r\UÏD ‰›x7_:¢0ç2[ù`Ùªsníz®/’¢wË’·[tÕ$)5‚‚­'‹-× ²´¦ Ü³t4p›†°£¤áDFÕ%a € Ã}õê7¸æ’[¶ÙÃPà°‰QέÄ|G¤ÑMÓh[ù€¡µŠSª5ÞõH¶CKÚZsž«Zï؈ ê²•ɀȭÍ …eáçÅ6`Šã£y|±R³ËhlYÛ%.]Õ ±iW¹Qšf©Í¾ï ¸-Ë,‹ÌàŒ%á>SÍ–”¤Ñ¶w%ÐH;æAÄ·ÔÄØ¹{{ +°\S¦.àÍ…›O¼|ìHÚQ-º>ƒ ÙOäéjrº‹JF*]‚v6‰˜Z©Õ«†õêÁV¹Ô!£Í'€ùšù¼“ì^nÛ†[Ú)±îf]¬úݦuóh½`òÒù‚@ì6äy ¦ÎÉ{éi6ÃUd–ٲ÷¦)÷IØ…6ØôÝ6Á8ײB…ÊÕlAûãA$ÎÌ R¹Î×Ï%x ¬ÝŠËQMi#—}Nî5¨¶ôò?¶Ë%Ë’¢[É tþˆõÔ8÷?mûw¬ñ.@2»¶3ÕiŠqgdŒ[+ÂrqòUç-19æÇ¢©é¹±g%ú]íz¤^¸7)~ÜÝ‚rD¿ S…N@‰³0$y:}¥ŸÏ¿òêà¬\çcq¯ 0›óã4H^áøèí; 4ì8y†,ç“àÃmG¯ûõãñþh·Ü¦˜±‰j_Þ¶Iêqx›¥ “ì§èî"n˜¥az¯­¥µéÑEuÍdIµ×œ“¼*æõª ¬‡â—N7êÈx #>rraUyúj19Ffz¼qnaÆð ¹¸@r¤J„#@àÙ—fcR(¹ HMOÂ%øÇÔÛ_JEè¬ÈmûÑ,äxü·<ÜÂìõãlY(!l§„âÍ·ŸG?Î$€@ûé|(>êŒÎoŸ{4ÛÉÆH{(²¼«€ddk•æúöÈûšë¼vÓy.×9ÿ-ˆ„nlfÅÝ[†!Æ"»Á0·çÁßAê—º™`iæÞ{ÓÚ ðÍyüb˜ƒiŽ£ÁB>¸*„w Âá3I›ü§(ƒ.]9v3t”¶Í\ÄfCØÂ}|Ë{²Ea2zâùÚÉØgä>ð§ïH=¼cÚçÇ;S†@»…­¨wpHn‚JðüÅþÄoUÁäÍXOyB=û¯gwyÁœæ³óeLÁè ì>L±^,§^­~&œJvž:¤JÉ4Í ÷¹—h­©×~jÃcåìbŠÏ¬÷êXó©™Éö2Ìcsh Ü‹ñ%µpŠ=ÑÜÍq_2d”°-~¨tô9D‹h¹ ©"ù»ø”Ç©êr}¸çÆœ¸¼ª¡Õ0bN÷/­6JzI0¤rqptª%\V”w‡ùiõ²¦ŽN»Ÿô6ÌÞç|L$χoÔ•±IPï›F0­ÞUšlgÙ|4ý²ü³ š‹l!6/¢V‘Q) üéAqbGØg7ãCfK‘S½û\ê"îkÍx®DP<}ÍèÆ„Ú5t—ãƒÓ—Fèq¾­‰Èø6Ûº$Ì“6 GÄ}âòdÔ'ä¡L7æ2þVñ{ôæ ȇuön¿ÃH\.E ô)s=tÌŠ.ÚUâ*صú8 Ž^¡ j64̧LÓÁJ záüÓ!]³ëÕQþï*øJþÞ{hxÎYøàÛ}@“;g2S¥ÑÉ„æ4<Ȫ8 Lá)j¾å–røŠV( oÀ9å³J(R…ß÷›ç´vÏ´7nwÉäÝÉ‹ív^ q7\|t|³ò£\œàÔ#:¦}£~늞\„l~¦|ü³Šô3ºJSŽ~)J4JÈbNù®::î¢9å°åZ8Dëéqç M&-‡ã8½8ª!fóÔž x1sï;¤¨wé÷w~?âzaÞÞò”¢ÇÚÊ Õÿ€?;êuVê é>­ Ôå¬xê2ÇÎIÍ‹ÛéÖ’¸‚ׄÑ]}b‚(:ú‘[b³„ËÃ"n{^úŒñ7Tû9‹„¡ŽºãÇF¬P‘8ÙŠê…K¹_b‰Ú²˜½iÔ)ë¡·$OÖ+98{XX+-K§9xõ^®k#K®-ÁÑ&wåNøÀ»îøÒæò98©É=‚±;nmõ!m9lIC>ébø]Ð’µè±PD méÊÇÕ^ÙþA˜Õ…e¦HKóa7*jà´—…ÞŽD=”w–¨„Æ“r–pÙ‚Iîniè‡éE¼ ^iǽÊ0Þ½í€1cFw÷ví˜<~ø)‘j…ª1g:lcïÐ*m*§±×sÈ)wP'M˜Ö8ÕEÕ`ælüíbñÞUà~šç"<ÌÍ2p]3“ɦ cWì•tI®Z zsÊgÒ4¸µê°ÁîÏó aËöùnðDy )X,ŽvÆ·F•á ý{ßÙ†ëhiWBZÐu¢’FÕúŸ’žÉ‹¼c}@²"ÏŒÿÒ`¸¼B‹ú(îDÎmG¥½/ßè*Ý"Œ‹Üûø‹>~eMN>ÖÃV#ÿø2;§öÜtܤ½×d©cd‚ÍŸk2׎ùÍ›Ð6›Ú¹ÊTˆâYýoºÁïû“ ÑûHq×—ßC™±Ž©SîÇÖ /!Ñö»%âC»ïÑ7›÷ÄYâ0rGÓ×0DGO±‹¥.$‘ú©näi˜b&Æþ½Þ^p7vÇ}U«âP´2[&bÐÌ,PÑõÏä§‹x(³¹vm'_ks¬_’ʃÿÄ”¿¢=I1YŽW.¨O‹,q+ž##ªÃ‘Þ9{hñ¦WÀgÚ\ºX ›q,Œ2²< ¢Ü˜¬ÊÝC‚/þ‹k±UCixñUF:ûë:m¼¼[Ü6†q÷Ó³­q‹|-ÚÌ“£¸…×I$ˆóIžðÇRõføQ£yçÉ!ECFžøäŒä é<aMúÄé9ñ1*ä¦Zf’AeiTxu9/+Ÿâx}-?°à»H|;Émœk3íèVÚ1~[<XÄEô_?â^Þ[>¸äé„b ïµPÝXºWPÌín>Öñ}=úu޲VÂÌš_ZÅ]”›säš¿/ÅF8>A£ö¼‰WÑU¨u2øÁ¡ì@D­JÌôÙ!«"ZW’.ˆŒÙ~öZ],ÿRSà>`#Ý;«W¹÷¬þ gµ\LZCaTô&[’«„Z |Ïð ij&Æã•aµî‹jû0»Hlév˜õ{@üÕÜ5î0€QC!$vÆ¡ØÞIKª=œ{‰êjøý>ÀÔFÓ± Ä}p_R³é0SIŽ[5£]áCÙ{D8h¯zÀ8fåí1#ÁR·µ}-÷ ݲ –Kí¬/âA('Ø„|¶ç-=¬ò0;ÂöË‹8`XWg¨æ‚§+¸׌‡ûœw ™–㌈ƒ7)ÍœTrÕME‘t @ÙŽ>|‚‰Î‰c>Ä5ÏÏÓALr@ æ"*ÿ¸­3;§Òq³÷Q36öÚõ?åA¿ï E”FU—بlsÖìv˜l9ÍdcoçSâÉ!Eyg™® N`“·K›~ó-¯xKóVܧQ%s„Yi%]£•ßT‰ÆzæªþÝÞõ{rn/º>¶óºàάÛBԌً‘ÃÛäŒm2(=Í,Ã¥Åwx¨}7:×9HV·Y¨œmImoÆT`¶#>~ë™%>-üýR- Á2IŸÊeý¡Çp]¥E3|8|šìôìÝQ‡ÿbÀ¸!C1}鏿ºiîÚºÖ-ÂÌpÛ…îMˆ>52ÉŒýˆx £9ö¡]ûi0Ò£Ý^¿“æÊ–‰^{POƒúòµÀ>èÓÑtS•3(,]œ I¤à3&nÒœO\^Ÿ•O Ð%l¡»5Îàø¤—–È,uG—ó'Èø+3ãË™¼ÍÙÿƒÁ”ý#Râú˜B€$ҒؘÊlŸ—̈ÊÀØ:Œaæÿd—K’Ý0 ¯¤¿ìód=÷ߦR¶'Ù½R½’% šf=ß§¯ÌCiN«ëò؃ ì,‚Ÿdôu¨¼I¿Ehåñ(kqAÎkìÀ`•ÉXÕáõøÄãõH9÷›é•b ‚‹­e‡áØ~¬ã>Å6R«jlBî3´«Åý,b7… Û¯êoS_Ó4£ã9M¨ôŽ!Ån/JãÒµ†UïñŠ ?"öÝŽë ®•%ÔðÃ÷ÐÖöÃPk<ßA…ŒPµ«¸æDijël;âHZ×Êzò½ëwjü3žxoé{ì,ÝC ‚+G•æ°ò8­ŽŒ`Vô@Ÿ'5”˜™|Þ¶§“Œ KݨÅÓ£»ÂHô-Ý©êGÕÓÃLʯZVıXÒ-*ßF'·cÿóO7º"×Ô%€’i§­‘O‰%ÊÑ…Á-°!Y(ÕÊ ó¬ý®¾¤¦µ70;üª ÛFÒšb‘ȼ^T¸‡™„½´¡2”E¨2LØwÔb ¼µíÝÊÐ7‘Ñ4¦Þ)™HX8&'§çg<ÙX‡Ð["ýRô8îôF ý=,Ëßø¯š¬wØÁ`ž Àn-®8œ)´ –oKÍo¦”Äcý’³¹9wk–Äó|H”[4¹j¤¡o¼wÕÕcÞÀEôΞɧùt9ÊtAò¾F ™Õa¥ûèbûÄO²‚èï€ÄŸW€LÍ™Bz:O]ÁŤ-£j:뇴üŽ-²Û{jòó$JÝ9±9ûd•4“J³µÄî6kzû–OÏ2*̰ý‚jêϯ»ÚÚ¯þLºÓÝ?Ö®RÞúÎCq4M‹=Ρ 2BF%‰>ù¯* O endstream endobj 17 0 obj <>stream H‰lWK’%7Û;Âw¨ 8CâOÒzŽ0GèuÝk€dæËj÷ÆÑæS1ùAp× Y_[÷¼¶Éþúßßýÿï¿þY'â²u?ùºbÌøúN»Ïkì8°‡^j±¾`´sM£Æ5ÄÆ—›Òƒ®Kç¶?:×Üçë:Zv»†K:÷s° £MD²Êy\gYÐ8.Ù./çpŠåÈ¥cìvŽxÆtü‰ì}©Î™‘ïëœí|<.$'i\—œÅǸÖüú•oާ1iÝ×ŒÈØô2åŸëDŽðÜߌmžËG¼«º/óLpÌk!wâ~íaH|‰¦Ÿ} A?ŠÇÛ“N”Î>ÎÑšÐÍnN8 ªœ›\g.ÙaTE5ƪȇŸLGÆœ|)tê:®ÊVâÅöÕUŠ%§ú2ÌNÆl¨¢²Hzð3¢)°ÛQ)ûŒÝo§+›í¥]ј«ʉw~~!N†,üø’0í@3ÿª¤]†—ñ®¨ÙµÑ IÔ¶[ËRJB¾æñß"ñÇ­Çå;{¢‚–}p·ç@¶ˆS” _üNûD$š¸]•f‘¯ØY~TA •¡q_[4³bþ•îŠL5ˆæc”Góstœr€üö‘jÉZHÿŽnltkgc€þ]¼=€·ˆÁ?Á¨»ÓÏ@}#ýÅWŽ~ýȾ&;_Ñ!jüF,´Ü´òÄ+½0Ÿ*–޳fq‡+þõ„w03`þÄqß»‹‡H†'nŠ`3Ó S7Ó¸/(ç@ìS\f{Voáy££ùxk=ŒJšê˜÷’2„_‰p˜Ñ¨OõPɹ=~ͳ¥«‡JœI2Î3zB? ¸¿§qÂÃ0Ô+4V‡·ìÂÿ ç&D¬åc ¹»Ñ8Y—éi×I–n}|G{Žç)fªàPœX‡pBuE²1c£ º2bG‹NFŒ—kï4vA;8$œ´Ÿ±¡Ÿ> F:8á;ccÉõ60 ëÝY2yΖ‡S^Ña’ÆÌ@0IGÀ0Š1:Ç ‚Ò¹`ü,£›d‘ùʃ(kö^íÜ8±‘µ"îW„겪êì¾`a¬iä¿î™ú™ÕNꢅ—­LÃ0LÛ(Á©ýCî€Ç!l€5lHå®BT‹‚ã-{ÀöOf) .áV.£˜0à-ç¼R2°0ùv¨ap¿oûšè ¾©×>'³Ä’4Ï5ç$‹N<æf äUG':q2 5`ÿLµŒÈNù1ÔE½ê‰94ÈsÉúxðŽ „6’®hL6ÏÇHìv»ÖiÎÍô¤G°Då=ÑýNe_ggrüÍ8ÆîUÆLr1ÃÆ$‚_Eî=t5™Q…pµÜ©Ð èå)c`½ÒˆÑ^aù2J‹”‡ÅµtvÕ}¥ˆÀ˜H=ÅpÔ&Ý£¸¦SáÉ cãÁÍĤǚÚk Ìr€‡ú `”ûÄCpJPIøéhãdã~s@‡g|Ë5¸³“Ñh­¦–)–‰,ˆ¿[»€eÝX pàÀ2¹7$›6ùDØd’˜¾e 祿ń¢‹Ô‚’]?”¾cB®ƒ`C ûV?ÄÔŠ¨°• Ô¶#›BêÔjŠ3(® 9>_¹÷á'%T\€Çþ¨Ÿá9ÿÄ5ËJo?­·º°Ð<’¹ëPä¨Ñ¹ ÒLè*ÏÁ^ný´'ÉDå#”Â1uy›bóv&ô@ö,}ÂÓÀùѳÍÚO«[<ƈI×Jé)ÀN—8«Åod.à:kÍç­ùH,É®šòSüëˆn³4¥Æ¨ÇÊíÁÇËv—y{pû‡:›#µuVè­ÎV¤lÀ´ÓÈ'•P^9{UÒ5R§Bþ z'8o Zßǽ§³<9Š.´F¤ªR¬D¨•WxšƒäŠéï[ÕÏÁM¼yë`‹”¶,nƒÛtœ? Ómw]1€ØÁ·ðÆZÍ…éAÁ:V_.~Ö*=²¤ÇŒÔôðÞ¤`R{É(뀷ZÞ<±´8T+ÉŒz3ã¯û‚’é;ÿ9}DÔFMc7üsR᫃Bûàڥ°Hx~T‚›GŒdâÆ£É0G8S™¹z“€ ‡FL ¥M“)´9Q„T’­û±¥$ +ÑtRP²VþnmPV&(Qp·å)K]ånæÊkeÌSåÇå„Ôý¼aͫѲ®d/¾NÕÌê9©±¿h‰` ¢Œ«@ž`úu_-)$3¡ÆœŠD÷ò}öØ£üß¾KøÁõ‘x`,Oy åwdœî/rLBy_ƒÏíéHÚ¸£óÞ)xŸc7¥ëì ÚAJv£ÅûÇ6.òý©¹lºG;ùô@È7Ÿ2˪ó†0±rBrÎY2òé† ì)¶K¾ïO~3i[dD}x‘jQÀ—ÂßB¿§ÂÔÄóÖè×M*õyj86§¿d:t÷b•¿Ž8¾T~jÏ*¡ àõµ ã¢Gù±:ЉWn¤¬Äð~ExPqçeñ( lÞˆk–Ù­6„ãMZ‹•Fò"¶b!Wöã\ Kœ1›}Æ}1`Ó, øsäÖàÖGàÔŽfyì[si~ vÙ“:ðÖZ´¼zkCL§Päçfë+¼ ±¼ УåïðëiÏOß·}íÌ]@Cb),±²IdFÌöÉk ) ·fIS(ô¾¡xThæGÕžpä­Á—ÐôºN~‹.;0õdñÐ>"þÑokŒ, ÖÇë&xpBY'™{?â0SEÌ7ÜðjuýÔ_Qâ"?†5ºÚØE*O¿)eñþ­[òX!Ò'Òs¨Œò”È5;/‘F$z•HJôwz$àÓÁÝŠ‚2s笈tZ9ã’­; „ ,^[ç³H0¶OG® `ðº¥,¡óT`¥Zg®á§1ay*Cžf7SXzVopT-zSZI×ïðýldòͧä¡Q5Á0¶Ä n}—òs+7èk®Å¼áÓ^›.kcAÙõïÛ¾,± bPëM êl¶x6Kòª¥,üðE\´¯]GÝ—Æy¨ûŽaB|ÞKî­xFé¡[.ÖÒ>õáZ[ƒDœF´ù|Ö’~Ü’«+ÅË5Ï}@›F¼ ÷¨{lz„üHxž2½™Œ•«¤óMc*ªRsªµø¨¸t@ekIH€SÅ+:èTœr4Z­ö2bSY-9åú‘ð srÅÊG½wdÁ†[…B#K7¬0x{§âþæõn9A” 2*p'f²õ–óD,#–J¹þ>|HÚW1~&ZFúªv dó¤m¹öÁ&òHºão‘ƒœhÆ53íçÄzJµ6°N^kApûGºç•¿þ¹Mžs7„l)úx6ÊK\³K“¤FÏ2(­Ò7­¬²ð—©—kl¸¶Ê5 ”Y4(xlr- äyž#U£½#oTÔhAûÿËv¹¬Úuaxnð;ìI@† õý’Œd2ñ,8„x„bŒ’A9äíóýUÕkí{bä:½{U×å¿øz”5\/ÿVû—þj«güqºuÐ!‡Ì/]ÅsÖbAñt¾êÚV—»år´))‚ lqÛI÷z–9Ý»íŒ"Û!v DS6vwŸ¾”LäZ¸.v•‘Äí,ÿš‰åËTìí¥máa¤å§7ª½õ¦òW×oô¸ïOâðv’GÕzfpçQ»ükº¹)ìç\Ý%ôQ_Ð}Á•ø>¤u±¨ÄÍ,a@ö½“+´¨Œ£w°Ìæò~« ¡‹ducüæq‹ÄéU±n7F©zOØ>lÈq†)Rg Š#7>dÊ€(º„†‡c¢=v”9+oZ|§™éšë혊©±¢I•úpJ3ëJp»Sóæµf£ÂänŠÇpìó—ëuÄ©W‘”ÒëLGë´2†%Äì!Êë†{äxbv¾:Ô^X‚çÐÖ %D±Þ–lÀè¶Y„Œ¨²m¢Ã7L-¦Ðvº1uÚ}ˆ­(&0œBM RÖf *1»¢ÄóºÝXåm9@m„Dµ®Ù·d¦–Ï4n{"ª¸u+mȳEúX15zð65"?vD‡™H“`EZ{& âÐH̓›äC¶R»f5•´ 4§[ËD¿&dt4Ü«ÁåÑø„þ”]aì’.³1çQÕ0Þ¶oÒà‘›%‚E\yµèb­¡ù\)Œ<áuõ%·-¿´¯u¡€Kü_L*o—ÖXŽb8Ø¢9ÏcØ”!Ømbaä_— u—¦ÎÕÆT2Ù ‰éëô}[«=[©vz.Äïh†ÈŽáÛ~Orm«D²kBëÀì.›Ð¾îþT¢ÚÚ¼/¯Þ|ôT¿›y2жú5íÝ‘©LîP fÔ‚-4¯i£žÓ?×7ªÖ˼ e ØiP¶j;™D~C½ˆZ5±Cw÷dD Ã’vƒD÷JÛ‹WE×û4N}-Døçóîa.HHƾÛôQÇ’¬‹5…ñår).Ê×忉JdØS?—WÁK¶a!Ê6ËIÐüîbO™÷aÏ‘–Ð#r—tr¼=…‹a<hmÒ1¶#ç‡[Ê5­ \jÖÔ/W¹m ¤øsÔN òÚ%wM ²¨ã,ìóºÍkÌé$`rÞFáðœ>þ] ]‡íŸÍŒBi‘[rp,¡á"·}(ªÓÈyLÜ©<*ïèÄìÐ}½³“Ž0¹nx§JE[åØ$¸Ñä¨gwÜ–xЭN2<#²1Åéø0;Œë’;Ü;Þ7$‰  µ¬UÜ 38VuŒ®ÓΑkÎíPó@¼Zó3ý} ÿ=äÀ0}™½<2p7èPÎî@¢rÎ uÖ5õTilK%BÁ–¢¤ùIΚw,mçïÜý-EôÅw{ø¦ÅddÛ| €Ø¸›pÄì³Rò7>EBÖg×[8z{5 À¤ÅK,®HO}}Ý•›bቜJ÷¬g²k¶é•h«A‡_0‹Kð°÷ÌlgLK°å}ÐhɃ•à›ÔJÜÝŠ 9iÁ~’àá-„üÊ ,*Æ¥µz±$%·/æ mfr§åçáq™-ëIìûÔîž¶ ­jϯ§–.$ü˫җ3x‡»tnW [ººo÷ÞÎãf_òrþÚÒ´>æŒÀÚg¤¡Ç9F¼%eÛ%Q2ƒ· [Ë9 Äd¹Ýx™ÅÆ¥ôÿOrpÐãÈS† •“¢µ6rÎYc•žô‰O0íЋ7-;»Ýl¡˜W.ÒÖÙ×tÖóˆïmEE÷6´¾Ý’Oˆ"\{EW{²âù Š¿ËOñº«Vñ>h™ 9qÙ¦mk1вq½–e¥ßÓaVÄì_ªÓç Ø«VþÙB¶Û$¢+–ŸD@Þk¯ç4ʤ̩m9‹•aJ[Ñ ªÓ-V]&*ˆ›6ŽØ‹Šô;ч¶‡˜ƒ…—[:,® ¬ám«’Ÿk> Ç]W®kám8`o}t1YyzoÇÑu }î«D°e£]VªÜg:P/ÉÌ×–¬l+Æ‹Bëtm"c9±jÙƒåI`>'Þ5ô!57TL¦SÔüËËᜇ¿Ò¶ÝƒÀ1ïÀè1&-¨߬h—²Ì$ ŽQÕZdg˧x; ú«Tõ¸ížíE5À‘Æ:›•å*ä@°!ì^ó62ZbÓYü\ä•ì!üÆ1zK&&–+²ÌòL°}ÚazÒ£á<Ä_Í fgïôXpnáOŸš¦¨/¶¨(ÛCF;õfɵ‹ƒ4`¹#WíÙýZ$W¥Ìu8@±õH.›“ª²‡¦-|¯´ÉUÆöyš;º‘å*êøÞµ°W7n~À)!Ë)­–çy7ÕÆj±Lɽ¶'º5éZõ»g;— z»€›x>Q‰0úY_”ÂÈ%Ü V7`Çè¾,‘£øê® XéT&!¤¯lÔžö}é‹ùD§7šÞÇd X/¬¡/šš<Tè^”0¡ë©u ©Õä­˜‡£žV |EJ:ñî..wÞºI”~“Ù ÄïÇE5(­9—ÕÝ:rŽÃìÚðó–šlg*¸‘÷OÏ“DÍö<oóËϧ۾(M ¾ˆ>o{²æl悱‰Ñ8ÈIHùÝøç»÷__þòéã˧_¿|øúßÇŸ{#/·ïïþöòõÓ—_o¾ÿþýÇÿùüã¯/tö»ÇuòÏú¿³¹ë­]ú|* ñ²¥ƒ’ާú”6ø·»Î#¼Ui´ul%#Þ»E(íµ‚ãÝi¨+Ìä cо²— ŒÑ“{(A M°#åëÙI¸e/à¼tÊìÛa°e×fÜÐzÍ'Ø{0}3Û‰û0ÉHuª³øÐ\òØfQcw{V)Þ\}žV_—¹Ñœ[ß«¡OC~°oQ¹î5AxxUU. == òE‡MÔ»=Ãy¯LïÚØ0õSvºáÌ\viaägG_sa7Ÿ/)òNå ³¯ôŠéH£!†«–# ª Æ2é’MÙEÀ”Õåæ Ê ‚®z únãŽBcÝ ù¹C«ò»fŸ[’[Ý{Â? ø+šT+ôÄdëh¾(MôùH—iâ¸"ŽƒWT<Æv9!Ödˆ¬`¨ eäVo}7A}e'e3Cl™ Æ,®V¯ú7™3ªñT»}jmR»žì˜äY¢J5AY£eTÆT9J+µëƒ²X2­žîvìa*d\GD¦B"B]¨1Ì¥iah&5?IOñOµ aõùÈ‹è·$“‹L¼ JeûÙÞ½pM#“CV×÷­íò0T5·nl´(Õ¶J ßkÁÇSvœ,åI<±ÃØ? c²–‹©wTls‰>¤iÄFnÛcæ…ÜCzŽÐv¬ù^ãér’™­ÝŠ7ºÂÛtΔ>NΟ‡KëÎìÒàî+Û4Úó6ó§RÝWÀuî§–•U:ÝÒñÍ d‡ætÔñ“fvÌÌ uÿãI/™ô(bž:Žffeuxai­ –‚èOOë¢în{ºÀfŽ;;0¹¹µ(ºfºYco—QªV`eY nЫq÷ß¿ý&=Òã§}ûÍx¼ùîñÓ?,öûÊ!?Þýðååñæý¹þõÃËËÏ_¿üøó/Ÿþýò?º«­UÏ«ßò¾¡½0®óáÒ„*HDðÛ¤ ÍNJ5Ôü{ŸÃ¬÷Û1-MC2Y{½3³fžÃ÷R üðÝëPåÓ“_þ÷»wßÿçÑ™tûųwïÞ||èí?¾zóú×ïÿùêõ¿?!ûd÷3Oÿòí«?|xøêÝ›x†DÞžÐç2¯oÏÞ¼xýÅ“tû%‹|ùÓÏÞëWºý¿qoôŸø Û—nßòò-é¿—ø·ßàOÿBì‡[»ýöö׿¥Û+Üöò÷"8j²iëàúJŠidx¯ÅA"}y¨SI6~.8².ÞäqZ±A@ô~ž£ÏÂLâ¤.-“öûìñd—.­ˆ’ì­¥+˜{)³Êìí=äÑ8±’Ïñóô\“•Aûï b…‹­øl›–MºUPD™÷,¼èu€8fR •FÔÂEךÚEŽÇ”ÏY2EÆK­ý Mb]ˆ–÷å ž±†ÔÙW=÷èÓ°Ö@Ÿx·Ž#{î„î5tM·:ÇáøÚ®–„¹Kó܇Š×áນôíh‚X·í©—6B:/z)³…ÎÕõ0jpeÅ|¢|õà{û9ˈÇF0`]tž”Ì ®’ Œ)£ö˜šJ-4b ,T þYjÇ£g‹ZH"Tלö"졸¦pdmX*ÓÎ^1è=±å…°‹^ð‰~¥U´HGK»¡pМ>Q_4Œ§añNy’’ ²š´‡ð3£F£”žÀKîð´–3ÇžÂ]Ô»­kô«B½bˆØLã˜N”ðâŒ÷ï,ÔPö,ÔíTH‚Ê%•Ȭ’I•.$y˜Š ïÊC _*’-UîÙPüÔ,^Û¡=ÿ‰–!¯oÜL¾?öjU‹gÔ*‡õh”ÝqÉ=ú«\ÅòWEOIÒÖ®~|ØÐ3; g!‘Yí%ª¤vÃå°3ø±B‡¤à‚nŒ„rê銭ÍìswüX¿Ê†9HG3v¤0l'ß~°˜I\]ZP+ë­£ k©Pæ±lS²ÁÀŠÜ>mÚ§íűDÓÖ¥uGõ8§D”JÝ2Å%Ì ³Ï­„A§67¥†A#‘ B2 Ñѵõ›‰yÊyJ{¸ûÓÓŒov˜ƒÚøµV‹D”°)Å$#=¼CSFiS #»Žg%Ÿ$öPžÌçA/äš >RõFÐ ߉¬iä¡1±ûQvPòcg_.…üpⱞk9;Ä ¡³$/>nøîuPÁÔ/êÑ@ºÑH)µCµµh&лPq$å1„%xœ£çä:ÅË”|Uþ&q¤“FƧr²›´©¢K\Q³ºŒÃ¼º_޼eóÚÈ;21Ù1¸ííXàR!:¹Æa÷̹OqC²¾Èxü$ ¼p¦D×욨øF»È/en.<ô⥠”%Ñ ì±ïF/)ÚYî jY0% žT1.­d,÷…KB˜Ïvï r΃€»a/Ì7åbEŸâƒ;@p‹áù¹`}À!ì’bX¬¼Oqø±Õrðå,žŸI4jZ?7§dNvj+ß0ã%%ÂɸÎ`€Ò³9+´q¶a †¢›÷ê:X{ïãª"@—Öç\3¶yÁÍ)EÀiÌW]ÐB†Hî‚nrW%c˜.L2½¸™èýpƒ:’…¶Ž‹{@]pˆnœðÞm·Y¢Ÿ9‚,•—ÞóS.ÚïLh _¥*2wŒ¤|'þ™¸î`2˜í»âò„È–:ð`1ž± ‹9-Š`Ã$RаŠç¼÷¸M+ q;ôðé1¤O :0𛋶$_÷#%ж&¹„„ YŽ¶âƒ a!¿áhÔú7äy@J²2T@žë âe¯e1Q“Å/‚)òþnsþ§EÜë»Ô .‘¡x8ñh?ŠªÅà„{v“ÀÌw€“ãš•Ùæ‘¯/æy î¥à[XˆZ¸ª?šÂ}ÂÛÁ&î8@õL8ä‚9в"D](±ÅB7›qT=ršTV±¿‹†Vr• W[Œ'6G00û§|!pû˜Æ{f!2…oO+v2°Y{=ÿI«’Ó¼¯Ø6¸Q»!ØJ EP›µ‚ɲ–2“~=Œ@Sz%dêÙÚh3ùaÍËÞ=\À1½’P1ÅÚUÚtßg à*ÙÍ‘«_šö1Ç­+V’þèí2dýñEýP!©R2ü4@¶–:yÑ)UQ•н•{}ò›bo<)õšÎr5oÖr‰ËƒˆHuË5¨Ð…=j¬K³÷ª·Êýî£.C J ÊC} "º|uX#ÏÅøôлΡKñ0ÕÀ E s»_ÒÃÒJqiG*à‚4Ý´âyÿ¹­«ÙŸ®‡CqïpßÉ‘ÚûÅx´>õMª^bŽ¿8d>9³2 R’ì3àez*óè Ä¡„ÕŒu@dJ‰šÑ@­?µá¿moBºœæ “†%¼¶9-"°ìáD‡M‰T®tpC#ö$[^N´¾ÆSèˆö%„ôVÿÐÎMH´PüV)ÊÒ¨ÎmÆSÔÇ XTˆ—|ø^EõCÝ ÄE]b©•t0»Ó³Ó;–’†6µÜå,pÔà “bÁø´O7غ\|˜ûçkËQ_ĬLðtviÝÊÈÉøc?u!‰¾@ÔêSõ-àWz¿“"(Y‰œ×y³‡ƒqKp„šÔ^åŽ÷z¬Ä|ñ4êq‡¿õ¤³ó¾ ÉAÄ©MrÓà Ÿ3«Àf<ò^ƒªžÊ§V.šµ%0½dgÄ,F4²J¨ÕJ'XOƒQÆ„ŸÃã·È×nÂ…«¿mYŠ£¾Û>ý…þ˜BÞZ‚†ÜœáM_ùñ ½ U§ä ÄÍ¥ôuƒ£³@ÔJ>ÈeÍçç']çn®LØoµÙå ,Õ‰r6õíZåèüÂï¯Gëñú P<™ªz©ÇܽrQäœÕVí Y%äQîk×½»ùÐ `E^VÃ6ÊQ¡˜˜îÅŒï ~< wwÒY¾8ØDdÉhlGÀt•^¡M+!ö€œcÚš¢E¹^܄ǯö‹è4{\ ºiuF|`C¯ðTÑe7w(ò dQñ›“›c`g*¸½®V6p\¼Æ·z~ôØK•K¿8ÀR%$Ù&%î†æ›:—P+JšÍ—¹!k4Ÿý¬S§ê1ôÉMâtxKµ!XÁç?1Èí›'ŸýéÉgûöù·—9”ÀpYgÓ•ã²Ð. náÿB,nÀ¡U3J]Ðçï³SKG×2»7âqqä"r¹2@j¦eCp<ÍÐa?e‘ÄóQÞØn¬á¶_¼ˆ˜¶õö’¡Õ*ÝMÊv1+rê ¼eË¡zqâ¥Ì8¯™¿â˜–î8üQ<ç{i ÃDåà„üùó!õŒ}œ¡De¶I}›“1 a9Ýi½ O†aÄû…yy‰Ö.EósÎÑdñOªf-Êm¶ÎØW¼˜¶aEž•8VÄÃM… þíô —î(PtœÁP|NÑ`j­(á+¼.Øpn Æx Mã;‹ƒB° R*Ù‚X»¡A^÷ÂKèM0¬^Z¢F„æYÀd¨&E_¡ ™Á…a>SXÜ#;ͪ„IÝÇ  Ž~ ˆdÁÒ6/dí2ÿˆws» „Ö«†œ÷à ²œZCk« d’>ÏúKà>Ö…4—a÷Z¶“Â+CÖ‘NÅeµI»‹ZTAÑ &jšQ”³ã'µH%i@N J\ }Iñ¨Ý ‘@ÉdôÓ¤|Ì& ðRA^ÍwYˆüÅ»˜ƒ_qƒ,ºJEHÛu­9ÅmF³TefIËgjžƒ™ã…¡.Cén sx$ÉÏáˆgï‡U×(O¦N) ™¯¶°A¨OÄ,€ »f•LUƒàš &=@T lƒœ†Á¶Ë1,óŒ2äùHÓan2¥㣆æõ²á-–¦Q¶U—‡Ã ¡•|àÚâ€a8üÅçÄ«EMsíq˜¡$GW8‚$Ù6P\ åÀìCƒ²œ Tí>%mÐur%(ØeoZR· ¹,ÏÑœQ7ÆQº1 ¥¸Þ¨©ÚÌå\䯖‚ˆ´!þ5¼o2˜hþz ÊPtkÙ¦˜íôKüI±€7VôÃÎÃ(z‘p¨ ;éb.*ëçF³­E”óPX0•Å`—•TXÆås€<çç¬ön®Çñ#lj"ü"ÃˇâáÙ{ŽÁß¾0¿x«a»¥#¬^ŸÇ9b‡6«/§‰`‡Ý9Ç|v8qÂãIÚ}PjX¶øqŽÓ ,Ö“,¸É >:¼]m¥=ëƒJ6ÐiÖç¡ñíã5*q#˜zL= Ö¡nÁKÏ0FK'‡±aY¸eŸv”Ö=ªÌyŽÓ‚¹»5y«Á‚«/øè°_í(íIV‹°Ý-J"öõyÛÚ öCJUCä¢Õ<®àbx…trE»îÓîƒRÃÊàñ¹¸`—–”:Ok°àÂ/xwx»Ú.íY¶ §K¢-εǫÁD\¢ ØŠaJmª£Qs.Ñ‚ˆí.~Y’·hæaaá„Qƒàq‹`R gÞÏl‡{ň…UQÜŠ:¸Ün!,È 9øCgp }.+eŸ÷A[ôÍOŸÝÝÿñíåýÛÛ›×wŸ¿gìÑŽg9>><}y÷öæçãçÏŸ]^~¼~q{ÿš‡~Ç£à?ÿŸóÀLmL#ÏÞ!™¯— ˜ÝâømšâoªNpU(p`ìH1NÎyÇ¡™K[¢i¸\ç×6w’Á=¶Ý¤-ƒ’in®áù±ª“Û–eYI+h{éI‰ÊJ`w ‹‹†FÕÌÉYàÃ×|€_g›Â9H†Lsë?lc™†AeZû0`£–ãŽ@T…R¬Ú¦YgJëïí,ä/…µ~ËGRÞ×H)—¥Ö$ƒ*(÷Vš}ÍÉ`^”eÙ¾vÂìÊÖ¸0ƒ©0XT‘…Ïå_jÂ×]û‚Ê5L©˜¿ÕgßRhá¤.¾4w;{[·>ç·që“cÐ.C¦ ³ Œ£¶ÿhS˜@½WáûÎõ5å&ˆÚ˪+XÐÂ/¡Bp—R!ºVN}5ú¸ ¿!Ô æ"» }vŒˆ 6'È{ŸJšir¶=øGƒ¢Ö¢×XãI†êˆŸs E¯×2XTXC¢FUàgÕD,««f‡:Še­ïУe˜ªª¸YŠvüqé‹]øºX£2;×bâ¹Ñð^{>Å Ïé ÁÙ†Mß°E¹XM=([n·äÝúJ ö‹Ý1P©) ;YÕ7ÜøsË0C4XZ>Ÿ‹Ý`Ée1몹ÒÏe¥x C dhÑ/‘R°`èJ«çmøíP’<çâô™ƒ?Á.ëÕͲa)¡Çl)›ZI1že4q `(*9w‡3ù­œ¤Ý‚VÃʰœɫ]Ú²yÉ­ .âÞ®¼ÒžõaS°¡­wÕhPBmƒ­’‡™Á4]z ®UvO»; ÍÞreL0ó7ÂÙf722‰¬…HPM¸£„†1‘hµUBž"(a’yß@e]´?!*%4ôu&kÚàœ¬þ ¼¾ÓP«píåuåõ„i)[y.aƒN ƒU}¬®ìÈ>µ¹wD†0G³Å*#”úb Mê'(ã€å]„;íz„•­aÈ­Q°+£JÐÆbµ\EË€áÄØçâ\·PÄç`݆?þÇ“*×2m·ÈIûЖï¬Ü ÙÐÄM‹Ž–S'Å ³ É>7òÖ4Ó7‰(¤ËÈ‚ÀxÊî^.…R†äÀSCÏ8ÜfÞjè_D»JÙ>XtÌÍÄiì¹ùqíg´Ã½¸øœ*u‘u¹¿äÛˆz¾ˆ÷؆=]Ö¤º9 dHÑžYÈß2D >sU'¡AQMW¤@ˆÜ´RÛ2”ºÖ°¼btsÀGpÑá#}ƒk¡ÅžÙI} ŸK«0¬{HúHIAp½hÀÞÔ³ï~ë‹hÄ¡M§¤ÒÔ¦4EÚ©‰u)ë†0TyI²nÁµÉ¬aº¡‘·»ð £ÅS+VC†QÑàäê*ìÖ‘Œõ;GÓ2`Öú(¦»êtÒ!¼Œž²âØÀ9U=JèÂ{S[±ƒÎ âmÔ¿Õå¾øÿ㦹fëûŠäx8…#äL¦h±ÝÀ~û|nÁ}kØQA‹þp¸…©|û™4Þ|ÅÃBâ¶CäÀQzLžÉ·šzÖQÁjþ,žæ æÖôS½mŒ¡ŠÙI´f=h‡G¯~ø—b_âñðôû›ûãgßÇü÷×÷÷Ww7/®~~ûáþN4ø?>¿¿2žÎO~÷ß÷·w÷»3áðôùíí»ãC7¯zwõ§oß\}8–ôÓ«ûÇÃßݼyùùú§ÛwxŽBn<ôè‡Ûw¿\=ÆuŸñ~¯>=|ðqs”jAý@8DûåÕgþögüôÄ>Êᯇý;Þ É+ˆ½'}®2¡,ËÁ¸Š}ò!‘!á!r xˆ>³i3p ,„øg9 «1Þð¨-gŽpžmH°Øþö¨S:¤T°}L|Žñdò¦Ap ¬at‹<™T“àPWݬzN.Ò$…R½! i܉û·ž•0ÆÉÍ([Dˆ•€ äÓÌÍïYà­§É t@iZ˜KƒóÐj± ƒ»BpÊÕ€–% #ÿ#¼ZZì<Žè~`þÃÝ$ˆ¤~VwÇ+Éq‚ ±…`Cbd ò„Éq5‚èßûœSÕ÷:h‘5=ýU×ã<(¬æ•n RUšnhÏ/¿š3î]mÔ(BY-2ÿ}.ƒRu¶‹c0n€’®Ô¢)BÏë„ dÝ)Öý[Ú.¿ê O`ºÐeîw‘C¦6äa|8OÛ˜y°^#»‹W`ŽÐ ƩߧÌÒ4½båq0¤ë[¨è¢ÖÕ ’®Ï-*J.!€óÒ Ð34c™šuÀD~C®ŽØˆ «-FSê¯Ä\áZŒ´·g²výœ„Ö¨Šz‹é˜ÒQŸÆŠHÊëäèYÅ1òHÙ9̆ÇM÷$=Å3÷d ÒÛT¡lmD/hÁLÂ\(Ξyã:²FŒk ­ß½ŽÜ.¿€ê¥k QÆÞ½b˜Ì‚NÄÙÕôÊ8¡. ¯ûº‘x¢ÌII#ºJÌW±ÄØPR×…ràî¸a°Åükݴ‹Ó?¼ï¨QÕ¦-T$•Þ|B€ô#n04–¤¨¸ Š‡›4=mä¢2` µ4—"qF K&Päªûp¶ÑýÉֲŵÁ ü¯7H«¢„–„‡ñÐ Ç7κųáe,®ˆãdîá"Ë& ù­dsﻪpìsOÍ–J%+Z“0Ehj_+¦Ù}Y.ìcWm§#€›¤Ÿ½%Ve±}V’(•0F=£S“U*Tó“¶ LieoAþ‡ü(}«…áˆGÔ]m7¢¸]ÊSGw½[­4¥ï›¹C€×™£MËÛ žb'ßÏ.³°§R‹àXª7ÖX8"ý3‹ÔÄnnsLóá×úùÉé„&•¼ÎJrÌ#„j‡Ž šB!Ýà2YT¯ÅÁ>®Ðሆ×q„ ¥\ì%ÝÞj!ð±r¥÷‹ò;qôB)ÅØ46¾dNŽ€…\¨-ŸÔ³ÚÓ¦;NÝP'"*ó¤A£XTÕ²<³fn0¤ážÏΡqƒ­•Û°íôÏÕèPJMƒN­†#hK‚(÷Ý7v%i|à ïuh¦§ÚÊ»ƒ4­¸Ä¶ê ³V•XÅ`¬á奓ÑDÌS:O$Ç¢ž®hn1Î`žR·ä™â¶l„ Dƒ¤\—2@µRk¢)®Ò”´rwÝ-‰ê#2Êšä›H:YnUsë^²åe«Æ¥› â9£ùæ6&ö’²¸-—Ø7}äHljeBº¾ª¦°Øáò9Âxé0}h¯Õóڷ⟖È~:Yʆ'èÃÑs½\ý0ýž(\®©KT“‰DE×y«+·IqBÂÝ@7Àâ)Šp•–/×íªÈi‹ò¤ #=H‘`:j4§ç%ÕÃ…ûµåµTQy¯¹Øƒ74ê¦åFReD •©*-ú öŠðJº4ù²ž<]HÑ!#jÕô¥oÁ?^_ýóúêo^¼<=þùî—Ç»‡ãÍéóáOŒåËo‡'/¿ÍõõÍããíéøÃíû»§žûÇç·OäÉòåÉoþûááôø»3éðâÕÃÃýÿ:Þ¼½¿ýë§»w·ãØWüãújž<=üüþƒãéÍ7Çw?~þÏÛ‡{:ÿÿ滇ãëÓÝññîøþÙ³ˆ¿B~Çßÿäúê»úÙôŸ½¾ÿ„?¿ûïÛ_¯¯ž¼|÷ðööðêôé㯇¿ßoÞßžߟÞÝžžþ¿ü§_ßÜÿÆ~Õí¶cá½.ÐwàÍ.l`cë×’Qä"N2ÅLšÆHÚi»¢ %ÚV-S%7“¾Ì¾ÈÜõÅö%Ê–;‰§ÙÆUíXäÇÃóÇïÆÑˆáÙ8 rè°²,ÔÏPòÃÏdÆ osü0ÆÁ¸vÁ”Í¥ ÞŠwW‹–2j¬Ô]Gz€”2@¡RH¦ 1WÀ=L)aµ)£DÎi–fÑ0C(ü(ã 4J׋?KÆ1içÚH`žf5àÿD„1<ž +Zy†@VUóc¹¶Â•<¥Š”á/&d<Ì ÿ dÂÇX¯î·.³OîmÃÓ…Gílìvgž;實aˆöìdkwÁhIS»âÿÎw.#Í76ŦÐÙ2ÔæŽööª÷àÙÚá}(ê4WO2†<mô–R<%aŽx©\‚Žm—Áo¬Ð»Á(r.TÑvN·âü¨Ï½B»R_·¾ÿEé¢êV©2W£D wª“ Å•.DN½F-kS:Vq67¡díÕyuƒîò Ì‰L…„gcAßå$òî›@ÁÂ)[¤Î]\Ò•sÅ«ì&&éógí3š\SñÆû±ÆMhµ_ƒ¼UjA·ö•óíãd:Kà\ÿÅà@±äxŒ#Š$D7…þíóïúeW&·,ëá4 ´5k’P8M[ÛèEqˆð|ˆúC¶pmH[:@D(`³ˆ¦D´ßDY,†-!*¾`WK&Òzç J²K$Щ…bö%„æ’ aªæ€¢µš·õØ¢H¶l¢U…³rI0ô³WŽ!’bÐ(g8Pƒª>Nâ„EßDó,&}Bƒ(]ÞŒ#Û·4 ’b Ù1B“(ÅøF¾*ùBÔÛY =ó ä‡nK_ä¹Þ¾(Ü!!… ‡S£ cg|yž¿èý û ~}AvË2M]#£Ÿ >À%Wþ†Ü¿à½èù3°«ÜH)$»ú>KxÃÏ£W¬> ¿ÌÓ ŽlV±àrò!ˆ“`r¥RÚ $B‰à®Ç,«Mµã„†ó([•šëóܹ%µ×gP:ºÎŸf+eW‚ªŽ|›’Ó¯„^„áj—¬7±ÞËF!a{#5ãJ k­€5§’`Îu‘“BD=ù!³kî pO€ ï9¼¬~ø¯e:.ï ÃóWsa]ZïipOƒ‹­= îipcô¼Ž AÇæüg]_РÝ]MƒÐ<º{&Ü3á£gB{Ï„{&Ü-Z¾ëû{2¼ ^¬wúd›.œ#÷„yoÂtaÞq·Å`嬷vÑö¹È÷¨ë‹¬°Ù9ÞIZ;ÉÁ‡b£JˆŸ¢£û9òáéÑìK’BsŒ X€ÎšÍÙãaܧqRþž‚p÷†Ò3½®òŠ "|å¶ë.¾|zÇõ Nª¸h<z!~`óýP…^ÞS/†Ã”dˆßT›Â mI£?Ä!úJXŒ#2 ´…£Yq‰Qq_BêM”ÅPƒå¨;n2Lå=®™ÆÑ´™ޏÙ}¡Ùl‹Ó»‹øoôÞ ÌšÞ˜›ÒxK)ø-D#†Ã.¯Èï4s„™Ë—ß½_ÛëíŒìeü2ÿöíãt²œbîàt8$“luøß^´Ñ¦Ù<ôŽ¡} Ž˜§wm“Ò;̾öÜR{b<¾ÁYFq Ú'çßÂËÐEBsصx‡èýؽ åž°d†®Æ8L®—9·šÚ«YwélÈ»«ÚóÞ^Kƒ˜I‡µ:EYŸá@Œ™Ê‰3I”­0Ð9ÈÒï%!ÄlRöM Ý@2)ÙUA¿NhŸÁ¸)äã=ªc§GjÓÈ øÓøØÇiJØ’ÐOÿpýO¦-ªL½$ñ Ÿ3—æØ÷¿¨6iè“Ç7¸œ3«s½Ï5]*sçxDh†ÕtËt9‚SiKÚr|C燦a ‡]ÁÏR{ô]%ñÐh—#aììPò~´[úBä"Ð-­(—£øöU˜í.ï c‹;Ë iQÈ­)l)q–îîCËÈQ ·Ü Ì]óª8Ï]ã´DÀ wûÒݸt·p¶û~H|WX^¸Ò^P"ÿ³ ‡Wu’/ö7ZN õ ¥†SÅòJkºezÉ]_c›–‰pê@Sd”›sËϹ=Ý ”ƒ-W~éP™ž[®îSW´LäÅ ê0×X³åÙ°]-Zv)Óv«Ñ’ÚêFPw1›…¬ê1âÖ[ Iê*û2U¹;U°“´•;WÂ.Ûq•®žÙâÓѽë'°cT}ë*lGª“ã¹2çÞpTwr¼®ºS 5OçºxWºx ž¶•.¾®»]èâ/è®Ôªâ™Ž«¨Á®â½<šÖ+©[aqF|ñWs£W¨â)tª…¯"J0ƒ®àw€«‡Èl"UOL¤Š„z#ž-½ȬYRŠT5ª7â/áž µoñ5KÖklm¯±µ…Æ·‹¯Y"ÅC•Ž¡šÎÓ¢ SBäóQ“ø ÍWäRús:ɶ¢/PôÕ8aó`2ÄLÜÈ  åÅLæŒ^ÊDžK¥L¿èäÅÌ«©f†Ênü]U›½¥ÃV­Í¶ªjÕÚ,N˜\b;âP.c¥PsY¦i,É4«äß)*Ïr‘2ÜŠT_ínV+Jã%ÃàùùPw3|58mh mÀ¿N>ÑÕ¸ †M+÷5£8ÞÎÇ=iùx7ïèT ‡4vèè[jôèé[j5Ü×·´´V@ßRo\MŽb°~¯ì‹.¸lŒõ–ùù³×³¼¿sªÃ~¥Yõ ú\ p½=/‰x ÚxIÒŒEð t–ÐlΚËWX>2ŽX2œ㨹ÜÒË oïêk•7 9yu3$1õq'ÃsNɈÄ|ÿwI<ºCCN KžOÅ›€•¯J©¥ÜqMµhU¿FÕÜ—'I2iv‚3 ãŸÛj€ß›ø«vïÏ_½NB²bújü9)À¥‰yFRqÓðcøoó@»h8È‹8dü ”…Ú¿‚«Šiþ•ÝÌH>ÝøM?Å,}—Óÿq_mËmÛ@ôW0Ó—d¦¡%Å’-¿)ÎeÜqâÔJûR÷$ `P±óaýþXA‘ 2MÚ*yu°ØËÙ=‹%Ü Ò:v‹yV‚ݦ(àe[à oLýç7Ÿ*!’%.“5%ƒÒä¡?E€1 8³¤ö]Í€@«ð¯IŠ/OÊ8œ”a©`æù ÎRéÿŸ?.¶ÃÇ‚Ãá]œ lXôŠ0‹cÆ™õ«ÔéÞñúÆ"ÍpJÑ{©Jš4¦ü¥–j¡)οúýÈó²üÚm[Šñ¾ãZ•}ªó¸žmib!1æX$"×8æLPd¬–ëRˆºÐ g òì^¡@Š’fZ˜Üv…ôõXW>ÕrKµ‚Éd½ñÓJ½‹¹äæÖÏv•@×tKy9 à‰Ô„’–Y…NÞI[ÿ¿êÍÁ0¹)<^ÖR2ê‚}¨æë²ƒ4㨷û«÷Ë+¦i¦/$?POöÆÉ2Ž CÜXyFiȦ6ÔÙóSp¯=M°vC·¦´á|gÖLÅ@ÈÚÜÎÛ âB?ÉøJ¬$rqµµn‘ˆk—©…¶ ²ëÇÃæ{£1a®)ݱÝTn«¶ÔîÐnHœüºk¦ÍT/c3 ù½{>›y®)¯³’ÛÃû.]#^x[kÄzârÈ[5ù™PüÃâÊÍ +¢ª×5G(ë?i¥t”dv÷¥ˆÐθçët>Ê7RZ}ÊŸŽ£ùy²ö2zòVô{ôASCáB&Õöpk𩬅£¶«’¦WݨšGm ËQ¹d{·Ãþ¹qP÷ïÐ$×ÑŽÓ$’: ­¯å¨fÌii­¸ ¹Ÿ£OÚa‚¹…u£\[›nÖ‘±<”Òû$%} vŽ€ß+a#ÂëÕi™,.c›´]f"^îVL3×½aŒ )®ìGm—%›„†²ýÓèR‚ôúæÍíbr†îž\-oÐx2;={6¹˜ŒF§wOÃ<“JËã!íP%Uí:ª‰6õ‘ÓÓAù,„ Q'­2‘|æ[°jãAõu* ¤"YÂôÚHd ‹€p«gS«ƒ·eÄBJ@‘5-rÙš{ Pul¥ðØíÃ8T @%RX)öú¹´ ZðhéÉ¿[Øh®`uÙ<¸ÂXîõ(ßËÍ­‡Iî\q Rè!‡q¼æb¸_Š 7¿ë†ý‘öî° , 0GVvÒ–³Í ö¨S±wh]‘>§Ûç³0>–vßÄá•«ìBýÒÛĵ®Ö„– \Y{ºy¥c™ "u‰¬Î¶ ›˜Ù V=ØH7—´®z"Ö(iCî:èß ùí¨Ø endstream endobj 28 0 obj <> endobj xref 0 35 0000000003 65535 f 0000000016 00000 n 0000041498 00000 n 0000000004 00001 f 0000000021 00000 f 0000041549 00000 n 0000046667 00000 n 0000046739 00000 n 0000047121 00000 n 0000071032 00000 n 0000073703 00000 n 0000094867 00000 n 0000116321 00000 n 0000138349 00000 n 0000147580 00000 n 0000151373 00000 n 0000169330 00000 n 0000192542 00000 n 0000048157 00000 n 0000063716 00000 n 0000042565 00000 n 0000000022 00001 f 0000000000 00001 f 0000042678 00000 n 0000044445 00000 n 0000043034 00000 n 0000043264 00000 n 0000042048 00000 n 0000211331 00000 n 0000044694 00000 n 0000043509 00000 n 0000046105 00000 n 0000046153 00000 n 0000042339 00000 n 0000000077 00000 n trailer <<2E3A232DA26DAD40B4BA526B7F172E8A>]>> startxref 211501 %%EOF podofo-0.9.5/test/CreationTest/resources/lena.jpg0000664000175000017500000063702310714372313021715 0ustar dominikdominikÿØÿàJFIFHHÿÛCÿÛCÿÀ"ÿÄ  ÿÄ= !"#12 A$3BQ4CR%&a 6bqrD‚‘ÿÄ ÿÄ=!"12A#BQa$3RqbCr‘%4S¡Dc‚’ÃÿÚ ?ÐJäH?=YpÌÀ¯¸yZ|ç¿`μ«*±2†‡RÌ’=Yƒª×%žƒžíã¿=züIŸ *àÛT¢ËÇ:x˜vpÇ’½=ùí>ÊÕÀöj;êÜjýÙ‰ïÑìý™Ë+rÊy¤ùüªyAÊ·(£UøÖ^¢îZÀ´@¨µ×FöDX…òWf]xØñÃYæPFÔB†^nŠÝÙ4OÈRÁ>99SÇ9ñã§¿‘ÒÉ×—åQÐöëÖ‹ãn¯)YÓ΋ØríÈrY˜Ž`1žø?J¨©F.ËÑ@YÔ1gJòêŠ8u³)èà½&¤B:ô-Ù+îì{$ËêV§Äë6ò Øvj# "s™, 0ÿ¤ËFÙh¨”cî Ê*ã"¨0®âÙ'›t7ÛðI5|qt 6‰uxÁ—Â;s>ŸÅ¡n{öëÓŒ QìÈö=KZ•ƲŸbâ„rÐ!PÄ>6ùOùíÇ$´ -âªÌJ–«ä) >7W—4§Ç’³g@ 2…ª7?SÄ·ˆ|‰,[ãÙŠ²'‘˜SJÄ;’Šy,ÅÕ¹ö“–Gþ™¨"ò(…¢£óoø®I*@ÚÉD‘´ e¼š;x£€—'z«ö¼½ñmŽ‘³\EdÊ®T”bO¸€”ì£ÆÜ´›¦OÊ<°–Ìx´ÙÅA@H-È*ª8G`'Ür@ŠÈë©ä1(RV§%JVHx Ò9ª4Â=ƒ•⡇RBÒÅPzjjÈ“jÒC´Ùäû#4æ¨f¬ü‚ª„Ueú辡•qÆH!‰D(öÕØ“÷ò=Qƒ#4®ŽK d"©¹½±¦ñâï‚f ™—Üw=æã¨CäSäö™áÿõ>ê¬ÄKÌ?ܳbÓr½‰4™Uø‡`\…ø3À, P¡‹(áRÏ¥jÝ…½ú(oŠ•ª™#¼Ñ:¹ëÞKÓ‡ šü£ÊèdfÌ+& :ÖoD¡`Ž!ºÞ½ê­5*+™HZÔylE0 Õ“_š?Ïøõéâ°Fcª‚ÌÁ–‚…µ£kEnÍrHút­çjÅž«¿$pŒ—*Ý{²ÈôV ³2 ù’«<Ð襑ÉêqÊ· ìÔ¥˜2!=š`º«0ƒïÔ§Ëèaz¦l¦ÝûMašÔüu‹š-$fBhÁ¸òò‹’ä],OÌýkìÍDíbÁ¦U{¯ÊˆŠ¤y›öVr)åK¼{9ä… BØê¼S çã†4~ Yô˜ý·5%Fò(. Pžu¢HñÀýÂ×à§Â£U¸ÄV~­×‰K‡p:÷è¥Hä ÷áxì@2L|„LÌzÃÇŽ0ÙOTo7BWÞŒ“ à1BÎ êÊ@ee\îœ,‹´Õ¤†oÃ:TpîÀ,ǯnUÒD¯Ç„ñÉ1üÔ”µ,ŠìÊÀ„\w¡!¦YyŒ04ƒžãª¬åƒä«+íAA±eþ[š!¿jA$›R1*–šÅÓ°BwOðæÀ€v±AMÉ,ÊÊÅYIX¼º†™¯ZQ:/<º…uìËÈ÷ÌúU™yÜ3/`¥=Ô–('v߉…áùQÃ2¯¹ì;ñÕ•K¿ÎKÛ—ŸEÊ[¤M”,U{2òáÙÕéO‹NŽd³O(™IÑœp\s% ©ãêÁÝê—u ò” µ‰,š6Gˆ×€ÂÁâèÒãêý˲†Mi”‚FuZÙ`¬ ñp #ìJŠÙdeZ]¨œ©$¬ïv'…ŽÂÈSž;Çò½–`ºHQèJ†ž0«“ÏŠ³àð¥U»0X†ð@`@MENCý™I=è®J’(ʽz–ñÜ*Â@ ùŠç÷)]v÷ŠÕŠùôÁ»„íæ¥š ¨SÁÕ…GÈ'Ž+ãÓ¶"¨œù¬¾ 1‹HÉõR?´ÛƒÏu ü—Ÿ¡Ã#(uí#äqÉä*ÂiÁööbPð­Á>ÃØ°;™ÍYæâž޽[ÿž 8<(ñÎëíÕæk.¡œÝZ3RE¨óI°bŠÈ ð¤+Ø(BQžE¢£&ŒÌ:}FòÔ)¶øÜrŽ~J¼²ðK8'Û¨D˜›:væˆJù(Ư@ʬZ ÕáªÒU+Ü·ÒÇž…iÊùxÝE}™v‘SÖjx!ŸÈŠØpƒëÞD¢VÚÈmã`¦¯Ç„ØP£e­kž5o€aƒ¶ê U¶5@×#PTSòT5ñ,Îhýpèå„)ÁŸ7—Øø—¾]ºuà–à,lP£žfCÓž¿ ¸™xcÊ€¤ž¼·#ëù^½Q^ÕàP©YZÚHÅ?[R‚´N@Ôíô#Ȩ(}û»†ý‹&I£3Eˆä±ºJHšA3ÞµTá]˜ü UCÈ-þ~¿#ëÖ¿¥C23s?1 ›eYDl“¯ …¤xìV·A~ÝÓ¿ ÌÅŸÊÜJ!X‰ñÛj#ä«g‘gਲ³R¥X°2Fñ®Jöøäš·` TA T]­Ðd1¬ÃqãèGÌt‚Ž ŽÜ<÷ãÝ{}7þLìoö& ýHšøS£vcÿö3€¡O‘>¿K3L ~Ð ë´ފ£«¨(Ư&ù–¢ ·Z!)ë5PgÙ죰S"oY(þ[ ²ªW·‘× ¢Ÿ©Õ¶k(õCÅJƒr´hܵß#Åj®˜(D(ŠT5$lA*HÅ~<¬“©v¯×î%ç:c»¦Y`‹FO@ pHþxã†V© õáŽýÆCõe 38 DÖÚkòSþ~þ øð©^væ5އñIȺ'Z?ß’*ǨfQUW%”4qÊ<û)áÂòŸãÛŸ~r¼sô'ܼ¼j®Yó&ÃàüšUZgãÏpzÿPSä¿>yßr*ïUš  ®îR?¯§‰¯ˆ •*¼ÝûõbŒóñžµx¢2ñ1jÕdüvP®{|%ᩳi•ªÆ,ýØñ]Ïo€\Ýlò‘º¡<˜rhè6LQ–2H̪ˆÁ¥Ð1Øš»rA¨ä‰ÿ¤ùøàbT–èÓ–8á{O,ÔªI*]}'£V^¬×ƒiäM£×±ùʬ8㢠@K“ÀNY•W±˜üy‘˜Z&}4]gdM-CòE‰átF)t*Ôì¡Ûä8UUfr÷¿ÓÝgóq%YÐ:´ú2)§ þ–jþ>ü¹åÝö2Ÿ@yWzÏKxÃÌÊáðo„t@@äZGIS\€}NW.:Q<@ Ì ºýËVGÚÖ~}Y쇂å9`UØï:=ÏÿÔup½‡*¬9r¨UÚ)´|s~<“(]öGo‰û­¯ÿ òx^Ê4› ŒzA¼jíì“׆WüøêÓ$²ò©‚'Ïû#K£3;L§@È«Ø:Pµ(¡¹ä*ù*>iÐN`ýgÓ ÂXðÔP‘± æ˜ðÈ$ ½½ ÆQš7#õ¹ü¬kF¨ý¡l­ÝÍ‚=3Nè`†áˆºt V¢€|du%¿—!Ùš„rÄ{…aÈÿä7ÏסP˜ôGeFg’ݼ‹ ½ÇFä1_ãH ý8^~éüñÌÔÉ•Ôtñ3Ý ¢S³t÷!äHngãD_×4$Ý )d,}Ë qÜ{#¿.xY°š N‰{_"£`Ü­ÐËkÚ’HøóaT±±¨mT£«ö§4Ñàšç[°=³lvŸ` 3à’8=Vh‚H‘‚’b¤)'ÛéNU@Ï««*Ò|2õìUJ’¼ñíìXvêzü¸þxkµ)6‰n¡ (%¤Ý.¬ÉØVø‰<ß–PÞìÒY…$"/yM‘Ø‘Ï ôã¨FY£e!Of*áÑÝ×·ÕÈ|¡$[u¯ÊÐ[óAˆ5ù¾Ë,>H4pÕÀ’Ç$Š(4ÆÌŲ­âëÙãÖUbDûžqéâöå¾,B£«žØ5­_Ò202&(—…^ÿÝ8 —^ á¹ëϱàó=÷åöù›é¶ö®ïÒpÚZ.«“×9ñæEÚ‡!}‰ÖŽàÅ®²¯$)…@@ÎÂMʆ!}•°¢¨p¨Ý¦‰òdr³iü«Ïu/È€Ì G¡Pƒê¡i€ke¶´Eät Š'E­‹ÖÉÚ…¸Z› V0/_ø('[Ø€I'ì°´9³élj´žA@Î ¹^Š_°9B¾Á;@2°VRA`–5“¶(ꥃupàœ ÖÈþX/'ÆëÇòßïô¦3 yN|×±û%—ö€I^ʃÊÜ€S³tì¬Á‡Nøx‹fj'Ë‹âòµøðxº)u`¸hÎ>+ۀÅñ&Ac· )(> ’èBA‹ù!T³ àsìc…@û¤BFÖ”¢X ¨ò{a¹`±Íúéún]è³Lz¢¹«çʼn0HçþùNÝIÈÛèýê‡Þ¯Ûÿ§Þ—åí­otÛ#^m¾ºPÓ4œ||ì‘™,A&G™æT`lÓ`Šìʾ:tÌ¿¹OºM#nú#²µLuÖ³Êá^׫~6#:ôŸæe†áCÿØdXÝ@ÎBêš¶­¸õ\íKU·ääW*”¥žÊÌ”Ȫð²¸dè½}U¨J…çHöçôâOtAo\lŽŸÓVE“8‚¦VY³µH¯ÛT…,mˆ?…îŸtbtÙ—S#6.ܬ…‰ŠÊ‹e*$bãa’õ­Šì/´Ç!‹ÿw=”L•¨djò¬ ›ƒÖg…',¡ZM9$«ì¨T¨BB§+IðQ•hÒmJQYGnÊbô>D¥<…z+;*ŒÃ–ø•!Cª…èyÔ–û/(æEº•eu^>z/~³VUà ’ïúûwæ9ÊÒ1Ø _ Tþður,ì@­j(:¨y¯›,Ôlºr48~¢Bœ’Áˆñ°~Îu$” ΢˜xÐ}”T" nQÅž|`ÿ ò@ÿ"Á 4ŸrTäcRªY%qÕüÝ‹*r%7*OÊ1PGþÝ‚vv¢ž²áb6wåJi!ÇÉÇè¦iFNò°Dê( ž{LË™T[ã©c54þÀÍI8ì_Ä;1 >WÍäÈH›IèzîÖüL¦›ø¹•T’Ÿ±›¦CŽ|œ3¬‰öìPÐ/ ¸?L^Öž8º”;!r̤Е@ظcW¨&†ßñ²ßÓ¢iqgDs¨ÖþA¬r¤S~Õ4vIðXè´¦u¢¨fÁWö³¥Å):îhhŽ2‚*ŸœNFkÙ©>ÓgÛ 1 €²T¢'‰¬]VŽ¡¨Ä–³­ ¨=rÞA¢-ÉL±®I’¥œdØòê+*¢W”gÅðÊžñ™^ÇÆjû´ÿ³ti‰ùpîK­ ¥b}Ñ”<ž¾áçÁP@*¤:î¹å™ R´jJÿ¨…^kQÉ ¶õ_LfV,et¶¨X5?à³:íMÈ7©i<\›Eòi‘Lgd7…W" H“"b&Œ´Ã¤XxQÀ Ù:LõfÃFP(sV& $Á*éÎ"jËý••ª¯"/‘ARÖr‚`Ífƒè=8S©QwàÜWŽÖÖ·ùü‘÷yXfPÊ™€yŒÈPp‚˜[°,ŠU#r|ÊùJIæ—@Ö ¢– Ó<aI ‰ø»3§Â¾ý‚8à“§<@’ÏÅbÂJÕy›³1§Uº‰ ¨@ëÏ¿ÝøJg”üö_u §~*~YÁ-PÕ”§È…K|z¬×I+j0pÀ~³œB¢qÝÕÔ2ƒýžÁxà*¿Õ› T¨º'r/ö§ ¤sbˆ:’[ƒÅÕ„¿$'QdÛY&˜_#@Ø S·t Þ5 t›MÚf®ÕCp¢¡g0ª¥¦Š$Íý‚­£7ÔŽTdeªð\p#9¡5@è: Çd—…Y” GáÐQƒµg"ˆ…Bd Ú¬^“ íÁU2qØã¬úôöú~Åd‰SØ¢¦ë6F£¸*‘5rœ*H¯tø7^՘䒠•XÃ3à¨p€¨+j«ð?E6PÖŃ(¥lKe€’X—¥.¶ ì6‘ÃüØ­ 2“7þOðJ«Q[º™1˜qBȾ13Ù»{+FIJËÕX#x=xJº1Ûå0¿å¸çÉBÅ¡ËX"ôÆíåÙ¸ÈáŽö2È¥yG …UY¸ B¬d2OZ*M|d-Ã^̨Lé \!¬¦Bù’fîäT«Üj~5¶H¡CÉ[Cø4d4IéóÀoäÓ_Wk!ˆÓ¢¸I«Vv'à–sÉêU›±uCv¡…» «‘ÕJøÉüjEëÜݦU a׿¬í1ð¢ 3R­Ñ§ˆn È(4|ž ¨CFa5©^[äœtbX{¨’,ÕQŠʵRP±œv,¬ÝüŽ*”åÍ ò'Xl1U_S¯ãUj$ž(ÙWäØRuP´Sãph¹¶ÝA¢ ´ØªìÍŨ­X‚Uy%‰g­Z³°Ÿ“Ê ÏÌ)šÏŸv}ê½›ûtdPÊýcwñÞÁT„u<˜éC졽û÷>9«{;u˜byNB•.‚°FwjÍ»†)ÔÑè©äQǧGëï—ÇxÇÍEÓ£uUîÅYê¿ Q“–WCͧÕ_ÉGN¬Â 6„YÔ+Aänn¹+emøü~}Kª}Ößz)D¥³0!Eµƒ|[ZËe5iD§Šjf¤ÊÇ…%YfÒFTT›r¦qES/3rÉr»Mû¨ó(suìÊ÷âÒ§nAV a3ã^ΨL¦9j[ˆ¬û‘J€Hnn¢ÅRZ ༤ë5r½ý*°w#¡B®EjÎûÙY§K4_œÑª<ù4üxLŽœÕkä ̬sGªøò%B_xTóžœvvEVz:ºš'*P5qYª;DMK¯EᔺãÖuÛ„ºÌðZ©§:²7GP vìÊ}¦(|¿ÛÒHÎÌLiJ6,FÃe„*ålHØ×È5âlU@H‘Å·ÂVPÄ[¸¨ñ©Aâ~å&ý?Š$Bcõ¡Pþ¯‹ÒF´íáî:#SࢂLUe^ÄÄ!Æ©î{)~ÀT^À²ÑTPˆýF8b•$, ²”h4 p@^¼y¥BQ[·“yyníØ£·(ªß«evì⤠ PrÞoé:€Cײ|›•`¤±J­ ý|1š×T[ÐÈÔS…? ¾,Õ ÜkȰ+ô,mßb̧‚Ö¶\ò Í®Åi°±DlÜc´ÐOåÊQUƒBnþU=Ù†©n[ûüßÇFº¥<óR›‡NÝz¿‘<œ"+ÌuNÎHo˜á°d‘ÉI ‹ •jN†ù¨ Ò.T? •¸â9z¯+üËRMG:3Vd#M¼>*½@Š:s:tÈ t_!V4hÓTR[Å~G€ø“à~Òl),Ö¨ ‘ÃHBªÓ‚h -jÁ©?4¼Ó0«úúòO²²k,ÜÛ¬¸1ê¥|“u":ÐwIÐ-|ŽB,àìÑWXyñƒ¤ù u/’¼´W„3zžë@Y¸ŒçVfe,ÕCËš3„à3§‘9tfDj) JpÈÈÍ?¨õI>`Ìÿ¡VfÄùWÿ‰Ðµ[àyà·RÊ=øõF ‡à–°A¦`9µ@ äjÜŠ7ê:µøB |:5 ,«ä6vØY:¸ÿ )h#DdN´Ì ìï)tqF¼Û’Îè´îÉÙ¨{”B|Ì&­O›¿‘ò劊#'òE*…èêµfñý°òAxº2U(ªÌÝÿòùÿž«Í<à(R­Ï'ëÆƒ­¨Å&h²­käy¯Or"àò> ± ѽTsj@QJbÍ(ÞO€VE·ŠÅ8`ÍÒ„«ƒÞ]cÕYfìàÈ2°RU Ú¬—ôüL›Þf6Œ²ÙH"`²#͆«_§hrÅ;wÿ“9ÔCâÊ”§ˆEErhQš¾T?v=A&ŒW²žgÉ4?p,³äôŒ‚:ND**§‘ÁrÊU<3B˜ýUêyEGZ+Í™1™Ybr]@%ÂÕÂxò? …IÝŸ–  YÍ—õªüG*@éD%@ !€2 §dáþF€­“å=¨¬„'"7~J õ˜EA6âmÕË7³¥ŠMÉ6(×­­+幂XÑ:³“l&tuÐá–oŸ ¡®‰W?m(pÜ]bý½Â2ó/bÊ¡||r¢‹×öwTrÃO¹òF0*:§êª·vQ>…s•,¶ø÷yb:*‘ä!6VB8ˆ£ª‰øVA‘W–f@T¤“äisE,•¿õ%)jøÜ†Rð¨çÀsÕ>MÇeU@¦œüÀ#«7ºª¬MG ‡‡òU €´M‚h€j£bà7¯ªÅÙ_›4´l‘KàP£Ê’ß%à1õáflVUqñ~ª¥Ê·ÁiÓö+£8.ýÊ2foìÙ’"îT€ÝÃS¨dä~߇̓«ªšFV›’ªÌ rã~+?`ÊáÉfNG¿RÙÑX*‡3áx,úý7ü ª33 ¬€3vu.Ì® ³ò>*K *j Ø–* a ,ì‡W$™LgRÛkd«ùh\ø×~"ËLWV<–ZPmV??$ürŽ=5Y¦³˜.¬ŒÄ°`CήêÜŸ‘`À“â*+òV`ŒxÈf$RåŠ()ä>ä—åHrÝ™x¨xùtw´Ø¡.O Ù ²ðèíADJ° À`Î>,êàž „öÃø‚¤5DÍK*ºýüœ{)þå€v3-5¡(WHÁZ:^XY oRXš·‘ø¶7GÔR ¬Hi|®¹ò[-uF€Q°ãe»Üé’½h¬ªX?ëÉC6N*AbŒW§Bì§Û¯aîmOÚ÷ª¤ë/µ3²ªq¼iç%|l¿´+Å+©è:ÎÇþQ®Y <²¹jQ8 º…Bä±iž@b9û ê~ÖgÄÔò4MGUÄV |ý‡‘Ùéò!T›¤Þl̹ º)>V?3ñ%…¸¨hªï¹u']™I,ECQGÐî¡Ó“©`d`Ê£Y@Ñß“ªuòÀ‘øØ(6HècEÔ“2t>̱_u<ŽGÄqò>ÄüWø*A!®ŸtžŒiÞ©ì-c °J³âÒ’wE^s4B¼òA4U`ÈÊü‘ã*½þ½½õ#xí}75/ûZbYh‰t8îÿÊûêJ†Y­‚:–ad”N¤ÿüÌö<=¿çƒÁþ£‘ô‡äÆêñ7Ed"Õ–X_òµUmds÷lI¦æ|‘—í¾²¦7ƒ þ9/óÿûˆ®*7FÓÕvêÕ¶¾¨™ËÒõ6Æ‚Sƒæ$ØÔ8q;_ÆäRÌd%—ƒ4`ä›U›¼Ü.ÁŽÖSÇ1yxž¯îìÏ_pLGÖ§ÿ’ï¶œœ?ª[wO©¾šýu4ÅFSl?#Ú”3’—b…¼üöbÿ°¡#$t,ç‚W\{2£¡«ŽßèCEŠRjAp&ïʹ^Ó¡`ÏÐý®Ç×úLCÇêU yq…DvΤ!¹ÖEGà²Ó‘öïU«tè2ñ¹2iˆ\$Ò4{¥F‘j €ÄÊÚñ²që㋨”zÕjéüÙˆî€(à© íÇP #‡"¹©1ÐJ %d«Þ(ˆœ§œ8ÿ ¤ÙBÌ °ù2\|˜eøñÄË©œÖýÜÍHUCÓÅÕˆUà²ÑC‰òêTU‘É{õt=\Ȥ׼WÇú\Mù±dgS5“íe`ŠÂ¶$#bÀuû‚üÚ¤-³1•±‘l¯‰ `/  äXù†í¨ -=W ¤Ý¡TE¸êÕj8áÿ­$æ¦Þ%3› IÍxåYÙû”$…ÚÔ«­G‘‡^'íÕHUÎåf$8äc:|YZ#Ú_³d"¾ 'Ùç6­ „þ Z¡z”€šiÞ ;ó3ëà†?{ÚÌÿ<Š:“tvaFhЉ’ À0àxÈx‚S|‘äv$•¢ua¨ö12‹¿c# vû€¦ÊXøðeN,ìÛ*† ñ!E†y–&&653²íàŽ65Z´£ˆ«D!( åOœÔö=Hbʨ[/þì>í'ªì½‰{Ö¸äâgeaÉ­¡|Eñ°bZ¾R޲wùv%]Öm¿wÿy Îôï`äI³ _'PYÕ•Û!dðT?ÿùoÂwY>(ôËOZÕuÜ \}O yqogžKÎH®^Z\ãZ¸Ñj_šMÝ©iÙÕÚžVù;SVþŸNÆC'\뱂Ãáa?þ¶ºžüÀ±#Hѯ‰*EŽúO÷§»åÁAÒºK«åÉ_U‘|aÅ"Šì€<² pl¨ŒSXßÙ3ËÔ§—ª×.š¡Ë­s¿3¤Y©£ã½.n]‹9U¼ã™K‰¥¸üH®Nd[<–Uÿ·•ŒÅÉZ‰¤ÓÃQ'g™ñ*¢Yô á”›~._†½)Ýfq¬´Ã…ë•Ë<çL~ÞWe3Qk7J$©òÍ-&»U¦?±VF”Ë*0èKpßþWgì[û2·oÒ ²¯,Ó‚BJù%g¡,¾0펞^¥ü±@´'… #Ô¬ÏGj’GÝ ?a·‘‚xÀ§d(¼ÕG2ÎiÊ3ºv¡,@÷e_¥zdZõ‚–¡E.ˆøO-Õ1B ©UíÈ ª_Íù(»l ‹ZdPHUO”Š•È(1ÛŽi®ÆB@$¬J± A$‚ÇŽJØçîƒévž­û[Ž;MúqÖmŨ!ײóËSÈÝ‹üT'éàåÎj¤ÖJ¦ˆ«Õ¦ü3žãÙ—äK°•.Žz†ýkQÆÓáà‰"…ä[‰*ð(>!¼œ–r9b[„Ÿ±5qEé®ãPó³UW‰²ðH<2žÀžøfR Xö»5™Kîá¶@ª×_­…»;a°jõƒ.X.ÊÚHVû…êÀÖ¤®ÀhÑ$Õ1¦šŽZ¼^JHz‘C@É2ð Š3‚οׅY·ð"“ïaØ"©EìPÈ`S¯$vpŸÊžž_p„*¨¾˜5Ï¥KQ(‹ »U•H©è{uRÝ[Æéÿ¬ù?óÜ¢£+%šS@ÞJŸÏƒÏ@œDõ ^CQH$ò¬¼|Ã[ky™U~Ö½L_ à0×dbTEÑOŸS6:À;~(U¶cñGds_ÍÁ¾h£Õ\®žã‚¬ÁAèT½:%,Ç~]Òt^Äž®úí{>™ZZÈ¥Þ„TC0>OÃ2ttäVjÎY”Ž £=ÿÖPœ'‹?,³ °!‡O3²ÐãŸfBz±b¤pùëëþ.c‰^„"qQDñѼöëG ‹8Y(4ä´‹+‰³Ng=¹~§ŠTy™…ùmÏ!¬lÁƒY#VÕme—¤•LyËT‚vª:ìh‹ñ’U”(*¥sý¢®­n¡ûµU]žX­&$QÖ„½’Œk%¸’±Yº”tÏ øì«*°q_ÒÙ#õ"\¹JP³Žh'UU™̈—èB«ÓrÙ•âÜxÙÐ~U)ïïIÓ‰xâÈgÔ¯j/Ë¢Þ…V”(Ž «ÒáâC”uýª©sÓ™žÍ9$¡$­KãŒzReú5k;#쌩j_.uD!oE½ ‚„®còù$±$€çVk¯aJ|¸»c(l«C ñ¹F›"¼Ë?M+ã*J2Mϳ Pæžè¸úIVüwæÕ)$-Ø|%Õ{¿`)‹äUø ‡có¯%L±Û¸›ÒÀO—Lȉ³þú§ˆZäNoåvçÀ,ÊFª Ù ¥$´Bôcãüzã°j‘HP…bŠ¥©ä 즠ÿhf²5²þÁl@k­Ÿ‚.¸ ëGÕ–%£SÑ ®¢…‚ ¶`TQûT±ʽì8™NÕU{ǰGŠ’ Ïž@ê©Ñ‘C¥™ÝË t¿uN‰Ørd9Dyž Ü#ªw(íBÔ4H9Å‘ì&ŸÙ"wA×ÊóïÀUî´äÈ‹pÎ]jÏZ1Iž-`“¤û5žÇvNª½»0 åáËävVjÙ6×(;˃µhØãòy wb2Y‹…*ìʨ,*2ÚÙASnÞVÄ >§xté;=–m!ªÌ«–^Ù:ô KÔ1›üV}J¿ž±/:Òð$ب â1à(tŸ4D4š Ý{«/Ó\UŒñÂ!Z4¦¨èPðÊ iñ0¡€§ E U*K‡I"taGiò¥P«µ 2y<Ä /^Ó+ØäW´[‚´dìÅ•TšòÚ8\3XmŠ’ª9KêÓ¤ÁxPÍj–¢ÞˆZ$… _¢–ÏO¸õï&ü…›wPKP½ÕÙ•|t@ŒƒŠ|¬ÖÃédo:%ÝÛ”N½C¯duGPZF@¥ÝåVšNÅBÕøfH–ºR~E©éÛÊ­Ø~¤Çù–§GêÌŒaÝÔf~¡–j_²¢²©ìÏr…¹o"ñ%£X‹ŽB‰žÇãUú3q²…MüA$1atE~Ò “ÀQ¶ÔI”«ªöÈf EHÔê§åª /² ©²+×ò&—”Ñxwzò/j¿¿R ÕƒT7Geqñ=hJü:ØN~h;S¸T?4’¢Ö>êXÓ x²*õJ9$±*AAŒhÒî¾*äwbÅ‚õt Ìþ'F’=›yž[©>%ÒŒ|N±YS;4É©f¢“&Ÿ&?ð]‹Yujr¦'ÔKcM`v¢¢‘`X¨y,*ìn¬2€P»#ŒÚwîÅXQ"Ų“D”£éE«~¹È@ÉW™tïää2T7̺‚¯ y ÔÉÉË–×›uN"Ôá²9+Üõñ³|*-™…³´ñÈýǺ;ÒÒ©_• ¹±B+…P¿F%RŽO@\£.\w\lJyqª¯åp`ò«²N‡¹3òA BÔÌ –NŽ’ã•hÛ…, ( h•"è‚~½Y¼ˆ*û)Ø3}A 6TbÌCjÀ¶©±þIT%TñÏ͆!Tƒ¿\˜ è;õ\²_ÁBî|ÉŽ­ý‚P;t˜ýª§ãÇÒ>ÆlB·o#P*žönÑÆàfV^;2 ‚ä­EiG‰™ªõL‡PRHÜ)#¨(•.ÜHºªyVýÝœ2”~ÌX€Þ6㿼ۅPÖ*äU8ZÔ2Ì”ïÍ…˜ú÷/=»^ÙX×8Ô/6I? ðÜúûDÙu,I[X(¥C€ö,ß%Mù--ËÉï7ÇT`¨k5zu*¨©$ŸR¨&h9=Ôqÿ,I˜úd½+W­~ Ôñ–,½¹ÚC„`rz¹ù»òËñ2‹Fª©ß¥|'~®ËJ2òæÊ^"yU †\”X¤<î¯zy3Ýyã9%z³+ VpبÍ”ˆxŒm!Pä&ØjŒÍ¯&”¯AR@QK_ ð³#G[†  Ñ,Ȩ`”'‡O‚¬Ö,{ÑÌ™‡²E …©’U…˜»—j„bW·*´G=ÇEµy ë¾CŠ‘gŠu¯EF¡^ŹqÚxþVBê\ì²^®Öyuöžá›úN@¢ºdWÍLÊ‘¼QÁpkC:ø5 IW—*:¯Ô›nz¼·í²âhØ‘¾^§ŸKÊ:~«¤Y•q]Ž^c––—™…» e“ =Äé}Bj+€åb%„¹ =»VFk“T‹6ÖêÇNå®çû‹ÛÝ>'—/­àĤUC’“bÛ/n$Úbò¨‘ª’ÌêÉ£W—Ÿ2Ë"Õl–š¡ïÀ…‰*T»ŽB&Á¢…„«&ži¥•—š(¤üØ^Æ «ªŸè娨¤Xk}¬ú‚˜ò¬µ=Ê×t®.Eòa“…ˆÖe¶¡À¬±³òY¦¸úb¥õ‚ÝñÓ¿YÇu¶[0'?×9þ%­²ç™‰äÇ„Wº_:5éø‰UùÏÃd²v ­È˜tœõ×¹Ž\ÈIϊΊXÝ‹#óZ:Óñp· ß¾ÍpñÇîà¥dJaωb&8U@ãJû†% X÷‹â0~5\6b_ì «6<’ÊPøù%”°çéÑZ7QBÍÞtê(¤$øb’¤Å:Ñ»ÕÜ¡<ˆæf—¸v­L·©hÔÈKR?ì°2¡åISÇØwK( eç·É^~x›’\ÊhB‰ø¸cØ0â´i4Ö¨ÆççKM}ùrËåãnÜÈñ:·Û"29,»‹ly²?“cag„ÐeEõYäÂáXO‹$,,+…1S|žH%‰®[#SÑiÚHM\‰¹UebP!GèÀv¬øö}¦Y Í=Pp«ÙËò0íFz3wî9Uº¨.ñ°JuÊINžT¤ÚŒà•.½9 vìß êTÜ'”aÅ~Õ§C$nÎ꽕™E_0ö?ð¨X}ùb´úüê@œ+#蘫ôFìýPY—â?_Uc0K?À”Ø7fTR¨y¿Ó”XÔ#ˆÂ¡¤Eª@‚2¼XN  mJú´šÀ²‚‘N¬Š…'r¼‰ (7ª?…=تW*ctOØÊgûfzôUd7eP©Pê ‚ä3¡B‘KbyæB-#JvNE“Æ^À»ƒÂŸÂS§½9~Y ïæ¹W¡Bˆè?\È nì:-ø¬³FNÓê{X?^i•2­ÌËüˆe Q¤þ ŽŒ¼"ÂÌâjò #r^Ȳ ±f68!EOm~¦USÙ$T»|…@ø]€ºüئ³<õ 4êÒ“t[1g`¾>óã~ê|³˜R¼òhäxÔN~?ç%x¶:2xšB•Th‹Ò¾4ò¨9•±òˆÅÇiËr€)CjÌÍÉiÍT›ä’ö¢1DTI¸Ø0—ærV³¯Í:ùÉ/Å+zQÊ…£ªI¡%J€±ePNb唦ñG£¢TØ ¦¦È!¬CŠô;!TAª¯oáH!É#T!‡ ÛüêAnWbjªJqx:Pʬ\7v$\O¢-”ä 3†¤QG°¨åƒOü3ðÍY_©—QÜù$´_"{jïÕ‚¥Ky¬Øcªdx¸š2b¾ÈR ºUÓÈëu—B¬B73 ôìyužì¼‹‡ŒT'R­Y°ÌjS6Ðd˜P eUnÊ (bf¸$ØwJ™ɹZ ­PR9b»~K  ‘&µoØdQ«R[6¬K ˜-Wál_«µlfgÄüˆB¨ã‘äP€À'N[«óÿ}puâV _‚¬y À`={¯vn†(«ÀCÃ6ýDp@Ü13Vð§VEÊ7ôSÃv!Ž!iú€F-5í/#§ÉɈpé=ùš¸ 1†E`„lÔI^Öëù£È:•!‰ °ø$´¢ö ¹‘$Ÿ<ù„¡`nÀv/€†ò¤’ÍžË fPÌYOuᜂì;ò#ž³^² ?>3É*9cÑ]Ùÿõrv{|¸,PÉö,Xéܲbe‡gûMM¹UGvì ôøjü N=—yv!ÉeDSÕét>0¬³5ºwþŒž:RG€ÊÃÈyáÜüZÒ§Ú„IºüÔ÷ù ŽˆM&Œ‹Ûú¸WR¬Ä±mó¯ÿcÔ»°ìKy?^Á>7UÉ µt|ûmõhnøhùÉ:éºËÎ+çIº¦K WFïÙ^n*ÀrÝ|]ƒm¶ÒÌÂÌÃc(žò™RAx3ã†øzŸ`ASÇü7ýsu[ÐÔcgc_<œr…)SÙ°© Bò•€VÙµßVå»v¾ 2­Û?g‹“#ñnêV~EöV%ÃÀàr¥ŠGZé˜ñu(ú¿Ñc»ÈV,©ÌÉ- Ö7Ú@¢6p6 lZÏ‘²_ê§¶ÌøiÕpÃ1P#ÊUf:¸`Æñ*¹Q×—È!¸ê øž}‚°øž}½ÖQ‘϶³ê&ÄÏ×tL&®µ¡Ê™¸>4 í)+Ý”PÀ–,‰ ð`Ïíoqäû©GTÑtN®S6•Ö#P†vE%‰ÕÃ!p¦‰õŸMzúôî¤0rʈ¦`€¿Ö¬ÆÔ ZìŠðk懬ÁÔKt£š*€gPQ€PëGª 2·–( †š§fñÏqk+ˆÅ)ã¡Uª©ˆc4à™ ’)Ö„öáH›„rŸA::ŒŒ?'°uµ0i悤–˜ô›äŧQÊuz©ìäL¥<¡š­` „VF^OLl~|µz†“NkÈyÉ{0ñŽ[«õ+Ü#0~Š5éñ#[fáE2DQÕ¸ã•6Æ”y kë¦>¡$‰h†ph•¦KcÚ ¶ÖàêH4A þX“±c‰‹ŠÚ–u?xÒ£äP†Rª¯4‹Q\‡[x•‘È<É„¡™@sGîËï °?+búywÆÔ tÈÍÆÎYˆ#·‰ø¤+‹âº†>2ǯ퟊Sw=?~ê~îqpñòönÃÌlæ˜y–Z­Æ0ŒK¬ÙšlÔfu «âª†þŸ'3i›š2ó/JäfS¨¨"”¬¬©ä/váÍ%éÚhÎÀŠ7<0Òý‰ì3›*u¾¹ŽÉŽŽ JG¬Ò QIGÀ/µ›Å+ÝëNöþ˜ñ¾k!Ê«°Æ ĦÈ2ZV€OÅp¾¾o‘©ëz•kªeæådêY“÷òÞ•´üŠ^/oLŽA EجQÉ%˜AÈÉ\Ý#¥Ú\½Øª‚EI3bµ ýìGfAÈ%‚ e§* ?d6š/^ì®\EçVù3vV¡äI[¢Š’Ôp ƒÝ¾w^¯<=jÉŽei1ñšvköèYׯžb®$­5¢‡ ÆŸE°zTßMõrÆ}"zÝK ­nÅ‚ž@XÇREzÐqpqñ0mL‹tˆ ÷W²(¥²?q·¯–ÎPÚr÷Z2ÕË(`,X àÎ;2Ó³{2’œ2Hž ÕÐðgË5n¤)bèWõ %ÚoÙ™€þÜF+£ž¯:!ìSÊÎ<Î Z`£Æi‹ÁaÛËÖQ­æø2LÐ7ò•¢ùYRƒ– 5JOÈŒ¢ðÔ“Èih‹f¤†`urƒð?‚¬ÌÀ|¶`n–„2­¶ñzذիb|xVU›mu ÄŠŠ‹Ch‰…‘P¿Üݪţԕ!Yû!£©åî2Úß½©92aB( ಀ§“$³N‹É BÁ RÔw J—Dd§fD•"¢”Š2‚óv/뱕cÑÝmBÌÁSÉ*7ýÂ-ײ$éÕû‰å§×—,¤¦º++Çù?<ð£ä0JâìÐŒ®ß]†ˆÛ©jeQ†« õ™ƒ™C3X¿[””èÏ&ñÇú¡f†äl©2/Uðƒâ¿=j/‡36©ñ"Oõ±“uqÔ¿ÉWëöFˆÒbÖ´ÜÕÁcÀ`H£ÉÙ\I гÐ=+¨àõNoN||¬iœòa”Lª¥cÕÐ(·'`$Qûƒm¬ Û¾@#ÍûäY„æ„öI•<¨b‘œÏC²…=ý™/åsÂוñÔ§faU‹³#2?‡Ü¤³ðHíÙÁà}4C=‚ä2~³p·èžGþr;4û¢Ȩíåv=\€~?$0éÖ‹D ¯Bü‡-PÇ¡ Ê®|a‹yM[c¨6¶ ¦àë÷ îVù+dü“|µù`I-Hb)MM«UBkòH –ÑGª¼ó2kj7—…yÕy³·ÌªTö£%œ°ö3 –VHŽ¥eÈ›öGÇ»ÍÛÂC«Y8eí_$Ó¯0œ{¸ã…ê>—f=‹³5 ,ÊšþTRg’hy(CŒO Wê+™ap”säV*JžU»òCˆû=] Ѹj/µüTÂ䪨 Çñ!pwq|rH×dkõï¼}í”hÿÿÍQ”ª €m)oÇoO¦í^޳Sʰ/F¥™ÁèhÁÐÀ8tä’(º†ŸìIQó$´I‰–…h”ìËU6š$ü«:ˆ3lvK+·RPG©gÑ^…Þu‹²-û 3 Óœ¦þS¤·rIåýÉsF™kbÚ¶ÍE4?&šWçæ~“‹,]Åh®]QGTqÂÏÅ6‘e ¤2›LR;ÿ ÆÕšù¡¯±QÍÐØš±K, `upôKM7G†Ä1Z+³Û)$VënÉVrBh%8žÊà’³c6àu 1F uœz²v~ H™=T’¼ù±Yh*~ >ý †pT–¯íÓàÍ|Ê)nlÉÝ8¯-ô¢Õ•Ê0d³4Ñ™B(!Y:¿d'JrÁ{ϽId*xB(vrݨ܀¤õåPšP%ahê K†jÖÊ’­ãdÜÙ?йPþ¡°ûþVÇÃ!6Ú›E¯Ë»öEŸÌÖœÒ\2»ò {{3ŠOªµABݘ2`$‰f#·ìV ­/Ž“3%9o“ðýŠ*ŸèªuF1åÁÿÄá¦ä÷ä‚Êź¹&UVš*ð]œ—l,²å§’j¢iÔP¿Rœ^"Ûž;i…>e†9¢-ndÇû„¹n.ÛŽM[)cãŨйa+ Ô.‰÷k\p¼P¢jÁ&‚…ÔƒLÇÓ·• Ë>ŒKW«FêIéJ)þDË=&«0ì¡0P´•Åsfâ\wý™X{),§Éñì±_Ø¥%PfHtaÝb€©”'±îΡ!TÖ…‰V@ÀX¡3‘˜ÓjþBQWà´It eSî û( ­.ƒ•>ëóG|ıadøŽ@ò*|ˆò²ŒÀ©+¯«°Ce@åƒ(hÍì[U òu¶äØj $R{j¯…½Éëe ¤î”ìŽ{¨*ÏìàrOŽ_† EƒrU‚÷fi*‡YÌЩU$Ï–F=“š§I³ck> ž0‰ÁIôD/מ€8 Äw>üÀ… .>`Ɉ³w 4(þ:||Re™jMu–섹`Õš²FÀZ ~Ãml ÿ<–(  ^DHUW[$lþ)‰k®çcò5]x zK•jBÍ6p±£7PunB,‹¬ÊÌ3€Èº/WuQîÞùzv~ü¤‚(T`”tNfÜ23º–<Y;^~Aýé#T£xèdI%YHù5«Œh†‡ÄS³"õ^êÅÇÒ!jsÈdž{³—Rf nÜ0袕åHbÊyET¼yà8¥N(ð  êM€í@#°j£êC'ðGPE_'òj½T ¯j–)B[ß–vFšò;7¤ÙY•J§,§Ü¹¡™'£™½õMý;Ýx9v¥%§çUpóDçñtRTtV% Èø‚¶NÌ¥]ƒ• »öR¼™óä'N(ZhÊ_•âT Eçã›ÂÌrëE.ÃÝ@ =Ô^? wo/Ë“?ÿ,R b&)b‘.9#ׂ¡> ¨*)ƒQ«b»]ÛŠy>ÌwÃÈ"HåWŽ` VNH"¼T…`FÁmIä)"lÉ sMÁÉ“¼dê¯7PÀp>?ÏØ=‡óÏÔ÷rm¬Ñ¢fiùZãÒl® ­Õ¹^y†SÁê <ñõ–Ÿf>³Y°FÍÖ)SŸ¦´— ò-2o†½åÐBÌÒ ÙhŒ®]‚gÐîs²«ËÏò‡À¥ÿ9äãoç…ñ›Iº~XnüE” Üg˜Ý[ÊÉ$ë`QŸ‘CŽ}éвý­×$ÐëJP$B•€í*ÂÀ;°à©õËoÞÛ-½#õ=÷&ËoëÙ™YiBž,LmAƒ|œL9@þæà8|ŽÍŠurɶ0×eìŒÄLó/vF4ègƒKÓûR¼ùYo9I‰S@ý¨ôuþl7ç§ž—}¡oÍůêZv6è¼c…³ñé[¦vnàÌ><(`ŒLlŠ®K;{÷ñã„,o@>Cüô2µ=S\ͦ§¨?“3.ÂÙw¥Þ2ìè³%ÙÂÏ„PI…šŸ® þ…ô_þ­À“©u‹—ÛÙŸÛ"Ø7k;&Ò@ÛË'ÓÇ",€B‰¢=jXžöÊjôé´}C8Í ÊãFlh¿DÛ,ŽÍHVxe6ueô§CUÊÌÏËjå[#(µo“TÉKÕ‰_Ê£T-UÒ|»U‹ÌèKΙ—æDUnŸ#JfH(¡ÒƒÎ¨D×â{Mbƒ•I‰†® ñ~.ÙMV^TH4¼~Ï7(Æa©‹ªhq™ª-<¢ÓÇAŒIN$z'±‹?)±è„ñ5Á$u¯uc3ÓóȑꑨºŽT EŠ¡Å~l|ÐPUá»™$k$îY”ì[_“vÌI¿‡^,\¶­0Û+¬Þ”’têÌñ‹ÈNÌ#Dgo-|«ãlwo$©‚£Ê×|Nѹƒ1)CèÊAã™$jTª"¬Š ¨öªmCP–)ë œŠðþ%Q3±œ("˜ÂˆYÏYÍ™þ*<`G¦¢ä·ûˆ#ç‘­”vqi>D‹b›Í'`””+{qY…‹WE°]‰ŠxÛ0 ŽO4*¬Ž>,úý"Š4δuò[ù»¶$“Bþâwƒ^šr4¼ƒFËÉ£Eh£«ìèž7»«+™–W«)Ê:ðÛ˜GJÓ’§&9P(œ¯Å™K…¢«íÏòñðNgõ˜™p½µœ]O.žzde£›uyJu°Vœ\ä,.ï[¾.Oý³/‘@ĵ`ÑÈ:‡öúªØ:yOjXÏ¿ûPÓš4äì̼H°~¬•ÙyqÆÉî®›Löö.4 Ã±, yY9K$†³Í&«Áâþl™“å;1I¥©5T‚€C^ ªn òtçj²ßMAÏ’ehøpAHT7QîÆ¥‚;¹Y—š?ÓÍ˪'Y·iÝTž8§Å€ýdÍUA,Ì»*ü:»NÒtˆUyãÜŽËN‹äbŒ(ë>K ©‘+9gù õ#ÊZEÏ»7QG^¥³±ujäöSýÑœñunÒo¬Q ÒÆö6(B¶ŒKloQjÀlÔùâHYÈr¤îl€Tî~Ú°ñ"¯îÃ7©<! ”y ¢¿EtF!™z«£pRs³×Ü‘¤gV³§ÊwîªB«v!É3d¡£_  3E<õ¡;€ĪÏõò“R®á¾A –÷VE'µdû”Á~³³î2é™è«7BŒäŒïW‹7_† &(Å¿Z‡PéÛ@IÕ1hð$Aób÷Fãü2ª‘ÁüšMÝ!„x¹V¶’v¥@¿‘ñ`rÊUšµõ’ÜŽ&ZžYš³Vc,Ú‰dNHVO!士-.²pȵ-èSY,ä´"„Âlfìd‹Un(Ó¥An"(®hª‹ØL¹¢º}Ö-þúý—“ dL »€;Õ¨ŸÁTi,Çuq ›sǘ›vú5$dþYN(zYö—»HÕ‘N‡–z-¨lïP(JuV½˜”©â&‚ ­ˆ:XbÄæþ~J‚†Y24`•'‘ò ‡pxuÔšïZ¹ž>™’¦%G)$¥`)ò³pf¦‡ÝŸÄjŽìPž«^<Ê”Š1åÃÆŠíB”,¬9zM¤ÁÚÒ{"¢Å*ì'0£Ó›bf¿W¥iŒõIÖI:œˆ«2ÒI2ÈÅÖf^FJŽaPOëð¬Ü£:qL;UjM9-EvælO~Å#D X0NÅJ¯ÈÑF¥feØ6ôxQV9$1ûA®~àx5n9&5±#zt1€nH×@AXÇï–4ÚÙÞU¨f˜x€¾Ô©3ñ¿a*¼ YO_š‚½ÞWE…¬¸¶;=}¦\xÌÕû‡PΆí5N_ß«8Rl?Tç)øÄâ¡›«<Ö΂£Ù ]&Ë£­äyVY4ßNJ:U$ª³N`³L!’*¥- C/”+U½yHñäÙ”^DjÚ‘dl» p *,ø-YØ*‘òôF)žPX4„·mÔ Ôyš¢Ìu*¶ô,´Ý²­Œ˜ëR…˜­à÷eu£âϪ'½ aIp˜ÔÑ”?Ó¬Þ®Y»†HW …RUxúšñˆŽ‡±ÈuશcNÒV½ÆJªM‹-)%¥øŽ¾ÀRD+ôìœø‚EåJœŸ#ò” ¢QÚh¨_i?w5,‹)(RK/ŭЇˆÄý¡Bšõ.|Ù87Fk6ufb²d`Y«"µ;’G ]fÀ"ºøòÎU‚†);¨ë6“ƒ `„É:†^^” ;$‘…|¥¼2¢k5ª¿f¥fëã¡E`o˜Q{3•ä r "üb¬\3)=ƒ§&iÁRÊÝu¨`9Iï†Ö<šje'Z¢¼Š$jÖ·uj(ÇÀ6ë®Í[P¬D…w­­vV7B›à98ò 2›Ž½À¬ìñ3^xe,Tv"Jä™âw´wÖ¥:Vèײ±uc½u­«›ƒév¹§ŸÅŽ•¸/‘øyêŠ-©EÓñÆF.3 JªG6Þ‡ réZnM£,¬ÌVÎ˽,1ñ‘ò2 ë6yõÇ›Iœxڟח PŽ`ÝzåÞú®©·ôûh»S ÿÌûcD69M/ 0SZ7VòêWS˜÷pÊ-j4ز»(³eS!ŽH’L®ØGÖ$‘J@çÈÿ«pW¶T !ú‡§dŸ^z¥26ŠFŽXÚY™Ý£BH»XÖ³E0iq˜x‹ ž Ð¥]_#UÔo©gÓ1ò²³«FíæÎjY«ùŠ´¦B¡™4j)©Ÿj?2Ʋ^¹y¥wyeÑ…eŽ! šI½¦²«jR- z Í5½F˜ÑÇ=!g\uh¿’FŠOxH¬¤ÏC@'PÕéÙßÿ!j‰V62àÂR>DjªÕæ{,»ñG¡I gI¨£Ûä´œÀ^%ðgD“áÝÔÑÃj¨„4ª½°ª« Ñ„!V‚”.sqcgf$¼ÞAäyZG‘B–;“ËŽÌÖRÛbÁˆinZÚU¤±¤l’tɤÌç1úü&¬œU<®Ã³LyÈB| :rå®w˜8Òµr#ç_ɫζhÞîŘ¢všŽŠàÔõVê…uÎŽ;@Œ,Kн,’¹ر…*ò*aâEsìÆ¹+Üá ­ÐÉß Û:²Ípð±±)‹‹ˆ°¹Áa’ÙEÄã; œ¼fôé&9<6UfN-Œ‚Ô¡IUgBG‚Ñš ƒ¯ÁkXÃ.ʹ˜~Þ=«?¨ˆÿ©¥òX°dû…ª°o¹Ñ>i“Íü¸äI©™‹˜Ãl¡Ž%jUXÎKÙ%n^(b¯‘o% i“ŽTäÖÔc'¼ß2™Q 8‚Š‘Xâ'…©P«2ª€µÈ©|›–¤þ›4Üùß4¤c0SáB˜ìc™U*xüL²ôj3~E|9¹Ë·¦ŸùY«LÍGPj_7!a\·­z#GP¨«ãå+,šQž›¦I„R²úä‰T{EH¹Õ€¬µ[¯“»«ºÚ›uP‡Û] 9Y@(ˆk[ƒ…–¨âÚ4à€ÈLûL×Qu\D#&úŽ ¤†Džn¸xüœ¦Ôu)ã ;Ò*Šé,yA%‡e÷ú2èjÚ¬°S&¶Éšã.dñ&©š¹4{°í…‚ډ͂gj5sH)ÇÆS  ú€ËÀÄ›£Šc°žBdÇ/­‘'Q¶µ©¿Î¾9'âaÖl‘óVdn–˜u¡ƒ¹UÅGÔo›yÆÙæyNúÆdZÍ€ìá¥aøü“¢¡O†%ê™RMOkâcË#†ŽD‹¶A¡¡a¨_˜ö1©u.ž‰ÙA­I 5@13†ÝÙˆ©3±‘%fYV¶šf6%!Jâ²é«’³]A¡ž³.‚³êû†«IÁOð§¤È,Déuã¬çEÏŽ›‚/(®$/b‰åLŒ\w=;Uô¼$_özœäT-Z‚b씢µTô çääE­“øé vƽñ%–öšLøú€§ƒ0Ö¶5õ-JlàK¾P ‚yÛúvF4ñÒBÿ™Z=r‡äOXÕl³›Je;xô¸–ª4ñ¦&‚A¥3GrÄsîJ)nÑ‚ª¯»Ðí’ö ·ÉRÒc»ÀU}e]O#GV‘Èû©™‚ªFœ~¥tU‰{…e V>bÀãpúÙs8øO–Cg¾<ïŽ3#C‘D­'KmÈ¿ý½Ý:dd¢´K~~]åËv'š dõXåë™(lŽkLL+0ä²™¨YõÈxhÄVÀÊ 0ÔÔ+$¯‡¥³ ȯ’z¾±uiOÈå9Ç“-æ‹ÇZ¼H±òýã‰:Ò©DPÓX 5 "é—©žkXnh1A`& §Vd5ˆBhÛäw¢X¦­±j$” º•ž´ÕW& ´Uª¼ÈÔUjÚ¤q,ˆ´ŽØÓ£jôÈø®cÒ­–nÕȲßý†u ãKç;ø±™[¤“„GfY…QÉ“$ך26~ž9ÙÙD0^ÌôìÑ‘>1ÏÍ·¿ ÞmÙµr2wNÀZ=²r—ÓRÑ8øÎüsD¤•¨œßÇî’eqÑømàÓ2µm@âÇohÖËìýÆDÁÒ´Ù§žÔO>OÊn̲š¥Kp÷fB§ú¦¿…™§nÖÑm¥gÍ£—¦Ë+E×­%’kìæŠn(nHE<š‡uEV‰{dSÅ’ëU·‚9%i"f%{+.4€±(ŽDžŠ{_ßý[Ù¹¢lL³6'u_'¥·rx²E…`ʱ3bÎ…•ŒSfÈŒw ª¬fñq­æÒÓ’0 D YÅ‘º„"ˆ®Å¿³©&¶—ãÙ|gª2¹1@ʰaDwN ØyŠžP3Çp½Wÿ Þžï,ݺ};ÞÙ›gR×PÔtíxé]"óòK rãÎ1{¨RVè„*ÏfüÛ»·ÐïRw¦¢ã¾—¯í@iÙ Ù‘3Q66¥‰Þu4ÇÈNªŽµj9R¬‹ó+¥£±ly£È«j…˜¬c€ j€X?#Å™M7º¿ØÕ?oûɦÄ鯑ˆ‚yðó#’ ˆ‘U^dvb¹Ç!–‹fKŒ²)‘ 22ˆ Œ¥‰5.äHJ! ÝšQV«‰8“8@*ì͢®SâT‹Ï4DRElxDN7ÈF¦¯V ËÈ6Ø—[PÄjË£ÌëªPÔdX;Æ®Êí« $ê@û‘U¶óS"xæ¬GY-¦±4—à«ù ò©&œ;Ž®UôÞ‘XŨÎO¡†R¶23ÐQP©“v<õ’Äž+ýty³Ô‚fBöZ”sôÎú¨ ·@Îô^G`èÀ<Ÿ’žUP– äâ@¼¬Ã[Áç "ªhÌêJõW@hÀp¹$ŽýÈòp;UÕQÞ;³ý ßÊë%š×³;Ìòvœ™XD-åîìKÍ™˜viÀ×-´8°Â€+uûW[$ÞÀ†RH×…AxÆDr7i®àþGmyó¶`Y Ú¡°¥‰³z>¸™@c“įäëò¦–)«pŽÌ¬«ü*·ÿˆY_±úòÖ1{Û&¨ÅÐ7i†gèʬó Ë_òX•‘÷T/­[+~bee¬Û&Tuð¿¹ì­30ǯoÌ£2²1@ ·°@4y5MêA…ã’>auîÿ(K¶»ñ uw@`G#&ê{ÑP,úŸ—æŸòž°*8 QEì?žGÓŽB'ƒØÌP óÐŽÎýœ–¢vUv城À–Ÿôâ¨î]ì®DŠþä²–à1wf嘿,zufPV¡ÓñÛÃÝQzÔ]YkGNCpËÖjfÁò:rªŸ@‚lÖMj5o2¢¹Ýˆ6[mØë­ Tƒ®Æ=XÐ( ‹ã…HX&Á ‘È^OEØ/ñW¡+7rÁÚ}¢«ž„’T‡” )3‡w¸:'-Ëu&…||¸$p':r9V,fê:žG¹“Ñd9‡ì„ª–= .¥Xª9 ÀŸPÊÜ©TH¨ ÄüŠI¿µ¿Œ|¹ò"°VPfX1$Ŭ¥yRÚUÔ†!SÈpä–eÚˆ 9 H…£e†óA¾66.êïÆÂŠt|}|cDIDyh]8b[’­ÔW€½ÕŸµ ³IYÀ,¡q©t eº±~>C·TV¥B‚ Géä‚·ÅC¿Wn…}ñšuj8nBëÂÏÙÁ$‚Ò2€:°!þJíƒNåØ3Ð÷å«Ûääw.¹| )ê>¾íùPQZ£$7ï† ç´“¥U^3Ge!˱®ISðAãPÃn`ß'ò·hßQÛz¾âÑoøÙXyi^Ñc2RTîå«Ágh‚¤"‚Äê'õ¯{—ï#Ó/E½oRýCÜZv߆¹Í*Q"Œ¸Êæ˜ýš´È«ò’P®ÎÜõ zŸ¬ŽÎÔtÍ£¡ê;ƒZÉ–&Ÿ…Ž÷µlÜ(Ÿ–d)R¥M  ÈL’:ªsC÷¿÷S¸½pßY:¯’ûFÌq¥á‹´ði“ÔŠeœu2’ªóúꪭPQñÓõ 1¯mÿO³¨f\Iä阘H[ªõ4M¤˜3cǸ팩(ˆÄŸ`f` 0õšûÿ¦t<Ž•ÖU±ç ‹›4è°¬ˆ#e $ŠŽQAU[•}HÿÉoßööûòõF™mLÍ'Ò­¨dãìÍ ¶¬KµfU5ÍKÙäÙô | ²~:O¢žï`Ù¿ $5 >GtŸŸ´‚PõåVÀžêAU~B2 ¨û£QÓ6H œPñ¢&0×µTË!$”jÖ”òŽŸ´I¿$W‰2B[£ÀÊs|¢·,Œ^4•1․Ây–^äÐMŸ„£ûû;o¢tn—í.‰‡Ðº&*btþŸŽ‡-$M,òIËK‘‘)if‘¹ff<(U\|‰srVfUZX¡ŠAH …4PÅ#XÇà,Û$g‘˜•šmSÍüS˳„!CšÉšœVD,k[t´…9•Š‘I#²ñð%K2¯äªx+ʰj“ÀyÑÉÁ4U4áТ‡•´êߨçcc³<ŸñíPȳ‚íÔ¤g[×Ì{™o#‚ª( j †,\½~‘É£ããÍÛÄK[ጋE”Á%‹LRsê*ß®ŒYÐ!æTc9ÞSQƒnK¿†Šxæ«þÞCÕâ¢4_’ª'áxØ@Rö ¾m–ý*ÿS•‘ùwe†=Ôu4É´ºJMy+ ›?O ´ªÊJL 7Y0'Ó9錱ÄÂi+3»«%V¨ÆcŠã¾8Gr¼'JøÃËö²žKYã?.1Æ,üyrE¢¯Ê«Š‡ø´•ñ¬là#uzPÉ…+Ó6o½½¤djš”̱–×7 WÄ^£Ë’å/Ñ'ÙV.ÓjNK1ìÔkŸ³¸Â£ã¯à&ç’WàžI¿Ï¡æRŒ˜Y¤Ø[+Ï—"Ä›r,R·,¨6îØ¶·k1‡d—…¨êÀ %Urx–c)œ€ˆU í>®ÿP]÷¸ï J;kA9#$FUî*löpÒ-nÇTµOIš(V&ŸQµŒ½›ˆ›?MY1|kVunÏâK6’*9j*£ —Œw4¾ßãWì‹ÿ¨¿ÕRð/OÍŽ^•¨c³£UU2,®]ªñÕÀòÿ~…Bõn¥ƒÑ:vW^êÍ®&2†|§”¢*–[U–¡ÃKågM èò·b ˆc YƒjO#bð,ò­Ìõ[}ãiz=ìô0â’¨îúò;:÷þåÜתº€³ Uþ±‡Ôý㕾w Óµ¦ m*_ Jr$…¬¾i)¹šÐeRlWÜGªœÒ1.Ç&òš°áXøÜõàÒrn?òŽÚlK*ywiÔü8Œ;æwæ”­Q|Œ“Èz3ég * X°‰ZOÆV“ñ}r‡°ú/Ñb©’fžÓ7P¡¥µ ¨Û…થVŠŸ]aÕå‹'M„ð²•ÁmÜ@6¬ÍVI<’Ä; ºnž g“Ì¢Á _#©4Ù]  u5i…gì%+Q*ŸZ[öû˃§©ò*uJº$?™¬¼iøÑ™ˆe“õ îO³„\ÝʹKCÑœ4›º½\¢×š8SÂ)W¡™ñP©ov*Ëõ£?o«bá²ð¼°J£OÉâ°ñ"3U]ÕÝšI6*C‘óá’‰Öÿ½]Ÿ¤N§väSCî4y:†ü@µ5ºR…y)l^Ëy (ùbþï GÈUõ¦»D‹>ýznœ»Y¸™ê{*—ì½Jáù=‚‚KË«Ñ$ú–r’à/èYxb8BªfàóÃôyÚW#v§R©Ò‡¤Ájt~T*pB!Ô舓 z3‰ÕÖ‹Ñ• Ð!î¿Êö…¨ÅÞ}š‹GNIì¬á=üœzhyÊìÛƒ`Ì­bÃ|¯b„VèPµ· ¹Ÿþ¥ö`(°âÂâÀ€£ðÌh‚j¬W¨êj$*)CߨcQÁe$·¬±¾?ê&­L*ctV ¥¸QUå¦UÐñÅ1ƒ+7TD „«¸àÁ¤ø¥.¥NŽÌS”VUrêë èX1>5e(ê e .HŽÈsØÖ’yNýS–nŽXELO5£²È!%f‰Ò}¼ŒÜ}t"uÇZ§óGFAä³Ñʽ !ËÈQ¯ J˜àQ3Ñ ì8+D2ðôCÄëì¹:‚9Wr®)—cŒÀÅüÄLqç±£W•u‹·íž0¨ì¨·„ êøcðûUpA‹PÊ1 Õ!Pj¬”ƒsâ -í@&Ô·°]dÔ‹U+k°Û×¶+,ü­:Q@“T= Ñ~¶ãÆXÑú'< QŸaCä&k¥¸haã­‰•<È'EèMD{ µLéD*ÁD•Ô²ô…b£×(F§©j‚Ê´b´‡W‹ñ@…\ŽTöì]ÍË"a‡cÞ"ȋְì?ü`T(Cã4¥fJ˜ NœPUA†å²ŠåE€y>"‚©èk¸ °›nuž½ÛÇÈ›%¨‘a5µ _G'€ ƒ´Ö(‹ãEw¥Hd²8¸jqÔÀP̂Żöäp<”F¤‹NT˜AVf¡€Ħ î¨ £ðŒ'ʯÄïåz37P« \…ñ™<* òu’ HQ‹HtŸf“²»'—íe8êŽ<—óc ‹ÐwJ*py±ZrÓg`z†Îï퓜ún„[>ò+ƒ*Ö|§Uš‹?õa9xz/Z=ŸÚJ^j¦´ÜJT)V$… ¼3)“m‰¯·r»HI¤RÜÓ7«EãCÜRû3•ðj‰ «|øl2’h/æå܉·tÏ3;æjRœ,œ!l|Fä¢ M”ò”›­z‘ú¥.„³²P;S:­yɯšn2ÇÈ·ã!%iÛ¨tV à"ƒpOè9Z¶E Vœˆå_#µè‹c@ŒýJÊRp±™±ý¥; £÷˜¸É«c‘R‡YMÅ?Y³Ÿvi¿¢ÒhõŸ`³k…rØXB; –žÐ»óh¸Õh±4 ÷¨'{;ú§“–H \'íÚÙKnw@G‰*¼)F7éëOÄÃÄLUhó—G¿§~W])â8Æý”ÑžŒ$Ê*²åÚ¤V@0”d6^\åL‚¨£Nì¦sY¬ÿûÃ9þ%RhIQq$Q\ŠÒIôÛ‰)aÀ¤‰ÝI|æ.‘„hjÖ’E¤'ÚýÞEŒ–(¾%:…mÿy‰rå‘jäÑr†µzXäOÇ|t²u)' Ÿi‹¥91{¢Û'¨È¬SáHǤš !òZGÈ*ËÀØ«É-ƒðÌÊ= œ¬ªK³jì@Sbʵ¥âü°Š©.š˜ìI4=!Ne gJ_Æ["të nqÇ¥h#ä2ztÝ£>8ZT0é›BŽ‹¥á¦*3ȶA1tÌdá²Uj®[-»$¥4ïÜ”H:ãçšÙ°ñ±›àÛÈó–HHBÞ`§/UD\›°šV8ïj³uZù ²d¯æ—o `/vg!X,ò£û•†Áå‘‘%ZI{æ¹HÅG„Œ°4Ë:€;d1(±Ðlv²›>ÆwÈÉŦDŸ/2SÉÎEËÉÖ5Ê!pËV‚àáø+G„¤˜Xøãž5¤oep2昺6!kâ— úV†íf»µU+Ms=Ô4^<ØI—tIY«ÔT½š¶ÈŠäÚºŽ–sµJdÈÓ#UÔÔI1ññ°1MN(±›V/ gzÂòsn§¹t-§§[:飶1µt±‘1©äŒ‚Dò3î¹ 8G¶5 ÅJŒÒJdäXRSªÒâ›è¼lÜì ÜP¡ÓJURúùiØ`2?ptål•Ž5‘Ÿ’h•)ŒÈÀ¾ŽPn+¶º)—R)» OÍS#XÖ8ç(ÃGÓÏ™ÏumO<*›ì#3Ïò+p˜½æh¬×KÀÔ›Jl›jº¦#J ¤i2ð`âT# O´¼™:™SÒnÜÕG²rä<Ú:nöõàbhÊØû# uÉËÈÇÉÇÌÕþk¾iøþx³Ê,›¨ÆIº4#”—6¯húuµö ©¸ç?/7ÆÙ:æc­õqÇQzõøá¾h‹ð“rf“ ôZ,†Î“²Z†*l©"†2‡Y<ÐÚC&R¡ÝmýgòááHð<——MXÑ8 ±w2ÐyKHðâŸ) Ç<ÎASжw¨Û¾¸”ÊÇÃÐ4ª÷“Şݹž(>5§3è-ò >ã*‚v¶‹iSRo÷Y¥ç–Ô éDd£Ç‚™ò7nˆ‹7åqÇÔª9¹ú‰YÈ.8@äZœ„5YC—ÙŸ”òIñüÌ=šµ ÿ¹\Š3‡Žbõøð{¬Á½ÕÒòf ê Â{=¸B¶$IŠÀ) ÄÏ”íÆÌÎÌ^2Êú;FÊdZ#Ü}ÄÌŒ¼œ·h¦zŒcvq‚M÷FÃrÛUÓþJ¯º$á‹>baäf:ò@÷ÄL©ñSî-ϺjÈ>I¦TÀCñ7Veå‡#ŽÝY[þœÜ†½‹™aJ”Íà-¡ ~¿Ê*²ðÍ’ݼ™\Ž õ¥açæ÷1é ]UëB—ÇØ8Uä»*¾=Wåò™UêOÇëÈÞPŒ¤ìOžìÑE3+–aEÌ ^£V@ÈÀòB°¹J|Fªâ˜W¼°p+öïDÚ¸¢UÚû€Ïv”Ú‚uFø~=AëÏÉWãØô`uRߪÌ1ÿü¸ýÿõ“h·¯ža×'Ô½“8¾¯¥ãFv¦á۸݅s,œ¬I5/à³I©ò?Z,šW+%['—ó©Pý6ñ©R´[·³íìcôHÓ«¤jZJé§"Ur”U•ž/*£-ŠšÒn[†$€üåGÔ†…¡ÈW‰§‹j€] H™™µ2†JE‘ÚvO^úW\ÏöÏXÄë](Í øò¡eòÍ EîC(F$¥ ¡‚²º‘$hOùÿè­‘²4ÌÕiäÁïiT4í*cVÂØÕ>Ê‘±èÔ ]É—iØÔÚÉ:¢øÞü°`Õ•"(U`K RêYDWCËÙ&o£> K×O4¤®ÅõSxëz^™šhèǵêZ1YÊZ~g†Ô§wåê¤?vy™ä&“¼‡›³ŠÊ¹t¯b™K;«o™4ûƒ2ªzý\x2Q2 m£`­HyV€®+‚ …ƒ!+V{¯Úþïéþãè˜]Sõ1±ŸVLy“E›ÆŒ9“ÀP“)) ôcÔ2zÎÒœÚ.ýhvœÝ%ÏŒ<©ä^&ÏÙfHv¡à‡áçéfK6NžîìÌžU§n:5R\vj^K³³örâJ««i­‹£“àPjÀ ¥2X­T÷ìû©(øì¬^ËúIÍnНeöEî<þE ‘5ëÖO·!=‡!èõÚéòÓ(ENÄ||°±ÉÛe_Åt Ó§HušxÌ‘¾ìˆ$–Õݹ¨ IÉ XÙ'Í ~­àBã’ÌŒ2.8,YÖC°,h –™U£4ú•+Z"àÎL¿³©P¤õèK'@݉+pÅ‚ƒ–‚ìpÓ‚+T¹!O íÁýyç¸U{‡PAþzóÖsû™*Ô=ò+=]™±úö^~!A"Ž.ÜþÿXvz)™i«V l êx¯‡ sñè¼ßï¾ÒiEÍbÔÇf®9'(lZÏ#‘‚·ìVfNN†PKgnä¿õ=ÖyýÊM±4œÌèÉ¢éò…ú„j¸ Ç‹MZDPüèdG³ ΂O•ez•ý€««ÒêŒ{v¡súš¢ƒ7 áQ¨¯Üdð“AÕ«i—“3­ÍœÙ[’‹/áJR¥hD•fx“„§Ó7·c뱋…HJ¾ŠXoÈ;€ ð¾E€µp‰\cdöÉ.Àò…ˆ$¢‚uÕÀebT3(RHùòS™>—úéIoXi‘\%ª­ä©(±»~Éǯý»XHäñ>ëGòM¨áþ¶_Ó]Þ™Ø8í:¡òIRŽB5  |$),à΄Q@Ì&¹vÜîNê†_ãYñ„õ¢ÌO¢NrÊøRmNx›Q'^ÉÇ3j8wumûoõÙºN„É“äGÇY¸ï%ê¥r ˆzŠ:F€±ƒR%¨Ê (¡Mwß^× ‡‰Ô1¡ÿO60.lªÌ ¶µbˆä–Âç·ºì9“etÙ笘2Y~xI!hø±ý¥EÆú‘AçA_î¦J8<Á›ˆÃ…éG=ʉ€”¡(«áÖTÇ)õe#þY ’9ŒCp\ÅüÝU½¹[wUž¡…ŽŽÜwĈ =AîàÕ[Ýÿ_R+×–D K{©^}k&Æ.9#‚0Bzòàò…XϪ€KP³Ë䨟gÆ %nÈo¼–R‚,“T®3´LÁ&4A´?ò5ÿ4>OÅ€Iùà7§¼^Š|†~§Ç¢µ˜‚ÇÆhZm>QGwSî¼ßJãBUO>wi†H–JR…¦hæˆGJ)Thð”`ÈøúB\sV=Q™‚HÕÉaób½GóÜ;(ç«ò*,êSƒÙUBÇÛ«¬Ð²÷æžCY?P‰MZНÙBúUu%j•xæÇøÔÛSj>êÕK²«ÑBT/•cÈ*·ÈU€,†ã×î5$Ê ˆú©ÀO ¤¥Âtà='ÀZ‰ÂÉhKàËôÌD« ÓÆq£äÈr|³E-ã¡o gòOÙ•—óu˜ Ó±¦ÅfeÏVø”f [È®@ã·U^xñ±êˆü©G~ßUóï#×ý?íÿÒœÜì,ÙÔz„› ~vüšMX%Z,Éè žÆe»:OÞORËÅéøQ¤¹™’Ç J<»0K ªY‚’X|׌ƒ>;Ë3I 1«¼Ò¹¤…",ïÅ‘J û¯ö|z¡ä£îÓðÿ'Ò}Ÿ—ø õÌ­9ùYaÑ[¸OR×2Ÿ—é9~½¦£ FnS^މŽ¡ŒÒ¥2èËÚŸt·N¬,•S¼Zn|‚{•¼p7>±®ëû¯NÈÜš¾£’¹G&ùÕÀ†&]!ò%IãcÓ78¸Ž)9Ñl\™&JE±éCô‡ÏœÙi‡iâŽÔ̸«!jN~*ääèP$âµpï)ˆ½™Y^ý¹íOmbû;¡AÓ!í™k½Ÿ‰å““"©b‚BÛ‹ÿí€iNÕÌ]w®Kî^±4¯ ßEˆ‘¢ìö‚­ºG»0’Kg“¸ªlÒ³(ûèúe;Ѩgçz¤iä\y¥ŸÌǼƒ<âpWD¨&ˆk‘JÈ)?"LÏŒŲ^E;8U„ÙIæR²æÅº=ºò(ŒŽŠMrK)œãŠf ½¡4yáiÀºעѨÑ$ªt ¬KTÖa\‰bãQÿ’B¹¡çÄδ˜0z(D.²*ãÎRl…ÙÕ‹KÈ“žù57Ú*ˆ¿žWä“ÿÉù4d¨TxÃZUÕ¶r¼%(‰ü°#Ž©+ddjÙY˜Ä¤“­zF‚µ ð¾Y±’}hÊت¢HŸ%4áÊxÿ—ÐpzÉçv™6vLp­'ŠP©éÍÇn ¼HOnè÷Îjã ª™•žS;xä¿‹ÊUºAVTf@*þÀ$lXä±Ë»I؃Ñ&å(ïß­ç™VR®Ê(ŽDìÌÞ_ȺLÁWa ÓHê¼’ ÿokz¯¬Ûï{n¼l•Ñ1ògl}>¬]ÇqTò+÷žGfñ(W޾$³èÓüM#`c`hÚd1ñ§ƒ,|u(‹8¢…V£0_‰D<«»c%v?±z}Aý?Ú8KÄÓ£ c2BjÌ Òš°a2yñ@Ί…јL?©>“£äníÅ•6¤´eŠ2ÄDA Æ[ÈîjJÐûûUzкL`D“ ˜Ô3Šî © oä”pÀQà ·ÌÖujß5¨ô\tX¼ÕìdˆñQÑÝ‘¦æBG~dD¬–„Í¥#5„Þ‹æe pJ¯UnÄ€íU3òüÕPpÎè¦å|°q?#«×#ÄÊ“E³„Ÿe »3ÎbÄ)ºÊ¬¬jU€4›-~åUgFïedï\bŽxB«ÞFÄyzu'áA%~ (õB8€¢ê±€T/_À« ´E‚¿ZÚÉ%4’7zG ìä…ÁÚöäÙU5st̹²ZeáÏ· H»|!gI£´Èiù^x`¬³qÏÕþû|ò˜cI:E #:ö±ñ‚¡UAoØ¡Ý(T;½Qxv!jl‘+‡XUŸBÌ«øäʱg ¥€^§±^…{µ ‹ÿèR˜Ø«œýÖœ‡D3 ÔpÍBþF €yZˆŠ¬'ux n` ¨m` A¾ nI¾hÞ%úL¯Ý‘MsyZµvÙä€Ä•d‹+ç¤[?ßz޳+/)òªžO.ïÒ})ò ÇFú þÃ***¢¬ÕJ¹œÚlA›1 P¿3.ÀóË8…WQÆÖqqB¼¨:•'ÉÅ<­OІ= «¯-ʲ£õúœ³Ñ赟FàpÓø™²ö ¬ƒŽì)ý{q/úæXaA#I×l¤êN©´…Gˆà+XK@’¤¨Œûl–U 7o”¶:²ÕY²G#Ÿ‹ç›>¢ûŸ”ƯZ?x‚&LÖl¦u.Î] ¯€݇O‹õã†Íï]ÓÇÈid¸®7wƒ$^t k*ʨUý™^p(‹D%›ã¤zô´ÚT»T¨¤‹…§,ãŽT©$/ ÁTÌêJ:(÷Ç÷#L<¥>ÊRþFAV5BŠT¡ey•R ‡ cÔ}0ûf&þå†E Üj¼–òÖ”_ Áñ°t¶C‹’JÈ¥JP4®B¥Kp-·•ìãÖPj'#sfÆ48—|ŽI™o"¬©Ø=ª ÙÄ›‚B§ôázqόɣd«Á¼ž2…ýý¦Q†r©Ðe*–—Xõ~ƒö1l’ Õ¾æÉ^O•lù <"¥‚· AI5ØUžb ëÍ9"Ž” ¼(¬ï +t¯QEPzðêÎQi*rëf³*8¨=×Eç£Ç <Øí%l«¢>8P 9¹%k‘åê7Ø—'`Õú{màÎþUWt>AÜDVV1gG­uy$ÌK®3¼ Q=§' Ê+ŽRN?RtCîÉäCÙüL*#  ™pœøÕ{¡váÐúEŒ‚O*‡RæY‚xjØì·D%V~2€Ï èÇ­¢ÆŸNöJd—dWJ+/Tš¢ƒF›Ì&½;& ;¡êÈ–áÊûóöÑÔñÀáY>‹và¯Á%OŠ.ªìÊ7Xw6§¶uU%¶ A Z’E*‹¤ÒlæF´Wâ\?™‘{0³½$¡™áäNÄ*ôäZ޲­)SHªÈu‚ Eù'Uj'‚¤”^g²,ÙfÔu¨^,éñ )Cå,W’–¨$€*¼âà`…NB#©!&fÚ~=$m9¬™DY˜¢­W°vfàŠ7`èK|Â09E å\µì„©U<¶Ï#ÊÀäW`Ô–-FÚµFUÛm Ù¶¡ÉT›'f°CÁ¥—‚$gK:³1vSÔ“BÁ¼¡æˆÊÅÈWæ\Jl‹ã? B j(ëDI&9`{'‘i>ÍÅ$ÀS'ešM™ 6;J,U*|ÁVGªL©K+¨n{%T3ué%sµFIξ:Ùïí8“ÖlÈè&Þ'f„ô«@þÄ3 fJí3È¡¾Ì~Èß÷0$€81±\}Æ>WŒ¶$²)1)N(w±.sá¢æcW&ïäÉiþÑ—”ÙrNóF91^]¼§Í¼œ»ÞÌ+[£Ê¹Ù9m¹‡ %°P†Èbi¤F À¯þføK v>«G•f4ùh h¢ËÈÅVqk"`ËRJTjéY=ÕððªM _'¬žJΕLiS!:×'²£¨y¥JÌ3”E%»~b½%U5•úãɼ#ÊÆVue‹¬¨8R´ï1.K±«,¨~i–‰8ÂÖé\›«W25I' ]ÙüR)H'4›©+qØÙ(;„u“7âº2iË¢°VåÜ>@ZªÍæËSc?s%ž6!‰ ÉA‹Ù úgRA<ê\µl \z+…1ø€U”,ú•W+ÀÚÂþ«-—4³-7ȤWò[-Vìªj²ñJ®«á•ZU_…ÄÇ^…–´ó*»ãCü ‰ŠÖjãÐ(ycäÝÿ2®ñi¥Ó"˜þ>’Ë£Œ,|o#£\ª"6&•¨Õ±N[¼y2ê.†ô,x*UãÑó)Tz´fþ,JÑé0…¨¦xJ¸¾|w˜ÏUÆF¶VJE&ÖFŸäj9 ª/luo"âÁDÅ •WŒ®¢D 7]…³*”¢J®ŠÏTº¸Z#d·¸Ô’£2R†@Ê5D.XªBÞ‡™IRQÚ•˜†¢díÜFü ¶¢Ø•fÃYðÙ,qÈHš‘žQ#QÊl•yOgU“"b˜q0ÀѵË‹S1id»–TÔó‡6l²íZizc.*$Q’ݘˉp~¿´H_-|ñ•—=g).¥• n' P—ÿ[†Ñs@öîGº¸rž>H˜jz¾6“þ«k—222¢·’bÆîx€Õ³ÒŸ'»¢Ú˜ðo2…iË’Æmá䢑¤Ñʪ¢c“•EU™¢Û$“¶à áø² WšÈ­|).] *—fB„8‘œF×–ª²xß Eé•(m?(Õ6OõúEJ(¦V<üSÆÉË·S4Ëœj7&˜ÓpŽë ³ŒØ+ËÖ†/Ÿid|óó^ÔyŒ­T,¼EUÁ‚2”Фˆ©Í¢dU_2ñµc@šŽrJxºbY¢kø›Š>~TÅ\f¬˜Ñg2â,›; À3lc‹p¶Èö2mNÌÓ¨ÖDú\”监‘a3jøbäáe#ø~ÁÒ¼+#ãð¤Oûr ö 4´É(ôì¶£˜srqsæ…Ò1u“¶d‹˜f¥jPü¾HËÊrZ´½?!¼2Ö3†fn$‡— JÂT_"co³7V0QÃ&3cäb ÈÇ($ýgØÂ¬Š…-";ͺ³êA,y’¿Û*ˆÖ<௕32öÑî$OØ–Qù‚E¶¬]hŽâ‚‘ŸTªKlÈGt$r ßòo™—ã„e¥æc4-\wù ÖBÓ=UZVG)Sò÷^¤{+}zË!•×#;4ÒÔÂUyJ³fnJM8c^Îìfä÷Vqõꟳ¶5.)ªàÄeiyR+§È&{±˜jI®Lú{÷íòŸ¯¹d¶F$žµ½”„ÕxÇÊ3_Ê‹S¯i¥\s&§UV ê>°S"£ìX‡ JU”«Ùäµa«†TD2BÍ!HÖ)AìuÕT%€6ØxºÐîhH¦I Ȧ"ÌÅ5pÂņ2¢]TÔ'ë»0påOëSËràÎdMݘõS&>ËÃärc/'ë„Q‡’†F8êÊ;݇rb¼1à‡ú_/þ?Ï´lÔaíÔSÈ”2dävì}ÂûX8aÇÙÍz¨Yby$èÏ ÊkÑܪ‰ªÒ­ìǪ‘ØóÉä0$“*™X*Æ×Ä è;"0}j4Oo‘AGI$}ÌKI·1 „‘mÇ?šäŸSÍ_JÙÛÃE®ÚÞú6•¸tðc‘ªâ¦V;.B¼û <Ð)ef$­Áe'“Ï_ù$ÿZ>…¤fzåöï:i›gEÀÔów^ÌÓ1çv‰Æ…r)—¦ _"ÀpÓÉBOŠÑ™}t£å¾\1×)1»Ì”7,¯O)rÀÑy^Œ¹ìG=ü€@a`CRæí‰Hæbæàd¢äcXe½i:»J€Ã™‚ßO ¡ÊÌÇBÑ?r"›6!£·Vƒv‘!@%\…V(c—Àº‹=ÜÞÕêu>3Å$S• ‘þ—7,|¸‘Të(G2«ÍpÑr¿ùËmÝÕÞ-‘Açù¥AJª ‚viô2ydx¹PEK$Ó´Þøz–ky,§ËQãpˆ¡‘PBÅ{”PÑYU•}Úäzÿ*d9ßjÞ»oOSô%ôJ·þ¿¨mÃÀ¥°qµGÀú¦nDžxšjOP¦VL1Ù*æ$}ÔÍ„ßnZÝs2£4V«/U²2˲´FW-ÓWÄÎUP5á?«ãŠ'éM•ˆ C(ØR´Í1R)ƒÚº)atlpA¿½ƒî?q`ôþ«…4RcåÃ…iC¡B<2„b±É Ááu,´èEŽ+^v/VŒŒ¨’ ¨*Åû ^ÊêfYÙˆeëÉaÀ 6÷iû²‰Ø%ÙP¿#†´ ¼£~É¢…yŨŒ¼‚ÀY°ßþÎJyù'–¡;æÍîŠð²P*pᘩ=Šiј±?ø–d,¾î¡@E`¢‚¬Í@•%É%`ó•2‘« ÜÕ æëB³Í°Ø€¯¬®Y‰kÈ‚ºL(rM äqÏÍ'xÆ«åQæ‘÷’«øè"г‚Ñ«À~C/n3·SAþä*m¡ê2©ç“ûuañÌ) Ê—b}»¨RycÏO«é–¦pª¯Ru¨ø° ´onB·nÓ‚¡ %CwçƒõDþàŠ¶“©wˆrW!´ÖÀ›ÓØ•$öà5ãuê 'ª°tU#7 vYB‚nvd^O ÚYªÅ1R€ˆ¢µšöÍizZ說Çe²Ÿ–± k,Çnr=FJ`o=w/•¤šƒµñ¼™H/ŒÙã›8Éc•Žì꣙d×ñÝÏB¢”8}ºú˪é:ž&—•yË 6Êøx²ÂÅ¢¼‹®:#ž1 5ÅžiÅÙÇQZ‰½^Ã?õ–£W—÷Ê©!U%2ÍøÌŠªJΊ<`þ¿Ò­%?²Š×IËŽN"¬Ð¸(äÅ(îXº4æÓUò EQ.ERô~½—>«íø1%†Æ^Ø&µeh‘Ï$ð~ €x5†G9é¾éÉÏD ´ëÜ#V` )µ~2µÍê¶Â¯©ÏH7úërÉŽ‹ÙؼhÊ)4gùž~lCؽÀæuenÈ,õ¼YQG@¥j “&=ŠRzð­±™,Ç£p S¾Õþá`« +;7«ª¬©Ag²â±kY¨8 tHš%<.ÈIýlûGéVáÍÞé<}OÌÖØšV&FY”úIfôlYÔA‹ë[2Žì¼±ß“ýÛíüÌ£&0Æ©öcœ7ñH½€,P<$[Î7TÁ—§¯Q9PÄ‘"wZYcŒ*„ŒlÎÌ©A‰¢¬ ŸRz MB©.TP%1žÃGÈ0Ç3{+îr¢`2£Ð©zþ¯“ëGd^ŽGÀÑÀkT½Ñ±7¶ÛŠjzîÑ×4}.™’”ós4ìŒh½o©¼ô<ö£wn (^“…‘<<|ËâÝ0i‘hãäVO<{{Õe_‡“¯‚‚§ŽÃ‘Ê­?•F+ö²qò±©C‘ ÜEµ0u_ö¡€¦{ø­ãu›N~do/i$ÅÉŠxÄËqáW†G¹-ä…;úU¬ëzvÌÛz޽ªÝqq°ñr²Íò)9!*›µXuAÞsb¬ –(£ÙO×,x_r¿®ž§gäáåf ¹¥6f.8äÿÛ]Eç dåG«°Ĩ–mŽÓ´Ò~SO­ÿ$ßtƒ½Ùz•¿'2/-|âÒ llb¥x(‰^r,>)ÕÅ 1ƒ&ª‡ñ•Z’¨oX¬\ŽÃä+㥠A¢º™¢»•\+{¹èŸèç³>š&÷oRƒýFPdé1Héãð¯”-h>A$F@FN¥Õ9Gõܾ íÌ6¶nÜAÔ›å{‰Œk‘ÅI"µü-hzK¤iοˆ”gtñyyÒ)ZͲ¸1·AìP)*ï>L²ll)ÆgþØÍV‹â |¦&mÒÙ2>TL¦uÇÌ*ÓZ©oÊâmÓ´ÆÆŽNKH[ñÛÿ¶L$øð›$ÙÊö¬^¬Î¶¯L§,ª†‹9:£«ãMüä9ÉGËíO fÎ ³SË^EĦÁÅlgEW}¯"g–B«z.×òUˆ$ ^WÍ1<±ë0†$H„ä[PÃà¨( í{ju'a¯ Š@µkM9C!^…[)ˆÔ«UìçÝM«>€ö£/jP»‰ÇŸ'†ÙÒ‚ßýž ˜ÉX-f&ÇiyÅùi1ÊÉP„…¥kPDû›Oë&vÕ3œV™„øYUÞB̘ÊP¥ð1¡(³Éh!…$XžÚ©\“ 6@cðc²ð¶3gÈøÐ%COKj±a6rV`p~¤tƒ«=wXà„-®Üê[“ÏÀ¡~«ŒŠ+!)@)•ä>!‚ü8ÛU­ŠeJA˜ÖÖ¯|ÄùGä¸Ê”Fò–U3~Âñ…~+)·‘$“y«­‰ÏžJÌqƒµŽd¸¡Y»€öW¯oÖ¢&UXµœ­ïyéq¦@ËËYÚ²ƒ£È¥”6UdpŒij"<õAdçÚo>?i¨µ&<ìÔ+Žn(Ùv9àVÂéd—, s4¦ÖüŠ/oZ>,>l“jU¹€=YŸA},×=PÜZ}ñqò›áKåäNS ŽÏ ‘'—þDF—ˆ3­ Èó#UÞOvN±ô­?OÇ‚ ÈNpg˜DE†§!PªŸ#5«2¼Äú2ª"_o^Šhþ‘lìd$雸iØ™u«dZ;4™Ø±%J:°^|hSåÔ¢³ÏÜzÏáiõ“c?c—nU¦;Æ,If!¨ü…§Uéòk°ÿyûœõ|©11œÇÓqv_jŽGÀ’À !‚€,lmvä’ÇÓp,]Ù‘v=·š²­­qgä~¼š p&’ÓÎæÔpð0ûþ#¥3r&UJü)‡b#ǃ6%Ç_á僥áišB^)ÏàÌÿÑT–#Ž@*„O#³ùÏÅ#ÛcEÅÐñPCiT)ä.¼÷™÷÷^QT·‘Anö£ò¦àùy@~`‘Õ¨Íe` ÿN8¨GÅ9Åú†BÌÂ8Ù»0ïG›‘‹ ‰öµdP8B¡WÉoÜÒ;ÈS¥¯‘v´„(ý`7ñÈu*WÙfTbþB´á[¯ˆ°íÙšEJ¸÷vöbÎÜ*«ˆ³¡=ºCv<Ú±Y«GâÃÆKvPC7 ¥øÑUT³€®ŽY‚‚5"…OÓ°§‰?Ù N¼Šu*;‚O,Ýùd ‘÷AU†;(¿4§ÅWéÊ(“@>kk“"–6 âÊQ*O$9»»ÇŸPÝzµ]*ìA^Á W«"Ì+ò¥˜€Ó,åW¢? âŒä©\åõê°ž]][“VB… [‡eâMÚTTnA.„ZÇ“£[‘ 1@§B\ªWª·e*B£zÊXò½]úBI'4þá•ÿSY ¢YZŠªoáœG_»/ycÔž{wpUh»¶d?Ý1ÜTIª¨¥£G†!ʯ ’Gî!x9ÒÔ<€J®Ë+îK)* ƒZ°7T¦ÈR@Z¦#ÖPfgΛ§5#"³Bé;ñ- X¿ µv§J›O¼ÙŠðûÏÊÊåQyÆ­ÏÖu3<3öTª9ìÌ)8µG¸îѦU…-Ž­äÖWY¹§CŒê AÑܬ’j´ ^È'%@Ó¢­PÛè¹³§S2¤ƒºS¼Ð<Õ.Š“@¨ÊóòcžXR®«Ó«{t§PÑ¡‰­˜ˆ“¨“ &ÆôÍDüd|Ÿ’³Œuy@SÄ­d­½um€Éó|„Úø T¤¸§„ÕÐI{»·UjUÍ%Ü];K†þîèî{¢¤Ý«T‹§LgqGNZ‡©cJ üû¹-àTbyà~cc™ã¨¥Qè±%y['Í™dQºðWùZZ²Ñ¼”,¨W˜w–9éÿº€¡•øuZ0~,\zL¬šaÓÙݸUFš4cÀ’A²ÆÀQãÈŠaÁ`ù8c’mVÈ?Å5Ù˜Ûðºì@M•Ž ýº¹iYt”,ñröÐV²t·î_LB{24Ú’bê’«(p̦O‡–A[Qiv/V˜ýN w@{†fSÞ“¯òî&ªAy 0èÍü²`\߸vnâ¥i6Yš¡Ç•O )!ÑÊ£ V+ —T·Ä²ÉZŽü’ü¢*7(&ïy¢¯·Œõ«•²úÓé了lr7ëÓ°µ ®¬óÅÓ¯“«f:÷~©…,—¡ Pê#(c^):äN(ÝgFï#JÊj|§ô3/u=˜Œx°ûøÖCF?ÅFÈ–wªþ¥z¨3 Ø{>‘Ĥ²>¡¸hø/?"©”Ù4øçФÂݨG‰Šy ¯gæ§NéO«>— ^ж?®úD¶Ñ©6»ìœ_‘ ú©în¦Ý'£u|ˆÎÙ0cT äND Hiä]Ôl8+³€?Ê¿Œ36öÆÛøÑž‰´q±t¼@&òœ1´¸ãÎSÓ§#8„1S:?–F7‚/Ðä”Яå>?…ƒÍ%ÝýlzMd¬²÷µ{­Ô´U¤·ã˜š;u¾ßä'vÜïÓ«Øa.¡qŽVlr…(Õµ<å<Õgul{A@–%”à¡5–E?t‹1((¶nÈóÄVŸEšŠ³¥'áuFç(ƒÿ Ç_Æ Ï±c‘}§‚îÃyLù ûîe3É»0`ÀQj}­–€}¤bKùéX±àtŽŠRôéé«ÎílîíÛÌÍË_¤ÐT°CÒñâ]"ÂY{h† —ïC\1Ø»ÚÔÈùôJ:ͨ‰J¹UR°bæÞ!±¿íac4”«I|5ëURË“qg+øj?¯µ>G¤z]±4ïÈÖ5k¨›âÚ jÒq]yy½PÑ FIß2ôäÒLP¯ÓŽƒ›L¼ lôLÆ{ç™i²”Õ3³p¦ÕùÐó§aÐÓ‘åfe ¦nŒUƒ3l2¦„+¡Õ\*¾€kä ÈOë@ÑUf'vTn@b̨Á«pÛl«D) …@¬ÒJÑ%Âß‹‹7•3ë7¿fÆZÖ¹%mW-XCsõx¡ªÓáò)Gb½ÏéžJâ0ñÀ­¦‡ˆÝï§%@ 2È S™˜Îƒ¢´k}K3,rp#ƒJúר½ª¨ù÷„¦ì¬þI‹-@¼Êûê»#ß ‡Jü‹µIt4Öu65+ÓcDñɦRµ©QÏȧS<µ»¬xá]ÔžT´a o Õ&‰ ÚYƒ®èŸP„#m}íÀ ©feðÞÁÙu]·êT™ÕbbTÈvÃyÂy¯hfCò1𫎴.1©–)—z\i@³!|iI4BÊíÑRß7NËÊ–&ƒ‹ÜXÑr-v« !2dü!«<çMFò4¡y—³7±¢ôðÓèu¡ëZÞ4³5ŒœÍhʳÈÉÓÉåÌëÙ 5ŒþÆÔù,E1aÂM1D…kŽDZKÿQbcàM´|lL–\ãƒÀ´Ðið–È\T‰tE±BV"9hª—Úrvqx)Aj$™ýÀÖ‘$Lìnã^¡S»±T:/éY-EÝSmaWbº1ª WúÈXºÈ³µ¸m¼xW$g꺘ÉøÑ*M5‚F\âá"ÐÑû‚æØ¢IÐ+Më«î fº@™Õµ]F0t/N½±£[Õ*'Ÿ•Ž]õMB3œbÞ^в`nŒTVMßì7^òÔ[ní >™º¶BãäJyWüŸƒeê™rWž6:ù*1R¹-ãT J'9ègÛ®±°1uYQ3÷^Tc“—¬Q@TN€eàiŠBŒX‚C¯g­gHÚ‰aF!ˆ«ÈÊÆF K*ÆÏ« hÐôñ4œ<æ6a+­¤/ ={¨aôhYã3°mb1±«^["O-bQ²¤Qº÷!°hC¬BŸFþ×[^ÖSpz˜×ÉÕ-‰‹“¥mèT¾¡9µàúƒ‚ÓzBÒDzâ&ÙÝÓ±ÓM«‰¦ij£[“ÈÑ2SL¾64“#Å-¦$Q„˜À$êà/Q8Û¬ëñ#ì½Ù§èÙ  ™CE¬’ Ê'—©uù5‚UW¡jRÓJF–0Ži˨àeK3Q8š~¢h©BÔÔ5\†,òÂÆÒÁïXå*,åF´ïQʈr2²3Le1HÅ"Gö⌟9FÂEky˜§j6ÉmuvÌë*óõ š-–7LJRfrL«U-2Ī[fÒY,Æ=Wtêr¼±ä¯\e‹ä†r´ÆqEÁÎöiOñRr»„Ñד"®ïUÕ4Ê ÁÚÝsµÈ°ž-äËl ')jððçæ„"ÕR­$45`ÊzùS˜âú£®.¥…M©¡åÂS¶›‰“åÏÔKÇþásr¢¡ŒŠ;Œ(¼ç‘ŽQÉ¢÷] éVÇÁÛX`Aßñ®¸hg“Œ¦‹;NÉNe™>å… ^ÌÈ §0F‰ 좙ƒUãè °µÚìéK¨¹{j‘4°§§“ŒŒ¹XeP$Z’5Æ“Uõ£´R½«£$Môà †&K¤Ydn­FZµ¿ eáÒtÌãNÍ*â‚Vx™~Í …4yY—¹BîO¶8Œx¾,Q›€ÊÌ_‘ðÙO_nÜ/eX†>$¿/ F¹y¸æ˜.¨‹›øì'LL¥b Z~?D×·,…ö9êÑ#ͧ¡î…hW͇•0†ª“åãlE¬Ð«]fÕy)NÊ·áÜämYbN殚ɳjäµ´å¶Vý1"Öal¦a¯œLÁé:Tð~Ü(‹Ú CÛU*ce‘D…¾¢}ZG"­Ší@í&¾¨Ñ̺í‹äå]ò&G’'Ø·y.¯Fi|XEÜõíÂq6à+sÇɸúÓóUåÔcãe|rÝù²á@ø©ùPþL86U]ª”xçNNFìÿ¢)ee~>hÀñò q'—ù_ß`'“ G3—&ÒA•eeùrʬ è¼ý~C#¤g §•ªŠ¸ªÈ 6YhØ·Uô;"$Ôƒ"Ù­Û>ÁGM¼D}ŒHxÍ-ê½L±˜ãW&¢Èq|Å—“H• O“)áœ3 †f!÷@_¢êÉiÕ€¯(Êz·)i1JðAgäC‡êUIÙÙR”Újï7¨UW ˜¿ñÔp̰p©ýÏ-ûŽø0òŒj½ß¯ey÷¨‹ryU+ñ%½•oáYJžm¢‚T+ "Ž ³¸–Š º¼µ½c6c`ŠÊÂ¥Œ8ÕömÀ…ÔîÞ<ñäÂö–ˆ>…ŸäsÐ8}Íý ú³éþ6óuºíÚkFë(^øû‹DQ©iâXÙ±ÚׯüJ‰§r•ëÏaÅgÛnV¬ U†N£§f[ P“‡…#…%xäyRRŸŽdª™LÐÐÉÂ,»ñÑw=°OÔ9ªÖLç¼ÁGïÈ!€=IÈN¥€WùØ©<¶ÿ’O´i}¾ýÉi>³ì\-êÞ¯Oö¸ø+vŽ•ºže­J$‘”C;–Ș~L²ÞÓD áD¨é=S§[òKŽ»,YáPx[?¬FÌ ÈÖ±õ¹ÿø|÷Wößpjg²GQŸêzdÎN§28M?dcĤ©qÊÑyR‰û Ò:p)ð5›¯Z1ìÑF T¡èì…îʨ½3!%Yì ¯ˆUh+Ô±e@iR¤/vî:uìßBJ2’ظ‹_âqß")4.Þê1éÊ(WЉ¿'CÙ]²œCY+ÔµAePÌoU-ðó*#íò¨cßâ½~°LæÑ’@à?m‡“!Ø ˜–f_à­’çê&‡]”Qè7 ´Þ'VCP  %¶°ÝÚH§ÊÆtü‡pX ©TdŸz©ïýüƒ°øò»† C¾á)(ágÉßÀ·nÔpÓ(÷çŽÍ0 )”ã.P°æ^6f½Ú¸§I‡Y1 Œ¢nYùS%øþ²³'*¦~ÄgWÜεafI­dG:…Ò0 ê©Zy”SÁeO]ƒÎ} ÏnÉÜËÆÔƒúªO›1 [Aüѵ¡` ”× P3ÔœŠìyu#@e`Ö£e†äY¢Ǭõzò;§P^ìcù4(W»O‡b*¯;‚JùYê([Ä §Yª/”%¨j+V¬±Vž@ÔÌ#§z _`z%•<¹j90L swâ̺xôLW-øØE÷j¹øx8“ÍvNÊ=<Øþz£aú{éÌÓ²³t‰ÊTÆÀ”Zxm)óùzÖ}åò{6f£KäØQü+^ëÓ÷N·êå°ýÅŽÒôëJÊ–‘©n¨A1ZسYÓlÈOÂ<*m¨?Xã’ÿ;UGÕ–ÚûGmú{¥O JƘ£v¦NC³Zù™N8¶fNM;äfeØòÍ“Zwþ½Vjœ[Ü={+¯dýL‹ý³¦¶¿K‹£/&%kIer.5{ÆÌ¥{H}AÈzÇ[ê¹uTË—"Euítd–eÄÂX|Úde0m;+N Èd8êÃDSØšöüÂÞ¸øyz^HíM)¤“ÁêíÝfÏo&Mßݲ Yö_dû°úËöÏ·÷ߦú¦×M~iÓµm½[D`´Ðsïþ>ZÉÿS…vIÕh•? )D÷ÝfÍJÜM'FáGgêŠì¼©R¥×Û’ñür~?D “¸ÛVk*B3y¬®Ü¿$¹CüžT<† @ ùç…é´h$ U‰5sýT.¬õÄ¡ã”=‘ ˜]ÎËd•Ø:ŸZé²G….F,Â|wÅ‘ñÌrˆõŠH˜@F( H·Û¡*Ê¿Ö}7xè¾°zŸ¶=E;·jo]ŶµŸÌbÙ)Ÿ¡êYZq~ôñ¬‘%Œ—Çp­7ìØÎÔ :Tm™l\i¬‚Æ~L™ÈŠåšˆÈÈGÍ@Æó-DŸ¼cJ…ë©?çOÓ¼N?ÈÇ«vÓ°Ó}i;OZÁ:Ž¡§ÓKÌ~’2 ®FF\¦dg$äùÿ¼ÎWi5ñvîr{-K~(!±qsÌÑù33([ÊÍRRaË•Ðúf^$i tüc*…¨‰”*…PU£‹ÔV¾·‰Ôó:ÔiÔ³É6R×+3¹r`INÀŸ.ËÏË“äÁO©©HW6˜³«ÂuRôócÔÉÍgå«¿3ETáŽz¹—‘^Ÿ-šØ l=1”×Ç<Ì0 ñV£Æ HäZ× ‘aP9•9r#$ 2ýŒæ¹žéH‡”iqá‘zNtw_›*X]˜÷æ@¤uo“•Yµ> '+VˆÌäyY,åÚBΧ³D(¶_ M™)Æ@üE(×îgɾEÙ ÒàȇfQ®À„¥(€‚cãÃ_ÔɧÛ.0U§‹+¢cD¬ÊV®n䆂Ömuj£…(*ì!Yéåšdí‘“øÌ×îÊVµ©/礞APÏ‹NìFA•ŽL?Pbø¹¨ eßññ'æ ‹Ó"MŽåó· Õe¬š5.Yh´»ÉE‚…–fÖ8‘²y3P%YÊS^¼wdZ!^7éI¬äÆr…*¬=¼å_eˆÜ•€b¶<|XÕžEP%¸ý¿ÍaÆÌÛ$ê±’¼³„¯ ¡÷“âH²Žy;³Ôw ´˜"U¯cŠ1°ÒØïVgëÔ›Ê)æZš’„Íåv` -@ŸcÿkÚVÅÛØ{·SÒ›?.xÙN-&gRàùÜ•<2*‚J àèîh÷Ø_ÛÅ·þçŽêÔ0/M3¨ñfò*f_(RsI?ë*_±±@ïLfì¹ Ûëlxmí:.žŠ©Ž¨Î!?žì|d*(ïÓñ˜ =?ã•&Ÿ{÷܃èx.y®C¡¢ê’9GXëbÃz1Òðgúœ°_.iˆQ¢O‘³`üj¬ÚÅ_R¤´ì4U¦±3Rª¨£†<)RY)êüì>e¾‹û7ichøËFJ<Í'5f™OoÖ]d(£ú•sýX†ìýÃÔrÁ¶S`î ä.Ý9/‹ è ª„.&8(>ˆ_–ˆf‹Ø!ìøõ·Yµ€3‚€xýº'#ëê9‚$˜ìGåÜYfmv FìÖÁ¹Ä KÏÜœ6–ª¤¨>$-~…[%]~x>½iAªƒ4?ð£°ïÃ?dq×£IQÉåIå^ŒB)ÃQÑCwp½P2S’=þ3òóW÷èä輆_ZYWß²ª…pÈ&ƒ¿/ì+Pr f‡`¡ÒSÚ‡â¨C”çØ*÷SØuOräöïÇ4ù…i†áA0QüÐ ƒâ€jˆ¥%üƒq·ÚÇPL1£X}Ì+’9<®öµü± |ð)}`ÄpJõñü¨TofrΈ¥˜y\"Uبª¡$Ï>(½qPÅ$ÈM ê ‰³Ó¡›ò^ìÆÖæ}„„Ôù@úTÄ#«Õ;¸ñtñ·„÷ì½–«4±e ye˜)ÉÕ‘ƒŸ& rìÁpDIÿì®URJUWаçÊ¥•@wǑ˲+ÀûI·ÁZ׋ðÕ·ü@ÜâOÓF.‹Eîy?± èÈ)ÓJî3ª¡€¢Û·‰`<¬q±?*=0ô¸QÚIèVpÀöùb„ñ±`NÅT|­“¿qitod˜òJñì¼rBvRÜû¡!‡PµJ¡•9’žÌ¿Dß))RÁS”Qóæ¼*÷ ¿“©ì'Ê-GÀ{2uî1Ùø·EWîëŽTG.‹Á™R¬J1„_fVä¸/áãò†Eu=™¹TøG‡ìz{r¥ y’™¶3’麈ʿ~C쪬 Dª¦¸. %ʪ„ަGÔ»Úµ±øj‡‚þ/Çcãù^ÆáÛ‡þÑ™,Ür ¢ xˈý{qّ׀ݙ›4¾ãå%ˆJ:&9¹fÎ`‹0ìA¡î?b*… Óä¾Ú•¸0:éY%dëG@EX7ù8dRÎüð{öAÙJ«€fGÜ8øùöìY]zªUgF/Êò~ª²)LðÎÊ‹›ö¼¾£¢–£S°²ÏÆÛ‚I kù'H¨’¦ÎtFI ™G§îGÇÇà)ñ¢IEÔ+Pqÿ6}_1 ÈEd'¡ÙÖŠêdðñ¬üJÎ&gFïNJЕô Äc¶åA+'zxbzòÔö\xC¿@ÍíÜw•C…Xv§Å…“!¼L S¤Ø;Ä?^„„Wt,­1cÀf €¬€TþI?šö€@'!o¸W öÁŸ‹@>[WŠò”ÞZµ«Âªãå´Ë°™eP® Ãù4JÒŽ|ÌXêW³ŽÓ,lrј5‘߯y´ñ±[áȧu¡QC×»«Â¹ø ¶®54 …?'æèy7ŰW ;lά(ì´T3-²Ù ¸¦›µ¿RmIPiµå§Y„áÕÔøÙ¥¼ûE&ó« F(ªK¸o­¸ÿHmï¶?Q7ž\­½·¶|^̎ʺNÖÒÄÛ3¼Q«dÏÔòçÈi{±²œ ÜÚ¸ÿ^yw™©ñ™8Ƭîô Á«IÉ—–UïÉ(Qš£ÇõÑ×£RôËü|úY¡â¾F«¯h9;¶É•F— ºµJê!£^ŸöJš!–F éí’²«wçÅDÿ{»cûQ!,¢^£ÔñâMÚ…C¨1a"ÚXųD¢ƒ™!´?ê ýìÓ»mÕzïOÅv š‚“;»B¶ $;¤+8Z›Ö1}Ýn›o Ç›Zv®.‹s`ƒW`1Þø…Ì‹£‡´ár$³v|¬‹S¨iZ³V”|y#$¡8ã”|t.­Û¯[äd²Ì†b¸ÊôìæÊŒ–—Öm+:åèZ} ò8ÈÈ›»,²ì¾NYqøuž5Ôe=’¹9|Ö¬¶b`®ñ†‘«ð¯‹Ž¬…üoCÞ+bÝÊò³îjyqâ 8b}ª"N…‰mÚŒ…å”7"I‘¢Ÿ’F̹·% Œñ¬mF DŽ4±³}°Ÿ m¤ Ë€N^4}UÔ!¨î|š~¥ð4†lUÌù “TYÎÏòvQeJJgYŠrÏB~•«à¦£-=…{FÛSÆÁÑqÓý©“’Ì tÕ%[òIV X¸¯o%(QÚ´xÔ³mKN„ßOhj–«cÙrèVº~tèÔvhQ8{ŸpÜ…P;«¹RyZÝìIG¨]0M“kfÂ)g(Ë+´€È!šfý&(=Q;$bÛMÝWUr5˜ÙS¬²®$!ï1™H’ãí’ÊÙxr¯„¡¦î8U‹9úyÙ$hÃ7;)V,¨ò@$X¡‘Ó(ÎÖ@¬&rel¬Î߯RÒò•Þxù+YRà,ÒTëÅ—¯&]㙓©ë &­µEØÙ"ej1XªÌàÔòcÕV…¿žY¾§z»Õr1r#O2æ êÊïU3Å$ ̬_O#±î߈¯#TÇÄvÎÓ®óWH-ª+¬¨«ùò$”aËÓ«cX„ C2ûË\ΖD02Âaj•‚_ X„@ÆÍÈyw”eÚ3£H©î “¡ ê®ã‹#x¿ þê"ÙAÚ=JÇLò$¢,s Ñ¢wQÃåtù'y¤uŒ‰€b$¾ôf(ãÜRÖðÄ¡m@y‚:K¿û„בdwœ²|4Y¡ÆAHîGí‘-Ù¦¾ü*³'R;{ +kŒÍHä¸÷*6TÈ=‰bÆT*x;uF gaï×äFZV©5Á̦âM8…%ŸE<ãß–´§nò?µ{°d#Ȇ$€ -Âõooø³p0±³5{iµ8khÇþј ª)Èì ”FoB7þŒhSÅÔ–THÕ#xº,RÈà s¢ŠÔjD…Ü¥„+! *ôÝ39¶úH[ c¸V•tˆÝc¥Iì!®âÒóàÃô”;¨"k:Æ“¢ßUÕó1tšá®Ow¥’H׊;<Ü!>#I§$¸,¿Ï¹ìíýº7ÊÄd'ý3¡b]§ Yhšö­BëÊ™aI­º-,êWÞKFëÔð?êÇÓõPòÆ:bæ½tM#¦11Bʹ3zBŽï©ê3”ª|¢3“àͰ5¸s/F\V-—‰Ç¬)ðU~eÉsËèK2€š¿b`e]õðÑYV5ýHJYZ‚¹W`šQ•d_Óõ¸Pãâ:˜Ö|—bí1UX1H4Ãgµv{`Ò?ÚÀ˜|ÂÌKx8Š3MØœHª+Ø÷¤ÙMJ³r‚·Ž  ÁK‚Yá2ßõU'ÑdíÚ`‰%W_aì€sÖ¿ÿª)X¨V>£zßñÒm±ZrG-Eýžn¿·=Iì¾F>Äóç]}¢ãÇ›ÎDHHÞ$–Q*{–¼QúÑVf>܇^ˆ-TqÅ€”;è ×cä§ÄV¤–Î#LçP®áºèGüÀòH²¼Ýþ"{=vRtš°c×¹å ¸Fùe,<`pT)ç°<­÷±¶­›C'foÍ#VÒsP#&Dæoƒ’BˆçâT¢˜Þd-¨C†rˆúÿ´ÆÌ™ò)“‰÷t¢žÃ«õ"lOv+áu@—R«¨oÅÝ–Äk§‘¼ø”îÝ Øî© Õ¸P½@'ù©±Oˆ݉ô gï4­L\Û MA‘ll«Çmõ4_ T‘f¤ƒ'Tž9cb’F뮓G"•dd†Þ6R§Y‰³gÕ/·¼ï·­äšnEµm“®mSvç&EéùTàö´£Fࢅtþª½~™“"˜èE¢¼TH+5R\ðÄ` %ºö~[žŸZ9ëŽ ½Gô§SÇÄÂükH®&¿¥ãž­“7Çñ™KõQÃ×U74/Ô¯U@J²£“!Ý—Ž…~]Gj+#2O™µ¥º‡Ú¯w¥öï§Zp4+†¯»uœnº9f‹<ÍçdÉÈüug‡+žôïFnWn}5ûXдÇÃܱgaêY%üø[oZø-¬¬Ó|`¬ùDä:O½d˜ ’¥2»,Î^àφ:mÍ¡¢Gmiˆž?ôú@„u;Â2ÇzæK¾.“Œî¾ÞA\ÂW¶6.½Zý¯Ó‡C–<¼„úþ¤i±ðb!¡ü¾\©¸r•°‚-έóvž“=ëýcˆE“Ò}œ‰‘hS'¯e\Rœ ¡,©'l‰HäTbìš·ª=öŸþ8¾Ø>Ʊ°µ”Ðñ}Iõ› mOtë†Ki™Ì{5±À¦‡KY“rˆG›*£§Õß–ßÝ­d¦Fö¨ÀÙ²èg¡Ai |î…c-yZU%Vq):Xœ ½…ôM… #-SqÔäe³cir­Þg³·yòr©Ë³æå½²xzxßJÌ2uÐãáˬæ(²Pˆà¨#ÇÇÜWù—¬œìΡ8ÌêS¶vd|ÁÍô¸|ê8ùÙi@æEwîy•µ>TÍ4³E#Ï“9=þ§0w$±amXè,êbTT" BV|Æ]liØÚ^‡ yqDš²¡`½g%U+7Uà*±ìÄóôǪkV¯—,ý™À*¼ƒŽTp¥SŽ'ú—ùŸ¦o6NE»e©< qØ wå”'<Ž8A/Ûž8úP°œéÈ$6j;žJª/aò>äžOÅI÷=À¨À»™ec#škcd¶×ÃIbJþ(ÅtTòþMÕ’I¾Ià»óÃkô]U-⪿ɪ¢¡@íêŽC–`Pü‚ÖMYšÉ?’[o€+óõ®ânOòA¾Ö!—kìNöî¤"«e4ýKY¤«97‘i(k8äO€zÑ€êÀó”:F^>1T(]nˆŽª”PÈàϲ¦<±|bÒ­û{b<ýWÈÖ“üïÏþ­ýõ}ÌïÛAƒ¨z½¸ôì+²®CÛKÚ¹ÚØÂxù9sAÿe¤M¤•6N«âo;UÜœnâUW*â°’PM’S-Õj¾3J2e)WÊvWTvéž•áûo¡âI~+°™hVgOä”w"Ï<]rÛ}µÁ‡Šû‹‹¤îccG ä(^6’ƒÝˆõå¬éf¶ÏÈ=’ï'üˆêƒPM²‹2)U£$G†Šˆž\sÃ1«•\LdÈżQÂÒo%ÈpŒÚ]d´¦@%¨rêê–]¦î«TÎ\|zF³«|²ÉAPÈeñ‡N¶æf·$ä4è®{£cÓ 3 t¼L‡ÈÆ»¯Yr?QjÒ¬œ;ÔoRÄ·ìå›ÊÎVa?*•f~iIhÅÝŸþ ’ž(ßȾKšír 5!j‡n¨c¶¿âMÀ!¤‹lLgÉK 2J¹­EV9éí6uN“^OW™‘h²Õ%GÇZQ¤›cqú»ên·´éRØ÷Ìq^«KãÆ>J*32 4¾ *°TA‰?†G¥ÔñKUAB~{:{© ÃrÁZ`/ò{¨ä†ë_‡pä+шfVnÄ êÿ­Ë|’\$CüòV\pŒ “93üÄt¢›+’öìÌ¡”2Í勎ÈJ ¢ñä­;ÛýPŠ ò`Ô#·V‘ùVPÜ 4XØ,Mðyùaóà5×€ÃîuB8"ÀlÒpÇ÷x“VAv¼ÑÙ¾)NÞEá”3v?µ¨ÊP8P«ò÷~N€Ì(bé§òz+Re™¡PR|žŸ!FÖý“žI~,Ócùj/rXUÄÑäªG4b…œL37O(ª¾Ü6+ÇÒ7n¬êp:QPòxâ¼µ9jB“Ð/ €ƒÈ{³:˧ÏÃl ï—@Õà /$6xÁ¿ (©&;ýëkÿ‘'‚H¡²®ixõ‰ÎÆ+Žþ;°ñt3=‹fetš°ùÅ»+¯!¦…UË¥½ËZŸ­¤€Õf–”IºxZݘ—¶JŸ5Q;£»7™šjU<@WŒÖ,2*óT³¡—l¯Œ…šƒì¾ å¨Ô›…nΧÅ2ËnìN~B˜Ò›J}Uy¤G/ä E­⌗¢vyºFRê¤rMý¶‰±fˆ”’=mK!F*Ø[ñýW o¥Ú±6@S^œÅ!j»yYÑj¬ƒšp ôåÑg8÷n¥ª~8TÕëõm½¢-q#rÎÉ0W³)$ÑXM@ëO#Mn³¹=‰GNôä·œÍ)ÔB´ªrLfËB´¬™Rr.´ì¦N€ž«Å½ô)KÄÉ…PÀµ<•,¿ ðY¤ª®Œ¢]ä3’*½‚¹`@µ.˨k?4ˆðEpOÚAÜ)Ø#FEéd£+PE_ƒÉ'üƒ«¨½iîÆEÈÇä,âå;OáÂL–5äu^\¤ÕB”/E^f…jaÆÇE•»( Êvù²-&r· êç²/’}ú°ì\7LhÉÉW@‰B\†fPYJ BÏú¹RËã=Ÿ·è®­6ZrçÝf{玮T/õ›1PëÌ‘[°3,x6í1J#>lÅAÙt"K0RË£Ù Õ«0E½Q‡ÔËFјØ]t°h€v<ßüòNůp]=Âò…ÊyG$|¨PÇÆxuêW–jKnÙs÷ èñºJ LËpÕéZlj•9%fŒ\xT€…=t÷_È §³)o0Wé:woSâD½øøþ=Ø1fë6A˜ßq¼céÙýJø²'ÿ¢ò);¢²X¯GþüÌ’Îî.Y=¶¬z¦*3ìûÄä-ê£]•BÓò:ÐA•³þÞ!1ó¶)¹ e>Dߨks¸46õŽ:…[þ ÉÕòùM‰XþÅ!d{?å‘d|-Øš¤êC”öÊ\wɾFE!$ -É,Á1Ó$uBˆ³~¨"tNDæ²æ‰n”¨´ÃÕ¼…®ÁS¸_e`UÏb„ÍM9ehº@ ºdWñK@·P®ÓN‹’Èbm3>Ç’¸v~Br(}ÀPÉÒyÈ“z(¡ñJ±Á¢ÀÕQê¤&>󲪱.À1”[.á]H`MKøánÁ2Ì:2Œq”§¯Žni4™ K©e ¼øpX­n‹ÚMйb‹ûß¿O=}ËÑn®ä7Íÿ¢÷^‹Aʂբ÷í/DDÆ’­ÑѹýIE§[5 …›…F`x sÈWå¸úù^Qs!Dd ÊQ/~êWº„zª,îÜ ª¼®¿3'àUµš],HÿgZŒ)Œ¼†#÷).]C’[uñ¢J|Ð4 B=~A˜qŽÕÂ/*ÍCæ˜éâ Éì±F z·JüƒO¹µ‘k&Á/Lk^Ý;È"Ç׿VG"‹Z$åj(Ý•¼Ü–hÌ‘Ÿ¤C0(.£³/@UQ}¾<áh©F Ov=UŸc‘ì¹ RH;ùkEñ¡*Ø•ƒÑ™ b°¡O$þ«NY¿6(·ˆ¦5åðÂ…¨$P#ÔëBøÚGWfä)%ˆAj–¢CU7TÏŸÕõ½¿€íe–¥‡9º»;õµÄvä Ç•K:³:«n»ý]Ððt-²ö.1a…·ö懇?ʰ\l=IÃëGuC‰§ecbÆdðgØcÃ…J±<”íb-ꇦÑñâÙ­½vÔ̲Nu/­b!œ­ªVÌhôiùºyFBÝl}ÆfËÕ$©ÏNÀŽMìÒ:i“ÃǪäIˆt×m/Oß3%rÅ3‚·LÇú«#Cƒí˜xEî¼€°;1vÈ.@Yc’ÛèËjˆ‘iØf^÷w›Ü~Õ]®d0FZ«ô||VpÁöxÆC,d+y³h °# }aÛµÕZÙ8έ\ܼ¼Ü£\Xå4'IÏ;.ˆƒ‡ÎÌløx¾%x@_•‚‹E©žfÒÈÒDÜÆyÙyXîø¸øÔRp¡“KªžCÛÇûî…l¾/7AÔ]÷ hÓ¦V>¯NFD®˜H'Xþ*GMÓÞkD~ ·Ž–Aáeì$µO){õ ËWÝúâm­ËF­»jÚ©GãÖ.àP–WÊ1nó‰§nŽK4Ô R%‡¦nMë»/£ä¾‰eÈÕ²S»éØç"¨öµÝ[/=û]JÉÜMždÞ$6»JÐö¦•ƒ¤b `EqÛQD"ùYÙ)N«©¥aF“šµˆbkÁ¾@s x±£‰æýYÁ‰TÆÂI5±Z…LŠà«3HÚ“’ë)Ç€…rdI%UCØf Ñ mU …`#Ù# ¶Î?RYn‡¡h»+C†— Gó&¬Vlš¶«jjó§ýÉBY˜',§Ž€4Ñþ”j9ÒÖ´LcP³é»sKIä=U”5ízJ†8GæõÔ-@ÂR Ë2–ê…úfÕul,}?qëyM…¦é‘›iÐD lí_¢ÀÃÇ“µQ7Ø¿‡ŽíG‰^Ê=Ò#©ú¡¨bêZÜNµðж“PÌ%™:"¬Þÿ”1ŽK>@ ߬ã:ñ¨ñ4ÂYç.d©%%2ð#RÊCŽmRÕå\ŠžfZ‹ÊXÝ»Ùf8éàÆ5Ø‹•‘õy(ö8gW¥æØÒ×÷œ±×PÃÿ[³ôܶžÿ¬/e|O÷­ê¸xé¢ršÛJ VDrdÒ³?Õàß>Ó¤´\“ªàuçá£EôÅbªs˜Õ"žì¾A9Ñ‹¬™ÃJ\oȧJ¢uš*SÉ&þ{)GJ0R€xÑz•%•½<5enè¦5_:ã6EވƫôÍš¤l¢•Q„Gy#Éïê?Õ”,a×AÜØlTF’nQ‰˜D ®ÖQ¢@ªtqYAYŒ ¤Qc<Ì„,HÞrqµ´.Ü‚®²˜Ü;?¢ŠnHgÚ^Љm¯«W;šÝ+–Õ(Ÿ¨S¬éŠpHÇU‘HÖŠ´‘z´='G’S"4lu>YèöešØ·jõÓKöX䯼Ê{G'€¦}ØVÌ=Kn¾.VÝ“ëе 5…x3é÷ÄR¡Ÿ ÌÉÞIÞ™Ñ«Žæ¬UÝ»‚}·Ö¨³ÇÛ8–°™ ¢ê®Ý†Í@§W .Ä;ŒqøJULä&%l 1†î(óÔsId½œ]6ªS¾Ê&ö1qŽ£ÔúvCé- ™yf&} ‰^k*±Ì[å%È[|wIÄqú*kû¿C„e·²m-{-Q´Õ ùYsèWý}¢Ÿ¶ªôP$–BùKF›·¥“«ßPÞ±].ZŸ]CJKÑ×;4P3ÔÎÈFã!º Ǹfâ½Íû¶¶Ö&Þ®FåüƒŸ¸3d§2™Š“¬¬r1çÜNr YM4éæî(Hàºfjë®ô§ÑÙp¾LÕugìH fEˆ(ÊŒR¨åšu‘†¼¥«ÆžEtà‹H,…VÝÝCøÒ‚‘¼MWÆ4pƒJÑvÞ<ŒÇvj Æì‘6\håQ"3¬Œë÷öÓ`dvÈ|¬ƒ78uÅT|,üp1–ñ? ­¤¨{@ƒÝ*\„áX/"AmrêàiY’\lüÔŽ Ï>nÅÃã=Œg2Y3+u…iC)6;ôP¬lú踓ÆÏ“_H_hæMÏç`H•Çåžó)‘‰"”Qû u$2ösÕ÷œ8dž²œ=Jm5y>)‰Îì“NÓ™/.GTZO¨Hãb…Q€FjØGm²ÆlÈ9S,J¶ÁˆãÅÉHãgW§&2ıGºlR9v ¬Šªu^tWÚLF ?'íc“ÓžVVN&Dò±ødš++žÕÈõ|²åii·`Šý+ItsÙY¬ÃBÕôˆŠ6~52e7§£Ó«jfCy3ÓHÏ!c¦4Z¼¯M…¨éŒ=äd1ªBœÛ —§ã ÈùÂi$jBE d~2&aQðÂ.òHò:¢ D©>ÞÆÕqqS[Ô6[ËÔ™à-‡“4r?ÓµºÐª¼3©p9£û/#nè9:ž&ÄÛ«…l›dåfî{iÞ >·Ìf¥LMVuÈwªta$Vb€2ýÏfenŒ—¯d[RiY-;]§/Ññ„{(h©EƒX^¢Ú2Äö?D,eÓ´²áüvªYЉÈôu‰âg¨§Tš¨ÛâÜ(¥†Ÿ,í“3c.àŒ|s«P`5”È )]TiÚ:€½Ö = G<ÐBòä6FŸQf Œ@4;ƬFKD]ÊýEª;1ÔÆÙ´Í¡]k/#QÊÈËr¢³¾£L—…òðktdü\w`§ˆ°fq%¥[ÆÔ¶õÓ¶äqp°vz*'Žkä«û~ªGŒ z0T¨,iãÕ ^v#¼û-)Xv= GbGˆÕG ñªëB¤Ï­¹#ãó³/~9,U(?〠ÏÓlíeÏâ ^‡*ß&bÅ»9 ©Àç°Eùù_½Yë$`è¥YÁe÷éÇ=_•†=»‰ðG·Uø³¶:ûð>o²/V hÍü:¨ã·PQy?W5åB³¬ ðXr8çø Vï]½T:€Ì@&¨€At~~E“TOÚM)Äåkß¿sÈ^z¯tþ; 8ãä9´]ÝØúÄ4 d§äšôÉ¢u<ÙD Ä ¼Í¹=GN[ž@àzú•½qöÚÍԚʙ·ÂÓUÇf¶P®Eg!ÈQˆœL7E꼞ÍõDöÖn»¯kµÖÖ¯¦Êù®n«œçMZdÞ–`Œ‘H©­™Ÿ¨Yª|8<ÓÉÉegT7Ú]›g ¤Ö½Bά¬»)>š=¿íßî8Ù=C&A* b‘Ùõ< ¶ ö³ø•õ¨ºDWeI€„!~yvtn%sE(S‹/Sן_=[Ñ}ô;ÕOT5‹NZ~Åôÿrn*»ûI†—¥ä_*§‡¥2ò¼8òŸ J;¢Ëª]éŸÜ.û×IÛ1 ÛZ%çj×F¬UlFVz-2c^Ü T§WiäSÿ#Ny×þ~é«éÿÚæÔô+DÔ†>éû€Ö!lè¥L²q¶ÉÊÓõ=Aù#Çû]ôÍ9fÔ ™ŽsâôK¸0ËÖúLé Qó³ CukŽ’,“NP–=”C±?:Q>‡ÍíL¨º–|}¦™ÕæºãÌÓ 4å%ÑÈ4fI¬o«šfÛqë‹rnmÛ‘c©ëÛ‡?XÕh^´|GUÔm¨fªEjþútX#-…]u>é)6²Ÿ!{ ŒØ¬nÚyÈkù»ÐÖ~\zÀã.;ä;"Q‚Šõ…€¯‹IÐá èSò«•™à¦$¦/2r©“ãSMæ¹ÇDFð>_˜¿i_ÏŠnð,4¥ÇÈòŒkã¥Øb qB—’)Fe¹öýÀ,çÚ€GY$Úúê·NàD:¢ªE ‹ðHÀU x'Uº*hUÖ¹†"°T )ߺ¥Hc.ŒÌÄ­” ÄS‹P„¨¢xiÕk|ÌšM‘°šŠÌÏ’ñè%O *Ü1|‰ñò4ºÒ¢NÓEȺH#‰<|mG)úG²ŽÍW!Cy¦N3þ9ÞuQG±üZ!ꊇ´y²2²¯©êwùÑŠ½2ZGÉt´Ñl†—öSÆËH¼ãVFVŠ£Ó’nÌÚZ¾ýŽF÷ŒÇ”)üvÉf¡=&;â¥Krøøñ=蜴‹w˜O¨UZIFŒDFî܃j,QýËÀù7u‘d"/QÚþ´ª $d†¦E$&Ä’(ßãQÀŸVíOÓyz§®éãMÃL“jLµ8nƒmùQHÅò•Í „‡-vfB<Ýím½§ì­ƒ¤`Âq1ÅTë)ÏŽ“SÕ‚ôøõwrå QXr(ßTëìoÐXúS²°³³ñ¸ËÈD«y¤Ž¥eÉÊ£,ÕP2³y઄ވ!ÖµU*(é&îܲ„€Ÿ8,— 5„šž[¾!ïÞ»ýÏ©žŸŒàaá›­ÓÊ®l‚Áû¸â*ý;ô¨>“ê&µVÅÿØQ؆Œ¶6Ä7»_Mï™dgwbà8"Ÿü© ¡RÜ…,Å©î„1à†zªd³¨$/ŽŠ¥b&On(øì:üþ—,G׆$ç8¢dU+Üꧯ ?bJqÂùBÍèôZQ§"TÆ„«‚Ä{’„ʪOTUu{0ç²€¹.\­<âïHÜÕòh…«›*Gü‡ˆk3IÜ_´ðA  ¿ž6äØä€Zý"ºó"ÁYà-×Çߣtþû? ³¸RU~’¬ß«7BÁö Ü»° Êrêp­ËÔe%W‡Š· p´#«+B1?_pÄÍC†ìòT1g‚.zy:t+O¨4Ÿ~ç¡ IºZ€¨*®È~1Ú•×c\0?΂‹XjO&˜/Ûdì}G²Ðü€ÖÂ$>›R*ÖÙ@<†óº…p_³2ÿb)ÜС Ë€H(Gr½Š€y(Ÿ Ö®âÙPÄ‘]{P†,@^‰Ð„^WY§¿4d$5F¹nœöbh®Yyø£²{±då0g)Y'L™J«1¡Wr¯·ÿ{†.hŠß= ÀZ«E¦$Q$’TrT}̼¡ >Þt,äù{S¹“EXŸä~€6?&ê‡Üڑプš¶,\G#Ë;ÒWP<Æòe•sn‰1Âñ“N¥|èxEA?"*¦½+µX)@3‚Šy@è€+F –>:½OÉ€›S d¡Ÿ‘DÙ;óèÔ¯^áK•å÷#ÃÆrT8ˆ¡_Ö¤•,<ÁC,ùŒÝ$áPõ;ø³g¢¼R‡]"Ü[JŠ>5e¨$ŠÖÐ+ÉÛÈ“Á_±ƒ8ÚÕ›bö!Eªj«¨ÔŸ Ú”A1O!¤÷,|8­É§”Z:¨YÜõ4uëĈ»Þ„ÂØÒÇýM"…9=Yù·È°GGb’RÈœÌBêY~ª^—'zš§$'n\à¹<õi¬º5{ÑKUÕ`Ââú.¯ÛMh@b´y²½ O»?`+ ]ŠÍ8bÅ™CÝ“ÓæWJ;À¹E* |‘ð‡%‹‹®=2ôìU4®@¥¢ *ŽKY •k°ª¬¾4­]IA³ZÞ v,Ü%©ÙÂà¯üP1ã„'è“úº†%iQ>]zžŠ;z5BžH(ǰê•o¡¾ÅñâTçéÙGíÓ.Î aØR;T1,R›’<žËÚ`…`åÉ»wW,±,Ä«ì*:Œ=œ,„)ü éÁÖ@ˆn›YïU¿¬–îƒ?* РEžhŸ‚<‘~˜5¹)úô ꕱÕr£‚—q@ŒÝT3r_ƃ·ÖiýÉÅ[K»„ë@]xWV,ªÍü¡vPðuà¨iч^­¦š¼]ñXQ• òv˜î²ðApJäpW޽XfÇÜËåCEÔ*ea™Ñ %f* Ãø‹…4u¢ñGva$gë3AB{Ú®ÔñžK:Í–£¡`ʃ‘¡Š0›|š`è7ôùµ³¤¤($© ³ Å2lTµß‰#’úÆŒùÅ·d¼ÈÌYj¡T£s+&:JJP0ñÒ}[âo×û:‘ôPg.W¼ãd nj øø/ËUjZ¤MªJ‘9º'¸;YÊ?õ^Hj·lн¨ËÑš€Y¨RbIOïŒ{ÈðÉäy²«L™¶øî««½*k1U *©sWdTé £Æ«vfQ#ôægœòŠ¢$«o€x¸ž9_Ï#ÿƒIŽüò'F‚Ä—²€®GçQ@­hS_/‰QOY)£=“!UÞhª¢–pD”pï€ÉäòPÁË5H–);DfTW&žÔiEÂÌ”`]DÚŸŒªeÑêÑV•¶ã@ËNGÈ ƒÉø ̽>Ù´“¼¾ê½ÛoåuÔ=RÚ¢‘†;Z«‰ n99:ù‹ȵ«nV…‚rõ<…Ê®°r1­¥jÓHP~~}×8i»oâÔWɃ¤ÙS5¤ž1Í…,(×\e®•Ô’¡ Tv¤”l@„l;DÆìvŒ‚±i"Ç„ø8غ7CÎ/÷ã´ë¨Ò¦¶Ò;Ek`¦i3:¼MØEÌLl³ÝBp8Ϙ3"eÎ5*&ÙŽsmŒÙOÅU†'_;I,:+žjŠÎ;SC®õÈÉÂÂÈÉÒô]?­©k0‘ÄgiÓpg"è³¢¦OZÅPŧ ¢“½wÙ9vÜwÒ4JâÏ3)ói•©âåDaœcàºéš|8NÕÇJµÒs^(Ÿ#ÇM¶nF›¶t ¿¥ãEð§§Âtª*~G’™Y ™“{/wɨÉR  z¸ǧç¶WNÃÈ¥™ä®ÂÜz¤dÆDŽ¿¨’3Æ„‘¬ÁvRÈÑÇ!Œêˆ™!%ZpYˉ7‰=¶ rÌl ´fÞtî¡D%éZn‡³ööÞЖ?ƒ yªÒhÕ}@²±¥í`åò2lªÙ{T,ÙçÕ‹/XÆÛåµ-x7âäyí¡iQ¦~n\ä²   …“ÄäSÚXåRü2Xf}OKÛÚ>F©«dÒ ”ÎÛºg‘¿+3/-Ÿþ§ª»ÚγxÍ“%˜†ÁƒAÁÕ÷®}5d0ÊÈ™¸­T¾6ÞÛõ&ÒÓp;E<™³@g‘ðZµ;gã{qâ«Èž]24¯È,Ö|#WSr2°ò+ú+ E26¡Ô䕃Éa³:Í+jd·Ð³3)4êA2ém#«¢dsž‰¤ê¾¢æâj:ÖaŒôül¶|éþ§JÂÊȉ}NGU9u›ÎJù޵ÉPÀ©áÂ)Ý1c§á>f,¥‡m.Bxð˜i~zEU;¢'VYôtñÔ|Ù¥ËÏ—,¬YK¦éøº~6œF6›ŠZ1™\”uV¨­©ÍÍ©*y‹*ŠVa‘]ÁúcÜ[²øÙPÓð[RÜxÁ tl¢ãOd—ÈÊÔ€*«+ΞHÏFò«³ÎjkHí–ñÅi±Hc!UUH>r ˆ,F¤ÈÌ<¿Üoc ÅÚ€ mΧbänÑŠ­²»1Y‚FŽ4ÚB…¤ZοŒ“MC[t'PÓü8Ú8n_QÌÙ>hã’©Žç2ßœsD„ 35‘艭êxض¥ú``æeçbà²53µ-ðkþ¿T²2µYòs9Y²N•Y÷¡„гoíßö–ž­Üæë_Ž"ÙêMŸ÷˜ðT$Á°Ì%ÕÐJ^dIžLþšþF鶶푤.9¦6««(ëþ«,H¥^=‘±²'ªÈ,ëV­Éþ¡M£Ž±vÖ6î8o7edXô*´ RÈú·qdq³°GeHPˆÊ‡º$UM…¯n(æ0鵺ȪȥNÛÝcUןVa·6þc…Ç6ÕQUã¦FÎÎóí%)|‰óîªjr‚²p¿Sí' jiyQé©ém<íByqJeDeNêÀå37.2ûÉ‘aú:µ.=ÄÖtÏL´L‹ëÇM+ ïùVqá)%¦@µ,Žr8`ÍY°J?t`¥ÉPŠúݽ·ìõ‹úk³±°¶Ô)‹(n-Í““#.•¢giÚTc ¾=)Þ/—çXª­ñ_ÍÝHtî‹Ôz£?a4‚'S6vC$ÆÀ³#ýK2‹þöRÀ,Œ€@ÁŽx®#dXÉv̘Ã7lèÈG!ÔÅ©F1€T´íìs3Ž1Ö'—™—·áwˆiù˜Tn¬]¸óa(Yƒ{:»7!ˆexÖ·Þ—-2,á§©c-ó£©cãݰsñT‰É˜("N*¶;R†3L•2Œ¥ž™þ¾úÇ´³2Ôí+4Σ '#f#badS.U“yYq«5ÈbU1ÛâëçªýÒmmѤ/"¹ú_¨Ôô}º»s*‚A©¨ebÎyxx·šCÅgÉwPøÎTÑ.)ãå³ÙpHЙr§ÈŽY'N•±ê쫬߮¢8ÈÔIQ˜ƒ/z&ˆ³$«Ϙ*`GPxÛ71pˆC6úÁ?x-ù42©NìF@$‡F°ó²uE5l¬[ã]e˜Ñ¼Òt­Ã‰ªÄvå™{7*½ˆéõù—«éÛYxijg®uàš¶ßŠË4¼Q«ȤÐÁZõyÆAËÓ„duú«÷¡†¿µ³+·³·ÚÌÊÅÁÊÂʆ¿©ajY–”i¨âdÎ~ÍU8êZm3åÿºex£^¬_ÒÝœv/¬‹¹³7vºuužìÇÐmªSMÍϦV“L½CÍW¾.#O6YQG°œò:X³” 7µ$ËïÍІNrA‘ÛŸ¥âC3õXfhò€ma^TÚX”Kò*-8ó!(ÎΑ³F¸3©‡ËYõ‘¢‘EDVAQ$s\kêéétÜ:Ž«— FÃkmûÖI§à»yrÞj91Õ3â¥Ó±Éð²Ç='Z°k}?éØzf.NF6Ë -‘’ù8™h™-[d=+dÆÍyÉ‹Z¨Ã–™ÍG‡*Ðý\ôÿwê8z.¾´Zë¶’.6—j +UÛ…œJÃ.fvahÎ_6uîHWMŬaafÓ^ÚY郤¦VMí¥e §IK·åSñ•ã±Eó$å\‹¤Á’ɤγJêfY †è¡¾–e1dÊÌNȑȢI¤;4бµ$š†NÜK÷)1ÈdL¢9cD*‘Œ–šÃÎàÆ6í¬bl‰MÇûñ¿p¹Q¬®³ÈñcçO&2¼׮¢Ó.«…S>½ãÿlÌå—gfI3ITeçÏ'3ò1åc>Ä|b¾:Su™m1…A¨éô•(¢žíñ\9i¾ªì½Ó£éß¹±åmCQ¾›<ÃLLÍ;_›ÝF&¥P™89¶x¨ÄžB'äµ`Ñj Ÿ0WÕ¿º;úM‰¸óé²7Fé¾ÑÎÒ›tÇBÉÑ×v†-m‘‘ jRÎé€í›Hâ±É)ãi£:Áöß^ÌŸµJÌ2BdhäVyHKJË´‰ „2¶ÌºÈOjZs® Yò1"ywŽ8åš(ÖP;h^#ÇfMôe;®„.@‘.ãï|Êc®/¾^ÞyA f`Ì'-™'=ç•î‹7e¡B«Bè=ü޽‡§dËÀëL óÑ’«Š´`MÕ»L’¾>”—Œ?U¢xèâ}k^ÃõÓcz¡³Ç©~—ë¹öæMì™´x>&]qq¼cPÂÔ0è<ðÖ0ü¢óz"›/íFeNjYôûÓÍgzG#?R²èÛåŒü=-¾vÆÊ5¾n6šŽ½ÙÙgä€ëK+V²œ ,ŒFék ê„!vF3­:8ùTC†Ù{o ØjÈLi®ˆ>|l…§¨âÇñSÿZGJ×Dr•ˆ’!je^ù¤hÜ}7ZÜYšµ4M­„u-S 2”G | ¹<ÛùHcå*2?<ÐÕQ]ÄU¾Œ˜@Ñé g®kÞd¼¶Ö%–¸˜8Ú ]K#…Ž<\Õ•ÿ,¨yÊ_3>íü¼Ïnza… ?YtÔwR±ÉËÄñ¶:dþI>ljÒ³ECbù”•Y‘g/ˆ0h~žãíÌ<„Ô깑ȽíO=KQïI(Õ.Òg6½2,ÆSÀOèK')âÀÇí”3HTäH@´qSìZЍÙ#h‡ÃU^§›;ªL† X©\xË.d¨ ,†yƒV8{—54±ù/¨®•¸·Bâ>c~ÝÆ™ÉÆÑ´¨&6‹6¸8þ×Ç™ªxaÔŠPOyõTè šnØÛÆY7¦=ò£Iÿ·˜!ØøÕ¤d¡»’²EZ’‹S^A_ܽG!t¼l-?¨ v‘èJÌõáÙ>J/³»)=ÛºòÄ“m2y Ï5p¨‰VfáHì9NuVËÕ}ƒ_ ú­ ê ã“mKM5Í#¿Ë3 o7-±P£g"Õ3/)'b“†Ú11(Cò$Ôä±.uóa³+7Ì×#ycê Qã !Ái£"( ðY©X¥B€¦}¿– •¬NÙÔ–^W‘ìˆí?#?IÍH^VjB:yIã¨övýÓ4¨¡é9*:—VqÐ?DRÀ3!n® r:«YSêC?§-Áfè²Pá¹iä…€XOì~\ƒò?Á˜àtPIî;25†%˜Häý—‘FæÊ†i C¬[(à SZ±¨Ö¶-@pE‹mÃÓš¶6<¹TÕeb&xàð*Ϭ¸>Üöþ'¨â4QÈ ì;ìCù'bBŽ[Ø—'ÝT³(ÆÇà¾ÊÉægaÙˆ=Oz…(A ¯`ÈÄ«¨ä*0~yqÃ"ü’ÇØƒ×±ö•*¬AÙEâ˜Ø5ü‚,‹ /•Á~îA¾)I39 ü käÙüð??_È¡i±ñËPìÌÜ© ü•[‰|}˜u àûÿ±%I¡Œ˜¸¼ÝºN#¹ìB!{vjPpÈ>DºðóÀ#ëÇKÃîÐ|teQ#][vê8gOÛ<(Q+L¬ÍV‘*[Æ«Z1âosþvÍ®jûƒsjzþ©jeçkzž¥¬êYu¸µsu ê×PËÉÈ£ ôÉ¡·†*êhj TéßÓ½[«u™húd?Û±ßNE<îŒ-On%*éû;ªh• 3uÈg¯gunãác‘Óp¦†l¢dgN]”¶\PŒ$‘F ŸSvѨ2"è) ¥¤.ȶE®0LŠP2[ñ˜Eÿ!„(Sö0_ÝS/VÉZÌS2ØÜ¾«“*Ç7Ó!±d2Uëã|lŸ6=exud³Ñ_cñÉYLêÃrüiÇÊœNMøPý¤['®.WV¤R¸Ê¥˜ŠsY Wí³©e®}uëq‘« 䨬g.,ˆ)5PžÑŠTÉoUw—zkNÑ€ó1­P 7@€x,GU‚Çî ¡'f£XûµrPt«í1«T`6°Ú«( ‘º».N_ñ0RgÉQó@Öv£Zb­ŽUYÿ$ÐñT»«†,’êŸÓ²¯Fkº·+Ó$âé!?.ýiøÖÊòu,ôv<¶3¨vÈRë•7ø5¦{mý!÷©‹‚q3Þù9QŬgÔKñça15Äñ %¨ùç—“Œ’ÑšeºPûGô·ÓoNôêdH¦¥›ƒŽïJþ³[< O‰Iå{;ã(™Ð•SÄZJ}áÕ× {zWE30éò~⡨ØòXìO z?ÑàlÌÅ~à1  YeP6VßR³]5š×ÕÉž&‰§àé˜"QIÎsgTVyÈ/.£ÙLÔPµ Å\öi“/ÛZyÆ‘»É ©ÙVŠAu+Ë𬠙÷.üÍ¿‡?ü¨úŒé˜õÕsPÐ 4œ©nGe(A,œKÇÿ=¸™U íÁ2S”•gBˆá(KøÜ PxÁ/Ë…p„’Îxáó>TÅ6’f/+nv%èÜ’Úóÿ• +ÓFtª¢,EoöžERªð~àhð’8 ¤-Rª]dˆ,Êx‘LéÂ3rÜ·³Ž‹?nÑeI Re®™ Wa5PâYU›…£µ'»´Ê„þþ?ûý×§@ÁCv~Š€/+5cätUåÔ^¿Â,ÌŒ¨YhA%¹fäò¬®à7N `ìý‡Ù@¿'¯Èî"í«óböý>iš¨Ù@*XØåDFÛÆéT¯Ü‹ÿEš 0rЬÈQK‡˜!‚ö^z¹(¨¬Ç` tdR¬å%X1[*(-Ô†ä†ö0U £€CS‡)Gúøò:M²¯g=€sîâl¢…ŒÛùi¸!—ŽzbçǸsÂ’Áû’äÏ•T§Ÿ–¨=ׯI<ƒõñÉÂŽI°4@IUØyh5%x½€ØÈ'ÀP `ü’8ò¥G’6^I GäŠ Ëøª¹~Î5p¬¯cØwùyGfn;Âö轼׎ÎX+i«1tQ&WÇÁ*ÉAîžF@ÜÍÃqõæ-ÈAØ«¬ÈËÛùèf<“$³¨sÑÙˆRxofáÑ>C:Û–™)ݘvUúÏOgà~ÞƒµXŽÃÊ£ig†ñ@k‘äJJ­ÑzÔšóüåyäµfÄV´^MžhŸX“.C“eFd© wu$£SØRÌüÓN¬¡O>«*èžLt¡©aãkLÒ¨ÈVnrBÌ‹»ÐÈ£±R²UÂViѨ'û bRt2¢ ¼ÞnÃÉEâLx+ÑЫŠGµkR±Påù/F(Z½m*2þF^]™|džÉ%@^îÖBF¶£æÃp  <Ò®—_ÇÁ#òNâ 28 •–]@¡Y7R-m|Ϋ~LËKajG¥aãäÝœ¢¥š«j(/5ëGï7VqR  ‘~gä^iäëýMËôpAºpDlÀS«;šHÑb?õ÷¡œÀ—%QYB/$S}#‰Ê!^&€y]ŠÌA—£LÛ³UÔr¥fåÙ¿ZÜ_Gè”\7U&½‘ºiÈá€ÙZ}h\t x?Yÿ»K´/µ•rÑ Z€5%iA ‚σVÇN6^jP®G”Ž@Æí‡-Mz­(ãç–Ñm/;öt˜Oƒr:ü¾ ¤(;ž®–j`;sNI¨Ý|³!×̪©.¨Ì¬Ü£µŽˆ(ýJ’_€Êíì£ ‰Ã x:ÿâ&áAìY]Ïį°»)DT+:O$䟋†=¦ †V žåƒ)òH¨ù»c’,Šì\–EP´¬B¨R9µ¨®KV®¬§ªs§ÛŠbXº ¤ O,oçPÞD.ËðȵŸ€ì…€cSÜ… ÿã'ªª-ˆe=YÔ÷!ŠŒOS›_rÑgÒóÉ ?×z5¬TQx§ê<5 ŒÌiÀ<*òt‹VfüZQžJ«†å» ªýÁ@¤“ÓÉá(_ë7~çÐW7ŽÁ`QÂÓ¨!ш(xêÌŠXÍ üöÉ_ÓÀ Š*º5ð‰*êûŠ(>˜½»þÎZƒ·èäUÔ ÍP6~ëQÿ"AÄ=AÃn‹6+04¥§’æk6$*é㈷‘é^èh¥ªª£tsÙ˜\W  »¬½ù©—@{ TQZŒþ:$‘MèX”j–úêÄcîk†«š7ä M¼ÑTLš· J•ëòv3Sñ«Ùqè{©wnµ%‡DÍJ¹&j¨¦m’gUºS°‘y ñcÜùÓÈJ©êlÒ>ŸèhÇãT¶a¯ yü €XŠÚI• D®©ÜûœƒøuNXUf€Ï@™¦1Ç&Ô" ¬YÛÝ&ÊȇÃ6r¯íwñ)­»Ý‹T:ø2W/Ë4‘‹GÙ|UªQ…Ù ŽrrQ¨(ʆžgeJs×é·gÕ‹µŠS7‰yûÕGtK+>2W¡J/êrUiG CÜ–`Â$c5”_çÄËt¡U{„«U 3`$m›à7Qb×â­fЭ6È5±$ì@(eÛó¦éã@°$_±ì¯.(™Bù#ÔÉ ðjoÉÑiG« cUøóÕ™¹K/럗ç:ðÔ³îʵ$¼ÜJ†)$)C0椇ú3´ý¹õ“°É´]%!kÍ‘ýç>íqÙS³ª -'˜›\öO#!È«[ªÉÍ»š V3 È‹ÕÕ¨Mûù½y‹*H–ÈyñkºâÉáI<~ðku´ I$Ùf¢¦Ôì6ÛU&=^Ã>æO/á¨b}JþØ·§v>‚nìãÛOÒ=KÚVÍsaŽßŠsf·¢Û°,™'±±g^ä*°ì‡{âšçåARù©©ÚØõlj‰ê;¦Î_ñ´ÌkO“‹ `¥ºS!åRê*ÏÆç›é9¸:²Ýø¸öáÕÙÖã&5ê€Ák5z7`]\+òi>×ý7õÕG½+õ3–Úvùôÿoçgfé.iufÓ1ñsöÆ…$Ui~6\/ Û¬¦ñ¢ÖgÇBBfÿÕLi$Ãè=Em—°p¤ÑQiqrĂޤvi¹DD(rà +þ¦Å§Qè]N5j)Ôú|¥»ˆjÆËÅìãcPæ8Ò]ÉUm¢™#ÉŮ޷hÒÓtÌÜÜÙ/“Òò²4câœéøæôÛûX¼ûŒøÔ†¯¨ÀNžSÉ:"×,°ýBümÜøY:–‹ƒ‰\f`Q[hi‰¨æƒµq¬ð|ÍgSQLKßÆÌ†­GyEÄsuó׆ë±m‘f¸9VÓï-9"xhaÚzƒ ´{j ?ß®êuª!~ÕÆY£ãâö‡´t¬?R³5Ms #'O9xzv͇‚é ŒôÔCd6m<‚yñe¦ y >e¹RŒ”@övYòæÅ$¬¾㢣LY™\Ê"¡‰TrKÉ$ÑöefÈžx²åÊêŽÆš3íüÙå¹$•P´q³2˜ãBQ‡nk]>œ&‚XÂ$Q ¿Ö-ÏM{t>>¢&‰¢éÞ•£Ù(øšF•I,N~OÉlûBÕGy7V_ ˆaZÅã6>ƒ=/KN¸²i³ÑIZ5zdU‘…(¹agì)ÜVnF5ôÍ·tèh8S ÖfdÉÕÛ6 7¥W¦il.ñlUѤ؉rQ×÷×'IÐÝ#'×36w!´ü/(Ÿë26?šï–%Q¼¦aܲÛQ"”C=´2x°I“`lݹ. 6d ÙíQíÇ‹nU¦× ½’Á­¾ÑLˆºÙí)î–ÙÃYÕÅò­¡hYXãP¾#®¯œê*ºj½2q§<. …JY•ñ€…LîÅQ’iz<0+\²=PNÚ…KRÙ4å»dâYkÏ-Ô©luá ¯ô‡@Ó1—*«4¤ÎÇ&üPçVÞÖ¹–`ÁÞ¬¶ZdÝ[ÉtÝÍݲõ[åäGGÓÌ2srYqÿˆHª®Õg£ã§««=±bžéuîÚFz˜eê· ÍZ¢cI™_62òéœÄQè˜á"'êó×5}G#fúkƒ‹4æê!›Vgñ–RJTN¼*³c‚¯Zp½|‰½BÞ›ceíì¬lONÌM2‚:zù6n¨x’C)ß+ÈO$ÔMÍeÛ EiO#÷€ø‘Û[ jæïLýB³ÈÜ:Ô­§Û#'(Œ¸ffUÖTÅyŠFèÃ/«c<_öï·eê°}F>:®<‚8• i™¥ÌÉŽ1Yâ5(fé@H]g>>“.;Í#®LË+ΰ(wÇ€¢˜ã‰™£Xƒ]§—iX±aª¬óVÚþ£o¼Ì#CÜ-àÒ’šŽ¯¸SSÆÊÆH¤ ­ÓÌÝ{ëuâiº6©¬fëúíqÆD‘³|uóTÎG5gX³“`†ÇUN‹Dñ yó¨t>:lÅ#È™cíè@HÃÖe˜GnÄ,}ÇUv%>’úž{u(¦Š&’ y#”wŒÝùc¨ÔyÐkmÈAd ÐõÒvÓû´Ð5Ý#SÀÀÍ]¸sc©êZ¥V8^ Ëcå-%]@øfx™7SR:rxóêçÝ–‘¢%m´t?qO#\l|ÍGwtÎÖuS/é˜ ÖùÌqÚ£?âcFSå…›À͇HÑ´?Gö¶²û«$ê8[qÍ20«š“Ò5ýæŠ2u gêÓ2Ð¶ËøŽ±ø>JêÙ‹2Vw¢Šö/«{Ô_PŽ..ÈÀݹx˜Z¦© «éÖLÇ®¦AÇ­ " ¡hxéiG#Å¿rÂl¼e‹7Ñœ.‡ÒzlùmŽª²åÎe”Á4í¼¾1÷”£ö‘ÜÒ-#&2GÜG\‰² Š;òàtè#L}¤1جÉ’fU–vVÙçÈ~Üeèx² Rzú»½WÓñ÷~õ}'ÒÏKãSŒšÞ~FF‘ªÛXÆÉ«·%§Ö9úöE)þl{ºÙÚqªUŠÿqÞ©àkZÆŸéÞùÞºÖÑ4¬šíÚk𯬹»ŠpŽ6§—’úŽ[fJ¹99¹Ë‡§L„Æð#R"7çÆÄÍÌœ<9DdG~(šmL½¦1W‘ÐloA Ûy–Jƒ"|–HæÈ†0bQ‹²G³M`öÔ‚Ò¾ÉFQÈ„»²ýAû›Þ{— SÂ×5NÔÈž4Ó"™c"9øÙ||šg;þzd•ÅDʻ՞¹²ÅÒß±w§®Û‹tÏnúg«êÚöìÝ{z£;MÓuYf¾¯¦ãâ^Ï}u)亞Ñëù4MG:KƒäH0{Ó-‡¿~á½BÒ=8ÚÚ>v·¯ëYx¸PÈÓ±2¯“z|öZ2ø“qÅç9‘&'iÖ(ÎÓ‡ÚçÙÿ¥_a:F‹®×Õﺭlœ\LšgiûBÙÓ´ã†ØÒ/DË”ê'– …ñݸE”R}Ç×ú´pÇÖB¹9ÙnGLèømËÊ’2²Q#ôø·nÙRެÀ—R €›©u‰“§+I%1yÍŒh# d—"VuE…t`ÎìK1ÑUå¤._ã/ítý«ze­nŸ¸üª®'¨®•®mÿI°ªrµkóÇóõ”²%dˆ,«íÈ«—áJ ‚Ú~ŸïV±ñu­ÄÉ·6š+¾ÜÛúl[x˜ÉVY^ HQ§Ð°¤ÎA~Yyb°oC½×^™þ¥zõ˜ÚæðÏ¥ó'¢ä·m/@pØø‡¨•²qãYɬÒŪ]©õetýÓ‘:Œ==®ØéåD “ŽÙEèëtrRAW©>!ÀšEW¨Py‡¯û‚N¿Õr33aÆÉêL$||@ËÓ0@d!gÿW Èr$vÕäPºSH‰÷;.^š“AÓ3~¦xŠ+õyP4TèLôÈ䲈.59n¢iSb·Û>¦{c@ÛZPÓñ0 ¦^¥PÑ‘ÚR3.ý™êîX 3fzG$ðÌìŸ)üyÕÒHÈýˆbiîzò8àôª’C)÷÷ õÔ;Nr†V<Ë1/î§U¾,W’ /ö!•«'P$'ä*?x=Va>óòÑ€¥9ì(ªz'ÅʃÈR½·]Ïqè­N´j©¾l¶A:±`9)lód6îÎÌYÞF%Ù™RݘìK’´,ßÂŽBú“¹_YÌÑËQ—…O’Ûž’ìªz*¯þ­Ø– Ÿ¦øwɲ³ž5á@ å!hÁûsìˆÊÂ…¸$óÁ'ÙY?ç;¢ðNC©u^ê+C$Ç‚2†ý½‡v ¿#¯·õôˆfÈ\Ù55(¬9(?ò2òÊ@þH»ö¼“üñd«mv¦Ûšµ®9,$\Ë­³ü[PüÑ#Š»äx¦5êY†QP1>Ô@:ûž8*:ŽÃ³Óž?ŸëÔsíÇeÔºÂt§,á"ÅøáéË1DQÔvv=S¯Sðf3–H|Aº åA%>ÁŠÈUŠ«ÀnùåTöúóÝ[çll šÎôÖôM±¡ãl­OUËÆÁƒ3Q¼VÈpi[„¦ÜÖïEœÕ™丂Às¯,¿s8TŸºù:¨%ˆ6ÖëÇ–HÑœ»€ªªÄ°*,*ª¹,«€K†ÞˆSÂǧ i—Èò~ ¬³V%‡€¬:öþäû @`¥z«é£Ú=5ŸQ·ž‰µ°Ñ%Ðj™±\¬‡nʃ ZÙy/G#‘°áŸïê_ù†ðÐ7~‰öù‰‘ ý&ùZß:þ†>3´Å#©hz=’–ÌÇG¬Æ.N ¸ÒWCÿbÊU›Ÿýÿ«oݯëºÎÿÕõ˹²ó'\Ûj:–N£˜¹M’€´MñåEU°\z,æž4T‡Oê€G܈`Å&¨’eÆÍ’à›=¼+Œ ?+$íZE"õ¢ûGúq?¸&ó² wV—[,†åU‹“)£²O ×WŠ=•ŽàzÑþ^6NŠrôFt<Ýy™„NáÍ›`‹/y¥©‰<„WÇÇÍ×!’ônžÓGPNBzË÷?ë/«¹u}K_ÎÒ±r¯Û'K¾Rä6&Lš‡PÔC‹æFÑ!+ûF;¥¢ZmÁ‚l¿C½DÞ™ú}tm±¨¦6E—ÁLˆäcÀ°¢=hOea5áˆTêå¾B³`á¯ÿ§d©\­ÍV|¥yya d—P•ZꪬÍ%4<ÕŽŠê é1ŒÝC(<Æs2E–Eì,8‘  ó¨„)eB劆‡Göï·}¸£ûv,M.^N&ÊrªŠZl‰¤"6fÛìí„ÕK¨¥>Œï á©hØz“•dÌÔcJTƒ*ã–ZÖÏKÍ6Ó¯ yBƒ>ò :9û8û_Û¾ŒéÕ·"â&£Ši‘¨k§ƒOÇÆF®GýÕfe«JdùåÄÔnRH=*ôÃÒ}©}{SÅÒ´=½µ´Ûjο«^XÚF‘§`ÀÛ;;PÏ±š´±¢”ä+_ôãë—Ïò“þJ÷Ý©™¾”ú¼5míÛf?á¡Ã¦^—oRuÖs,íË©¤¼o‘¡"GDÒó¼RY'æä'“%S~˜:§¼³[¥ô%X±‘;¹ýK,H©qäê¨çy¬1#ƒ!†@³”O÷/\Èë2dtlBØ8ª¤fK å—·v%ŒÈòÙ£bƒPò¹t ¼¯üá}ûá}Ôz¯/F}-ÞXz—¢žˆæœUü5q7ÞÿÎÂÔa¬n VHÛLÔtµ<(hx¹"öÉÖ)—§C3µÈÃÅm+Nll8­]„§aI6[PRù›Ì+È(–cµÌYíÒsŠ=3C4¿ä,Ý2-b•fZZÎÝDã4[Ρۖy€éFsOW X¶0Ç™jDÙPôN,O_Æ«¹í#Õ®SÆíâgZÐ}#¦aô.—‰Ò0¨¬JL²•Q&FC¨3O%y[“H¹Ž ±íª¨ºwJ‡(¡Œ‘(‹b¤¨(ÅË•Œ“HÒÏ#jË#¶¨š§¤YX‡ÇŒ–ó®#gTµ1fõ4ü‘3Ž‘/5D:• l†u6B –~Žôs¢éxñJQia#ÚÆ/ͳ'Y¨V¦=^ÆŠ÷~ž5ŸÆßLK&ë§f®=<QÉȘ’øƒ#b wþZoÂ"¬å/Å(’-coÿ¹m68€æÎùk…9cÍW%\Yñü*ØÙ‘BU‹Z8í§ÈäccÑOP¤ŒŒ¸áT+©;!F§ÆéM4X *E“4³ý.+4´³I¬ «X/PMf†Ä1)¸ŸãïÓõ zkPÄfÃÁñÝ(ÌôE²Š£É 1Ý^tÇoû×ZÍLœ’Xt;fž>—),±ÐJ"fiȲäÅB)²ôndz·“…Zoö9èÜý0ôËKȦ+cfçJY•j‰J\©N•f_ËeéP¢t·F+9—EUâñmí9µmnżRÁX+-(à­QT©ìÜ É’œ(©EgùwW¿ºâu>¿’Šû`ôÔí'΂Em(VëÍJð¤èEYséÓãwJè%k<µ*7#ä}Ü~áex±5ÛGáéóȼժÓ^Ô¢(øþ%‘_%þÿ¡êô*B©I !ŠÐ¿xhª…dPÄtsF äFfagä†ì®Í ã@E]ÉN§æ ÓʲdgòäEŸÃ—!z§Ò ó-–x›wz!dkvB«ÏÏÇÍ 1'«©G^Àò§+’C4…Í‘BžÙ®Š¼Wî£ò('ÄõU§ie3Y°!H"ƒyä ¿Á¯GÒ +t£7OE朕@¬üvR…;—,ܳ€†EIi°)F›8Å”¹‚ûöåUEU-Én¿OØÈu%Àu`ã™[ÈÔ÷‹r……}Á¥{¡y‚ôìgeòûã§É¡à~«å ¤ þ#웕ç›ɯ.x”pll´¤*ƒÁøg*(£ÀÛ|jÉä¸"êÈ»fµYj@—)ωóçª{qÁ ÏÀ¢qìÂÄp¤|•åÏbÁfñã¯náOað~€ä€WÙB¸Sõ2L2€xG~€Àò•O…ëßÿ…PW! ÛËÅ?_T!Ç!”‘ÂLõ%‰ä“WëÒIµQ¯[U7Ål€(›, |@ *úOòöb¡‡qãt`9Aä*A&ŒÝASó ñþ>¼É…DÚ-åU V~œž“<†êÞéÿ·D2žÍÇ׿RËîìJº ^ªŠ/CÈì?òrBû— ܤ•ª¡$…j¥9NάèÅxEŸ“Ž\õád`3(<Ñ 9ìm© ô?j‹"À%½{…À`J³jêÁ™Vÿ/òHä’}d6bžkX³*Ò~EP®h(Q•þ=<ŠÊ‡Ü•fnJ£1åÿöõ”Ù\ô˜Aق٩¨ÍI+5ªÜKàÝy ï'hD7àJ2L3MhþÒjV 2­>mÖHª¼äϵ#ùÉE¡ƒØ°«‘Û„E¬:™†åxP«ÜqÑŠuò# à“ó¨6ÃãÈQäìH¢¦4¦ìVé­YŽª´àµ¸ƒKT¶Y@ñØrRáð¶…|¬gÙ‡À)Iä÷ì– /f³sä@æ8Påz5z‹)ŠÎ¦“ê¬ E”:°`Yh žó ‘;¥!lªÅØÖdRíEøM ÏÈÁ\(©(‹ÚÓ ¬F‘ddu5V¶~‡eÊ£̧‘ ùUä…fǪ’.ÈJ/ )~¨eòúI÷:0Ægµäqøa¯˜V„SWà“\—žâLiáeý5W¦Yœ·ay]_oÜN€Ñ:±•<€iE ñÏUDU°›+ðå™ÈàLžÃÈ'@I ÷~Iõ§-Ê1æs2î`LÄpƒE=º°äy±¬‹ƒ è DvêÀpܲð~®´à9,8àA- ]ÜWŠr½ŸÅÐ;øtS^ÅñÉ^¤ƒÃ¨—!qé#}¥gR««à³("‘µ›±.Â×0ꢳfä…jlÛQ_ÏÅêE ®«³zjÔ•‹™žŠ´o=‰*É5ä°äðʉÖdÐ:¡÷Îÿ¸Ô³i:‚ª²^UÔ35eåÝÌjª‰ü©@w,!Thή´L+J_`¤AV›–P9$ ž¨ÏÏ ¼ùÎÿ¸ÒÃEÕ‚ô¡¬kÌù^ªRÄÌ^`²²ôN¬ ’ èy<”ö奌KW(0(°\UØQP@«èÁ‹Ûži¶)£Ij¢Ê€É,EÕ•®>Në—uQ J üJ›óÕž¡:'‘gÍÔ~àu´Ï_öç©Zfí¼Ê6ÛÞ ä>mW –k¨ Ù8DÊÆ«v%æb£¥J€Ýsÿ¨=¿•ÒÒ"ù0Éõ¸±GË$¯3Á<«¯,¸Ó<˜±ººIÇ.Ê[Ò½:,½_¢åcâjs#’<ü”öÃåá”’8K5è2¢2á4ªÈ#IÙÁ(ºzê;qèòÿ[ªbjY1Ó#“ÍC Ùíl,åèt½Ž”l­Ç©•ógexÝ‚'PSõ¡Ì½åé† óúÚr^^žr?ÑÊ%µ½»~5 6.W˸%¦~%òò-ZdîT°Ö]ÛM¹½½>Ó·…a•·7N‘©mS‡ÔÅ4h¹‘Üx«©æ(bÆžhŒÈå‘iÆfÙÿ¢öÞ¹-ÙŸ1¡h¹ìµWùÎuW®v›žxÅ”N-{_ëVf˜gCi:lùR,£ê%1@±¡m§†FB®6ÚY–rô·¼Ð÷;íײé–ûg¬²Á#"d ´FÃt$I£vò"0ª¦²Ã$oAѤ‚2Á¥Í“}u×ÛÓ'XÛ[‹3t醹Žˆš‡’yz"ÅhßVÉ|©ÛˆŠÐ\c5£NCéÏ`mÜM Æ=12銋‹‹©‰Œ¨Â³drz’¡æÖ’‹1ÑW¬;BÐôk›‡Õ©6=´í¯î-7kŒYVøø‘Ì_¥‡•ÎN&5äÿ¯e^¼Eìè¬e1#×uõSüý<ã~n^cãÖS–ObÞ:€L©F§ÍQ¢f*ˆ&„K :b3`Ã/x êdVÓ|©¶B”Y„¤ŒÉ"«çî+•û—cm#wÜ‘ŒÑ€ÎÐi™„£¼¶š;•‰ÝGp)'ß[§WÁ®.´e-CQËÅZy]{6™ŠƒŠ_+«‚ì•oûg“µhÓð°GWlÛºt´LGäRT®¡•j„˜Ísj¡œ@ü’á@YÎ6–>SÛÃgèI„š†§›S<œösïÑ«I‰ð{|gzʲê;ÈôP<®¿OºÆ›Ý$ØÙTG+LWÊ–cš;IP°8m“Õ›Ãì̘»²atܼ€¸}> ‰´d3E ¬&`ů`¤SЕTOTfÉljšL™1Ðɳc,¬«ž0´íסàfërÒ4mgWÍ‚äG3P¶——¡®L2sÝ,Ž( 4Jâ&JpdM 3»nØžšdæ(pM°p4|£L\¬Ì•›ºV%_i®4Š;%–Æœ|IhÝ[ówhú}_?#imTÙú½i‘™!A j9˜xR¥Y¦ùÍX¡¡àštt·ý§¨âävN «”Ž¡Q+$² UQZXdy¡n‘~ÞuÔ3¼3ã™W7 : <ðC3l¦=¬®Ü+ùÛÀŽ6_4>ÛÖÝ¿‰ª¦ê&—«lºÍgQ“¬Mrt•éKÇף׬Ž+ xê €öV @®Z¾zÃëÞé&õÞÚÆ“%Õ²7nÓÓqôagÆÈúž^qÂÍŒÈül||Ì´¾_ä#x§v@¯T÷Þzj:Þ¯¥zµ›M3^¥ðótzdcjZ[$ ôøsï/ÁòÃ3‚´«¹šM|†·´}G^ÇÉËÔ4§Óö–—C&­_êYʲ\Äjfd8¶$%Þ6ˬò'•žN’¥×ŬûwØ8;å¬Åpæˆ&^${´r–häe‘cxÆÊ þ#ÅÍ›Î=Çî¼è!X†8ï†ý,™ qá]ºÑ«J’¹uÕ%V]Í3GÀ«µ™­ïÍ@k>¢nK ²brm¡³[;Y²½4ôÙ-]³2µ:¤±|i•5p¨×{zº3´¼m“éö— ¥µ2ro‰ oRçUÔ±ëu|kî e¼¹ZžM ¬å0f¬˜ÕY<‘}ûëfadÒpt¤ÁÓôüGÃÅÆÁ „ÿÞoL´•úåRÐdjÚ—r@‰øÀtôkbmÿI½[õÓ\Ô§©ëz&ÑÔ?錬˜ãe`éºÖtq§ˆ˜ÏIUFCWR†)‹`ƒIÕ!e+z o·xÕÑâĈ¢0¢5 ± m¥+V6m6ÂÙÓ-l‡”²ZYÜHªÈÚI¦e‰XÐ!vDbÁY†¤­¯ª»/M?ndåÿ²Ôë‘4Ö2X× áö²¼pE§äï”çR­Jy ã©Çlwë{>ßÑ‘¾ýrÝ9¸ÓÜùÚNŸ¥lM'ôG9ÿ.Ý4MI®*.«Ieåª×öZ:gBD²Ï>½?Ó¯®ï-QÔfù²®ãÓŸQ˾TÙ#!ë™OØN}²„øìÞËK3릿Lü-» gÕ¶ÞfôÂüuÒ[®6‰éþÈÑôŠ.$•Ù2òuäšž(såI´q¬À˜VSÛwd¾W‚‰§=°9b¡*Vˆà€‡C8ŠcwÚbµRD<Ú@‚³jѰF!Håƒÿ«^¤o?^·ž…³ôLMO'CÈÉÄž‰%Él DÕ¼ñ›žºVC5¦¹I™››g¢Ê˜Ö“aúA¢lN·NÈôÃUÇÖ½GÔ°ßÔPÕè4JÈž.Km Tt›Dζ¢êo‡O.sÈãÑWÌô ›gueúq©fghòÔ†áÃÒu\[åjšŽ¨dÑÔ±ï›\\\%Çi,àï—Jä5¦Õj/y!R¼÷žæÃû^Üû çæê»Äé>–±¬qq±çoÈÔµHb:£ÕüYK97K´)“ø 5î”¶"Š'm‹)•›bHMŽÍa‘E¶æöqâU˜½.µ ©†4xÒ&È·Ž±ÜrdÜÉ‹®Ñã¨Y–%dS"™d³ÆÈ·~§¹=C¶çôgÓ ãazm°´ëîP·ÒE±t‰·qMµ\ð)‰1ˆ2%\]=³Sòõù]Þ£'¬óìѯPýYÙûûUôÃlâgfn/Rý/ÙMdi¸›wH¶µº÷>NI«5ë8OFк^m“UêqÚ3Êú>ì¿·Í㸾Ïv/¡Û AÄÑw߬…÷w«{à ŸÍÑöM56'«ÒÎ8˜¸øø¹M øÙššYi‰Üß· ;TôËkè_k‹áVYš>æÇÑ}L݃ûkÙûÃ#›þFáÝÍþû~9Ùš®tR‹ ºœ…– u¡€¨JZ§ß'•…éÛП@¶g£B[g©î›T¦«­Ñ ¥ÏpÕž œ&™.Á¨ó0-î®§èÓ­ê}]ùíA@Bv4%\‚A`…wOaÉìJx³;?3¨gefK7PÏÊ–óz¤ÅUÝDŒ6"jV (ËÔ"£P¾N6fdë}wqÛ£tH[¦¸o¨†ú®£-îÎJÆéPV8U@hã`bõ ÖµºäÚ¸«"½òXÍx¢Å@³¦S€¡üÝW¢9!=»”ØtüIS­KQúŠ’ šStP­å™náDè@F›Ð¯<ùr¦E^xêôÅAgO°`)ä)%Å@ òB;r ¯Ò<ëÃ×4u½c›2¡ìÁ¨“œäX·Y´Iñ³‘ʳò Ç0˜ã*§ÄìÇÏk6â…kË j²l+îÒ¬jQùe|cá$…ǃdÜ¿§a¬äN½x%d8dî<Ä àvp¨©)„–kË0s×Ïô»LÍŸî‘ü…fPQŒtŸ“© Ÿ‘âTE:¸n¬¿¡Çaþ‡,G'&—‹ÆA^iÁÝëÈ#ÉÙÀ,å´ùè>!¹Uó K‰““sñäŽzImB¯…Nd`½”>á( ý~‰Rè~«ãö­‰'Z ãD›¡i£Éhà¡“ÀZÓ($}£_ÛVÖ8ËͦP@M¨½Éñôef&ªC"5QY9BÓàˆ+ÕÜpê_q–Xê)g(ŸÜŽx÷QÀ’ꀧfn<{±ñ:Ód,ñ°q-Äéã ÂÅX"õŠÙœÔ!UøOÔÁˆ£¨oîGcî-íénáÑp÷f¹¢6n”øÏM í§ÑL%w1ü©@™€Ü<*í@ëÔ/‡i`,cÒ(’fnÚ Cµ(”Ÿ€ª@!¨! ŽÐgëbBÄa&LȽÉEª«…•?Lµ~×pðj¥ýÍ•¿K}3ÞY>„ú꯬*s1u+Ë;ÿн“›(äM%«çâ›[VÎŽzFºfŽxÅcUÉÍǢĦ>âúƒ÷÷ƒ¼÷­¿+'|úo¹PžÍÃOÂÐô|Œp“Be€pbø…;-2µ'L‰äßQÊGë ¿ªú[§l=ÿ•MY-µ·N¹”tñ5¾F’¹76ðcîØKÞzvu-uc 9SˆùXY]7ym ã¥néíÄÒ·j~­ˆ¹†‘¼4þ¨Öüⵦ.F¨Ã WÉ«œ ײ¥<”ÈÙ=µÐ:^>>n:tÎ’8z–R† “:°‡AuŠX‡y%NÌó°YDzOµâöËK‡ *ç¨'¿&¦IŠéjìåÀ†U"6("šEv!ä±ê~â–m0g§n²qÉBê˜cz–œÍÚ®´lVÇ![¨œ“¿tMÑ}'ôö͉–»sKÈÔ¯…É¥ µ«QW Ó”î#W-Ø ÍIöásóq`fã`KRÚ˜Õ\ ö–ëÚ…Kcdàœ¦u]4º9V§Yߨ¦™HŠ¢’¢èw£4ÏÜ¥db@Îú–™!rG ŠVó.Y‚‰ÆvU3’:(ù—Wþ¦A‘‘Ñ>«y¢hU¶ìHÑ4ªuÛ¸À‰ ê‚Ù - ôsÙ™¦|ŽDQ¤Ñ0!Ìg·."6¶¤V(ÅX¶ß­ ° Þ„1SñôÜ ãM‚ΜĻPƒ‚­Dûÿú·Ãö?£†×ôë_'qn\Ü-¿£iXG;PÌÉxaáácb÷lÜœŠÖ«(¢ª×»Ñþ^CNx= ¾¢ïÿH~Ù6…7ÿ¯ßKÛzD´úßE7Ç:ÞµY‡ ÅÓ°CºV÷鎪¨f¦¨”` ã“Ï¿ŸòêçÝî»]¥¶2u_L} Óß-t]¤åRVÜSF¶6>nïÎÆº¾£‘‚%´ï;`᳠ʤE[ög´:ß»òåL$NÄrÔ:ÆH/Š6Bчd'/1)X"#ƒÞhT‡:çXvŒE ‚'YÎH9í²²â£îWWzìDŸt­-Dç?òÁþNSî'?#íÓíã/VÒ}ÚÕ0·.½ŠÎê–¿§Ò¼dQÒªßôì+ 6›bgª<›P¤ÚiˆN,è˜OìÙ1ùñ4¤¹<†æB¤q34aFíkQìåKȱWë4:fL¼ÜŠHQ•«9¯’“R´”Ç’Š1£4 Þ0^”›óg~kÄdZs‰Ž¸¹øÎøÙõyòœóBÞ2U¨èÊÏÂÌžf«E zû£ô®íž›Hé±ê©O‘;yO—@4ò]ßä*Ò„E  CÒ¶6 ,ì§–*çw%Ô3³9²ÓLÇõ%!K?",h«ª!øÑŒå‡‹Í+ŠR‘¯%(‘ª˜ðn©F¥¡É × "äÙW¨Þ¥wÇšeù£öP¡T=‚O·ÈÑ•”"ò¿!Þ~O$·/2xx Llh½Õ±ò|´gC)Z.3¹ñTãÒòƪÝY+#V™½¸^ W{dœo¤¶¥èÀý”¹sEi¼ªÔ|pk*ylÉE¨¯ŽIÄÄÛH[p,6çn,P¢ÀÙÔý¢FÊÈÑbç["´ ›'o’ i(¸·¶l&ÉXÇþâÖ‹†9ðøÓ-<”˜YÄI‹Ô†ýüžÂÇ}©zs©z‘궆5„ÈÔ1ð2N±©ÚªÀ.RÞ§]Ø““Ž>¢®ê‚v°ñ³µ0Ó&ØzŸFíhExÆÃêgå0£K¬@ç¼Èp(ÔÉS[c~Ç}6M³¥gîkbªyZ!æŠöTÇ•‰&ã"J ã%P¡hª³WêjõLõé;4PÉʌǎÌvo: i˜wÿ/“± >£êsaVbb€'oêSU»Gù š½LÀÆÆÐtÍ?JÃà¦6*…ø²‡²Éˆ*¢uZ›(˜ Õ@£èÓ°´c¦é¾j ù2Y»ð€9ŸB/‰*fìY™¢uíÃW}Ù¸°ð»3Ï š×cUg œDK<Ã2#Ez«Jûò·JË‹š(‘n ÇSØxÁpkåì(VH0ëʰ`xç–zëÉQIfIݲe&öòe5zØ¿t¼V™óòâ0¤Q¿…mâR/³ž+c­ÝUGॠÃÊtVf¥»Š+°êl>MÏ.«ÃSuQ×ú°R©³;ùYxUníñãÿÅÿÆCsØõ÷P¼¯3õk¯Â}Y«Wî,ì)ÕŸt O3M<·P8fúL)CVBÄ P—Dá{’ŸF•Uˆ^YpŸ@cÜ$€TTä PÆ¯Š ´m—`$0hA?äÑø (ØÑç”9 Þ6eùŸ˜3?§ŽBŽ>n­ååä¨ÀpÀ5º’àºu*)îÞêôR’!hÄ#"unfA›ðÁŸ‰¤ß製Wå@aO,x‚ü³vþ¼…nä(S颓™÷ä­'35R w#+1ê\Õ{qä,WìîÿD!‘ ãU*Ê>ZNßm6à³C×¥4v4)¾.ü  ó÷-údÈUfu_!=Óäœ ²!<û–§Œ) Ø1‹7O›yþF¡:™õù:ôGdàpNGu îÅ›û7*]DÕ¾S«½׆IžÉØ u-Zu>K1-ÇBªáyâ`ym1Æ #‚„"Ÿa$jTQ•§‚ßU‰!"ŠŠä|0<Áò€*I<´ÖÌ“<¥x ‚ÏpÁ]}º(à2ve¨òÐþßvàè®TðD•‹ýÔ#§RíÀB8Og,…,&¨xÂhP/ú«7~á§Âžà¯ð‡„~Óm–¬Á«×Š|g53r"’p ƒD T‚ed <@y$‚ÍȰXys²G+LÁkmX$‘86vSÅS_ÜÔ?ÀÕШØO9&õšI»2üèy=I^ ç¯1åÝ_–R ÷iÇr8šNh„‰º÷)ã`x«/Ëö¤Ñèìà±=’ŽBÓ«J­uøõj«ÚÛšˆÈ¬\-@F`ýQØwN|®¯:Ò¤_ÂªÊÆœ´šìÌC;´#qר•_(£$*i¢*5ýßòÔ€¶A<µøèN¿u;X­ö9Wahmþ눢ê»p]A?u»ÙHeõÕ«àDnȳWEŸFì‹2<žrJ ’ü‘Ï!¸B¨¯h>Þ²¼ŸŽÌ-Né9÷",,¹á–]áË5 ­ŒÕß§$©«æ;øUÜ"…v«jfyެ ªÐ5'ÓŸŠríeÅšûwj%B¼iÖ_'n§ž{öReÖ >è²°óú×ât©™õW±Í)”–"­¯çaWµFp§*îˆXÄÀíudŠà°Bš2ÀBÁ$ pôû#ŒXÊCôÂJÀÔô.”%8g+ÜȘr BY¹¤û'4^Ê š¹T±PxáÈxûözyñLJ¿OÓ4.¥A bƒ ¨Ÿ<²¸UOw%'C>;2ºÍ™M‰êÅþJßœy‘Ý ?.ËÇ(±uãÈŒÇ -@1fÖ–Rpx×a¢€`ªÀ\^­ÆdÅIcä6 dò¬\Où,F®¥µ°9õå«|JLòʳdgèÄϸ*à?Ý{#:*€H ÇŽJgÜT•ôFmìßVó‘ܯfùVLGE~Ìgfeá|)4WU¥NRû¨ªR|v`äÕG/$t†è¼†êVàpÙë÷–]1€>7“:ôgÈŠŠ³¨F§¿OqÏfcV•cõw BGP„¢ÑïcéBÅ«($[È$x›c@–OL^ÙmVPÌ´bµk`&Ä‚ªy­~u$LF ë…é¼­8¹*•[´¤­ãÉñ±5P” UP9蜲µ(Žiщ›z†5˜Gð,)3J«1V ­; ”ŠŒjÔYŽžJ CÂÌ}¹aáݹ‘ g2r×»)‡5•]è®¶ñ¥{*Õ»žò“FtPö€¯·^wÂÈJ"€¦]j\¸+9K wæJ{:µ™;1œÔž~«Éq±ì†:6´ © Ÿý Õê8 ­‘èjÞvPf Bšaº­ë®Ì#’Q«âs¦,OyR!9š‘?›rÝT+ùezá…‡Œº–V2÷ñÚ\¼ç7ai¡Yj£§D¤©Èo ª2³®àY͈ª:±d’v›•â|NÓ!ž`RÓDRÌÀ‰óÙ™z¼Y<Š´æ×Çg‚¯Bõ¢©§ã³vw1pJ²«P7‘^Jfefùn!€GÉ4iMÐÅ_£ÑP®‘ "Œ–­©X ÄßÈ׃°?€ß'y U6‰«2'ÙTFý•”­î½X¯PWÿY6ŸÑ­”*ʃ½‡»º¸—X9yr@¨ÃáÃ3ÙˆEU,@<“·Dâ³VËßÿf>›¹m|öÚ[¿qí >õzþ4ôÜœ=>ËfîØq|£^@»õ ßÉc×í©§äú]½ö湜šf« |]W?!¼M‡„™‡ m#E–-?í¥=/ 0Eú³Kƹ+‡ùv«'gʦE¥Ë¯‘†Z9Öµ=Äù™¿™‹§éYh˜ã Ç"èô€Ô"ÊéTAP>=˜óòo¦mWÈŽ˜š#!K©ȥёrb¥–ÔgòKT×’¼üà –n%g'?RÅž•£bÙ«• QòáYß )dW£)~ò™èŠ8˜ ÙÓ§?î"(q`‰o©ÉKÚ©ò–y»<Í(%¬ÝÉ‹….£fÎ Y ¦48é㢠T…T³©S– ¨BæšO¨ëu΋é: -srñÚ´¥eÙ’Q©9ÙOABSÁ¢ 7Á¦ÇÄK8é{G;Ç«nÍG0d¼#}+Ï)ir)?*Ù¤µr:€²çÝ~#ú3£^–tßLöîn«øí¨¦&/û<¬Ù2^ˆÈ³•rpdÊîù Õ¼©×£ªúk›ïOòª¸ÚoâW3+>”˜Âo<åYÂÍbçñ`‰AÅ™û0è¡È$’æe»CLÜ@²yejöå•Êj)Qú»²Ù·õãè±Ð¼™¹G=†1± QœHìFª¯µ@UxËnáÛ™ÛÉöÎáÐt÷ÀÂÛ”ÕÝÇ*´l¼\Õ†0INôys|IJ]W´ê•÷'©¥ûŠÞ:Ž£«ãé{uêšÎ„qlÙó‰M@¾"夺VyõýUñ€¸ÐÃT•CS­Q;Ô¾í}EÜkÔü,½—¸0r4cL²~.…‘{dªV¡s²ú4•Mfµ„˜%a‘JTYùÄþ©­úgéö.­•‘M{~fdêO‘”‹“¥à™O —ÉgÇ)2»RJkÈâe¥%¹{g¨ ÆÏÌÍ’\)q¡+‰,¯”]Áóu³vd ¯å´¶p¡¶²qu^˜ç"<>ÎX•ñ’\xWaEAÝI‚xÌžX‹WñŒÝ)+“Ôìm7ñ­Œø¸Ð¦Û’6E¿ +3ÊS&XùÌhÕ&Bƒ/9e+Ñø&íÅ»a›±t| L´“ç`è¶ÏüZ÷®J?哇|¯)ëG¾,ZøôIø±ñ±Éw\„‡Öxã«åþ-é;Ù,gÞIÉ£—f_Òu{MA“:‰¯ 5+ 7é¶½®m´žŸ…º0róóôšyr¦¹°®;Ë+*e›ÍIRsŠUÙ1é‘h ¤ü5Ñ!1;Z€¯¸‚±^\¨X¥R ¾ b}Æý Ï‘4aÈVÖΆÕl¬»0Ô€…ÉAuÈÕ„;³kgãVxš–6‹ZàVz‰uªd.h‚Ëæ«áÊšªÒDkØIXÍâ‰kvn>fðÛ››íç¾9¾Ï¦¤$DÆ ÉÕµ=¾úe2 C¹Ë¦|±1¿û‚ÖRœ(þÈ6õ>íºvf‡ltü}omgdéõŠÍ³q¥)ÛÅ ÊQ˜„²¥|¬%Ì žÄ©Ý_pkþ›zË´7¦…Ëtôûknm_ r¸ÇÍT5ʶ’Bµkâ|¬\`A¸Ê”óP3$Yc$sÅ#±³Ÿ"T¸%Å먵½/í;z+êdP Ê£½rw…¢©â¯cDI“f° 1ïQpéé"j¾•bc VÖF›ªj”ŽD3©RËÉ–><¡‚¶]Q™½ë#‹<\l âì-_?(1áš&DšÇ¬Ûµ1Ùri.Dë#àdU›“ʧëJ~èöÇ¥ž¡ì?E½j×u|ý…«ï¼-Gó×N[bdäãå»V9øÂXæO K6üʯåE ò_†ËÿQ#¦í}M´­#shÛ¿I”Z³Ö4›ˆ…Uë9Ç3â$;0-äÊUÇ_ EupùÍÖ“¡UIÀuW;Ñ ¶?ƒW°»æl èæÄêñ´"Ì_qRã°Æ” ‚•xBwâ )V»™ë®ûÓqäè×É„gY^Ú^’gLGœ‚âÓ¾ØÎðjM)EzÓ"nÁzK½=ZôãEÓFŸ¢àmÝ+zåjù§OÓ¡¤á~úfÕ„±Ï·‘rà¸Å1e|¤VRÄs^þÓ~Ú7ÇÝnÿ\ #l›¡Ùrw–ë°yiº˜þ?$ û=³e­ Õg[É•½÷Ggý³PµœE}"Æ®¤úLô¼Ë¼ªõL,ÅÑXC.îó¨³f³N–uË`‰Ý()Z¸^¡îøú$¯€:ŽýI1ÎQŽ|‡ìàã£!;ª;c%•ÝTÛ*Æì¤0ºpÏWÌÉ^ßMÅž#•—ÛÕc‘£hЩzýMeb‘¨.Á«W ¦@çÛη¾µ­ó6DSVVk¶ZÈÐ;0eÙ·=‰¨ì­;VÙ˜º^¡«êé»7N»–'mOZnÐÎÓd#Þx:dÿi$§{~<ÞŽíÕd0ÆØ;Ò-Ñ·¶žÚÑ7nÑ]™ªkãÇϾckÚN§“©åP+18:ÃÚSËPÙÆ4ŸX™Ì´¨Õ8çæg ŽdfÿJbRV ó?êÈ‘ýF÷¤¹½¢MÒ1GÒuœxå—?õä›ý,»(ÂVÁõ,Ò!£W¤7N×Rê8Ò™S½ØÂt©W#â’P²Ë³¼Òȉ×ÅÙÙ£ŒÇõ-KVʽT¶,ËM¦t3þä“5B¼¿»uUTÜ›®Þ[ÂèÄ4ü…‹ÒðŸu>Z<»ôoÞŒÇÛÆÒýÑ©àéZŒj½^” ":J~^ºQ‹¡‰ sã“)+ШjË•—«Jå¯_) ˳½;(ä;­;*ÓªU‹=æ§ †#ceˆ4öôX‘Á²9 <Å€}O‹×HrfD†8•„A©~#âÃ]– D²ó° |Q['PÈÄBÛچŒ€|$»+U‰Q|ÇŸÉ"¼"yÉrTý~=WÌ'{K'=G‘¦(K¬±âÔ£ÓæâlÏu‹‘E z–r{ççÄÚº%3u\Â*N¸±zùoNˆªÿ [–`æJ"®;3õëR OÉÖ5JjÙ-˜VÓŠÊ ¾ºz¯'fó*L±,Áˆ§n`Šëõòy1¢­äRÑ5¹$nø¨ êK-\©bT–·ú_HÌêŸQ.$c!`2J¬XæA©e– cB±Ø)b f²&•™]HéúLß'&îk•E øØ„< y¯Õ@¡’õ.?ñÌ·U&ý3iÍ0ÎFu]¼ØÊÑu3„Û•@:Ökä3,YÃàЀ¼(I³ô™éŠ%‹‹8D-P4§PÔ ärõ`YÛ°{±=ÛÙ€öRžœ¯|J«Ålzôg=šŒØ±,­üŽ=—âpx-gB®‹mɦ‘ òUBªX(fbÖKU¹ó7L‡]æÖyPû±¨ø®Uh³0U "•BêYâéË'z$™Ý_ªŽ|ÅX«?UeÇÅQJr¬J„S¬éøz¶˜óÌă,äþb@.ê&Á˜(P!¡ìì ”±oc5Rm,U™ÑùVP5^Tß‘còD`ÌêGŠ‚9zËÛ”ªP4™^‰ä FèqI„RfäÌöN¤òܳT™Œ²Ç`I5À‚fì“g`VØ\=Y1¬Ð´¬ ©MH½×U[×ÈQ¢Ç†¯€T~¹{ûñô§ BÝ·ÔtxÊ_šôÄcUeÅÈ|±FI^¨]Q.®bBª¢©Piýe¶ƒë]üËèþüÕõƺOÓMz¨¾‡œ%Tm®äƒmCmêk‘5ÛšÓd*è¹2ŲÛ–8ýÿÏOòÛoåæã"41ë~S¨²³ÕÐ$òDæã»7¸áš` ª£ò]÷‡}yâÉ—¬r±%Lj]¨É’j¯ÃõªƒUAí%gpþ]'úQšÙ“Òr$[>1b6ŽAÉxö²ê‘Õ°CDKN›×¼±`ê¾Óèá†ÎL1$9*¹%£Ub &åW,Oƒ:0öÍêv6§º}"×í©eOOÜÛ?'4ßÉ ç*¾ãÑn_•Ç”X¦¯‹‡bjÔk/3ÏÅ4ûfn}{blÍ[QÚ—Í\[þŸ©|8Cÿ‚«ÿøÍ¬n½ËÁr]ÇëDçƒÑOU³pz[¾uá‘©ãn-OÞNö^_×ÌÑrÔ$éuÌÀ̰£wëã˳_ßÅ_®ˆ±öþ.—±÷Ž«äzâbãêz„hmJ ãåé«m9'L‚8Ë⇘3øÞ¡‰–¿yá¬Ý.h%ÿS¨x˜~™H±LU ˆîâ‚•-ÐòËpÖ<¯‰;Ї%£vKÄP’6°Ùš=l9¶,U9 ûÿõ+woïXórõíÕ©îŒ\YÇ;QÔ'ð-–À<° õÿ·•LSR<‹ÙnÜö¤˜·b“ëuœÊÑòв×!ûsO~Œ6ñ³7^œ±SÕ}Í]Õ½÷v³ª«ää×pêKÚÍ.%$§ŽÐD¡¡ï+Ÿ&Ï)‘9º<àx¸îYeâ\zj™*n\Ä‚ÌhÊ&Ý‘“æ dgA5pöö }ÛÝ7"… q†HQ;ŒŠÏã &Ø‹Ô1ùå‰$·V‘sz¾IEt†9Õcù¡M¹¶â:Qàj ^Ÿ§¬ëE´ûªE…•KôªÐvsѼ“‘Ug¢¨§±n³’~ ÖÍ‘ŽJÑ@woÇL†4&…d³ŒÝ&B¢¼êØ‘µ<‚(X·à‘"x+%)E‚\*¥çSVCDMW'ÆænñËš´dÕ°2‘ÕpqtïÈ2A4"UÈü‚‡0ù GÄ–È›ÖrÉ<˜¨&Ó@ë%ìiO$Û$Û7 î ùãÿ‘ugŽG+e`—ƒ¡ÕÉ¥ ´È@ y$ð‘ò¿*[# É”§±ÇŸâù&έv*+‘?‘É*ý±ÁggGg †¬êˆ1–j¥1åÛÄx±ZUR5wbýC¤j$I*9PÉFòyÙí’j¢ª'z­ë†öeÇ6yäÀ‡2ïw“ÁýÕ‚FhïiQb§ãâãáB‰Lù—gdòßö‰DltsÙŸ›¨e [梊zÛD%c‚=ƒÈû0üêÜüUðMðúX¨’wnmVÖ|A€ð5ã@¸ø&ßG¶ÖFîÝ8¸êkJj9Xø¾)<—Õ‹^!ç?£Æ­$[+ Š4L×¥~·Ïmh0ÙKÒ0]œ¦™ÖlU"¢ÔÌNj¬J²•˜4ä.Ý™Ø6w}€úIL½FÛŸ&<ãÉñ½Þo`¯:¤ÝÀPï:HÒ};2pžJu†ú[n-{KÇì#5Fdñ»H°ñšðí@Êuv4‘R¥¶yïÞ¯u:TMpà ’^Nâjº•? 4¼È5SàŬm#­hÙê×C[¦µª•/ód6Õè»è‘øJuLˆxÎY™>åiEaäñ‘FjŽGì3(;¯ ‚kii^Áÿ¯Œ„Y©!»K²³ðÞîÊHee”? ¯æ$¦R›s SIÉB27ô‚„ ?I•`øÍ[²Éþ@ðwÐÊ %&œž§¿Yø•»§É[Ù [·e¨‹p®¬òåe<ñ†t⨓ªŠ´#Ž-¨+¯ÉUo^¦¸Uª€¤¥$Øå€»«ºÚö?‘oµ’;{Ý|]Ëpàóˆ*éÈWò»3¢ QÏUáiäîW²)àEì³îOœtOB®Vä7V?_Kl&Šº^¯þÌIEîÁyäQ~H㲞Ä+ü@Fþ½ ¤nøî,¬Ô(ü×ÝÏÉHPùÓ±Q `вW“§*¿ò» vªPcBKL…¶·àkUÈ-F¬ƒ·$Ÿàzôéã g£ù1á“»– ™gNKYÜðÇâTÌŽ~MEŸy¯Kз*(Ku¢qÒ˜pÀqì<ó'éD¯óaÀAD¢²¢õè‹ýѹÝsÃö$¢§_¯Ü„U@à°¼Û¨#¨W,½É3ø2ðC‚sÀè¬lD쮪Ä3P† ýÄ€;\àªó~¥ –RO&ªˆ‚,þ,ŸƒT8ü ²Með.K·F¡+B•èç…÷ã¨SÏuç~š[³MÕ=V|€ö)fùB·‰G‡°É.ÅU‡ ½ÜðÌ:µ;õZBƒ´É0ç°¨RDù ¿Ä}#Z7FýïÇ þýÛšpB€¸RDzÊŽ=›•@fÔ3+kåÜ ª“||–p§Ò çóIÅ–j‡ýÆ¦ÈøâËvLÛÆÃÄݾ 2á*òÝ‹y—P}nIfÊBkJ¢jº­Z"’޾ř&ߨ®ª{*•© ùYH(AØ„fò¨V^Ôþ½xQÕJð=œò•ã™êhýÐ ÌïÓž¿ÏÈáèßÉý9aÇØ¤¹"¶»fQCeNkb ‘©@C|3Õ˜bSafo33NŠ‚¥(®þÍØÌŒ°þI÷D`)S×Êxò‹8áË纕˜êŽT‘Eìf>•þUÚiÔ9­<ÈŸ&^_àŸ˜(Q(³4ÖTcI†^î K(`ê¬Z©ER.±h‰%B…iunÓnDþ O‘£2/*v{ûjÍXµ$ŠÖ€ <…GÏ7¾j;¬¤2–ßE œ1p }•ä~öÕ5±êÕœåÐ9₽biQP±èT•åGå€er&…G5˜ûyí“»28éÛ$±yêÀ­|Õ•d ²¬›‡áükUõHÖ2j-ŠÓi#+1`à/²Í&^£¨ I;‡(Á‘­f>Ý;KÏVµ{£‡`Œ¯Øù¥>@íW¡Uáר¢°*­B3¯lzDåIPU áÈ#OƒD†“Àk ¨$\éè¢D%•©¥QÅI=¢a|w¯`ÃÖ»zyÒØ°  9p(àž}“… Lþ,YAá{w‡^ ÑŽªË7à°âTöÚ¤8.Üpá†r+ýQO -骇Çè²à" sCÏ'ÇÛÊUkíó Ïw.JÍY„Î8ü€¿Gt 3ïQÔ1B]ÈVÞÊB) ýP?8vbVç$MŒÊY¿FFÛ|¨È$þ@¢×›Z>©Àò$“Fê…^GåJêã*à/á®Àûˆ¥5è‰)LF¢UÕ˜t—¼V'É0ƒ’Ê´2—ŸbéÀ^¿N¸Ó—Ž}.5T™­†âOV—>F˜ OÅ™xdb üÛ¢¿&ì )_ê­Õ1ÉíÊ– G Ñ ÐºÐ+ºc¨UIiQPwå®´£W‚ÄòîM‹{9ìuX)ñâ¬FÇà+Y·Å0¦‚¤v¥7“ªì†S· gU ÅF fj3ô@ÍØ*H¬Õ‹Í¼ˆ åB™‡íâD*v ě鮑·óuÑ—½ëšú“ êÂÒ]W?U8zV5ø¡ù4o2ë*4±¼÷’Q×­ |)§ŒgiÔµkÐà?5#Ç;*P«TYæÕÉÿY¨Êî’ÌŸJœœl„òΆÈ1ÃÝh³`ý”SIþ°àÌ2 vE}‚«".ªtVh»—ä’¶å˜~¯ªmª –7_ oeW•’"-¾Ñ$vÊ +äë苸õhîMË©k˜:6…‘ÓIÛúlÖxznŸ‚‚˜B¶aJÒH'[ePVº…Ÿ&·NõïõÈÓMä&ïYIÕÄÌ×Ù¦æeƒÐû%%~åH˜§»†:ÎÍz±C6´•²&gGâ¥_+!’'g«¯ ª°Nhÿo­`Ì)®pNà)l6-ãI-B?Zª¬[–ìO•CM ûhe›PbÒÊÏ&¤yÉLòµŸ¹ËHͱ'mîüj˜ðˆÔ¤Q¤k'ˆa E@I •&=vî;Ù«eoV›üuzÁ‡èÜ^‡¬Uå´½H3Ú{…©’³ÒóŸ4ñéùvŵ‘Þ“j–é KÿÊFƒ¬Gî:99…m¥gì­'H¤þI(âeØ];Žy[V‡°U4d¤Õ_§ßD­©¥G@͉¦Áÿ3QG#YÉdÕ–d­1Và¬ÔãMb|Q"&F“sÊö;3làé:vl3oŽú®B…ÖŸ5ÊÎÒp’ž!ƒ¯ŽX©Ö³œx£Ðš•E%þ‘î Ë¥heÎ6vv›£cS´5¼]W$*VÝháÍ]U¢ÎXvá~´^Ñú¿VÄy1ñÿü¾"ŠÙ¬qÌÀ³èe”)š=Ô…T:¦“þÛë=K¥ô™Ò<œ€“ÈKEÝÙ®8Æâ0<¸i$Ѐh䨠“Ö7E´ÿ;¯_Ópu-ñ3´-'50à.Ô…í‘íùHz+I"”n[”i£Ïë'ýFÝøøù;Shkgyê«ç$/¨O;:ú~,¯m8G9r?9ƒ@âÅgRì@¨%Þ®ú¹ºýIß¿KÑ3²¶Þ‘¡èz†¹»ó0Ë“M?FÇ ¨í‚Ù1®.7XRnöCGR;‡½ÜRÐ=gÕñöö6^­´öÿûm#Zc‘][Lž§¨Ão騏jÇ+®>.F{ë—3‘ÈÈüH⇜¡ß}—í,È0;AÒ$c܇(âV¡—y¥‰Ü… w2Hf¡³R„LkÞ~ééí’W§‰_&9"Ç—%²&eI&ì层 Ò0 wáTC²’¥É*)Ýó+^Ô4ý RÅÑðqô"°Í¶›¥b­³²§ø«Dµãö®EãIq8¬U¤kÍ ìÿDïº [VõKJÓ°òΙƒ¶6³iDóY¤3ðj£°a[\3×ËR»V¥f€wÚuÁÓôL›e#küukOšµ²á£âÖÐÇ¥Æ,V©Ÿ‰OÆ‹Ñ)ÖXÔ´–™1jŸtÍ͸=\Úú&ÝѰ²p½EÑñ¡·ÈIRkºö¼¥‘Tž~]Òž+iXþx®FK¬NY«\Wó>ňÇØÓ222õP–ïmK6sEÆåû²ÖòÇïV*”êÓbÑ4Œcei˜_í±[954uyŸll쎵|F@SÃûu%WÅV¤A¦1…瞪`iMÑv: ½[._õ¡¦ãjm ?$¸‘üz¶5ÁJ~EçLº€gévÜþ£lý§×˜S+yòÇé?¯——g¹F%ÞxFjÔ-P¬ S±Y"y‰Cµ¥ì4u-tÁ ¨ ºÅýÙŽ?yø Žà5¿€D¦6~ ‚K>â>m]ß+]ÔŽfÛ•r{‡=tü䍨Ã'&3”ñq™ªðš["NkEFè|ô\‚µ+õr7§['umÝ_#Í}ÔÝKdÏkáh¹œ ™Zçѳu$ÀÈ´Õ#YàÑ(·ZdaæK!q¤RÞzG®Kþ®Óÿëm&9úð5ýÐ2ñcŽ<:lam,mØÊ¢=Še­—Qo“Y÷Iv3iº–ñõfúá½²³¡‹¨m}¿ƒ¯dÁÈÀÇÒ·v6&ÛÉÒ´º]æÃYÖ0ôÈf6%hìd"Ìk?7Ñœi5IF:èÞZ¨bÒ†v¢„t±•µŽ½ÊT¨‹87U/{/u¦ÇXbe¢%”Æ´(|M•oF-cÓïP÷ÏØÎæÀÖô¼qöÿ꟩iyº¦~,!ÿLêûg2šŽ—‹‘‘dJÉ”fˆéqó‚˲¹ñè¡ÛËîcÔM7`íw/¨j•Rø6•Š\¶^K–"« •A‘7¡ 9{34ÿg¬Të¡z+º—TÖö‡­{o'AÈÀFËËžåÆûWYù #\,‡¾ 2‚ªÆ…éJIc7žÚ}¶z·>Þv>“饹8{·Õ­óŸõ®æÒØV«§å M'  èؘ¶ÓœB”áñr™©]CÈ‘ïrGíÜ>+?SÍñºf)c2Äd^ÿÖd²¬`cÀ¬êŠU.X×bÍi=µÑrz¯PÍÄyS¦Ã“&{ÎFÇ$M]™©s)¤½Y#c™Íè÷¡ZÚÚú/Úÿ ¢˜ºcÎ5õ yÍ5Ü9”'RÕ5Ï‘t.Ô\yʳ .bƒRv_§š>ÍÙ´Ú[)V6˹sœ›;päâÑ/6öš†¿¶4Ç’!ù¨² ìM£§zS£ÿ¡ÓÈibÆŸ¬3G‹3BLŒ·qÊÐóŽ',ňv±ÚV-ÞUÚV6§¯êÕ×5û6Nt’3ÅYц.1oÇÆÇfIÅEH Gp½œõ ؉§Æ¦T£õ˜›D#÷èP¢v*\7ig@"Ÿ"x,ð?pâc«€Møp;Š¥€=\ij3wƒ!"m÷ü3$WYΦ,ªÀž.¨æeŠ3öf¤‚ñNo“:…æKæ;µÂ’>!¬Xħk7LßÕÌgâáB¸Æ‹Â)2¤(°¸ “{rmÑ&ø«¥ 3AÛ«E”3wÂðˆå ÌóèÜ»òVm…*fÑh¼·u£8 »yN®I°FQϨ†ŸScØ9 ‚”“‚{¢‡eò­ÕVòü„÷ e8ùò™¢äZ‰(dòv›´þa•@ ;:üTuIwö¸T+|x,X}È/çîEžEIÈsÑÝ‹·5`(àòoíZ4\üÑ€z”iŸ-ÜèÀrGbµR¼UX RT¼”-ÁdW>ü¨áQ¸ 6R^ärò¾ÍËÉú‰àæ(#±"a“’¬ý nø³—èÀ{û‚@àûÌp쇲üÈ.rŠ?²·º‘ÿ$1${Àsì~¥Zd ÕeãðJ•¡ä~EŠ¿oŠô}ƒ?(ø¿ðO¨Yë>¾óö\õ½«›A]üVê…N¡”²¸Yrk2„p~%”{€GŸwûi'©dåSRv^N<•&Ó tð2ì…‰F9î$àwÓëöß–áÙÚÎ$—Éqlì<ƒ¢(£ÐöV ¤†aíä$|z‚~¸ÜûÕôÿêÛ³ Õ&¸þ\™$ây“9nþéÒ"¦ý&,å«C_ à«–/ìœßí~çÅ{ ¯*©ùã¹"¦ÖE›R'¥¨òµÒ¾ÃÈN¿ý9ë=%ÿÜÄÙ•B±uÕ0MŽžo'ýײ35¶²ìc‡¯þF®Jš‰VÒxO&Y%¼ŠévÇTù° €•F“8ê÷í[wêçí F×õ« ¬†ôÿXÐuãÔ†ÿ¨¶(ÍÒ5:e3Цæ"Ú¾F[ªø¥>¸ýŸÒõ¨¶I¾.|Kž.•Gn+;Z+÷R«Z Êïû|kÔïøË×1µíê¾Ã¥ç›¦_SŽôÅ[,ÚqõjâdkXîÍ (ˆÔñÚà§W+e4›P–=ï¨#^”fU¬ñJjÑK#JÀ·þœ5±4v«$zÈËÉ>(wØrÄ\'ÀëØÐ+nñ°²M/ð]—žŸUt]}o-+aéØ6Öõ<Ý7?:]¼sËÈžv ²è^ÐÙhÉîÞ+7(Îè`ø¯˜'ù/ i댨,÷’bãVEukdøß¿‹ö xÏÂ… ôeû£Ó³q}RÜK©ŽšŽ‘¢èšN6šñ“þTt榋\ª¼éoÿ8é¹7`´j2ç K4‘)An ˜–(·eF L+<ŒvO’·k##œ[RòET•¿€¢3ՕЦ<‹?Oœ¥¼‘DÎʾLÝ”²€|ªëòYÌ­^XòE!nÜd†\HNÄ.§g¤7­ª” 9.ë‹€¼™·”8“s@+"µá¼‚UciS¢M[³wŠöiª òÞy n‡¢Æ¥(îÅÔ·–L“f t[J+7EëÍxœ¹G4]a‚XÇ)2),y×”9 ¢˜Ç³¡íiÌ™—EîÓk1ãX¢ñËÁ7¢Ù9™Y%ÅSÿ…Ùˆ÷€rÂL¦l€/w7¬+’úð´¨>Q,Ô p¬÷,ß—ã“Ȉ8á¹.8ÖìT)²… YƒÅÙˆ®˜­ù lù“ÃxŸ´Ë×±GølŠ…P]¨½O˜=Xräc_^Üz^‘§x?+´±eÛ¤Ìù UWfee:8êÕb¾ Pÿó~Eüó»I ‹2·¬Ñ©Nô^É5 C0¤BögìÛÓÏQ=LÁ×rò×Å¢Õu ɱ«ZÔ ޶³û4ÚWO‚ÁÙ‚·…žÔrŒq•Ô[ý¬8­Ö¡Ø(Qz’.×üãTLRóÚ„ø‡a± v¥£ð X°¶Iÿºõµ?l[¾úM¥Ç&C-ôÙ#ÒèËr8#°b&`XÍÔ sû ÛOG¶Üòo‘¬XpùK 7 5%&.ÍÕ”¨Yû-Vœ–àù¢ã~–HâCãG˜AO,åæUK†o™þ´ éh¶.-'A‚¬@¥ X¥ ZtcíϰW'º1`~=:O/uî¨ù/˜Y–\ì‡ ¬)Ö# 1„ø…>BÂùY·*G£Ó…ØÉ¡î%½I›Øþ€ä€ ®àzK¬iµkRWgFeF`fÎ,Z-ñ.£¿’lyQU!ŒûN'x2RŒ_¥ Û©êÈX=»ª¨*;P[ÆzžP¿Db£]J•>@OaÂÌ8Ï% ön^ГñNO#ª„ œîöÜ(DšÈ ÁF^…@FrGÍÆ*\sô¿–ñkÜ€(lÜ( æ¬ ävªŒ3² dæ”ÍOéÕk²‚¶GÇ Éÿ±ÈÄ ér âDµ\1^VkÕPòÄŽÌ¥Pþ ÌßOQÜ“5ÎêJ8·B½…${€Ü¢Ü)áÃ{yZt¢fSnÌ"õ=‘:ò<亰nÁߨ'V œ@ öæ7•¤M›Ây úÈ`9+BOUÍA*Êyç—T+ißP€kÏ'‚U¸â76IbÝ`ëØ”¿ÀRÊÁ°Hñ²HR#í^(±rqwFü¡Ýkwdèüý8n³á¹@¡ú1bOR(g¦L»yü¬©<ÍÏüð,§–ìX0~¦g€¶f=àï5ÑÑzGÊÕæ¤= S°˜÷anÑŸéµ±'!kÅkf, dŸz¤ pîH PÈ·Æ„•ê,mˆ¼}¹ –Kç^A£O¨°m<ÜQ zˆä£J0 €¥k+7$Ç«b¿´Ñ†·I‚É^ 7<´^À1íßâO¸ ò*£’Ý‚¶VŠøÈòê {p„`;:·Œö¨^ßÈÝw6tö'ÉBQÇ=€ï2þJ ù!,å|d7¿b¥z…Ñ×qoãò² Ó†Ÿ‘C/bĽ[•~Ç+J<•<ùŸ Dð«ÜVà…®W…àYO ¿®ccW/íâù"Ï#’,ŸäÓÉ`e”°*Üz‘þ¯ÓÄäʼnä«9á]×Ù@ÊÅQ¾™³2'E³$«ß”_nËØ8@«Ëã±ì_†ù[³ý{b䫯ä½Åä@Ñ”1÷ù³7nKñ/‡„™QU’@ $ÍJªN’x¯^£ƒS6 Rò‚©>@CkcÆì.Ì>@º ›B‹aé#ç€Aû™MÚÝñJP%hØÞÖ&2Az´gY8vYѬR’T˜+ÍÇf(‰2ÛH½Š#'z‚8eœÌU©X"{bOf˜fOdáP ?.ÊRÈÂXóE*V|÷$÷e =Y3)gvQ`¨Ý§é—Œª…'tkÆ…Úhè¨ÅBÉCÑÈÉG~´<öy±)5`ÎSÀšjm]É5FÃ.܃ÀceF¡®†À[uQù¦‘uÛÉÏ%³€TŸ³`6¨F­\s R;2³8cQå)uUœd(Uä<Ð(ìH ;öáA,å.Œªˆ¢ëÜíæ¡N ÑA_wVF"ÅÔºª&õÛ]¼`ØP²Ñf˜à«QÅK(níТ²Êò;: ’¡4<}¶=Z¼f¬` Roäì-$V-UøÌ¸KVíVO)AýY¿üšv°j¼VüMw½`ßíçîÔØÊNP(© ‚h»‹`Úº©R¬oÈri[ÖÄú{Z¶Z½yé5(¼¿¡ î´˜¢T!꽞ÊýñaE˜^9NÄ•ú9$ŒBW€G_’sÀèT黳”›LRbhgEjDÙIPÈŒUnÉ>ÃÆÃ/SSÄ‹ÌU={#Lª…VeÎ> ²«S¨Uq@ÇŽŠ€˜P“i6U÷u*I[wVBä'’‚l V½"uxHÊ“Pªh5xëA‘|x-jKfÀS|óé6¬@Ç`hêì()Ë"üÙÉïðè¬ýÔ·ÇõžTw g7Ü\¦t}Kà®YI^ÜÞ)öäð­ïÑYJ†*Àóýû+i6¤žM>®)5Uº÷P§€:¬Ðu¡àËü÷£ï_q¥4MM+? 1©—eI¿.³òüC µOëÏöIœ†ûÑþáؾÙ]m°-Ñœj¦”M$×µ\FòÓ!dæÊ ËYäüóϬ'ÜHÕÝ•^ã—üž†LX [$¬¤‹ä˜Pêd|€LÒÓV “·è©Â–J²ÑC²y^¬')ÒONfdME{»aÇI k3Šn|ùÙˆ±­|LÿŠü³Ðy̳ Z^rĸ ¨Èá 7o i×¥¦E‡JJô{•Yðê]˜¢OÃ?>YϺޏ ë<½)·b@%à~QwT(_ÅxL‡"tbU{¯«Þ¼fÜyñ÷qÀÛŽ4LÆš^l †6<™IcP­9U¨¨ü0îy†`ž{¨EUNî¿“ÉY1‚V ­ Šø‘ÖˆªÝ¤ªªd°.zycªãa¨¥<ôw%ÑÞ´R´£OµêFJõr#WE˜ÇR Ïß̵âÎ!ZÍTÄ:ÿ%”ºò½Ü4³ sÕ'ºp@R‘ÔZýÂÀêãÀ4j¸ïäÙüú;o{(×Rx$©o$Ðù-Ï‘š/Ò™RúÈi,‹%)âåEÄÈŠ L{¼Ý:…W°!jm6Ñ‚W´jy=À ã¬Ã0"Lfá|ŽK;:¬º…YùçÏÐî¥åŒ2¤,‰ÙŽ’ ŽÓ¨3F«db?±¡O:7Ža¤çœp/8Õk‡»¬ÅþÅEåzºžçÄ“«3MgÙÔ-6e*(V  ¶³á\¦‰–˜ßÀ_2‘cvQ!¢+RÅT©éMûh0 Å˜±†¶O.ýŒxô%ú• |Õ(€:9y)U=šeØrOô»Ó½wÕP6·§{}±±õ]Ï©Ï/*¾ \VÉ*×Ê©3=§%ZW¨BDç3òEêÃ}•‡›¹µ\M'Oå2/Vg£3ÒÂ8áî\ñ"è ÄøÀ(ì\S”n¢æmý§©úo¨èû—lj5–äÁfÌ–§Øôñ>)•P W¬ÔÏ—£ðJž¡k,.4r1Tyûr¡rU˜ Â"¯aÚ€rÌJ] ³óÝ!|\Y’,Üœiþ’Y|“ Fâ\y,±,„R[Q£ ¿T§ïÕßC¾Ø6W©¾šçgè^ºo®h8›v ™ƒ]XÑ5*WTÔ©Dc“¢`dÏ+iä][+Í"Ñ2³ÄOö×÷ç¢z퉕öñ‡è瓸p´ÝÄ´ÂòíL}Ŭ>V5×93{_&ôwÊs4˜£)Bå÷õö“ë«~ªz{¯ì¯Oð¿×z™¶¶Þ&Nô-|¨¶âÍÏÇXµ1h4ùÕ 2ðdØeÞÎÔòJ¾ýzIê—Û—«¾¤cïí騛o KÖuöÛºÞ©-eaȧ‘ÿ6@°ÆH'i§ïvî€jÞÑö—´ú§³‡RêYÙ¹½V8Û¯áë†be1¤±Cƒ…”0ÄH ‘Ú TI2K"eµê>åê¿Ý¢Ç„ÁŸ;ω “ä`G’ÉÖñ{PÁ3eãCŠpŸ½QÞ,1sVŠC,»iÆùÙÛ«Ñ; Ußú^©¢âê¸zÆßÊÕd˜ãPÅ"+lÜZü}Òy çýq•&Òs2Åó³îî LÚû&›ome¹ß›¼ãæáåöžFŸ…˜ÜEšËJ4Î>.IÎðžW’Nuöf–ýãz鿵]ý6©¾¢fæéqÓ5}ô2)©àë1ÀÒ§“„±ÁÃÇËÎǶ>«‹9ÎeïÓLJ¢Åüt_`héêö÷Û£GÍÄÑ´}.1’dË©Ôò4ÌdS+&l‹ŒõÆÔ»B¸Æù-*0Wohô.¥ïÞ™Õ£‹¥cY ¹4<=?R\Ü<'†Ž™:eô»é¿ëŠjxtŽDšY7¯äcøúŽøUÇË9ý5™¹Ø²­(d¤vRÏl‰%/Èä>˜¥œiãÜQ -n €`áòU( -ÈÕZ%‘jÙšŽåÔ²ul¬\LhâÊ|ÎdBx²yϘñEüd.‚s‡Yøú´h³ O’ÆÊ|ý;7uïl 3/!ý6Ý8š~~¸ÀÇËÔ°ßBüѨ{ôll ܫΨ떹8§°¿¦~à6=5Ýzž‡ŠÏÓ^¾àô±&•iÞkŒJü}EîªÂbôœ ZLLÔD=.ßzǧ;Ÿ_\Š[EÔiÚ®cü|½ÆXùXÔÆ­ñ’¤EìqA²Ôå0èñà;Ö‰¢WìÍ#F &ù!$îÏäùµØŸ¹}Zey .ªdFMé y&¡„,|ÐsK·“ I ƒ?¦X9:? °¶KÀkÚ„%•§iö‚¦F¶u=­LÝD ²´T¾½„M^l±Ã–HeTº?Ô3}kúÙØa_SÎɸң¿÷—¤Aún-å»m¤¾¹¨ ™ÆÒôH`KNjâÙ¥lÝP!›ædTw6éôÖwik›G//+câé>¢i>¬h¯˜¹³OÈßyxñžK®ugé‘8:2iúŒò(°ÊŒ0³+å¤íw?±¿Cm÷ê¾_©¾¡âÏÒKa¢än=Bøñ¶rèø‘ÇÑt%œbädXàã,x»=rS^KœYëg§ô®›‘Ô²¤K‡p+,Þr±È°¢°Lù…á‰2áâ`ȧïÝBq PÉÜ›>VŠ9R¥Gã*Tý2­‹L±‘õp>νÂôGÓ×õÛ{hË_UýSÁÇÄô‹h×y £ãêËâž½LOõvñê²îêØøŽihêXß[¹öÑöý/F¶2jš²×7ÖýgkY6no¶4}Gã=. G+‹©äË­££Ã‡†ùøLoÐÿK4͹¿ýá÷N’´Ûºv4´_Dö¾ €$F ¯ƒQluåSMÁtl‡°)@Ô¯v¹B½<Ú—Ê-¨jijнò2-`¾Fgu·$ôö˜`‰&%x‘—CÊpüîsuN»›0yÙrº–²ç ,©ƒ‰a±zd +R©oÌ‹!v%¨2,-Ý[3 tÓãÁ™N|ê#/ÔzŠÃ熲 ÚLL9úˆÃò2m7Ñ2]õ¡âíM”ÇŸ—SR±`Äp­e#¬U˜»õWs;-lH%ú)•}–¤¿òÙÂT³™³Ì¬˜ §6›yË¢Ž8ð¯Qc©ïßPqt¼dq£iÝæŠ|“B‹ y•Ç@ù¨/Üå/N¿³·¯­^¿zkö³¶0´ÝS/Vߺ–ž_lìÌKÅ3¬—¤ÔjšŸŽ5ÿS¥-ÝU³+j!ü|)Y»'Ðü(àǽ’ÂíBi z §>+ÁºU&Ü(pT:„ýK­`ô·‰?Qëj_¨Lh¼ä‰\ÛˆâUFNûÈƪÅÊÄÃÖ}á±½&Ú¹7α-?IÂÆ‰ÊÔulß{œ=/OÇ£dêyKK8Ž<"êŒgLŠFHOÖ3o½ÿS7¾èÌÈÓ=;Ô¶W§Ò®GáäêøÞ]ˬHǬo«R&˜z~-ÿ[6.FGŒ÷нCðµ_]±}CÝÃsz™¸týGP¢“¥»Ê{;Sðô¼:VŒ¨@EK²=2l;äÒ®ÎËý®ýÉz;£ï ‹µ5ÿõÀßym¢Î^µ°òZNøyù 1ÑqBb6“BiF”Ñ[šWü` WZ|EÿèæôÛêõ½…¯jú555ŠaÁõ-lÓŽ>M&ð°V3Ä/iä±²¦9»Ðd-kôC§gÀ%ŽlŒW%¢'ë bEY’a°ü—|ŽŽr#°kÝ@ÈðJeÙC ¡pΡɢ®¤?>º»Ó¥‘†·•#hN}УšL,Y<«ò3r†€¨ À7eîX·êä¬iù”é9«¼º³0'²´è¿ßݸQÒAÛÇÏžŒÃ¾×þæ½lÛy¸ÛgÔšÇ\Ó¬óŽ.må\|•Ž=_ƒK²¥"² nC½’J³<ÇÖ®áoˆj‰,ÃX4¨¡Zð½ú£ÿãvW,£³0 ËË)P̱ÔpæÃ™¢fG ›,Ðȯ¶P¤W"Ûƒ`µ‹jWÉöî~+$LÐÊ_G*ðUjEaLÈä“dÐ lK5k6Æ©æiZ2¿Z£­ ÜåœÝ{²S¡,y—Û>p´Ý.Za<«ã÷›Eˆ=C:ñ [”@; S\§çr qÙ’Oÿrz†X"«…UP;b8wîYBõ+gFücÖÁ8[ƒîˆÐ•§“âO=Wz¹Aî jpÔ+ÿfù;rÇÊÇ%¨ [ciDÛf=c§¬=O¶Êà?$víAöE€"Í_ˆŸiš©àBÝÂ‡ÇØ*‚èÜãŽ`ÊU@ Vw¥ê'jÖk9ŽJŸn¬Õ¾>ä2ê üxçx¬{ƒ}é›-79ß8øÔÉsj‘ Ž(UYCös_‰˜^ßUn[*½rÿ ž²Û2›Ò-tì;^اrë)4Á£¯tQ'ñv©-:«õAÐ+¢?à\éæíã@òvwi(£ãf2<¬Ŷf?h$u1=—ŸÕüàXa€èLÓá­S¶»x1Ö0Ç‹"­”õƒÕ=­µöþ¨ºÆ¥JãæK È•8.?ÿ°)0C0UéØÍ–|rOWtŒÍé«Ãjx­ éå¼/!LˆVsyµ(õ6ÊuGU,ßöîõÔoP·Mq·÷¯’ÇÈMf8yN.v?†±ibäf$ù5Pë‰\œ¼¥¹ g‹0½¯HR¹ú·³ýl­X¼ÔwNt4÷uϵìc:W÷y€.)ŽVJ‚Êć'»wCé°t¾­‹ŸÔ§\éH˜8<á†GÐ!@ÌÎX6¤Ðƒ¯­‹ÚnÓ:†&¬“fF±äfeþ†8¶×LâFb *ðÏÃxØdMüZ–K¯rÍbXÚaf–±©žEˆÑG,¯ÊQèsüBn6OZrö¦m±Ú»³ÐÜ wN“Á¼»spg`gbBSVjÖx°Ó²nrY$Ôì‚uš`¾êÛƒBÈŬg® Ù9xç"ˆ¡±—6qAãZqåK•’"د°U'¶°ÿ‰½R˜v>’åeO$ÓVØ[óGŠÌ(´²4|œAD(̨)dv™^ŒÖfJðý¢:éLßleº‹¼ Ù C!„‚ ¡óM¶·G›Çú„m/VÇB¶c/º2«6ºÉ|êàQ¡¨ O0¿M¸›_×MÔ™8Œ¿õ FšNuŒTUÕç—›¤Ý 5ga:ÇÈc–éò‰WJ•ª¸JB ‚Ø8pñ>4“';¡Çvµ2ò"ô­®·2\t²ò#áL™.˜”íY¯qS¾Fƒ}K Rª•A(j:¦álŸØdj’–3 ‘‘ù 1×4ðs'“ hö”˦V&«¥Û*«@“}'":Š dJ…¹lMV®zc©E§nj‚T:Ow¢tù?ÝmZ9Qœ®€(`ßÛN¬xbÿ’Ëœ¡å…Ç´pT‰A[ô¢Ø½ß$+áM˜¥õ래úf…ù0-é9ŸÅhQçV+“ù,£Ê|·¥$b€Ê“ Ží<—_7Ðrl›°ÿ»¥Y'&plX5Ú——bÁ䴌”†L˜N®$K±¬ßzY"$Øùʉ²”U"6œ¡OQÁIµ <"©/ú¼SV“´2pkVv +‘âÇ bÂ’ìN–'|wœáj‰Š)y(,Z¥'î$-ý£Z'ËgcµçRhõWS°—ahý¢|Gàò<Žök[ÛÒ}\Ïñpq ©7”39gªW„Ÿ\ƒô›‰‚éöêóQÉ-¶_`Þœãè;=wÅü\¼ÄKÑ8Vzþ•ÙÅ{¹eo%§»‚Y“ôý%7^µ‰…„ò©“‰:ÉÇ»»$Ê…˜ö¯F‡Ê+&?g`´=úU·—dú[£iâ2ÇÊ\hŠ¿Wîî—,Œh€udI•TI¬ÇtKþöΞßLHÎ’gN©!Úζ›±‚ÊcÚ¬pSy·w(Êá™Ejµ`2¦Ü)>Je‘’Yk‹>Œ;K뛸8“•Åè­Ûÿ_8=¦¡€ t§ 9^V“bmšÓñ&©ÉH¤÷ ¤2pxïEù¢³30䞢e\‡£ÚBC𻩥2‰bÌŒàÐ*~̳Ìä(•á9¯C6fL©BíNz£0£rjã݃0™þŸUfá8!¾}~¹›¬Î$ÌX¢CŒK0à5|Ž,ÛÁü3Ú†å¦j7ã@¨Ûäx¾?‘ÅnŸ¶ÊZ Ìý—£vñøÁU+Ï Þ¨ó æýU.'äeìCˆæ ¼ÈÜ0w!º‚Ê® ±ä2ŠSÜFuåXÒ]UÝyä­ âœÇ”u%Âö*Áº0eRÓ¸ä‰éBY ¢ÓŸuV"Ã’ta×Ýù4eDn>‡¨ÞÕVÇÚJ)d ÂÚþ ì Ñ…õE±>¥xàA¿‚ ð &È<Üæ:œè€w å–œ…ñ]^„!šG/ª‚’U>™õ2 Ô£ÌhéN„©fNóSÊpኃÕ–•š³(ÍÇ&œ€ÁKÐðôëò3ñQn{‡aÂL€ ¢…9”c2Žx Å×Ü‚bzž{vp¬CÍ8UdoŸd_©¶Xꤱ±4âþõ$5pM Í1ŽÉ/ ÿvµ\]?$ vß WÂÅËêè®(gqÁPìÀ~É… }Ô±3‡ˆ?¼s3G¡B£—+w~O•dGì½H*´‘¿§ƒÍ$”"b}ª@‘ðD‹©v¡nšs6‡ê½Hî ú '½ 1fY/È‚j2øÂªžK¨£0R]Uÿ_Ñ|—]B’ëHÊÌT å”°©Ú¨€¥I[U>¢še†ËtIVÿ±Á¿•ç‘óC†ô=:E@«ÉØ/g3¢jëïB;AìO<1@f²àqj³nˆB! 2ŠŽîœ‘Å9å²°^ȪIß´yð)ê>‰€¦…9 ÃÛ‰rƒÜ¿.®;+,cRÓ¢^Q~S¨HøÑùF&nXT¤Ê—QÑ_²1P{+7ÍŠˆä@Å‚6;EWI%C¨ ü­mÊÔÐç•ãí¾Sc–~N4Àü–4áÊŽI °^ƒóáÒ„L5J§îF ¡7M°ÌÖÀ1b¤ÓÆå˜]ºv~©Ef*ÈŸÅÙƒ{½OL¶4*](ÈÁ¢»+ §±ëÇò«ÜKø¸àÕ‡ÐÛSWí‘s'I^äL €Hì uçöÓÈÌ»»âàéðf *¥Õ[^ÙÕl¨[ùä^­dЇ‹XÝMâCZa( ̤›<ªÕ€êx¡µÖoRQŠRp¬ò …F4âëÅi㤒Qo å¾IÁJ3sô“#WR²,·¯v#­;*±iÅ^AYhŨ•[…íÀ¿U^¹Xê²xpffË5èÔ¡5“P‹ÍA3wR¼ÅGº‡›&~<åŽîþ>¨Ôä9Dãò8&‹îê¨ÊàR`R5Z3öSª· l^Ü]±A iX/ù·<žŒC3僩È0ó.OS© Cn߽ͬÄD½&ìÌEoàè%Û÷ø–JÌæ*i.Ü*׳IT‹Kö·«¥2]EºÖ!( A17E à*u©è xbS778éJ=h¯DÈÇ^9*eFêÇà¯ÚT,f r¡C¢¨NlOÚ6LÎc9•ßùQÜ2»´Th±ÿžà{ì¢OÃà}Vë¸Ê½,¨%¥f ø£°±±ø-TÞC›3 ¾Xƒ#ìÉ»eH )cz H/­ÑôÅš’›M‹ÐN*ª û?AÈZ“1)\*Р‡ªØXõåŽÏãìGŒö=ÕAëÕGR ŸƒóäbúzPU!ˆÉÊE¯ôê?ÄóìàB¨§%Éì½E‡ŒK:*ð¤¡^‡³5 ¢p{2™ÞÆž?Ðr|„u/ÍýKfŸšS÷)ñ³±åTj‘ÅnVÊß*v@3eû”Seû… ¿‚?5Íò~5gÖ€\Ž£°ê[–R­BÝ‚†eUázò;د E ÈLøûÈ5Ñ59»H+ã”y# ‚¬¬ZOEöù²ƒIÍju3ÑÝ_K…i™Š¯‰Ñ{“>9‘T~ÿݦÿ"¯Ùš&l}À¯Lè÷eí6nÌÊ »M¸ã‘Ô°BŽ'Öƒ€ÏÃsSôC¢³&N1 ÷Ô¬BÕ”U¡$´E–öfƒ€¦}¢É,²¤V?$AIcvù­®îì¹&ìÈóÊ¿ì*Ö²:Ì­mA<$¥æˆÊ¦ID¢ÍšóŸ胡["v”ž½¤þ3 ‰ÖEÛ$²™uåýûc•%Y©Ýê¸tû.òË4á¤ù!ÿî VCžÅ8w@næ"‹Ë+Õ"yRÆÜÄWÃx°¡uŸÿoØÈÑçun`Œ¸ìÝ\„xÚ]zävbÝ?—’£‚hcÅÈûM "¿p GÈÏ"Á#Õ¸1Ái%ö™í|XöÚOÜhc ŸàÈ?3,¼sØ¢4©Â /iÝJ°ëÀY•šUæœù(Œ;uIL¹p_¯@Í×É›¨œùD(¹b¬8FKR¢ÑIÒf¥ØRÎä̪Y‰`¼k³Rƒ@Y6*Ü]h€%Âl–äƒa…'ük±Pv[ìOÂú‰j¬±ŽìiYwcJ¿â’ÎVr3eÇD謰F.«ÑÈVñß/³ŸµíÓëÞïüÜÒãÞl] ·bÌA¯iý´îVtõ/jímô7¾²¿ì·¦›«(êšÆM'æ¾¥-WçàÔK"°»´]ÐÍ^p­úËï¾ß^¶ 8ø^šz“O?pdjÚ.§«m 3®~>›-By6ÅÔ®Ïé§;y5ÊäË¢xÖRY3^›Ó:ÿYëX;++#ªõ‚ØýBxñäú$ %ÏÓ V1…KŒ•X£hؾ…Y‡tn¿í†èñ&.|FnŸ¹C:x×%¦’8ÃåÊÆYb1eäË Wo UW'KÛÙùÓuÉ®-ê%mGz”s´Ì%%lC•” ÐeûÓ]pýÀišÇ9šý7·¥äKqjÖÇÉÎÜ_ŽŒí‘E/|Œ;^éitµñ…&v¬U*<8ðb©½˜Ó€±ßé³Å؈£EbªÜs)cšÛ#+#½&ï—’ýÏמ!.Kv1ôB‚VgÉ!YÀ…$¹oûÿ¹ÚúOJJ;kk;ß[Ô²‹ôÄÅÇÆÈÂÒpqžíA óÌZRš°J,ĪÃ5ö^F5½fÞÚÆ-QëZz1óüâ¶¶F~™­¶“©c2]¥‘|Œ¦‘ <4rAu§ÖÅn]'?QÝ\rðã·=7Öå¢àh™a)LLÿõø8J†>ElŒ<|MFõÈçÅÆB*âH o¬7(öÎÉÀzbÑj©[)ΖZ Ì~±É¬Íd«–Ù†Ñ^†’¢I(•ºœÌŽÊ#Rª#ðÝ´ˆ²½Z¨dUµx¾Íµ’Ðá<™Ù9R—RÄaDÐf øßZİ¢êÃ<ªµ*€‰?>­O£X£ú×°·‚×3}î +qi ™¦.äÕtüöüèã VÇVÊðêÐêF¤ùåfOªs¨âjÚ&±“‘Ãþ^™›YµÛ¾=ñ²›€id"ÊÓ¡6$¯È¨ró½—­ê{ìmcË­¹ªhZ ­Ÿ³ŒŒ|ö[xlQÂÕ¯ŽÎV#?!j1cîsKÛ‡ÕmÌvF^%q7>¢ûÖg•ÆÓ°·2áêo¥¼gGG¦™“|ôÍù¥©©U-YPLÓ…íÈ¥µ 7<³¹oˆAbV3 ôn“ë$ˆó¸ªU1D0FSó[¦N0B 7ƒ©°,=?ÉØužaìë© ¯êÆÇ†¥]q †l][L¢¶U&W³O;*mwÇȃ¶6U°â™ˆÌÍ—¨ÏÓýÝéÞ¡XkºbfíöÔ#‡§îÍ,®¡ jn#jÇñò±Œ°ejâ]/lL”L¿,ŠÐcFi·¬ñµ ‡-—‰ˆµ›N”&r­6b%å¯sa9cÐB‹ßÇÇž&ô×ñô­©ƒ–×ÇËÉxtÍÅuDzQ‹HÑ yCVWé&øýT–X³Êã˜j©M åÒH»Y}jDmW$3Ž>Ÿ œ&ÍÛ(Ϊ§Ñþ4};^¤™*½C¨<±tÑ)DúH2ºêŽ˜Q0H€,¯4 F™½Y(`j9‘ÅÀÂÿ]·ôd^ÜÓÏIc`hx3„&‹0“©y£äuá“&ŒHq8õ³­Ò¶ìq1§(½qT¢÷ñE’ã†^縑ÂzöV <Ø{b÷†v¹¥GMLd☳ÈQv,Æ’>0Âkâ@A/Y©ˆn÷1÷)¶}ÚôÔ¯jÛã[óâì±6,Ù÷&süýB* 14]5Êdfä•&ë4ÅÇäÖ…1|,Gæ›õó'—Á‹vwrìCDÆ:kfmmRÚßRg=W*n½Õpz'GÆ›'YqÀŒeïHª m!,9PfÈžSBÙä:«±«ŸxŸvûCìÿlå +LÜ^¹nÌ Ócmz¡ÉÆÒñÖtÝ»†+B%¥ãÖöo\c«äÅ%2¸É“yòê‡ÜϨ;—vë[£vkyúö÷ܧ#?]Ö3í_öL‹ñ8$œÍ11!:â®.'\\I˜¤‹_ÿW=5õ'Õ«ë[ÿW×suó¼r¯}cS½¤ô•2)OÇÂÄC7ÇÂÓ´é™baàLÇ—ã#ò³¬ªÞ¾“ë~Ÿz¡áoDæ–CÎ:ƒÏ)Ö¶5²ÊT’®E{Ö¥…YÕñߤ€)ÉöNé3´‡¨H™9!$nÓ1rÈ”í*D ÚÌ“²†`¨8º3¡{S'Ùý:ÆHçë¹±ÇRpºÂ;i¦.;0Þ,h_‡rf”lV _Õá«âÂzŽ»—œØ³ÉüuÈK42LÍy¥–³F0–9¨= *ª„+VÖÅÞž¡î #K–­©j6ÈxéAóéEÍ”©hOØÂå²^¶•JÊæNÔ¶,èl/¨ÞŒèšWú}õµ‘¬í}chÇkî}3Omd1޳ ÊÈJ4ÊG‚³¤«:«Á²ý®}·îTw.ƒég¡óÝz†Vµ¾´Mÿ*ú®¦ì\,5¢fÚmàÅ-“›Šåü+Õð“ªÒ˜/§ôxznf,rb`Å´ôUVxaguAÙÈ H¬WÇ}€>·ÕópYÌÊ–ÆI*i¦ÐÄ;+/wŨ‚undðíí¸Þ÷#öq÷AèΛ§ïýç¹³c«i2ɶ½;fj–c›XY–^W„Ö†µ»ÆÀp«øõ ëöŸ÷o\ Ý¡m_V%ÿRi‰§ÓûoUµ§;èÔ²e †1#6·€ž5rru (A{BQo®é÷W¦7pl$ÚÛ¸ak˜ÛI¶²i›ƒhª8Y•nÒ$W ,gÇNËý¹<Ÿúö³´=:õÃÔ½± èØ›Êy™[kVšqâY³ñ?³AÕÛöH”²,ªó±’4’ú‡Zè-ƒ“Ó:ŽX Èa³xª•6€išL›;ñí<ªG:VùÎ’ÓŠãÇäV¤–~ÇŠÉQÕ•ÙZËã Ç›E Îô——“Q7TT&3dPS£¹tá=ž„íC_ü--5 säÐglîüTQðì`U)N¹ §‰‘Èìèäõcjö^¥•š±Va?=VŠYÇ-O!tþÝY)>ˆ>=¬œð[œfd”%’I"ƒWÞì‚Å~Wšñ6­â‡¨s1Vl0³^> Ó5#U!†;-k~´ãÑå¢,™ >“áØ²ÙÔ‘Ñœ9'‰ÈTû€Îý[üÍ NNn¡@˜˜xí–ÖÉrœÕZ…Ùˆ?ÇuoŠ'r=ŠÛöÍ·Û77‰)Þ‘ ÍFCÔcvF©¸§Ë¢Ë™ö`¯îGŸågÕíÁ±½ Àô×fe«×½E¶F‘[ãÕÅ—Gǃ&r_ÝŽŽ• C2oH¥$ƒš3¤C,‚8¢AÞžNÚûc¶@ÎÍË*¥å`¯üI““ý×Üê~õÆè=Á›)׸å‡èÇm4Ò)ޏé,€¥‰`h}c?ßçùAÚ¸zþµéϤwÇÖ³6þEt¬ÍÄéÛAÅÔåYX%TÓTœDjפ8Ç$„ZöòÇzï߸¸=kIÓ#­n ¼mSt¦› :Y6³®ÑÛGr± Ár³牦-29Öá®ÃVÇÏAYÆùCXМë<ªÚ´ZÉ’*S£:µ}±ÓºlQÁ¹ýA¡ú‰32U\q»«:V†–FJrYØ6rº¿QÀ{ÓQ¾¿|ÍZÍįXãc*´Ì±1±C$åÏeèÔd~,mÀzžïr–ÿ½ZÚGÜÇÛ‡v A…êk=ü ›ÌéÔ¨ª(É<|1:+r’³Fê}fNN&N5£‘ Ur¥7÷ã¶=)`ñl¢ø¹‹’I•\yøyG.ùbM$û3Šèu_gñ¤T.nyÉyˆ¬–Û§#ti±5¬ ’ÂqÝ䓟CE³G±vŒØHè9¸ˆ_ ê&0P‹ Íx­š° ›$¯•IóȳedÉ"ŸÔÅjJËBÔcjWí«SöŽWÍo—ù0Óð1·Ž÷Ñ3pVÓÈLÉY¤©–ׂŸõ†êð­n¬¹Q–Q—ëÿ¾X•>J†\uÀÅÉÓ¶®*ûV:~çÖ%–déG±4ñÖÒåC8| ¹6”Ú &¯T·Öçÿ‘ì,L_V¶½2KÓzí[KËf›=A–œ“~ÇÇÔçæ×ÆŠùI‹¥2#7úÅ­ïþƒIÛx‡Ï¾FàËÈcóK%N™§ad(é>“2ÃC’½Ë­Võ—6¯’‹žÛvþÓPnfYA;jjvKä÷Bh“Aˆ!€13+ãôöšÆÇ$ÕÊ#ÆPƒ±äGvX€)QL‚¼kÙ¿“«ÐIY&¯` <–rEkDfqݹD0î?²H[äêËù„¸è^îÔ—ŠÌÒT¨œg&©&NaÈf ÊJ°Y#ÖJ™!²=ò2rª½•çØ^”ñ#ÏÈéŽÑÉ…’ˆ¥gdT¡CtJ¨-õû­‡Ç¬1³2¼X÷3Œiñ9•ví5à( yqWpވ׆dˆTø’OÉ’Oˆ½¨Ýž+Ê☯4£žmHPª½3v7¶¤X#Õ‹û;Ùz®ìõßOyÉßLÅÈl̦Vçÿ<‘Y…9êË”Y³LÄ+íõц£¤>Eð4xÉÄOLULüM>nÒŠ£†˜,É’¼r²Yö`:ýfgøâØñѳ·ÄY-¼Õ‘e R¸ïx÷ìTÊŽµRÝ*'VŒßZÅ·1­¨î»cÑ—ä¬è8pÁU@ãÆ{Mzç„3TݪiÿQz¿­´±\~›Šc4tóáKmayrJó÷ ðÊ t¸b‹d}L¶¬ÊÔÖH_ dŠŸ‹'/F}Ož¤áâ«&J™(^jRjÌÆº¸^Ó?Èä'?¹Y$Ëb  QW¡èÍÑ”ò¢eƒªö'•rµ áMê€:1y…¸`£§T^Ê9wtTT!Qý™jCûŧ6²t”ÀpÔ'¿N£ÿpÀ;ù†F Èj !›¶#«K$’HVÙÁf…n@mA{£®ÀÑo±m5“uÅidxæ…ucÅ ãƒð2˜T,úõ%IJ”qÕnýzÛ¡G ý>*¼}«K&ÝX*7AÐ#ºLºX#Ô9‘â˜67U­m4ñ¥<Ô`­ÙhÂŽ’PC„¢¨ UuJtøõLJsNêUÿfÌ/YG¬ø©y“0¿%<©,ÆiíÏUí6*=˜Ébú¸ ÜpÔ54/_"æè*–4¥‚Î `QÁ° nøØ‘Uth,xŸN°£Q¾>>Ý”1D×’C–áTqØŸ-;3p®:ü+teu "À”f!Ÿ·Q¹"‹Ü“È)Áv^Ķ9í(ý²;)RYJ·25œv ì à†K„<­ÑT’¼*ržÅŠ–2ñ¨ñöìÌGeñž²¨NÍ|2ÙáNñådÁ´ ]r«p<#{Z°F¢È ,lI5À@Ý1¯UB݇¸ñVG½³ Î亨¡vç†d fø~¶>5Ê3⼺ªb’Yõ~_äÀ´¿ô*T§u—Gà© èr3|¡ƒÖHÙ{S™…(“ìÈž@…90å•«'"”hþç4uep©>þaûíÍGB¥¹›‚&_D0¡Ü¨!<­o“glËÁü[0+eÔ É@£’K Øßs|­¯Ã>i+g¬ÒŽYJu hE,(ðíò%“Ž=™JQ¿ˆ†¡¨ÊŽÔdëÕ˜_#üùb>C¥¿_ ªH!JÍÏÓ~~«Ä»ªãr}Û¿³ƒÿˆõ C'½ÈuìôùBu U'0І&}ªÈ¿Êæª 2ö¯Un8 ØØ›áuÊN¡h~ìk‘jò)˜ `Àüqâ¨U«nl ÙGšjçj&‡©õx»=ZŽ•(Bªry<ØÅUÐÓÝœ@ €AŠêY QBÍ˲ªã-N[·‹š£†ªüÖ«É% Bbã/;.ÂxØÕɪ³膂<¹ d³+Áv œ)çØ—¶=(Ý’£ò 1aT!â²à– ‘f`Y§ãWV^ž`îÔú5xØHdÈÉX;aÜjbÑèIL|ª…-<¾Ñê„’k®¨\•‚±ûIðØÀPÝS`~Ö9|øiE¤áAV”Ú©çe4Šòª çÔ‘ä£2—GÁo—°_¨ž¼©U‚¿™^!eN½ÚhÊ€å{uÆd÷u꽃9ê:Êc3J‘ïñ¿Ù•lÌÌ¥|X/÷~xN“ Tm®ë *ɸ>)©™)*É—„ÿÆü¹wK‡’$~>;»)ÿ‹´<Ÿà­­^7åD±ºvI4qâ̤È˶§z*Cø‚ÁÚ€8 ÖÚ÷^Lk'™hÄÞy&“ñ™+7yž³>ç¼Q Ô¿%Зw!,Ú fú“Kõ©5í-i'f¸È‘MáÝÈ@³«K¯=EOÝúÃâa@Œz—Ukôb“ã`ý”uýk"óVzUO õö]«[+\¬²Ãv¡gi9¨«HÐ ~eâPP¨ªŠqÑGH ’õødÿ鬿[Ñ¡_€l,+ŽçÔý-áþàB›4„Í•Ô  T,§Æ¹> [Ð×¥ê|`CPÍT{ç iP/¼À^Àôñƒ>=¹-É6_"´„qä Øäu²ðWä@v+UÿJ«Æ$‡PïÄ[ÙÇIS–R‡³Y_¿ë ‡„ðmœ¢¿°ëRMúª1`ËÙ]Ý9O=»§teÌ]J2®»…^=H TPNÖ(òÈhQäÚéSÜ,~¶QÀò:ݼ©ä+YâÏ<~8ëUÅ# !ýæ<)ÇfäɺöŸÈ{¯`½K͹`{v"v뛿pøApòƒƒÜb=$CÁ°R&Ýþ]UŸª±T£¸à€P 0Ô{~Àä*)£O«t£¬Û“ü+vUnH½Ç §b™Ë÷Õ°³ÍœøO@?±ƒt K€8WbËÚ}J*¡ú›¥ÈbÈMœ¹ öÐe«vÓ|‹®Oà1e³¦~½¯Eùãä’M‚ö°Ï^I¶íÌŸEMäîÌ‹F(hZoÿæQ›°{p´t£?‘;}vî/ŠHº¡ë`…“@eÐð}šf«v£ðëFìVlT7¹A}ë’ök ³€T–*ØÉ^®ïFV( $•øŠ ÷ ™sj¹#ª÷ R’\„ZÔ!™¢3)X³±ë.ÄZ¿%ÌÏDg¹8x¦Á¼tð?¥þu¢ »GþËV×þÄ£¥omÝ÷Ÿ£j¿•¦cjùz~«|kêÃ7+Pü±ª.C+fbäÌå\ex: J•oEqçâÔEuC½-›ìÝfé>‡¸tzéڀȶ·q„ñcù:þ¦!Ä<°ÇÈóœC5ÈÅ帗5ÃÕ߸ݑµqµ]c`íí?Eº¥±0·6©§6««jù6o>¤äʪ¬ »GŌ՛5Ñ ›ËÂõwêÚ‡¨^¦ÿÕsF•µG×5÷Ôã¨jx9µÓEÒNiY¤,hÆÆ1²LY»V‰NûgMèÝWÝ8Ù/4¹880<-Œ3‡&TZ´pý6<’&LQ:$šË“ŠvJ0FwgçÞ»‘…&$lȼ#–^ìŠ8•²#®ßÓ˱‰X¦ÊÈfuFXÊ_­«û¦ÿ3[ÃЭ©“è—Ù·ý8uÜm+ÔO]u¼5Ôç”Óå,Œ ©›¯ tÔ1±²bâf+ðs|¬uÏ5\™óÙ²í®}Ón?P6÷ª×Tõ7Õ c_Ð7–ãϾ­­ë[¯O¡Á]Bü»OQÁÊ| lZÐ,“F ¥@wÖ-á•¿÷žt ØÚfT 8«ÅØkIªš` Ë9=Ü"vʬ²”b¶S7ìÄݧöû»ï¾[Eò1u=­¡iZŽ£f|EÅÖaÛ#53x/‹ãÔ—.p¼Ä:ãô q›6‹ìOaôOk)—§¤¹ùQk“Ÿ’Ï‘˜êä³c¥ÈF'N%_ý, mf~ôÊe9ÞjÆ[6X›éò2ÿÔdd1 ß–&ˆE6TÂ5“)ƒ>¾Z„ˆvàŽe£&ÉôcÒ?HwöÞÖ¶Ÿ©^®zÀš¿â`íiéckíÔÌÅ3í—•—S—›—âÊdT¼Ò¸U¤Á,Ø€ŸÜÿª{„ú‰›µvž>Øm.7ÓwCèsÈž>Ná¦E¿/S±…²ñt²ã”P¿“-Qœ¶6ZtÓÝ[î?b_ch£m˜o/Vò6Þ.Ÿ¼t}'/R×1õö¬’ÓçC76òhÕ›cW¹gô2Žx}àú‡§Ïté›[nè>V™••¬¼ô—«j·Ôs±^9©Yñ‘lóÌl©aâ»ðBÝŸ«4h_òŒ‘4sË~!a†ãvc²„¦êº±î–¤ÕÛìNÈÌŸ(.F4‘‰®WÉîã1Sbh¿Û´ìc§Y?UšfÝ×·¥ZetµèšŒÜ}Stë~¥ÈÙ3ŽV.6¡¡Ïkâè}«bc?R¤›&I4S’¦–fñ‹½*פž´hûUzWRÙ;‡Z:Sdccá¶ á2ÏŠ’ª¦V=c‘[ãæ[1²!‘Á¼é:é.6åÔý>ÈÐ00rós6ŒõÝͧäMíYi—ÍÄÓŽ¥§ãeż'+¬0픥¿])”‘hYéz}&Ñp¾â§©ïN_ozͤíœ]§½ô½^ŸlL»ãµu½8É…hµL “Ž µðç•Lzd#dË!íb¨}‹k¿mP+<Ò4BË»Fx׿ž\°nLJcBåL‹ã%$‘ΧdJìÙ˜/br›éª7æËèúßÙ­÷E®Û.šÞ‡¸4#IÛZ|$NUð±ò6¶ÚÖq°ñÚ‹‘\ܹájè±óf©£0¹o¬ˆûˆô‹Ó<ÖµLVÛx{ŸsçO6üžGU×4¬Mj«¬n]g’üÜ|†ÒÓ0àë¹ù‚Ê2t×jú·Mƒ­ôãpSOß×Úz£—«ÇBÓcŸŸ›–ùXúV¡iìNI‡'X&.¥Ñä™n²3È“Pï¼YßOõ7FÏõHÕð=]Ö6Ž›ªj&‘¸ ñ6f5òR{JÊLèjº6môŒ<ìÜãÀfãÛ!c|ºRbú×l©”‚Ikfª„3"‡ív„‚W÷ [¨QH\uS£I<=Q±Œ±*æG¦F”<¹bâãbD1ã+B,YY ¬ª2£€.ùHéD,úu+j¹F«Šs…=¥‘‰ù—.ìœIº-“F¥|¶ž-(² e”»¤›;&“–Eóbúlï™Õo8¹=ücCAm5&̈¿&ö¢¨ä³+å@äÞ“rK¥o`˜ØôùîËãðB3‘=ÞaåCBXu_}<¦Dò1ÈŸ’LŒsÞ]Yb÷jMÖµñ8’R Ì‹Fê“Y­ Ñ-Á.ȈH£àmøcÅÑ`Ñÿˆõ¥#ä!‚¨øÔVZ§k òà?ƒâhøY q±š™q¬¡Õjf¤* _Á‹EȃäF¶ÍSUÆa“Z\IïíÇÒ}Å뿬»Sch¡žEÐêÚƒwtÑt87;;ÊÔU›J-Ia÷ c{É–ë’£%aûQ¼dƒe0ee¬:Ÿ„uyˆø›Ç>í%ŽK+%c=³û/ô„ýºz =Ç•§Ñý[õòƒ£bOþf³,͈´›jÊ™«Z®3ÍAjee¥Wm5ÿsu¦öÇF—(lz–sœ>“ ’L©5-9[®Þ,`ÊìªkçÔ'ûƒ©càBUã4™nKvbˆ"‰,‰R6%H‚ëD°'M>Ô=6Ù;§Ô–ÜY:f;z'öσ¦ìÍ1q#8î]ß´:›#õkäj¹ñZµ;xc†2ÔKÛëSvÚ¦±­ëÞ\虚þ}³rÃ(¦ùQ ¼? ŠYeVUDI©*ô3ѬM™éÆÑÚ8xã7OuÖ7Sºù¡¹2ñÄòãPª¥ÊqÀœˆ£Ï*yÊÍÀ÷4ú÷뇧f¾k«o«&F¡“GÓö–Úļ¿ØîÍÓ‘¦Ÿ¡i‰ÑÜ 6=ró²O+ƒ…<Œ¼Ž“F Ì™3KŸ’¢S$©ŽÝ¤M{“fd»þ³…Vc,²Î_ì ¬1±EîŸ.EG–l燣tœHhÂ…‘`T ¨[6a'PÈ™€$Ú6| ÛTÞšÿ| •´'ÑËÖsfÞêž9Ùð´ =Olüú¢wc'¨+‹XÛÏÕ kRß»ûU}wtë¶KS*ü~6ä…ÆÒ4œrî4ì •\hÊhß±Þ‡½Þµ.íßßp›ÿPõ—ÕÔÕw&±’•ÆÓ¢Õm?oéã—ÂÐtlVdž6›¦FŒˆ;y2k¶M‰º[pÆÂ/¢¡œÕf¥i+–êo—äÌ–3.F4q×"©:þ¯Ø]X¯± TUnÜÝdŒ¡×·貞ÌaŒ3o>8ÅR—¹^ sÓ³LνœŽëÒ¥àë9mBóÏSv¤tÆÌìÆu`Äv”´©UGed5 ¹º×!ö·WÂ#©E”ê f…¥g:ŽZD1±tqâKmh¥èÇ }çÛÔédmì½pèZí­7YÍÔÊáa œmJ«‡“›Ž5:½%KãÈ®2Æ®´f 5*Ƹú¯éæÍÉÒc—ºr­ mDkÑg;QU©ÎVašdRÑü— 9(¡²UybzNÁÒ4IâbÁq{˜,ˆÅÇǘJ {þ¤è³ñweZ«3(á™á;ÓNÑ´<Ì©Æ#PÏQnƒ6­ä|‰Û¬¼k Gõ%ùnŃ0‹%ðÝ){¹RÓ̱͗#Ղ˪„ÀP|X›¥ßnccôn ¿Øšl8¥š˜kxÓÕª<ÝøæpËú›dE¬Šž Cæ…Ûý¶¤rp§áyצE]?±˜yѨÉE­ÕxT%Jœ‡ÀG™žíŠMu]B•ý•ürþ?"ÛŽÔ¯}lÍ7jêN4¨2é\x·å*QkR ÈÖ®ÌMXÓÊÄ’Rj@ü„ýN5Ï7Òý'KË­Ô\66,[¥(ªØ©åT>>Muá]™#.XM‘ýÅh8¸Θߥ§,]IcC:LÔÃÂ\\csFj7U~$ÜÑB-&†ÿFý¿Ö@ÉÄÄÂXñdîLÝÇi$žYcÝ‘ÀcN‹¥ÃÀôWªtNÔngÕN&2Cp Š£Hã"C±òCNÅŘö£d[€0sWQ+†Ô°±QüxõD–EyTaù– ˆëJvU§f£0˜ºþŒ^š_ÝGÛ^5qñi”Ø,M™¨_RÈñ'ª†!˜S…­dåÍŠ+?Õ'ÚúPl†“©.º¾£–çºwÅZInª¥”šRI§sÕÙ¨SiZKµXcýÊ}¿Þ¹Ml…Ö6J\±Rï¹#L¹ªÚi\Š7æc½©Ë³XÝ‘J²¯ÖÎ]f3DÄRt¾«à8Ûý%“Í„°oðA:µœ"l_§‘èò $Û.WÅY ° CZPOΪì“m¾ßô»Ô?ÅSþ›FÑ5{òI’U4üìkÓ¬ÝRLq°º2º´ÜU<ÁT·“ý¸Ž£]&Ç"¸ÒÐôl3?,²©‚1ó_++ÁRÈÙ¹-œë&&žj­(­u£ôþBôêåý°œÖ°ô½‡®JÔ¬*ãj1Ùšn [aß4ªÓâ‰ÃŠ„åÛ˜TrWPÜ{f%3²³¶ŽØµ¨¬É—Y×Lm*5U[=j_1&ÁâÑsÓ'¹ºo´ÝNÃÜc´ÈÀÀb>|YK”v«Ý‰öõ_Q±Ø.)³bO¢äî¤^W ¬€UU•,ØÇ½²4üsfµr2„oÝHûX.=€ðxæI~ÉRð^©_!iΛ·±÷^ñÐöãçfO'7NÎ|G+&s­Áyã`Ý𕵠eg1ËÄL«ã‰y¡¦BC¶Þn6>±ME0Ã7ÅÅh™RvN¼©¥]]•8F·¹eWSgÚÎÝÈÞÞ¸hl|ôÇÇ˶k(Z¿Š=Õ–*ÊÜI*·Éqè‰4bÎ 2fã.v ,S0’ÈF[¯Ð yÔ ¢C*Å0î¶Ä€/^Ù§¯%¥o%°@$’‡áw‡íëfOÓŸJ´}(ÂÉOÇÆecCÞˆ’“0F«9¯‰DÛÆU/ñ!®§uaƒMB£öQüaÞŠ¯@Aª¡äŽóX‘¥Û ìߟ@vÕƟ¥Ã±áq1ºWŠs0éÙ‹¿VÀvR®Ë.Í9òÂÑé²l/ƪV*z2+†ê¬z uäyYÀ dò:‚‡3ûƒ6L‡Ÿ#ƒ&\ÎÇ…*Rõ¶»à±"Ke^o–$ƒì‹1¤ì…”l(jHª@üÁôw :P·ò*¢?þY?’±V#°àŽìVz5¼nÀ ¹jÓ§pݦÀõ÷†3à#• Õʰ?h²ÿ©êjEEiÑ”¹E›¨™^´uèUœEá„Ϫrx-I íOüœá‰!‚Óª1˜*Üw°$riÖ¿K1¤šÔì6ç`X§ñB©Þ©ãè>"ø­~~*Á¾H5òGàýbÓƒ$¿*ÂÌe¨ø‡ ­Êy&Í0è\"½XÿíâWÝO+"ø/‰ùÉáséEXÅò»„‘eþ‰J¹~‡öžfŒ”eî[‹L7ŽÕ¦IÙY~¹ò2´oùcÖ½“¿Ä¿U—ÈÒJ3Áÿ·(Œ;u>4÷ †¡nzŽHn(Ëõ`€Z@vø`C(WPYBA~eáIú„þžBç¹òW%@+ aÀ>'A~Z5ŠÓ¾>B2*-Ô€ZŒÅP’Žïò<³ƒGSÇ3w <ƒ¨é¿*Í0ìµ£ >2QºÍÇrT?Í”tR ù»;ž‚8JÙSB½–ŒÁ‡κ0Ø+8§‰;ù —g,¹9n¥ë2(MAýžî'ÂÈ….îsÔëËõ Ò bÞ@O!M›ü©¶½‚Ylãa¶ô’éåv „ð*ˆ_Š[ùâÆ¢ïä|æjN Jù9Ê#쨤"©T;§Ä”Ñkʳ‘Ë0¤_7X^–u‹&_ R;µQOrh…‘Ÿ»±P\üW©›ï.áþáNläO³L#§ûOÑ}{sÝ_> ‡Ïþ5 çv P7P•(Šˆytjön,ÿ£¿o0€–¡¬­«™DYÜû%:¯‘d:Ï¢³( ¿òQ‰R{Ûí?iiš$'*(N/HB¼ìÄ^:x#â@q{ÿ¦<˜ý'GŸ€ù•Ük°„©檘8àô lµ ¢\œEuP¤°üòª&èÔ$øÅ`¥P3;̩žÉÿ%ZŽx"¸éU<šÅÙiiþÊn­¹ÃÎrAf1o: 4 îݨók’Éäñª$ºð³qÑL>æÆû_¨’ > Bþ|_À-døâßBÈyúÄ R¢¼€–ÜZ€ÄOÈbB…,}toé4Õq Œ…$ˆÆŽ¬:t5^?VF<ãæ³Qú‡d³øLÇ?TíÙŒ‰« RÅX„<ñЩîH~*×¥TxÃoFG 4îr]UOnTþç&ƒ¢:¢·=ˆUú²Ø™È"*áK2¡ OØP=˜³ƒÃÁ¸pª4nLê‘H“8k!ÔX7@-¸t%AƒrQ£Cúé?ZÌKH¤ðËòû•ü"…‹²(kæC©žpoFbˆÈ³•@æaAä7 ÊÅG”žÊ³¥G9×÷\éyÍÛÄ%CJ€ä3",ÛäÄvfpàìõU¿š†k¾=KƒÉŠáÈeŠ#¤{vì*–èT{HåA&€úù0ú~¨®à»%Õ»·3Š©••øZ%’¡˜qÄXSãJ"ÍÊɸ…¢ Èv5k㸵­TϳýD…Š9-Ž¡EVÃÈ 6x4¾6yÂ]Õ~ûÃ)Ê]ÑrHˆ õ@Õ!G ȼ<›â@€ˆŠ\©cÈÁÕ5¼‰âiò«dQä‘KžÁ•‚¿„y«Òe„gX*p§Ù@pîè°¦úÉnÑw‹*L^ŒcLÀ”ÙUjçËÙÕiÙŒÅ)ÚAææMªùZjc=a\%È“Së2˜Ù +†l|€Ááá±[«ÃÏ7~µJxÀaÒïx¸ÒÉ \º5,ó’Ô!'æéÞƒiP ­àî½GDÐÓS͸͎<êÀ{œ³ïÏþª9ûgdh›sM]Cxfå/LŽsS%Ó"‚+“ùr><œÇz |PÝE :Yÿúm#uLÜœl—‡† ˆÈz„Xì0cæ7–L¾©swJ•S"ÄH j£áfèÇÓÿL4jáìê>à×h³9{¦ºR¶¢…8Ýeƒ`6_ã¹´aæ³+Oê÷z_êF›¬ý¸éš®Ê¶f‘®æmÝù”õS@Ë-ugÊšÚ’üœ©eÖ˜øŽ“é9R­4âLX±Æ—]ÜmVF1“ªl|е ¥`¤$6¡d E{¬fÌðÄ{Z òS1#ªä’U œŒˆcc ¼öËŽZ8w¬úæÑû}ÇÒ·†«‘¹}UÖ4Í_HÖ1䙸Y­Åõ[õ…¿:)¥IÆ-S×+ÝŽ5nç×wåÔ÷6±¨K;]Õs71ײO{Ìô_3øñˆ˜q>hí4’9jÛÈâÐz“‹m{ÏÓkâääëszåj4ÍÔß»\iøtÒ´kJ/zäÇ6Y핪äÖ\³.X‘ÇHå¥k®>šZž¨ifJ@dK†3+Ÿ <êÞËz× Bü—?³ÀŽÔ[ÏÊ›¼C’ mÙ*»ZZ„R«÷0 Üi•˜÷LĹ#´Ò2±î²(2ªÑAuHÑ…[Ec·‹1о‹úѺ=/ÜS¶›S- ×ý¶›YKR†F>\ªù èóž='fP”fU Jc¯‰MæÛÛ“ÐÌœ¬]Gxyý?Õõ­rY»[sé¶ËÕ´½XŒØ~ÖFµfÁÏÒ1ò±FZê3Ž^+‹b¤*ÒÆ áa{|^µ“ $F©!e*;¨0Ѧé´nê)šÕÐ2µ•Z£ÒO™xÎû;´]éˆJ–,GvµcrVNájí€ 4Sxýôí_B·V©µ¶¿¦»_ÔoVa̱ýeÔðç¡Ùó#käéWm##_/L6JâåÃýP¡x7ƒÌmJLmöÿ¡ú—éFŸëFöÎ}OÔÏjk;ïVײ-“l^ö¶nt©ÙU±¡Ñc‰‹ J8Ж<–}$^¹ êMtí׿tÍ Šáh{‡NÕó³%Š_&YM&– ¢hÖ²ê3¬¦:¹-YðÒgï>€=*ÜûOozo²÷ЈÚÛÛuiñÕ5kbXéÓ|ü 9tÓ—`¡ã©eÆ-’¯nÓÄÈțĦ@2Îýßî>­‘ÒúVO~U•áÉÊê7=Œ|p§&ìÚ,m¬JâRQ‰,€0ôjatÜÎ¥“ •’%Ž4c¬Óå"â™×8X•‰)‹Å G‰§ôÑHb0K{ãiú6òÜúaÍŽd?ë0²ÔÌxZFqåðÑcÑ®T$…ÊâS•!ê :ã;²ZŠËÑ–ñDrŽÔ…2B‘VC9¥ÿT¥(¼w¼ßä7íËÔOF}XÕ7nž3¶^îÍ®v¶!:cèÆžHËD¦L¥’4×ÂÀüi@I!{/™Å@eÍÿö™ö–\q—½2ꟶe‚¼d–"l( ¸¡k¼Á+4iQjèÿEËÇêXX9øÎ²C<Ûì¤îw.Ä‚$_²KýÀðG«æú‰áVHîÑ ¦¯Z¤dújˆR@¡°Ø0[©öuè­½|õÏlhú …v&‰Ÿ¸·¦s¦Dqqt}'þáëJJE²LütéåSg#'£ýtŸö뵟Ôÿ^-¿r±6_§øO´t©A›L‚ã´ôÝ£¦¸ñ‰£æäXêY«4,á›b¥,îs{ì÷Ózúöã¢Â‚Iê­q}gU6ÄSŸ…³°Î;`b-bØóËóø9fTÿc/‰*¥µ¯H-±ý,ÚÛ}´Ó=sW\}å¹ӿ𯫧”ÑôÖR„t=øòX÷eJÖÕu˜\ßžä®u¬¬Œ6 ‡ÒN“Ó¦¼“%eç‹!?ÝBŠùÁ$JYeÀì=ŸíYòr¦g¸wÇ@|>ŸÛ ›0,»À&8’2àHøÍJ·è±M­é¾ÍÜó|ë¸:ÓÙº^§º7~¿¨dN8q†4i¨feeYº/‘©ç°IrôgNˆõª©ãcîcï7týú}ËäneLÝ+ÒÝ¥“Ÿ¡zGµ-fœp´1’ËMo/¤â¾½¸ZC;Q¨Gé âi¡ë69»?çïeuMgìoÓ-z­£èº†¯ë>§¤Š…×woäBÚ>Ì[È•¶·æÒÌÕqS%-«×^YZ^\~ßðã§îñ‡Rj13­…j(É™žYФQŠ8Ö‹B ¡î;Vj/·ý°Ý;Û“û:5L¬œiGHƘq™S:;K”X‰\]äS"d'loô¯ gûzÆPi¤p[¸žðKA$*ì<én¾¢6î¡×/M4vÂÑô²£M¿Ëù쓪ƒ“ÌŠ-XõNÿ6T4[?´ØMºs5B’“ –Œ%")ÇRyü‡‡#ÆÇ–,¬+h8| ’y‘H›ã eéw£{²Uœy —z3ú7hpu|â÷«¸EŒŒ3K«ª/+@\¸îáÈ @ÉÞg»–là‚7+­|rÄ·‰#óäH+ë¹;añµ -A’‚I,Z€ Äò>t_«C·rxb ?ŒºÙ×–b§ÇTcVóÑ ÄqOrIǽSÊÆÇà¼>#?fENó¢=•‡*¤’ >$tE5kCÉËÇœ\|™nõ¸Ubíi¯PG³r̨_‰^·!¾Ž›S^¦)Lu“³³JmP{Çä©Jr¥ÝAyá[ȰYÍw—‚<µ,JëÁeTP¨@ ®¢Ç,Øæþáéò•fPÈžà+Ƙ±"mÈ mR/ŸFê`­±±màü©§-\{§Çå¥&#^9SDcØbª0Ošix¨(1,˜ý•‚x‚ÒaOǵJ<Êxù˜JP¨qËrúi:ª[æ´G”Zž2^JÒ<0^]×Í?GutNªŠêù2¶8È@˜îbRç]Cày×ÙÙGz*7C@E窹S œ„Z¸>5j °Rº+_ [c¯¬¶Hò~Ϲ9e;@a²Ó#h8䱉0f¶&.{,mûh{ÒÄ­Uz¿ì|níSŽ.¤®{ò)•Lž´92f¥¬Ž‘G,èŒ8øìÉ0;Nýz›µÌöœiÒ•bØ¡K»§i’¨]~£Ü¬•Û•i³(¬UkžïÕ,”*Š-inH2™˜©pÓJ¡Ó¢ð‚%Ïi\#sÂ…V§àK(SàH^(5ûoC&6dmA€U6Ž(üëð(|# µ> €"Œ•2¥@u/褓ÙY7³èÏÚoû ¨ DëvE+f¿Vb~u†D¢±,îÄJ¸÷wÀfïÇуRÖ<øE¹éNö­‘À]nT¼°Dày®V•î`üpÿÔâŸÝ¦ä‡ý_fgî4øá«À;ß;(ÑRjä¼ÂN¨ÂNñœù ›w³!|scƉ²EœH-ƧA_½Ñ€ Ð7Á-éŸÞÓCÑòf°´«F…„*[­ƒª!v+ø z¬ûS6„ƒäÔ·&.!‚Ë<阭h ‹3´ÿ%šÕj1ŒkE]i/Žu4¸I3(Qé¢jþ›'ã€0ÚNFdÜ8óÆJ3 ð$ïB¢33<Áö§µ-µˆ1îÿ‹\Ò„éÉ^‹gê*Ÿ”ˆÎ+Ãôᢆ¢ŸTu?ÂõÑòUÉ–äÒë9«0‰H,ú4%CÔ)¯ŒS5}ß±üº´‘±›§u"´@*ª´òÞÁ6ÀÐÔúçR¬øðí"©3cì‚@e‚F«kÔÚªß$%ó\õß÷7¤6ýûvÜ[B'/7`î]_= PxÕqÀ›£uHSÊk1Bµíxöp¸íÖuˆ¶íÑ-›“+KlÇD¤%”l| Êü»ÇQ «›b!ZŠšp&Üva™,ÍÒ]NÖl¬ Saê¸UT°YëZ>ùÔC«#…HVCÆHî¾ÏÇ‘´m{ìOY·®ÜÔ0íν5Í «ÖHg-ÇLº$${‹ã \éø× §»+—US"ìFî·RÛ´J’¿oÔ1ŠBƒe$‰!bIÈ;|¨¸ÌpÆX ˜8åÝÈ­”¸ñV™Ø/˜Ü*qtl¬›5)l‹s3hˆ,¹œ¦Qä’KE“Dò31F¢êøÙذÎÔ5½Ý‘¤ç“Åæ,±ÆI’ªËË~ܰœöiÍF`ÈëJgNîÆGÔoø­Š£"Éž­(:ÆtÉuøEQݸÐ.Œ£+C#ÈãÞ/±ý‹ÿCz=£ä;$ruB±`­Êy½û„ ÙGõ Uöê *¹ò«µU:ªUú/P*ìè혊õVfè± MðŠìH«÷êO, ¤Çêßd¹Š¶5nm8kbKk±"ʰû¹â$x¨g¯$áÇ šcc˜8±–L‡«ØÈ,Y–ë_ÍGÈš²¬ªÕâ= d˜þ’Þ "ØŽ8‘ÿÅþcuÇ6uSË':ËsÈ$†bÄŽ ƒÔû–!KÖ6Z0êª'r¡9'ºrdžúž~*%øzÒ„rzŸ‘åBÿ%fvÙ~¼±^[È¡> 8ö üÈTç‚9çbybx*Ìý;§†í™Æ \|Xd‚ÌTÝŠ>>ƒeupX|ª¹`¿‘Ç?üqTAâøÊšÍÃèc)ùd¨§&juµ&\ðþ2‹C0åÈ£õ’4ꌡIÏ!™3a'ò°È< ŽÎiÑYüt™òL¶i–~¼a*Pâ³L•WfîÔñeª VbC1õpíE!޶d•«G$;B‰äc• ¿/0‹«§³7‘8x«;“ÜXù„›žž~ÒY¶¿“®¿ÍòH‘…Ff[$*Y™Yu$ìyý¤–°Ü k*ݹtlZ/˜­‡™eÉýBŠ]ÄY©5(¯WW… ‚³©o«kö-™ m’j¶±µ¼¹ÝP{:pb<ÕU+ÐPLŽììzÒ­è¹#¶FD:´|ráÒ£²†U™F3,•^½ƒÔyyËðmGØ#äÓrežÕ²2‹]‹È‚OËFei¯Xªó'pýË×÷VöQqLŸi5ò6O< «–òAOkFÑõìtjR ‘…¢æ” ðb¤”[»fßöôÝéY¥±±™j[·_`åÔ-Y•UHàÙHêGvn<ýþ¬;³Rrn€Ip^Èê_Ä´ù ÁêCv'±u+7ú®¾«ÓMÃä’Ë?»ŽéÀÓØ®jUŒ’Ç`‘@ŠÔðÁ¾HüµÑñ'}›]þÚ’™«›çôîîöñ«¬ú‰‘¦èÚFN ÖÏ#‰bdåTv"Ž1ä, QŽì;xÈ è·3jún}6ÒtÝOxëù89ÔY×iiy¹1Ôîžy½YJ±VVŠž ¡'j3ÈÈéË:ábI40¶ ˜ê“ýY1Á,rvœ*Vl,q¼]¾åÛÇ$lÃÐɈÁ#ÅŸ—,¸‚8Ì®N’cȲím›s#Æʶõ´rY7Òm‡›kài›ïvDÎÝ»­ÚZ—qM'IG[ç°%i#ç2í7eì~³Sïú·êg­ú7§zNí¾…´24ý? KL×ÛûcPÍÔse‹‹‘m?–%1­œS›Ø†DTÇnŠ—[nî¬ÙÜ«išmñÃV˜O|49*ËUøz‚H»˜€9W«\/u¡7ïž;ÓY–þõÝ÷´&­¦êí « |a] )Ù9昙˜m6ÊÀ½¥Q.¿ŽfŠ·óÖZ¯µþ†|¨×õ11ðÒe‰±–uŸ+O¥’V±ªjÒ¶–ÄejZ-5zÏG"5œ¯|Ö‹êY,²™\`2n¨%ª×«nYíÖÜÜñ4íOwj)‡ªêX«+áé™·ÄÇÃÛ»o!a=:ç6Í66É™·Î }j8‘÷ÁÈ›iÄ“£ ‡ŒU Þ•S¶$ÑZÝöuˆ ³ÊH1È1ò&PÆë¿¤k#†.ª^5dˆKÚ&8Õ£…Í,ªGéZ£Úœ)•Lze³5Šjæ> ±Ü>¤o,Ì ÂÄÍvÁl´Òt3jS&$Ò¸˜.ôT½^ì3Hô·lú9 éP¶­¹½7ÖµÛ¨ªÑ³²7£¦dkØy/îóÉÇÆÏL@ÿ‰Ó“ÆádÇêŠúù¸uMð½ô/Rs5 7:þ£ç_2q­¹÷¢i¹·‹£4 ÿ¥Óë‡,<Ë ŠãVõŒû+x…ðô-¶×Üö^ÒÎÊü©ßÓ­“¨èªÌ˜æÑž1µ)Äu‰Òó;Ú „e¤ÒHž£Ö0ãgfVXdÄÆÄ™ÖÑŸ&N ö %E!D@Œâû­ÃÂËÄô«Ö|SRÞ[:»g{Kñ)—=ñéØM?.ðä¦ÊÏÁ:v¦ó¥Ø–o*,nõ?TïpæÆº6¤út¨¸™Zf†RÜÕŽUq"©zö±·WÈ`|Ajæ¨e6:[OY¶dµ}½÷Gé°òÓ]ôÔ¹ú¯·Ç‚“q£åeÿÒÛÎ)ãyáþ6¯·óZhž)4©Z¸‘›½2ÑöëGU×l4=ˆ'¨9šåäêµJ-|zv3¢´al\N©•f"TVvµ¸ž!Bê1H¬î 脎xBDAÙ˜ù<‹œQf©A*,ƒ¢t‰Eزɋ$øêÊ ƒ'g'h(¹L)1”3 ƒÀ6} ´ºêÚ†­¥ÊB4®UñXS;&PQø££w®\ÚhQ‡“ÇêˆߟD=%Ûºç¥{¯"»†ÌÃiê¹»oStk€ØøYÊÇÓ¹¾6f'dUÕo|dª§D#ê‘j=°u]!±ð%¦iÚÍr0ðõB5¶IÀ\ÈÊú…gáC8u£»RSnÈY®‘¥>•m=S{m;k¿}5Úº.Èôó?*ÙúΗ·õmѯâcê© ã"g´3o«íÍ ãbÛÇ’15…ZRS®MÃ${¦e#aÔ—§ö; Ü*ÄÍÝížMÁÒÆ.L‘†à•D*ÄzzKé}HÞÙ™xû{"{{àÇjß6T–ßLœ|Œzkwʤçø÷|neYàâ‰Òß‘%˜„ü¬»á¸~Þ6^üûÖõ]­¬ËXÔô­Z´õ]2Åò?ê}?#&9OWÃʓĈâ§ÿoÇ+Û„ëF½5õÒõè†Ýؾ–ïöÚ»ŸiË7TÔ´Á´Æ«ƒ¨ëYIijuÑ5 yYTŽ>&6ê ‡,›bŒ˜ž{§ÖunϹ ?ÓM¸vNÀõÕ,m׬ëù™šÖ³6¶ÕΕO öÆ%f’ˆl—ŽE²R”Éð:eÅj;Ên±îgNƒ/I¥uþÜ»RZVáÏÒmñTž[äkQÁÆá1oW ˜ÂBŒƒMº+¦ø¾Äè]^.Û‹?Ü9™=+Ì‹,¹ZBòA“~œ[¸0¨^åT}Ç-*âËYëX£"QŒÆ&ËÈtTcI&x£Ò˜ÖvØäÕµ'[oöÿéæ7¬ÿp:6.˜¹;/jbRQÄ’2Ëjí̇ÅÓñò¹‹KõI×ñÕ¼V½Ë77Žý’o¾ý½öèNfáÁ8‡¬»ìgh~•mSx«¾¢b7tgc+—]¿µ’ò© eç,V?ùá´mÁ¹½9Ø[á´mŸ o½Jõ–¡º·La¦lý¿¦â-F ®M¬™yËÒtË8¡Ìß"È\y:ýrÉþOýpÖ½xû´ÜZÞfú®óÿ§1t}Ÿ¡Â8˜GIÀÒ4Í>KLM˜z¦Bgþv}óõ,†xa½3rì¥|fr\ÃÛ>ßo®EÒr»a`AõGõQgÊ(Sô¢XÙ¥ 3ß(ꀴ­¤T7¼ROruÅì²KÐz)‡2T”‰B "yYUâvŽyqñAhÀ•eZS§ëšæôõ:;‹sêÔ·íÞgXܦuml­OV×5‰åçddTÐS+#/*ô9Kái·•Å(-NÂíml,½ ÔÝÃ2^ÃZÉŰ3 ZØ_#Ç .Oëf«2Ôp~©Ï§]ýDÙ%ü/A½6ôÚw{<ë—cHÕ£\WÆÆÐ󜨸óÁñç\i»ÏD·>MÕÝ[Ž“]O;ÚzN‡£$¡Lo+°ºäY=»,«E˜kTøÒMKÞÙ 0cÄ!nšÑÅ T ’€©QªF©Ô44¿éÎ:ÅÕ$6¬ŒÌi¨ F[3~© €Á‰ ëE†ƒzsäªÆr³žg²rì” •¥>,H/p„ñ–÷U¥„Ón†€,mDUnY|¢¯vþôe %?Rxñ3³ž+7¦PÈm7I`Ù ›°"j½™FlŽÄ! &OðÝÓ.x—aÌݨÈä&}P3¢£ðè:ûû/lŹæ<¦ýF=Çò>U¹àÕªƒðH<Ñçªñü‘(í¨ M“§"Ã%IÔ•#VaN;w2¢½9>ECZ;Žqïã•yš' >ýzü[Š3…qôaÒs±ã`Uš­:·YpS¥/.TSÛȦÑj h¥\¯º³:Ü—–v|~œÈ¤ÿi½8Z:°jðªÍÔ¡¦åÊËãnÉN!¢0Vy‰Q‰áK+?4 ~äÒl:§Íé‘ 6RÚî|@S‡r¬€!ªjG«e‹Î´˜,‚%Ôù€O1é òx5l9~{($3iô«~ e#‘4pНFrâ•bC7ÁhÄväy:'È•ø†V>ƒ( FxФ¹y•˜’²T f pxGíòbËñ ’Šƒêöµ‘¤éó¢bX>F]qùfךÉe>À*’Ÿ±x~ ;1$ӯʼn‹±ýÞ![Ÿ"C_´šcÅ­†mâ‘B»³A|؈ðÀ¹Øµ¿u~6Klò1òB3£Rtš1g²veU x#Æ+!È+Dí”`É뜌…„æ’y«8oƒ*šp¦ƒŸ`OYË©,Ì¢k´4Û×L]C%Ö”¬ˆ¥*‡æl…4j¾J1ãߟ ½Ô=wg|&ÊJÇVk6V ‡ƒÇ·»?*Ó`á™\«©W ´k-©Hkaü(4 Rhh%SUµzÐñÚ8%h˜€ÌËNÒ5PJðÊ(&Èxú´nzºGXÇÊËrÁ©ªˆó¨ýn¾ü»tbJvçÏÏÛya‰=íé&¡Ê¨†N•“…!Ë<â´Ã†sÙ‰=?¨^ê;{ƒëÿBõljë˜P…h©ä1¯Oȉ°*³Y™ß²¨ã¯ðýèWÑ\ìaéN^•”§"PÈy-»MË”Db9+5n•N€Ý}ø`ÁˈFÛÊ€$D¨,ƒÈS$ %˜è ‘L¬5óÈßþ"º|°dôî¥:Ov1UÚDup51¦Ç›Ro+8½¬äõ’KÁà´ŽV-Uè•ý¸y/Žì£2øÝÙ_¹rC¹`¡~€Û‘2C”ë*xù ­FòÍè;ÑDn”@uòT{¦é¨ÔïMçr­§ÇxniGª÷©c«çPÙzà2Àî¼|‰¿Ð+xêA©J¢°IÏñ€#â£ö—WGäjv‚¯7=OÉ@èXÔX´d X ®Öº[VcÀ%½lž×ûXÒh£¾ä I%w‹uGg¿yq­û@o­Q4Í++%øjªÐøhIVacY¨ U¤ªÄfR—UU 9ñõ×_®àõ'PÆ…®Î™t|¢¸ó*d(œÅKœ†/ZR„P|nÞ•;-÷5¾ñv†À×3³(&=ÿ # ääe±²cõPü˜³ ±ä‡UtÖQð9m«ë™:–]­jfQóMOݘUY¼Lç/‚ üž=œìë³J:S:[™M±|À½Ë‹ n¥…pU¿«q{8ý$šdiª‹TìlÝ`Ь›6¬U­[¢¹É­±FŒÕØ|”Hø—õôÇ4DWµ»?tùY}ÄäÑEÇɃÿ÷oÇ`)GÚ¤~,Q FxÊ?·Bƒo‚?mÇÖáv朸 Ì|¹#×]¾—jyzè^²oT‘މ¦e†£# Õ4Kè8ÓF@Ý_PË€¸þH ё“Ío߆˜úWÝe´Écѱµ5Ç×3V¯F4¶|qW0Ø5šT];;YZ…ðÕ¨’)^›Ûö¸í¾þÒv~s^‚º.®™>*Qèa]#XÔl“QUZŽ–Ób‹îVSÉP>adïùSÚ8w©º&ñÓ¤©çÛ8Ç2¿ÔßO˦Nƒ@Ð|¨d_OÔ³­äZB5)Œ† Iö´ƒÜÙ.4°çc‚€Ø›¼h>À ãÆèêM5l¢3–þ FîbÇÉ}Pý¢(Ýr),6<Ç]˜ÑøÐ ‹¥WÔQ¶†•<0PDÝLÀy°b öþõç{JÍÖõI«­H¤ÇïGwìü"÷!ªxRÍÂø—ȲY*•Çf UŽÅ|ˆ«‘ȲG îI-­!oP¸ 5mT©²¥ƒ)°ª,ß‚&Èk'Ó+MYYذùÕáBù ²ü¨J¿ÿ >«Ø½8bó!Ku{¥»«Žg‘ˆy9”ßá%`U'§ù%KPÌš0c6udì{„iÐb9=JsòêXP ·T)ÞtŒì´—Užo;QÙZp_ˆ¬Ñ½ 8à*°_$Ê«´*XbAýÌ¡ù  ^­©“b­š,X”cT Ö–TŽ‚­êáˆUÖí¨bÕÈ£-Èiõ;Ó»MîÕì¥Ð–4ìSùƒ²‘%擹5ì-/+3‘p´ ܲyÑÏ ˆèþïDRoÓ‰qNHKu¬§„ò›«÷¸éÀ(èÖj­«#©—N´UWfu`y±Ÿkûýžµþç.5në&*;$&C dd@Ìîy¿p±)“tE` ÕB€K=ùPÄu^$‚T§hÓÇêh=Èö$Ç2óÿûnŽÙxþÑtèãIhóC†÷àóÉ^8'’?¨$fu'€úyÊÈ=@þ§Ù‡#ä¼{‚KnxŸoç’NÃ1+#r³•^&*+…RH>“z¦|“ÍÙCQ­ üP®x¡À?ôxùôª‹5IduÿH ,=Ëù ±ùG) ¶G³0Wª°þ?Á À©`§ŽÊÅ¿žoý•Ú,Î ³TÇŽõfÿÐÿcÛƒÂK–úQ@žÌA*~=”t*O^{xoŸHì¹úoÅ„Ê"~|M( xN¨Vk@ hì„7Y#›Ô*ÝóCà]]‰"‘¨. ¬d- C¥_VØ¡µ‹áB’T;­hµÔ1²$è*¡èU–„Yø“ËÇZNü,Þ%¥B +Vê:Ýÿ±½†ø5Z±oŽKº„$È8››¯Wå½™@ViÐ “|mJ8=‹×$ÉèÌ i±daãbêxGƒ8åÜòeF ¯ý¨èqÄt%:­¯îf½$¹Iü‚;do!ùµDþ`ƒõSÝÊz,ø–;SØ€ÉMÙå¹›^M‚¿!ltŽÔ9ï’AÝc‘¢µ x4TOä/ o@kõ«ÞšáS 5㨄ÇRÎ:Xðœ³ë2Cê½Ê¹NÇø("hä—§ü(`IAÝOeÜ0çäªáŒøQ”„ lô”qä9 ÃEå| @G(GNÃÿ† 7%Gu)`#ѥ˲³/Vµ?‘uvSDZ!U¯pKŽaê!c™ìIéü ÀƒðX¿âTÕˆz“6FC9±É$•H£Áž*è‘Ç,o‘2pÀ+†eäƒN£‚Y»3’àv\£ü€™ÿÆOÕõòjg˜mAY¸³†g ØÀÕ¹#¥)ã‰7P((iÀà±¾QZÏ ÞȲtåºÞåW° ÑÙƒ+©èX“Ðö?To׈©2:IÖ%ˆ 5YÇÉP‚Ekϱf Q2Jð7§ÞtD "XØ©#Ih’6PÊ @ŒØ{&ÕG¢þÕ f04+ Àb ùSA$1ò ö“L¤afóß›‡EÞ9Zv×Ï®Œ™G"™8Ôœ2óÛÍVs‘fâí%3eš ,ù#Òb‚Ò}'RÔ®3u;gæÞÈZ™UWÉ£äyè­¡Èn8›TÕJ|1 Q_¨¡ýÉjÔÿ÷MÁf%Yr,â³£pF‰eîÄ·º+IPX¶Ï—Œq2w€.*Uæk#*P·*¾-Nž>§´•¦ŒÝC•6Dý?Éòúx”2¢ê»" ÿ T.‰M}\q¢ê3¯ê¿p³܇j,íDŠ¢­ø@+±ûMKPѶV¿Yb.JcèÚ›w¨¡oÂÈšºÛÁkDtÉ€ÐK2=±ò‘B= Ó4ibï½3\Ëh&¦Û?/_ÊÕ±4÷ÈËÄHãR,žE%õ —VÇLÇ௓›#&•mÍ‘ÿVìm[?räÃníM7EÈ S$¬­11ŽÏ4ý¹NzI+K8DV4éŒþšåî9úǽ—TÔ¿ØA×rBy9ÕÆ£»ÊÍ’¦Ô®B4›Oè*ÝåâU›ˆÍ&û?ôᤖˆ7ÅLa/p&@‘G%AÚ4RÁ‚BXÒÉ·¬£ú‰$PË9=¹> É¦„2bH&I|~}»o,¬›éß]©,]Ýû¿vôgCœõ•¹rõ=Euz]NÈÇÃÅóá`Ó)zwÇÇ™¼¸ŠÈ>.XP0'ìƒh&åßë×Ýý£BÞ—íŒ;àèzv»\q¬î¬9„ÛØt ¶la«kwº/…'òPåHÖèVêõóSÑpŸ&`ÛXÊÕwF¼×?ë4&ÔsõŒ¼l—oVND¦‘”¤ìÔÄ,¡ÈVE맬øë“ zIée—GôŸk~&¼“ÆÍÕåzceê•™r§—y-)T±åæ¥ 2tÕñÚ\O÷Yß+)žTóElxƒ£5*…í©Ö E¹Ô±›G …õE!¤cKôà®ùÓF]ŠE4¤Ku`ù2…ŒkÜ]?L:Vc—ên‹¸½]ׇúÌ·õ JÀ€ajêÓglá¸5œˆjó9—P˜ØÉEYህéŽ4de™ú•èw¨ùx«×Û{c2yT)™ Úù¸D±6¦báþªÄ´úP«™ƒ8ýR|mCEܼ0µúº6­¶µ|L{Ïÿâ‹Ç7R¾8­ñào¨G+)IË>DñV÷Smi»'plØâjI«¿¦;{KÄÓ°³r±žÔ¡Òò3Z“g|Idj¶1g¥O‚“¢}Æ1ˆ–"Sµ"<.W$;~(Õ¥O¾¢(¬¤°«ÒMUÃÏÒ8˜²EE m²Åv!+…öMõe``ýúàë.‘ƒÿB}Óú9¹°2ç‘\lŒÝǵ^oo5<+C®béóÄ_Çwu`]/E#tüNßYû7wÓ*Xš.åÝ&§ŽÙ …l<Êáyå¬hôìÕünÆ0®DlLogN…ý/Þ »vÌÖ·›þ&­éW­Û`%ä«‘©iZFð2´¥¥‘‹¤15|ŠKÓTB ±+R}áú ©l¿¹Á»4=2´ÛÞ9S‹”\Ň…§Zb¨ÅÆ­fi;wßÔ ç;gíM]–ª›g*øÒÊÜ:äu,];ó_ñ1ÿ'ˆêzy?7œkBá—:ö¯PÊŸ¨õþ•Ôº{AÑó‡ö¬·ÖXóñò|ÐjOœ½àï4F4·Dpw_¸1[,^§ŽLÆ~ä2FšNÔkÈÖxÒY@ر GCu]Ó?µ¿µ*jxº¦fÞûšÞúž¥ ¿¬cåQÔú{gÓ- úiµ³Œ#©c‹ø2I¯xo+NÔ“æÞ« nۮ믨n}kUÈ…olx×PÔ32µ‚]q–‚UÉQWQZÌÕ|Ž“¨R†zaééûÌÐ5-ß¾r3-¤ëóºÊzjiù<¶/ÿLèùâ™1m§¦Bò¨Í‘tn¿[öóöEù™PÈݘØZ'޹L‹Ž¹™˜¸A%u*QÅ¢0|XØÏqÞË:°YÄ]_¬áôy³&šÎI–núä}K¨éøöóXåcåeϰ˜–66?Zs(ùFxìæ¿5ø†¤¸Â_Pw†ËÞªãlßF£¥í­±§j¹»WifE‰ËÜW\ᇭïlŒÅqùgUÔ1[NÑÅkOûT9ÓXdZÈÖÓ×ïZtñÏö•ªæåæéš¿Ý¯é¤ú{§êùxÙù»?G®+%÷¦Ls²@ˆÒ’…ðŸýæ¶š^+M¥‰Yã¾çËê^ñêØ3CÆï l™ÓÄi3Ê‚¹€äÆ#Œ™<ò΂8¢=Эƒ/YéØ}#¦be´™ßÞº»Å.J1Ü Ýž\© Ñ)[''·D‰/èí²Åtûü¹ÝO`ëÃí¿ÐÍÉ¥æ5ññu ÷º´|üõÓ ¦§€v~:Æ4lmf"3Ô3*m<üUüdœ±îïFæÑ´ý_#T:¶±|ºVÔÇʶV[÷¡u©W°¥ù⽨ô¬ÝÕ’„sÔL?éÌS!µìýJÚ¾¡“—lœÜ–¶¥™—Z[É|ŒšS.™½Zvb× Ú¬X–òQêVÔλ¬íü];4êWÇûc°ž"D>;G Ê7®[E± áÑê¡XË»RºÿFöîµp#l¹ó²ãQ“ÕÈÙŒ‰#XбU‰²\øÃcÚÅÇJ’>ñQ# X¬qí‰Õœ¶¢¢‰ahö;7©› ñ ,ŸõŽÞ”åjJ“ÆZæà&gW標¶òq1° Ê¥D)íB“‘F™¯*ÁÐÌù8f‘ÅAáIÃLzQz]ø¢1 Õ[æ'#6™,JàMˆÏ«*nF;WÚ¢#(V•˜á ¼±TD¨À¢»M) Àu*~‰Ø ”ŒŒ³.ÖMUÊ8ÌÝ()Ë„›|QP½•¹²u‘$Ù‹­È$¥ÅJënê£øacñÕXæ!¦¤ê,@%‚íÃ=%4GÅêu%Š‚–V2ŒŠ ü¨ìKMé3Õ{¿=WÞ*ªßùx$‚½œ‚~žVnËËQ3+”6CHü‘—­dM¼®jx¸j2•£1›2¸=¨X¿'Ñ-‘QÜdd§°U$#Õû'NIj¨âƪ×íø¨mmM’9oŸçë‘äISÀޥŻd5ØjMð¤9µ?•@*~ßSøÞ N’1ZƱb%ÎTš)AÃü‚Ð-WžÝùV–cR}©ÅCW—‘*:ò‘`×ù(HPð’_àã}5ÚìQg_ÜIÈ>5?6¢º:ñã^Gp:ñÃNbf-jvz— S5>ÀqÊð‚LTNehÀñ6ì@oâbŒ-l†š'aµž :Ñ[ p|  ™°×É7_ɲ¨VÁ‹k¥_¶¿Íú_©Ek‹˜¦jÕU BõÓu 6~Ü€/ÕTª'šÇê¦Ù:–’öT®@ÃÈL©L;¡ZE¡êþMEEj7%H_'RQÚj(¼8¢™M|àÝCsD%Ðs"åÄ×­YúžA-Õ1p²¢Ê&vd¼Ør¤üI›õ˜ó³ÍÔpf¾6nœ1lއð]xò½”›ÆÚ±`Vø`xüUé¹E’efÿ+¨Ô³²•€§›à©ÚÆÔGÔ<Íó©ll½7Ò̼mvX‰™› KO Ëd cfð†ÎõUG´­ãEïÑ:…`¶ÎÅû¥Û›ië½·•ºsØx¸ÆXÞQF˜¶,Kè;€ÓuJ°%—‹ù­í ŠÂ±”ÒêQ‘U'Ô×næ©R߬³+ðeeôlôãí¤oÍ Y¯oðjfËWvòøQ À¡…*W€Ëä_aü àeŠ&ÅL\ Ÿ¨ÈIŽTñJz‚c=±’ÜXä$N0ëc_LýSÜ=¦Ào¨gåâCXäÇB’cù0Ná†@äØðÍÈÊ‚,ŸT ÓMç«G>W}3+BÏLÙÇ/lÕZªØ´©„Á­*I]•ÚlêÊ ÌR}Îêm/S5Ì/Gã•$ËÒõ]OÇOlÔ3¤fírX†=T„ þÿ˜N“èqöÛèöÎÐôíQ³v¾—‘©`5|YY˜³ÈÊ 4»÷°«šÐ¸)Ô*‚¥z|Y–ë Ï M‹*RP2"_×& ´ÈSÁ:”puÿÏ5KRãbEsç’G,®$P"Ф‚7”òqäLEX[lÜúýùîüwuÌmÿnR¸9qIýÊYGËéÕÖ!ŽŠQµšU*Jú¡û‚Iƒ›šìi•7j7‡>ZZ¯ZyC­?o8k->J;µ _ †èÍò¨ŸxK9ŠÂAhKS§ ã{dJ7^ÅVdp^Üy¦£+Žn l–f%Aœè§¸$²»©›P±I=›ä)¯~ âúoéþäÝz•ÆÁ¡Â›2¹ËÍ»*iØÂb‰J+äuF½§%¥õ»±µ‹‡,òE3dNË‹kã³ÈÉZ$Ýì ,ot­ &>Ÿ„gÊÒ8ñãWguGn"ûjÃÄ€6$*þ+AEr7ï{Ô‹îÝó=¥e³éš Hf 3¯åê9TGür)TB'Œªëåb:W²Ì::U¢ãørµXš>«€Ì¬Ý¯‹Yô nè©#Ñì¨È9Wc;;WÕòµü¬“—¨jY™9ú…š:ÒÎ)jSŸ!½).{¢Ðò‡‘2îÛ?K¶}³X«ãà×+*†½ßqŸžÔy¹ÈÈEZ˜öf›F<޵èÝ*?oô,~ŸcA‘À ÜšM òXá­™‚€ü/Žfë]aýÁ×_5¹Šyô†&'x‘6XÓ†ñ$rAä“Í »¤`>Õ‹NyÙšŽ‘§^˜ífiø³2²,VEæ¤yqP«u›²:#¸^¡íû„¶Ý{®kB¶Å˶·*wàÍo›Sù|™FBª G aØÚÝ:8pÚ>šb]e(kš–f©™MðÝs131>-eDSEJ™”idPVˆ|ußté“ÏÈÜ™¯óËÉM?OÆwÉ Ù¦±ÊüÅvráaVŽ’£ó,É/Dܘõ3r&n?V‘)²ÌuÖ° lO1s”©Å¢ ªCŒJž ¨_òx$ŠØ… TÓësÿÃ>íMcÐ}ë¶\.Û×5Ꙃôn2ÖY˜åW†„§ÃgòÑç°¨wìç³V¯òy¤^ÞìMÎøð9pֲ马òY]F•}+½jÔÈ™‘ÓåÀF^ï ·Rò›(ÿ [£ð·÷ª{"œÆZü02¡<‚ªŸ—‹g—Y$úIó&(ß>¨£ÂÊ‚MûéÑõ kdâíwÊdOÕŽ¥E[KÝzFTïÊê×Òæ¥¥Ú]ÑÜ1ùûÊ ú‡;±+Õcå5ñ¬qeŠ¿ üìðÌG>–Ä]çžÙL°%ülÆ µrÀw© N©@.ž¡ßãÒŒ}¹¢k»·£¼õŠ—ÃËsQJé¹XØÏ„¡j¤O+¥›Ÿ'[O"i–Ám˜w×+’ˆ†5<},Œ8Ì• “*OE˜ObXöD-PûRÙ_ý=ôOièôFŽF› ÑœæNÊ”b$²Šª# PޤQºõqöÌÄq5 „^¥ò ·Ñʪ¯’•(½‡=@ ¼‚ÀëÁÄ=ÛÕäê¾éêy!” dlj#´E¨#R¢ÙØ+ªâð.HŽ$EBV4Ðí¯–· bªô6`KƤ»êíÿ $– “!9u^WþM:¸3PÃÆKù÷ É)p<«G$9SìÌÝ]^iÃO‹(U™%º»=YœjFDR,†ŒË’ÙUˆJ‚z:ÑLÉùò…•i»†ÞÈt*ÇÛ¿~ÉìÅ‹4ä@3rJ–š?¡Ñ+¢«²Ñø'E¾67Èæ6ÀSYô½_Åß”ëdÑ%~A Ù²TÕ@ׯ Ö¡ÕBŠ–,Ó,ª}ØG<÷i±ÿš³]BÒµ*Þd%]"Vaø ^À·AÃpÝ™¦T*¸vnr€ÅH<û ÈEøŽˆåø`G Tôò€O+ßÂö ¾0YÝ%ç%è̼:|!XÈv¨0Xª±”-Áú&Š m[ý«^"(R%GÁàQ_Pµ—PU­¢•®6Ú †üŠÖ…ÓUȼåãU`&ÅPñÙÕèGÅ““Ú`MÕb€3…nÕyÌÙ‰wAäa#(… ÕÙ …š‡jyVlÍãšsAÚ_';K‰£€¨¤É>WáéØ{%Uº¼Ü9ì M[±þD&‹7q&x°ç™°ìÜZuíåu(Ï>þÓ£ኯÔÑ/êRWB¨Ik`6 QßçS!ä Þ.¿L¨:‹Y"ÞJŠ$}”BÐæ¬M²rW|ª½×&hX›H—gšE耇ȆlĪúÆ£ýºí•ÒöÖ+ã3I§A>±$K±ïÏƼ1`Tö9“µñ[UÝZ^1f2•ë݉UiÑ™’½’¬¨ÂhÓ£½(gÍ")1²^à®ÛÄDO\uÓ¡`I OQÕxþG =0úAþ©õ7Ç阸 Á;ìÏ*ƒ÷« vTêyV°u&¬]zñ9¬[«2H€®0@¥³vÿ$üÕ›ŸÕ¬=%€aÁÙéã ªÇäW·ÿ<_s)Ñ4 ¡«ÔžÄ·#’ÿr?àõûeQØ‚AgÓ1ÞôBgÊòŒz–<žªyáû½—’€’9ßþ 0‡ãÄûô.ÿÑC)!½‡üŽ?õ?É,O%AÑñ­Þ”“«_‘$³£ó¨çM”`‘g„έ˜bŒc«}v֢ŊEÿü|qI¼¡ |G%½É$‡Üù<óì?yíÈV[Œ*Ì vg Ë8 ä=ǰ$Ÿs“ØrOÒ^ãÿ>Ü«ÿþ“ÈáHöä1<…*yBçŽBpu,¼öðöëïÿ%ŠóìTuö1úxÇ0 E0 v`ÍvHÅ@$Øÿ‰£a/'¸Âì‚B|qv ãçøþÈà×òc¬ÀëÕJŸfüžG,9‡ v<?ŽIç²|‚…ühÌ{{rY‚©<þ;{)<ž¹Ï…ú_Õ~GŸ‘ìa$’*(Ò5m®¹ù UX'Ÿ‚käe %Ûbþ!Eÿ?ÿ"ˆ5M~ùÚ×.>h‚ñfŸTš­¼ËG³ô› ȯ&ŽP§kÔ¤¨§”CQ²Êª¢kÜ.DëF£²“ ¥jˆ¥ž½<ðÉÂpÎ4ÈÖ[;?òU+;ãË¥ž n¦8Ç cÞ¡ŒÏRÀ…ªó7UPÒŒ<ê>-|òüh¯ëR„ëÉ(ÓwF„ÂþÖ²³R}̔ïWÉÓÌzî M¾8k¯ãnx4(‡€.»=\*¥ …j˜ìMNw$¸l ½yÌoåR'ÓÉZ)8ÄŠUU”Ù †ª¢´™ÏÉީ٘τûTÔÔàc"c¼‰É—ÂIß«™ùœöìëVnV$ÝxfúÇÍW3UucÐ9‘j‹”EQîh:Ó«üˆ½¦³­ªŒ5Óí!¤Øæf¶Çtuê²tñšzº‘òELöUÿq…ú9hu]H°Hk¶-gÿŸÍz¿ŽÅeVgºÌ@¥RÕ|RñòIàpWäÞ½m3cÌ(ù xGVñÑ{p§~³aÙˆ$­[Eè .'Üs0¤ nàtå€ö茭ÿ¿,‹ÈãeÁ)8¬ÛŠuuqEë6è¨&§ù@Á€aÇU^Üè[’öU^QA ŸãîÆe˜|þ©§H¿'ƒäP¼ÍTsXQõrSêš‘·!P§ðàŽ(1‡ì¯>Gk[|‰È< :½®¯ÓôƒW§I• ¼ü¡º©~—‡N‘J‚A^xš²‘H½~‰ÿ_¨a:ðêŽyâ)ãå±J ¸öå‚:÷å=ï+2¦û|Ab¥fGVåyv,8 ’E(åèËѨ×Ü5Öz~¡F*®ËÔ7rzô™xš„_“nÆ ÊÎŒÿ[  K*ÃȰ¦û’‚·“p¬Æ›Ñ¿i'PÐÕ6A±E”V~A,hX×`\õú£G¨Y8ó¨V¿oy´ûö«¦C»š£*°UP4+Y8•l¡›'zê”üŽ˜Û_FÔ5ý_*®³ÆÃÃ\Wº5"ÊkFK!©6f qÁyM‚û‹këû÷Ö˜í]¿\ýcYÎøÜ9Tq?.þUñøšAr¯@¨9!¥¡ßZΧ»wGôGkdË#'É—½u,mW\÷¼Å/lB´I)¸KÖf—N’‰—]àá¬]/§dä¯p (b7æV5ñ#o-˜¨ ÉSU>n\èO‡ÓÈÙ2Ê‹+t™3 ²B‚Œ‘ +y6 :£…/î­á Ñ¡n¦ÏýfÊÙšÃCѬ½™²N%&s³¦z5³Æ4kpÀ²ã–ZŠ™ÊïIv¡ÝÚàÕuÜÌ]/_•£<1ñu w'YÎÇoõš~<¸¾xÍøOoͲãÝ XH%Þ{'?b}¹ï˯¿ƒ/RÀÇÿUˆö\zsl;8Ȳ%n˜ôBì¯Î2ÞjMx”ÈN7N­´µÌŸX·)ÏÑ=8Ó20ö¶ÙI‹‡Ÿ®äU±1e-/ç–{jÉ‹ù ÑÆ¿ˆW&bÛôá¥?7&pªí˜Ä(>F%Xc^CJ@Ø--¹ßzÇ=ý$ÌÐá^Ogc†WÕš\‘}Ù‰;M3günIb  ÷‹ê~§‡¯mŸH½;Ôðô‰ ìöÿ¨ptb©…¨åf¢#GT8´ZÚiŽë8—*â¶áO޽k.©³t\ÇVÐÏâSYLJ:NIÇlí;LÓa›ç¶$±Byó.Ø|&3S pï­W¤ã$õ7VÛ[ë}î]Ý´>ßÔôÍ78±/K-¾‘î¿M¥¦¦¯©íœGqÔÖ«\?$ãWÊgŒ¨Žé/Òhë`¼àÙܘŠhYа¦!Ô$Fë+¶¤P`>ÃÃ@Á â…7ÉÇÌ#šEyq%Q[#0‰Õà셑ЛÒ€4QêCöó¾´jo-ãéï©:µ°7žçÀ¦#b±ðéz†¥‡«>nßÕa›_E¿ì4¼ªU?'8¡Íóßi½{ôËrúå•£aSoo}µºö†¡¨Ï+k†Úm¿IÜ™åœ\ve]þ5ÈÄØ»ŽeŸ1Ðaê®.ܽã úͲŒ§¶5mD”NZŒ¬=+!•ñÓ;Å9iô±3²‡eGðãÖçú}êþðôëqmÝÕýw,î­Á°æ9Ô£ÇÁÇdz–6§œ&1냅i]2›œuüŠÉ‘1ݾ¾gA&\RˆÊà …‘cÈ1ˆÕ†âEwdRËÜkõ;œ´ê8‹™¬ŒØ®^c L:†_§“Û&6UPK†ÕûÆõwHÙ·oN=,Ö03ô# Q¦\¯=Á¨SOŽ>»ku¾nfRãZJÈØ·V¤œ´oÓ´ÝѯhQÜûÈk9~î*à븑ÍÁÈms"²¤Qs×@ã(z³VM’-“­Î3Ç·Ž² (õ\húDý[+£X%HðúnHš^ìMqwgËì˜W½ÿ¨Áâ“#nÒ²,ŒµÃí Gªúg´ö.“ ÇMÛ;wTÅÔ°%a‘¨_QËÉt9Ù"ݨZÉ)YøŽ/p’âä<}ðúá¤z%é«zM¶=Mß{zí­çb“æÙû?*ï‡}O&‘V¶>£ªåQ´ÝîùöÍÔ8'M„ ¿û—Þ¾•ý—úWªkºØÂž¿«êõŽÓÐᎫMst곸ҢîgÞxÖLG+ÙŽ&ŸŽÔÁ'ŽØ´v©s^¹&v©mŹ·>·{{k®xÀZaù%þ¼‹1Ž¡í¼9´Þ…Ò´ô™ýÉ<^§&"7MÅ}XáôÆx™ä,òõ9HZw°aŽ"WäÌ\"Oqõôêa±ñX|8ßul\={‰…Iò{k6H»´P9#7ô?ÉÅÞ[K )‚ebd²Ï%¡VDzÁrr ëý«Zõ 3F Öê•bOÙ:yÌÒuu2L˜Ç¬ínaL+jÉ‘ ²c°É¥ÐÅã@É^Iî^PD·É–«ÆwÊÀÌÌÀËÆbZ31ÛÉf´ )7+1JQø›*YTõ›}?ȆždØëÓ?5Z’dœ¥(=OƲ[ÉŽÌõiêYm. ÔT;tW%ÏTb±ð]Ú¢ecMf3lX–%­U ` ‘t Rú=‰éM³H¡«Å —íJ,ü‘^$ØFtÿ]º¶óÝq…põ½=²ÐÉLKCQÇo…"Ãðü’Z„`ÜŽŒŠl®íÔƒbWVÈy¦V—¯hnŠ™*˜Ú5ìzø¬¥#Óo‹H'Y×À¤’ì&«[Û4¿Q5 +ujÇ[–z±b ç’ÓΊ7y‰ãO½È^“,ìL±²‹Ô²£L¶Zõ”±±å@³Ï®³Ä’'Ä…Ãì\.¤‹¯…ª,a@do•ñY¶ñ‡·6eŸf*<Í7,ÅJŽ:ydGÄ=J•â`LªÖÕÍoÜF¤'‹£M]*Zv±nÌ /ü²‘ž™žó0X3Ê…Y;"¸Zü”xXw üa‚»;´ @ÓO‘zdMS»¥xsÉq.Ü¢ð‰ ì€BªÅÙ«Á©ThÖyk @Û`y" MyÔyqbõšP»SFŸm||ý”µUØÙé*¸¢™‰²በˆ›’:–)7rIYüÕIެ³éÓŽAèŒêÁ»28ú†ÇKéW«P¤Úw¢8†c”¯‰§E$˜ ÇbXýTýã÷M·¹ó4‹m½É];Lp¶×ðq§|P ªªLþEAsà±øÑ¹"ØÌ²¼p$ÓH€Èêˆåý?Ô6ÈÕLªŒf²ÍÓòð2M'âI§\™Ëö"(Vø ˆSÓêX}zÛ/ÊÆUÔ—½äŽËUg(ž9ÈšpÎÝ‘„Çõ J:™º0G§R m«)$qLà—«6ÖÅ?AÉšKŠêÊȤ,`•sª—*'ClPŽnÜéxùO7N¬^Ž ³¬ÏÄ•£üCr 'ÉØ)ÀÒÏ· [CS’Á…²«!)…íŠØæ¤‰…W«1îéÃ2° 1U —÷}‡¦ã”WÊ£XÊ¢ßø F’»<P_«¸`ÃÄîíÑYšìŸºÝÑùÕÂÖµiEÕL*¯—Šfä‚(Ö˜(?kÈ^Ôs×*$-O|ªMïûz"MI*z¡+Â%h†P:ŽeþE=\M_uèþ—i¹¯øº:júî:;ù;/ÿÕbYÿXâ8y†´uªlôP”lb‰®÷uàzGé>¹½÷&TÑ´½#+.â—iþFP@¸øP¯?*eæÑ1à8°uwçÇÊó »76§¿7N©¹ušœÝKqeeê9¢²ÆMŸ“,‰ÆI7dÇ–#—ÇVR‘™P³h¹ž·ý3è±æõzÄ‹´2?ÑvRæÌV¦à4 mñaŒMtTÔ°10¤c;Í”¤ˆ1ãPdûm|ʬ`xØ$>Ò68©™“òfÏšW§÷ñ(Å^‰ÍV…V¨Þ2Dn_ÊA!l|fžlbùz”-¹F…­I~ž\©˜÷yŒivi%;2”&“v¥—Kö¼ñ.WVê¦ÕLYYü– 8œ‰¸ c”ŠÉâ*í™þªêNÒ{éÚ~“OÈ”…é<˜bQ¼ÙaâÇ£þGTZN®¹KÂr6§”>œÊñ•RÍWÝNØ:ò? ä) 4>2›Œç ˆÌ‚®Ê~6¥Ü*’?e‘[~ ú™Œ¥³a¡ŽãI-"–Ž.* ÄNJCvÂ3gaAq“•F ©ÐŠçº²trõ•ðÖ™—ÎÉ>"¼Öú¡§Ç™žÓé†Õ¼‚™„„!2¥{²Ù™•¥afƪú=ÙqÁ~º.ZEüˆ¡ë|…'F“5Jò€mB—Ý_õ®•(VØ:^sˆpòÇiQ/4j̬%L¡„«!i„>Goxé›`:, ÖËI#;Jóë±þv2Z^¦À“¥HÄÂÔÂ1ÛU` 5jŒˆ X7ò*ÿ;üOêÓÐþå¦IZ¾ >F®~•‰R *¤î$ˆP"‘r?HN_V>ãtjê>¨í];PsL5õSÔ]²ö”û)ÂÖvºjÞ ˆÓ´Äë5y¥e_ÅUíÂõ‡ßã÷XOîÓÌœ”¤ã—¨åèÙ,J j g õìSòa‰“ØSI„Ø“Ñ?©7]õoQÔ²f›¹öžµh·•_UÚZ¾…™I÷ ¨MmFê)ù*;\Š~þ“è:Ãõ <¡¤§§lhraVØ-ÜuäÞ˯È[é1wº„¶¤º2)$îK¬TÀ«JäûI°v+êS´°“n`hóO× ¤¬Úa^aŸ€¨£ÆÅûyB¤môlÄW†<MCµoJ»+£¢Ð¬üLYÁã•`H «pèr˜2¨”€iÉÖÜÌÚt6j9åH^<Ù¾Ÿ"ž Be$yGI≊3䢲©‚Ç…Fq9‡Rª‡åÍÌfÉe¥È`ÌYÉ!híJ YØÙü°‚†›}Í7m±" ¦@´ÙÕTQ7ÃxZÚX y Iñð&Yzsð`ΜŠ*ž¢P#J+ÍÏS?y³–*¼Ë¼Íä&È®ª tI·E ¹VnÅ835=iO™wvòÕKŠãº ä¯tð·—…â(ã¢P%9ì¬ 6ZÔ–vo—’jg׃>Ayee·É”?^輑æ=‹.=»-:ñª…QÇÜ<‰çà°²ZÂì)‰áLj£“’O:nÔÑ@º²[sJŸë(K¨c0ªßøÂ•BÁ‘T!z”Dñ”øª «wli’ü8‹;t^„•§W*Äuñ•;Ñ‘\::^àÆ,îªO«*Õ4Tt^¬«Â!j¡à=u,Ÿé_^éuñ/Të “»TŽÅQÙ#…W© S€9P '! 6ŽM `X._àêl’*‰ï°'áSai*µ5É­€²kƒ 1QÃ7ííJöY27¸’”`Xè'ÅTgwÊÔò_ÊLìfSÄ)ät1+ªŸ!Tê{¢­K(fè Hš¨‘.ßê7 ʧ~˜°±'à ½Æ+­0ÆFo0¡{•ò)—T'«€H•`(*´î»LEªØ'•ÂÆÀFú©fA_+¢ 7$a{BC{1øÔpáu­×(<‰ñ4kÓ磳mC~âr:³ªÄR¡n=Ÿ¹Zº–êÝK+A‚³–Û˜½4Ì)Éy&J¡B©QÉRO ŸãâàÖj9Çß¶ìGÏÞô¨ëÄüs™EP »~3 À"ì${òQC}mvËÓE1`}ÏëK0ø%»HB#’OA÷ê¿Xßõ@}OZÄÅV¾Ü+q©bFÚX…"ÁÝíµ(+Uº¬Ë‡D*ìG÷,T×ñ_“t‚9˜hšx„æôAíÔ±¼«žTpCÁ<“ÀpX?·G»r߬¡[…ÃÜ/ºñÁö*ÊTóücñ+§øðñ)êJ2×ÿVàû²pA$–çâG€ÿ€z§uíBCãÓŽŽ ÿ“ÀŸcÃPb¶~Þd'[¼’¼/=Õ»¯`Áˆ?ÉQÔê}¹ úªÜ/`: ©…%@+ò‘òþoíôµº, 4< ç‚ç¨A,/¹RK{çâ(cÔ_žO.C·ö;-üû+9gôظP•Pãð,_ÅÇä`€êö´IÄäßæÿ#à|Hþy¿óÇ1^‚ŽRÎÝQòºüžÅíØšŸ':#Fdc$ ~¥ø5‹äê´aÊ®(q³g¥%Õj®ZuùÕŠõŒš½¦ù>¾.a3ŸF¶0Ã~Ó ÓñÀw-Xr¬9_)?×À¬j¸ÓÆ.lêî®ÂÅk˜t«¨£¬Ñ,ª¨f¼ #¡^ÇÏØÒ¯ÉP 7åkÈ«ãÇk4 X°Õë©úFTB;21´±jNÛ0``2@$Ø’<Š‘ÉûÒÖž^­þäW³Q|¾1Žé@˜á‡ÁÕ¯ÙÉä@‘Dž½}°V „çí<–Y¹o/ Vò"¸  2R}™iÑzP;[#=Òé©eêHâÅÇïŠ9%ÂÊ€Ä!ä…^hÊ<¸f躅öϨÙu¼ÑHÒo´³¯^O2½™ËR…jî †bfÉ2@ÍýÝ8‹6+¶±î+J²ì¦¿_|ü“éË¥Âr² ŠÍç¶ F ÊÍ^FFZi€:í³{⌜9$ÑX·*¾?‚îÎÝʧ(h¼t=W’înÅNQIî¨öU*‚¤sЂ nŒ[ŽŸ9öwt%˜ýW=¨Œ†Æ˜t YäY=bVƒ±~Ì”Žá¹Nª¯_"J];²¯`ËÙT¨Cpíñd`³ óË]bÓ!ÏØþâ@a¨âÍëµWÝ|ÛAŒQZ)À™Ë|¾à^V5~ ð.ŠÌÆš`PO²FŸ°Vù2ؼ‚Ÿ#GyôQËrÌP¢þ½èÚ–N‹“‘‹‡™2mLtºGÉ9ùf¯jóE,´)9—I‹ÝZöd3~K0 ¬¤rú íN¬à8ã‡@A~“QõH}vÜzî› ëXšn~f.6Pã!øLK3­$… ^0¡/N½d@½žzcâsÈo_½Ñq7ªÛc>g3HÑ1é®ê&Þ\ŽÚ9|¹MÕFKá¶l¼3U3Šþ82…ãja]úŒvuúѽÁµ·7¦¿cJÚ_ú—U>¡úéèø¾~cê[†:vÞÌ¿T¤1å•+‚½Z ±w( 0}.Ùþ n·ëŽ•§ÓMõ_Gžv¯2߇=ͥ㮦)Ôœ‰¦EÔcÊez=‰&£·›&}¿LÉÂ,®¢hõÔ‚ÊYHRÔÀ7*(”ŸŸ ž±‘,¯ÛËêýYq¥G£nžëǶüMräDTvJ+äÀúîì<Œ;ánÌ]'GÕ´†ÅÊÕôíÙ¥IrW:ð[|0q8d°| J1)5K~¿¡·ëždµoU.¸ž hš¾×ž±M>sÿi³h1ã“·­1d£Ã/ ­Ò«q”ÖÀÉGð³Ç¤ZîêØ;Ôúu}¹ªn¯O5홦>“ᕳôíDeåÓN×t¼¬Š6:C#MSq“àǼ²Zwv„1¼[ƒfmM%%§å¦êÉÖ²5OR´|h,t=GTÕuCNc.æff¶˜Øÿ‹*cÉc2a4]©Î‰ó™cXApYdÈ ˆÊ[EßsV3J ;@Ñl¦7È=õer±º|ˆ²åä+CŽðx3A }¥fem4X>Dš"} DQûzôKizQµõýEŒó0ô¼\šgØy¼•Å탗S'@µ”îüƒ5ಖпñû¼·ÝõC|k*z[´µHî½[9‘tí7PÐñÿÙC)(í8ã˜ù®*å@|zY›²E£§hؾ—‹•(øgÜ5Òpulj]Àè¼³}[ÏCô ‘öQꆓ}k' MõSq&ÒÁ}:~lÝbÚö\´ÜÝ>$v¶NF ó°±’¢hÍ”W!—MgÊÔ~ŽãÝ™žé²"Æ–)A$Ò/h`,r6N4h^B²Ã6:´0¢wLŽu·†VïHòý¤ðcÉÕ:ÏVè¥|c(eê¹LJjNOM›§åÏ •üD1Êc T½OõçÔ-ç÷Ýë3ìül‡ØºMµ,m‘ù ‚R‰“*n¥@¥§JbGð´…`-’õl…@ŸÝï­ìsíþßož‹n MC×ÏX´IiÛÃvèÆCPÙ;bØ®šýðu0‡.zñÈ]'Nª#Yð+UŠÃ Fox=võ“ÒßñÝöë]Å‚p2½UÝáô_Hv¶T¡“©çÎúSiZǨ9¸èÉXí˜C77JÚÖáRøMVLù;‚ÄäÛ{ï}kÔ}ݹwÎê|œýouêY¦~¡\ ŒiÖŒƒð$¦!GÊ*aOfÀ†þšô|¯weOÕ§^Ç´znOo9cNç]ˉa;Oôð±S”¡ i0åîòc÷,øX7Û1>›†PvÑÀÀ{$ ‡2ÇF¬¸‹>dsì†8ªH.?Ú}³ŠƒtlŽZkó)–”Eç#—ñ·+è²ÐMQ´Œßõ[ŽyÕEnÓ’­Yi; ©>iâ u­[öÆë{hÛÛ0$x¡!v² IµJ¼u¥Ô]FN%²|ÖŠ;<Ó/¾=,èG\”ášì§Ý›ºN³ñýp wŦœ<98¹MjõƒâÑmAÔvI—I«6¥ó,ÆhUcÁ8™•·åZ§ÖK&l¼J™ÜS%¼^Îå¨Ó«³B}RœÊì´¤9™ã¶6<“ òŽ!MCJÈò@â5âµÂ§Š½£jØ0üS71îåĬô— Ž8£,Y’1m†Ž‚)§.—«[nG‰?X‘¤aÔ³6 ŒQ]¶C'ÝAoâˆå¯ÔÜSmÕ¥jVVñêšn%-"בˆ&JÑ©ŽÜ8æ±l¬†'ö{:­³Ä×ÿÙêzóã_¦.VµnËamzc2Yj€´ÿéÒÔE’ΙŒ’v>G«»ÊØ9òÀÍŠTß ­ êbØÒyd ‹5$1¥ÊÙ ¦§ÊÓDrú99hÒkM§M®êÛ^Øn¸çrM´LÕ&Z½ †N&f\JF¼ùO!fí5n¥MÓp€Œ+$LT b#ä1µy] I^¯cÍÛÉ‘™]DÍ)"/IRË YH×í>¬Ÿ¢™,1j!hÄP¼lÖD¡Äªõþ¼›YÞ8äP¢òP»ZVºÏeìxhÉV¢ÄrÆè­C¿RŸVVSD* ¬žô¯q×IÈAŽ— ‰•iåN•@‹ŽñæbrâOG·Œû¡Ã™rZõè[­21¡tÉ2ÒØœÎW€.T/.ý U!™§2T†úÂ}ãÑÄBGÒ•€`/Qm©4ÀðIÿÆÊñøòé/gu“—Ó1Ã0b¶€’Ô¿N|´8 }ySãc[G©"x€§_!T.ñû->ü²ò}™8.³gf²ŠuJ0#iº´©I.CxÝâ+6J2ŸãQò-FFw˜;+’IjW\‹3,ø‹4ÜQÝ­¦óvP9ìË’·§±,9Tá˜vRæ“–ŽÆDÒlX Y»|ùnW£/4ù:ð_²·%~SûB&PÔ myCÀ ä“÷–÷Ÿº¬B9,Äí°R- Ï4J†²vSÀ › —LäIMIj"§ –‡y¨ç•ýQ¤ƒrž0Á¿“ËfëÚrRÿƒ*¥)aA#¹ny¤Üõ*ÜðO¨Žú€]´ü×=ŒË"ÄôP ä½Ê€¤!@"¨dë^­ðBß§‡éôóŸA—ÖŽ¬õÇ<ÕBöÔb“îÌ>aXŸir½™]êQX¨*‡FªYØ?À À¯%ŠÿI' ( `ÞJÄ('Ŭx« ùHx†Û'i×!)M5ËdþAÇ0e¢r®xãÝÁuªž£Ox’hú.‹%ž£¢ã´YéD² ÒNÓÆÈœ1¦GJtb¼©‘èC³–©§O$v¤Ã^$ÓWåU‹8å–¨JPr¥ ²³U‡#NÔ×Ë 05±˜Çºð‡ºõi° ô~ÁVc§²32V>ÖL¤pOrV” ³V²Û¤߸1'¡­E:âõŒQÅ“FwRHéhuÔ‚‹R-"˜ú°Ò_F5¬\Ý1hÒÂy&ø˜ÝÑ(&ô)NDUÕ­@G3<2©ßoúOöµ·5¦§˜Ò¶ƒ@‰àlîþJãù¹ dØÒióãjèYû …¹·”Fi9N<”nÐZô¦3w£øTHõV?²*нIà{©ë1–åß{‚ë¹xJ’ˆ[eתÉHcW61PÔ«€KM T½·«>‰ª˜È!u=7 ìrÖ'x˜°¥$’Û …$úNêý3*i—ÝSU“tÃÍÇÅ#PQ‘ŒƒË/ 4µÙß]´/Fp±4+Ó½7¶Í»­+D˜Èä v¥]ÉvˆVùpLÝ£B0˜!ü]HžEññÃbqøªH.•FPhœ,æ„Î'“Õh`õgPç¦:'H‡ û¦cÒžÚI‘ dÉ”$™.FÇbH1Æ<©#D'ÄW7õ^¥'XëÓåÌT‰ÞC8¤‰P¬hC-lÞOb‘˜ž= Ò2#YG¼Ñ@´²Z¶Sg³[*s‘5XªÈ[¹cF@Ï…P õ.i¹tÍÜ:.ÑÊÇ–7úË„®>0½"ù5ÌlïÊ<º«Ú8jUŒ¦EY—©6úŒåé?ë«&xp™¿­ ›I´üE5jµE¥WO=¤m9¼þ3ŸLôñ®ú»·°Û¦;ëU[ÁŒû«äff'˜Ï¸ LŒzª€Ï4˜/5g£Ôêy-"dL|Ö,9ž +*DEØ›Ê?p l¼»ý"(T¨ ÌÍ#)²…{øf¤*/b¦¸]À±ùxVÆÜÛ¬‰Jßèu}} /RV8ñF«*÷gL^ö·nZ“œUh“‚³‡=>Á9£qšââã6ãÓµ½)" rQiþ«É]C"Ñb±Æ¼ñºÎu­ÕÜ8dÅ••LøùY¯¨¹fê8û×5ÿ,ZSG†£¤2tf¹Ó©AR¥ÇRâ¨LiÒcÔݲš×NÄͪÃCäÔÔp²²ªHF&ñ£Sº—RqVY¶WÒV<Â4Ë@_ý˜‹8O ±*J©É Á±Ãº°ykÉh z¨h×¹l\39KRÇb¢Ü‚-J†$ìôô ÛKõ›gf",N&áÊÊ ;I•V¶–M«nõÆ-B€wYž“#±^µ5í!]ÌÌ€j.¥²ô.µoêù:fv.kdÂøûápKŒUl;/ ÉϦøÕÒ½SÙ— Æœzbã•È·|Œˆ¾¹|J&^?äD¼éùäQ9¿Z¤Þ§·ƒ¯¸d[IÛ5(uM›•báÿ³"‰á”øÐÎ-•2@pj©í߸ý\u~—2 lž•‹²Š ¾Ló|Û›@Xëc‚¶trÐõ¬dá;Y¾·Á+ 2“³Ó8ìwQ±_¨Ý`3>NþôN¤–í8ÁyìÜ0eB@ØðÝ‹s/²=?¥=ÏFG™@÷þAà±î#£3À¨˜<±ù'‘¨ç2Í2ù$’­Áœ_G†òùx`ˆ–döè^?‘gÔ2øvp¢“˜n|…BC˜èU‚û”î«õ€bÄÂ1Å––vÓpò— |è¾ 1,(Ñ? Aµ×²Ëæ¢[/n(¨€›,ƒó|Xª³`‚y›“ŒE•š‹û*‡§4£©~7n†@6Œùo"JÅi:FaIº#rÁ@™`P³òM9ç»"´èC¡É¢)d£¬æ¿"´åKðM\r]›’¤=Ã’ä_—Å{AÄæÀ!ì¿/ FãÄÿ Ñ€“#öñÏ’dŽiG•¨ð¡¥I}yàÓpƒèrÔ† ž>áÿ+4ÃmhU--Øà›>¢´Å£tñR¬$R¿á¤;óã+5M(‡´ýÙMIì àPr_§‘ÝÑXMG@´=¨ë1Èà*Ò<Œzʾß&3SâêÜ!øðH_’·^ÏÝè„·ge'éƒ(t¢°vìÀ’÷e$Y[¨<Š ÷R¬¼ÞŽý B_Ä’Åi(ù@–¤G@€ù|© SbÀH®;–Kx#~DŸI_Hê+8§~ êòŒü¿™¾³jz̰Rz1=ÙG»’à%™€óÀ4òJhTñ½%‡@nõ,:ü›‡QI~C܆ëTNÊyCu ã—PÎ)t«+ƒ© Üqºó¬§!ƒPB½¢­NS“щ%g^‰î«ã^‡·w’‹°ER¯!² ü·pl*À7±;Y>6 ×ÔË8hÔÑj¤qñ­+Ô×#€9à+pG«öˆÙûŸ)ÏG)ânë0ÿR¡HòMçØ¼“Óú«ºMn6ÙÒÆ>Ï•ü|Sä=Ç!Ýœ‚,:¨?ÉäŒKû²j¯=ÖY¨n‡©eGT)å!éÛ‚OôBì '.¡7¯ ǧȓËxWøê°QÈ pöãøØç¼ /îÌÓÁX"ðHR+`’‘Vŵ ¶¦ >óËÒ,Žä±"À² #ƒFÝ~mI }0Øä‚¥:r¥‹1fnJñü0þIž{{Ÿ†Æ4BŽh }Ãr8±ŸÇü@R¹Ó˿?ò¼€¼7 È÷ã‚ßû’ qìx‚»8áøUvbyب¢AÚ¬ÑZé“•$”N bÇçäñùüò@õéâ™j„Í[Ü•^£ƒÛ–äOPX|€?‘Ïéê3 @pÇßþxö¯õáO x$ûôÄðÌ·,į Ï'Žrx^xìqÈç‘È ÐiÕn³ÿÿÀþ{’Åy uªýC>aúHZù°¤s\ ù&ÏýÖ.ÜX˜é®ï±ñ°¼ówV7øãŽoƒÇùЦléNóŠMoúøÆœfŠÁ¤ œtH¢Ž™Y›§u5ùdÈg3KÍú,MèD )ãnŠÄ©wá½çîÊêUÛÆ‹*YrÌ\ ñîŒü·Ffdì¬B‡f.?üSû=éxš~K0î$1jåEª-VB‹†U$’$Êcú2¸êä÷ $2óaýXQÍXüzØ—1áFX퉀Ve«:q¨ iSåÀ#L>Ù´¨àì.’Él›~EÑ–³QP–œêÞ5 ÝQÞiE{þÁÉtùú+þNe•Xä:Žà§Vü’–`¡§²™@ s37= gW Û±«¤céš}i†¸¸ÔÂ1ýiGœîÍ7ÉENÌÚnlOC_~Ä1¢i/¢:y‚ågdY\Þʤ„&îÔ>%GZ(³:¡á"‡á\¯9ûɧ‚nªÓÙçz[&—rÀQ¥ ¿tbÿÍÇ­¿Û]‰V@ ìOÃ;1E'ad»QBÀ}ª5këI½.ì-Ž]¸“T`T¢:°ø‰«:Q8Z'ì-^;•ŸRWÈX¤Odn¬_§@T]þG°^ä êjߥ’3œKŸí7fâH=(®ËÈAé`ŠJ€%‚ÖrvîÈ„…¡Uç¤Áec³ßÔ·e˜|Ctu*½›žºÀÚbB'ĆBþ›¶û èWb‡ÆÊ©õO®ƒõZUo ¤pšâ¸;R·ä‚óJƒu3 û+åGRx<†¡§Ô•n´ Ÿª?ëÕ€ÒóK,Ó˜»÷Çaò!¯diuBÒ% I¬Ôñw Ʊ$õª•NÎQ|aBËÞ@¢Lr]=P¬½Ô¤þ¿Ì+(®gæf±“öÜ?w=¦`v<¢/ÔÔÀ÷£R‡É¡ä€(‰Í]*éU°?›cÁ/jjsÁ"¨Ù'e¿·7Ɇ°#üzç/ÕìiQÐò5²2kÀTùM–ë_!´¨Ö)> ·uy8”šIÓ­ØÍÜØ{ÛdzrÚm[néóÛ¸¾ªÞ9Nï °ïã+Õ²F2…nW³VÝ(çªú„eê]èéÇ‹?"Á’t) ·#³Õ\å¹¾.à" …z"’ÞçÝÕØþanT|Økt’ìÌ6§-”[¾v¯|{ÁªØpž:FŒvK<{…ìðí>‚fþßÒ1ŠYñ!mYµk‰Ðš,k$QnÌ¢Å΢ÀOtåÃL¹ *¬˜™Y5’5#½ÑJ”¸“´ìP'ó¨?«hú.îÞÁÖ“LÒ02²SU{[Û'/ÉÞµgëOʶIðÌÔ7›†ðƒb=õ÷PÖqôí¥´«‘|Ì=©·õœ¬,iÐô…5lÕrXÕk:x1±tõ ñR¿9G;w?XÝú®™¥éøîçPß:NV¨Ð•c•›Ÿâ-“Z5(Ñ›£Š–?öÇ P3y((fûŸËÒu_W°õ]"š¥¢.‰‡hcOoj §²È-'+éàµú1^2x±véõ±¤"/¤‰š”Å+¤@±û6[î*¨yUµ6¼ëÏÈ3eHc‰œDZV˜ +Ž…ØšIIogà#+$– ý·b­uoQ5·Xù´í­œô•z-¬Hñ3±*V)G èxTúŠé,û‹JÁ’éØù:¦•\„ÄÉÚ9Kå%f4«IÅÞ2-ÖlýžnÂ'ûÛ[?|…õÄÖ4tÂ\•Oר²Î\¾ÒI8ë*Rô©1ƒ­.¢]»¹Ÿl¾¨Gõi»‡&yâ9›cZ¸ÒqÝŸ°£dRbTpª˜ðš»õ ø..&Mo¹^A˜Óe‚l QÇ’©þG â5‰d-wMÔ¶» P+|“w¸÷Q –è¯~zéšÞ›úR˜ú^vO¡Û#PÏ–:ÛO·¶çÃPÓj' }?"9X´„ÏJ/Ié·ôLmݵ±°ñôÝ­»n¯yeœBÝöźîm/NËwnàÃDÈ–-ßÇ!”徂¾²úh7wÛö›ªmËf WÐ=¿‘£áMÔCUž—¸umeòÉ‘å:ÿ¸~b&=hý’ÖZ;öÝ»÷vÒÌLõչе|¸ê:6²E´ÝOQÒ(©—§<[ªË#7–ÃÈ V'Áâ»J Ø¦\qã¾Á•I–PŬîÄ„êçIkS!%ÏyB©õžÃÑ`›¦æ )°ç9Ô =øÛDue&¤Ô˜Êjñ˜ûñÚ–®þÿÑw†™³u}3nbS ?XÌòjÚâ̱›éùJš†› ‡˜¤1!åj †ÊjÝ'óe “Ò=V;ëÒÏSö‹Çð'¶v棦¦VNGQÁ޽••“«d;šŠ©Ôp#„¤cÏÁŸŽí”9ÿzé;¿PÓ+©ßOÛøxXšv&ª+ÇÂÔ§®¤¯¥Vz<Œä‰LRÑBDe* ë_tè†Íô ik:ˆÜz>åõAÑ5-I˜4ᛤß\Ò%;Õ"µxÞ¸•:ºƒŠr$”$—j¾Üþâ=ôÇì{zo­íµu|l?Irï¿w*O:ZÍ2(Øzn.ØÈ³ããâÛWÉÉÅÓ£‘Œ2+’•L‡ÇtËÿ¹}…z%³uuÐë©zséÞ°ÙùÚÌfk¸¶Æv§§GCÖô|¨Ñ"øëœOª™^£Å)—ZPÿU}Rõ_Môž»[HÜ:ü}ß›7`é^¨é™ºdqñ2²v†Cæmñ€m*WU¤2òp² uŽrÏâ„Ö îÞ››îŽ•ÑzœÙpÈÓÉ…Ôe‚TŽ9ã|(àËx c–ti»8å`˜¸e½' >¥Ô¡ébn¡7·¥€tìžµV驼£#,N¯,ƒ$ì†B¸9bX¥c‘݇2ã«ÿx_s›ïî¿Ö]GÕé4„ÔWñv®‹I.…´0ònº‘‹&” g‡I㤿(*8S0<5ª‹¼Y”óG˜¿o3Hž–Ç!,d^d±DIùpqæV’=Ѭ^m[ñ°à™3Ž>.ë¥iرž.Ÿ„,Ê|xÃc‘Vî¨Y­ÖììÙ®[-m‰4 œR’§†µy[ÎÎì¯ãirC±÷EéFþÓñºOLéÝ'pððñR(11LtJý)rÒJ ó”Ù’Ey ÜÕ\„Êy²ÌˆXAZ*°HÖ5Ò%MR ¬hÅtNØôó¢F¯¦cdµrÆ,5hŒÀí$Z¹F´iG”ÊÅ(½©$n^T“+.«“¹rºÝLüm—fIXŒ™åÌ“ºQç_yÑf«"VÔî´"mì üX%ršŽy‚f‡Lv0ƒY••4ñÂq.¬ÞXâc«U–Q ÚØÂÛ=«Žò«Ï"äÏõ>V\ »Lð%E’„qJV=š€åC‰iº›ð 1°ûHÔ3ÐmM“ä£_þÖÛXk’%#è÷dnÞŒ¦À UXŽ•6äþuür[üÎÚuj—½/ŒÂŒŽýuª¦@œI^n•h+qòGA@²³»i:Ås%D¿™r'âQ²-Í$qÉN–U,]”«4ò•)Ø7iU§•Ó'ÃW|LâªÎV*í[’uÇJ*EÁŸRæUt?MK•‘“ñí7’°´ÈbI‹ ¥†î¯D¡E*U§™ÄÑeH–74J‡J]†µnOkäóëÌRE²=jNêä7-¦§‚·ex+µAÈ$de ­:1µ&«E|qQJ‘Xl’€ƒO ãeîI.ÏFÇn…ÿ6®¥™‹‡d»K3M«Flæ‚3çâ`áãò;®Af~ªGue)Äš¡vÊÃí¢ZyŽØÇÎÎ0ëÖ/'Wi­Ç䬹›²µl‡àý¾–¬_¶ÂºO& øy,è"â,É fM^´*°.©’Ѽ`Š0¶’BÂsqd~@Ó‚ûmóû¬x/ÑžôLQÐó"TÙ:è”!ˆÖÀÔ’@õ7Ðõ+&òÏÅÓk“6bÀ=n Ü=O4sE¾¬UI@¥T±+®ªFö·_ËFí~¯Þ‡fù4ïE@AJ/~ÉŽŽÍÿ­$ª?«w^½X«,]h>fi>…^àMú¨bŸØurª¥I=‹|zü›[}èyòZcçbRÓSiåEÕ]’sW^Ùè¼Eð#Æ‘85íÝ˦ӼÆl‡vkƯåUZþÎJ­jhîîî¨x*¼Oè2D@;lÀ9Ù‚ÃÍTƒóWgo’6nh8åÊÈ$í8.E¨.¤•ÑX„¢Ç€|@µv>^¥ºNÖMJÐ%ŒÃªÔ‰ù:4*Ì€U›”gèœ*­Óêc¤lIág{cIV®;Z¿ÊWšrá«×äÊä«‚óá˜ñ=YXÓØ(i™“20åÔ+tf,8íG@¨â,vÅÕ0õŽ$³ŠÖPA’½qfuìÉÇ'§™Ù8'à½9˜£!o¡6€ÃåoíâÍÝ0UjM}§PYB±Rê]S>_처ÜCÇ¢Ò³ ^|‡$µ° ”; C†/7Æ’ Idµº G3Z"ð…  EýG’ˆ´b#ùpáÒË,I4¢;ð†<³hö J‹wO˜U¯\” ìDÏ’–;½¤fâ}WÆTŽ¿ù‡. ð]UÔQBòÊ9¥¨l×õÝ0i·”ç/;*;åØ ?\ffeåP9Z· ¯™1sO*…FæÆºF¦ Zü•)OÀÔ‚ ˆV^¡œ*ÒÏß`‡e*€ Àßܤ|ïƒBëþ¹Ž¶»Þ­ðÓ¦Ý[º°ƒf³Eû ê8u%)N Ç5_qÞ¯çz«÷5ºµy_'lzk§î-o#½e%†…hj´xò5³LŒlƒÉ\%ND‡]ðõÃyemßM7v^™A-S/TyÝ-ÔâääMÚ4B¯dòT!¥;+NgØr‡–M¬ù'OݹW|ÝaÎeGÎÍüÌÎ@>e£~*ž½z„§+±³jÿÓŽŽ3rº¾[&Ó1‡5u d‹"oåXCÿ]¹ó°ÞRL òp4 Ld6©+xÈ ÈÁ!¬…PàžMY{#ý¶óñ™w’n1ŽÅb2wnƒQJM%x\ªÍÏ™”11Ù¾‡6ŸþõõªA´Æ{FÁ•|o‡…–Dï1ÊÄiIàÜÓãs5ñPØr?}W­|ºæÃ ÆŒÊAõ@È!gÅV6R¹/PUÒ·9 ÐÍØ îS×G7\lt5ÿ¨%jUƒxã@Ù %Dñrñs’O¬•]Ï•º¤Š" µsÝUF²ô-Osu¥ýº®Õ±¢é½[¹#©ªîD †K*УË~ Q^ 'ʪ½W¦Ä8»ÃJÖ”0}kqmmÃ¥²‰Í¨2µl,ü–æä'¦[#P{ÍV…“âôŠacã¾ßØ"„›®…Œ(ÉJ2">‘¨HÈe<ªMgF(£ñ¡<…nÝ1ç‰é{S)òŽ‹·±eDȓڋ±%¾TÆJ¢û¬•¤‰Jhý~Ã#vÿ§Ó¿*ÓÚº%ïF,ž]8VÅ‘õ$weŸVâ´!ÜžÈô©šÏн¾\‘¶F\?‚"Ÿy?žynl;Ó ÙUË/Vƒ·÷,,å – pÇñò€³(â”]:Ð×ltÏ™jÙÙ™6^¾ì˜Ðz¾:÷-ìk2¬¦~D>e'–@¿RŠ —Y°¨($ÿÊ•ð9V U»r£³9Ÿnõi‹NÓâÓ*#ÇyÍ ãÍ©@£ÜLÉùuçᲩ˜W~>¤Ù:æJ:N¼ §äÑRh(•šÅQ…œpxŽ ~7VˆhÚäµUÙ•ö…vM‹0UMÞÁGu)^L܇Ó3 Åí¯sá§àZ%UO¹d”֩˸æ ÅP(à†ì9óÿËv ¼DæÕj¨Ì ²E”7tV—šr&¨Cö’¿Œ¯òIA*ˆ´(M‹‰.<Ê E^VF$-’ºÐ¥;2·,Þv`¼2äÔüDzŽÔx4$ ”Ð!,•=‚påŽ}("ʨ&Š Å@_µ¼ˆ -dóñ°®ûFtRí±ÔÑåBø›•Ù¸³KãÅpB¬¡ØËÆ·¡Ú¬½•>D£³;g>1ܪûXuuç2Èð( )Gå¹|M9tEí/á$ŽU OŽÌíkq0ÄöEílj^E€JyE”øÛ½A%Sß©™!ˆ/QÔ2{{°P²b ù }‰= ª…F_’¢ñÚkÂýYʼn¶;**ù y2’ Ð49Z4£mI$‚Õ^BýÀš²TÀàX¯äšUm«p¶ úlʺðÄxçØI™ý!™À~:•`Á¨gEd©5R$ÝïV>EaBÈôêM³³—€òH RåXvSÙÝÛæAöVSÙdUغ¨~{uïOfY¡ì‡ö2²‘ãngÃ} 7nS$²& !ñ {¹á8D™D’±!õœÖ%8è bÅúˆ(50…¾xŠ›k¿.u6Í©$z‰f`¾'™6 T6bv±ð,i~9>¯?øãÒ²s÷fãÏëJÆU‚#0y>~K)Ñ^ɤu—9gP7Æ(e #+ÔÅzŽqÇð s¯r=¸^2ühm“ »©ë—ëÔ3ÀŸ`9u‡·ÁŒÐ™«³ðCS€Ä5É›au&IEDÉåQ”ö㞃nO¸å¸þxì¬7ÞSC'¹ºä‘ݦˆ¥¡HQ€Ç;W[JžèÉyó°±ÍbŒn¹­ª‰rOÅÿ˜í,’¡<ªå¿°÷'°ä©ç…ëÏ%W¨* 0ì§ëÀåU¨Áz’ÊC{{ü‡_b?‡“ÇðOäy_¦åBì}‚‘É »=‰>ÊBð?ùÿòHO§X¬Ç˱¨cì9$1?ÛÛ³à{žOÿ+XÙÅÑ™¢²8½yÛž,‘¨¨IôâTaÆçÇš?+ùæ‰øâÍúo¾;¿÷î{ŽÏÜxøç’Hùz“rÝz¨úLWJêIäüˆ%¹_‘$û{ ö`O®v_Y*¯P}ýùöëמ=òðÏbxÿ˜–FX^ôwœr³gëÉ<ìAR ÷<Ž}”qÕˆ õú\¡ø¢°#REö!HÔðTŽ‚H¢Äѵ…,Á,0ûQwòW5óÍÿÑ?ŸO-³ö*ݹqî\óÇ“Çaß–nUHWù>6ÔçÙCì9,VëÀö$rcÉ zû‚>ƒû«Õ-³³å[ëZ¶$dG{dÎh« vgö{ØCðyà~¹ÿ•Ï·J£—»°õmNˆšn”é›’mÙÀHü‘ eì —~JŸXiÔåúN›‰Ÿ™Adƒ 'nH¯U˜‚M6‚Τ šºµ:ŽZ‰“ pP6DDZ¶–šR#_Í‚ßýþ¸Ú>\‘˜#õeýq9(ÐQ|•ººÙæ Ôí–‰áívDi˜²²cißœ©ºør 2$¬Ô÷)"Gr™Ç‰©7ZH£,Αï_¶ ͳñrL1§•ŒqòZ–’RymÌ¿’r2k;Š-œ—ŒÞaJs:ÓÛ°µ ?ó7íÜQS%Zwâ¯æö°åO˜0RXö4$µº/ô_¬âäH¥UvÔ*±`Rõ`,ŽT© × QççÓCb¼±z· Ô Ù6 QÿÏZö–KBpÔ#KB%f oö’£Âƒ[ðÔ9 ®‘}4¹¬0²³(Pt_*¯ ŠOÉHBýOõ, ` XD˜:ö#¼û‚AQ5á§E@:°êT²° ¹rÇê¤ú%ªGÉWdtP «„ÿŽT7Œp€ää‚¡M¥ò¿È{!™Z`nz¿@ Ð+7€#&f¥CåŒõÚAnÈÂ0Á³Àv6 7È¡ònËu¼vLâ”Ù©JÐ Ì>n¿*­@]¸H™kL{!UgnÊÎÅeÕ9ùPùu †Y·<*ª÷#ªV:Fr«³d¢*Ìþ:S™zðO$+vFR9?W‹ò³¸¸ÈÏVNd‚S ¡V"‚c«/N{rœ|®ËÊ1Do©°6{ê{£Ö7É®6†3ðvf˜']_qç?•¡…˜ÍÞzv›Ü'å3þ´uXùUx“¢tÔ“2 òËcôä‘™- 1!ÇŒ¡ Ï1$iHþTHT"éN•$­«åeêÍ‹ÓñnlÌ™-BF¤·U‘ܤ1dšHÑŒ‚ôWìWCݺ>ì~ë·úqöù²æãœ±iê·9S¼4M·§¡umCX£¤q´ütódÖ’«<¢ê=ꇧ¾ªzÃêÖ®þ•ižŸl¯Fý'ܺ¦ÉÚºÖ§‚º¤Æ‚4§\¬wyÿ¹ÝZ®©®ÓPÔ'IJ•ÅÅ‹G Nl¦ýÓ}ËúÇ÷Cêþ&ƒ­>V/§»$f6ÀôÇBÈ:~ÍÛÁ…kªf`Jmù9˜PËÈÔ5L¦95rVœm30o«{/í»í[p×zÛ5}õßXÒoÛµ³vw¦XÉ]Y£‘=DöuœÓÙX¢žV¡íÔË›l‰~r†Lè}/¼²ãÃ#¤­‘›$&&›+³‘"8ÅÄF+ äȯØß¸©E›—ÔÝ3¨,Ãècwl^›ŠÍ ËÙf(gÈí(Yò¥‰‹3¦>?ÓÄLytÇÑ [TÛþ©iØÈLfÜ®.F=±rI²ÖØð+Ù¼Òi_…5ZTŠÛ$]¨ãÒ¿Og0HÒPÎ¥u$RÜ<†;rÄåÂ8R6Ô¿Ü-´³§‡Õÿ$jºÖ?bÕ®H•2e7§<¸Ñgž2Ìãyò^•¸+ ]ðõ,dš´­|Æ´|“i»Œ¼+¨YY+Øô˜i ÅæjG*ç¿JwŽ•©z¥·5+d÷À¶ôƒfR«LÄ8Y•†\ª¥Võx*TJ™[Ú}±âÑŸÔËÕŸJe¶·>äÃÁGÇÓ&35,JÏ ´ØgåIÓ®F>K~*ã<Þ2“ãÅ8“§WW[¸S}$ð»_2xà(ÅÁ ˆøZ ḭ̈™[]|B+ðh¸ùÙ’‡’7Sµ¯­¨ôUÒ3>Þ= Ú›ë S;ÒÜm¡—e øz^¯¨ê:~)\d’ÿæÕÉpÔ9i~´ç9½vôÓÒÛní¦hYúu4íGQÕôícTiôÕ´ñ)†¦ÄÌúMÔ õ-7KøP;õ‘ý­ýÀÌï|¶R%+àbéú.N©˜†X·ÉÁÅtÒ_.´oÇÆÏócÇ öÄÍL6b zýX_^u]±«m-[aú÷•ªh5ÃË:o§ž£éx9­cŠ«©´qm$¶'ã \·¹Êêä”y›/ú‘”–$5ÝÓöи†XŽŽR„mÛaÝ9ÁŠN‘FùóJó¼1³9Òy¤h2 D$ɦò.D@XŒ,ª¬#¯AïK=eÙÛËЭӡg.m·Þ‡¶jšv>0üµÏ¶L)‰›K*,LßÍLz"ÕÓýNûK×ñç»´]RÚ°Y´~6–T¬2Ж®6U§ßõQ„›’©`³ák>6£ç—AŒG[ñÁj:„ñ©ua7gV›†F÷±î_§¿¸¯Sý=ÿ®ò¾Þ½~ÊÒ7W¦ÛŸT>Ÿë{¥uDÏÎô×YÄÒF>¹u{,ß)tëkŠÿoׇAL¤ªŒl üöúíè¶·öïë6§é–¹”šÞ6=1õ-»®a:iÛƒmêfÇGÕqo!oÊÇÌIJ7ä#º œ‰ø('B â΋7 LÚ €†StxÝA* hwbÜhX€êËRêJ—cèÓåŒÌn“#Ï98î½Ð¹8ÎTEg“µ,WÛÈ™ŒLQ•ž9¡&Y£G{;5$dãijœêf{eY¥ƒ?ü)äg+&zQ{r|98äý1{STÜÙǽc·u·´­O1Š {À\’VœK½#ÓÌæ%ŒY¾™:»K7— 1Ñòôù,ijBÓŸ“"k)ö[Pyš*ˆ®¯@`Е©#¯H#2ûÍML§ÿInÊLwí{@ãæ#â_¼äìžL¯Èá¥ÿr„»­ ¤B>"î ]/Ö$–5E£3¿&Õ¤E™\ü*®þI±4!}ôÌÆâutr¥’…À*áX¨'5‘w^‚‚Á«Ãαæ˜ïÅK Š—Râ„Z¢a¨ —¹þYHeWeVvP N§žûw›ÑÇ5‹™9V<ê¬Ú€ÆÔƒä¿; ¤éâ9clrñIºöƒ²KÚP¨ÌWpåÔØ5ä m´4y-ðuL´HHäfxpáÇ’Aª–P¥!À#–(§¹ä¡S °ôÇLÅÔ2ÞîµzDi­àK‘5$ôø©N8UÕsJÏ0“ù]È™C"Ó¯Yö!¿ª¹äRXû§©[m{"…¼oE@Pc©¡æT»~Ò °ƒ?ôCå_‹7j‘+ê)¨UR¸èv;o÷‰²ö9ØÚ‘v õS7)å5#×õ$JumCk ßÈg±JŠÐçՃɾ‰ªFR¾£›ˆ½§Z*¢=tFöZK7@‡åÞLyD¾šòýŠ#)ò!¢³'_«Q¹úéÕ¾NJ(¥7!˜+1Fã°p9+F 0,ýÏŸ«[éæ ðâ1@2kâ È3UXÈ”ÿVg=‘ß…nü··ÄýBrû0HPî Â„?Ë.#VYR¢’îý&u†Ìé8lñgJ·äÇ+Ç,{ÈMQ ìj”ŽHº¥ë·Ø¯ªÞ¢úk­i7qh𦥓DÅʧŒª¶#Ë­ÈJ4ÄÈ¢—.ŒÄ¯×9°ýŽ}Ä}¾e2oÿMµ¬]-kjSWÒ0ò³4p@{V¸¢ÀÃfìÎz;?u»lâÎlðˆ ”uV ê¿ÏV<ð¬?qß·v"a™¥èúæ ´½oJÓµ½;%¼y8š–2ñj…>Jó´ÂÄu~O`G<°`¥ÏÚÿÿéi¦AÒñ¥ÆÌŸê2D-,y@ ­4ͯÛO@!P•cŸ}Çî¹ÕŠ&Fgyq±À²Â‘Æ6uލ£¸T33cÊäo@ª¿çÕÂK–ˆ«ƒlžÆÞm šHSÙ8‘š/BWÉ`¡""••T鎗^ƒ´‰ÏÓm‡xã²»¶-Žõ’ø‚4dLtNòCÕÈwì“îKü@}ºúÜÙÚÆÄÄ—¤ûÊí{­#'Eȵ]èV#tìü3Òe©ÊÍ›ƒ4éͧÝøçû”ûOÊÍÔõ½™ÿSìy×Ç-Ý·alÜÆnŠr3¤’j@”öåüå ÓËÑe7ž™ï_oû¦.Æh-†ÁÊ^Ö@í²µ…º•x;C+¨ZÒÏÉt§Õ%ÎÜx¸™™­=7”¥1æi6ª¬93Y1£)K-:7ˆUãªu‘[«è·‹D¥UŠÇã° €½º )¹ <˜5<Ò­ú±Ú”çMOu/CäÃÕs’tH¬†Vçìc! Ì,+DZߨIƒ:O¹ñÁ4Óc¢êP‹È˜hš«&%ª«ÄF$¯pYî>F?dîMRžF~þÑú“î ÅÇõy&:É鋸FTþlój_3F®=|5…+bVÄòÌÝQ#Á4œ¸ããjã$Ânvæ)CÆ^epˆd§Ì’Ÿô™ JxÛƒÕ HBÀĶÛÔ3ö›’Š™8ú¶Ú†*…ä-¯i™2HÎ5ð®:=I£åjùV³X%úêWÔ-fzƒ*£ö¦‘±¶FœÔ÷NÚŽXjPK«OSÙ§AÌè'ÝK®h}=¦>àõÒm ãÎÔ7æ×ÆÍ¤Õ&‰§¶Nf¡‚è’¡`ï,|Œ–•¦zœqU¬Æ«“YÿÜ–=¾IÎ]Tš«O™IKt ÌÌ<€/Z{+ö nL«eeE5M²YA$ü¬ý¨©ðš€8FFbÍÄÇBÆeOÓJz¬š„üI?0B‹Â a8ÖÜÌ«t[“žÞ?çÉÇ`BÃÆÿÒ2·6“ƒZÊYÔñ1Êz3Z¹(“¶ùHûGQTEgþCŽ bÂQ¾ «´ Pm²Ø` SÅWÄòlˆL¨ä‰Z&6Ëø'oÀ®@°VüM‘ë§o³ –»SÒíµ7˜Zk߬‚—­”V¹D^{¹íÂò ‰ð[Ÿ«aªj½ò Q¹ u>ëÇ«(ûp{~@vÿ‘Ç èV¥Ž6„q^o9é˜Ê­5 5n“ä«Lx½Ë7º¸#’8 Šäå³~L {ò¬žå:·¿ð½8'XŽ£–㾯ÔåÉêY|žöFfL’y»4˰cD|ñÅ ’-'ËÔ2§•ib %´ß+Zø ~êF.Áªž²uPG!œ‘ooãž oíÃ{Hçé5µÉb€ì¿ ?ç·¸ç¨_wíÃŽ9úñVA4“Õøà–÷ä©eìüü»ÃŽ;#/ÔGxê)§Ó-,‰â“†*Ày-ñb‰UàòÜŽ{p§åIª$lDž?)òÔp<¨‹âƒ]ÿänluyUXmn%X º'Ïä3ï=ó bÞìÜõ'—opDÀR>DÿÉðyNA$çë¾ô¿Èü=Ó³F—'ÊÔ‚Qc!Uñ3©UO“)g >L“…à–QñúüûáûúÙ^†iÕÒóó'©ëyRqƒŒÂ—RI’÷·¿*Ä)UR õ>ÿ\¢zÏêÞÿû‚ß:¶JVZmr•ñ`Îx„Ð#°±¤ñüNÁ,h±Vš VO(UdÚ§?Ó÷EÔ:Ìs§FŒï.L¡\.cíCŠ*­ÛmQY©îïKé=..—yãA6T‹xØòy–òDÊ ùqD×kÑ×Ï¿_½zÍËÆÔwf©¦é5¦eFÒu1‚f¬ÝãæÈ YIUñí r(:F^G“Ò°íý“¹÷&3ò›2Èj kPç»3YÚÉß¹pþwAãVtèõÑOaúa‚Ùpób° íÝšk7k*ùL„È*½˜ +YÂÈe;I‹ à6>>ŒT”¯hÆ#¯ÈWEW„ÜP÷”ÍM|JÝ‚ìý.2ú'¶!§{k§â`Æ«’X Ê Uò`7‘È«i-ˆâøôc¥guù=Vy%‰B˜0ÓÂòbD¤"­ Pµ,@(y­ž¾ÞÓõÉeâ&4ìŠzŒW˜ebqû¹VfQán‰ÂÓ’ý:¥+õ“í®O‡ÆÓú# Ò“¤jàW«žA"%ÑÛ„gʨî8uKi釨:¯”ñÓs¥—7å²y%ׇ֯¢u‡U2Iö?ø¼œ/±63WÐñw›•Yã“&à:ºtªü»ÜÍG@z‚H%• IqÊÑCN”䑊6Ô_ËbAþG¬KÜ9½5`Ç@ªÉ $Q+LU¾ÂvºnlüÝ_7Þ¢úpº&$a48ÉkKŸ(wW¬×ç)+iñ&ÕIw.¿©…ßn™Ý·Ô`â’oÍÇI̳5škMø9Z”³ÑYºµ `KëOÝ/£/… WSd|óTrf%0¾NÝB9i¯È²°j•—(k‘þ†ã®?¬9 ݧ‘$Hµ ³²­n“eêÄ¢pÏ0ËE Ô©ÕE”ätn½Äw#Çw—äh%xžü]õ¼ûw©EÔ&é03´mÈ‘Uc càÚø…?´y<}uöè¬t=?´j±›!šqω¦¬Ã–ã‚H(Þê{ |ºÜ|vªsË) ¯Çº·+ä޽‹0 Å{#¹UA¨?mÍ_ôØ,Hk<åÁ¢2•%eVR€*wnàö#“ÛáîMà8ߪ%T7 ª‰¢ Gà{Eeõ*ÈC*©?<ÕÙaÉhÔµ—náƒPª Õe®€ò­­Ü‘ÔÖö³ü€¶¢ˆ#…òYçŸæ–Vvžo|[Y¿‹/LbªÜ°aÒ¼rnVu&ŒLÈú§ÿpù¯—¦j Ʒɹµ÷zµìÝE•˜T0ᛪøèOgê (äO§‹“Ò.[à¥xVtìʼn™*I ÙY}È`Á¯Ã½vÔ±t‹z“±[r(]þ©Ð×=Z"Ñ|_ör®@ȹO˜ê¿¢Kˆ~ è²}WTÃ!ôŽ2,ìHí#+”Db£Ro¢ÛÃÑ^(¤ÍËXUå‡iMAy 0†Aj¬Ä@ÊÀ$S läÓýÒ}Ü[uz’˜ç3ÔßT4¬l¹[×5½0ÙÔÑ÷¨?‡;‰½ÎfN¡£íØX s’)¬ÆLMQ~ù}fÌû‚û¡õ“ÔãM+SßZ¤6Þ“bâZNÜÑøÒ´,(â&|ú~šh'µÕ)aZ/Hßä[QÙ¾­}Ñz“¶ë¿rvNG£~‹gë›L­Ÿ¶s4­­·0½NÜ©‡IÕ<ºŽ¹¨izNqðÓò¯:ã2—ï3É^£¼k½S\ÀŸä›Z¹Y¸æs(¯($êèóµÝ$ò  ÚÏä¢÷'±£\™UÉT\œN›,XèåâÁÆÊ•²1ÈZRï62ÆZP\ÒÇÓvl«æIÔ ÂÌÈÃÔ:Ž:åȬ_¦Ì)0e —ZÀŽ”…Ÿ<‘ (¦\¼|*01¤«!ø¦µìßWìM•øO‰H­xì{ù%Ý—ë_¾Ù}0–ëù;vhÛåw^ÊÖtü ¿“aƒ®è[¿TÃÆ‹!ijЩÃC©Oò1“ñò'E¢ò ï™ôþÚl¬T¥ 2-ZNŒ}cXÆô ÃÀf¯ätO$D{v£¼Ñ•JÃJÈÒvÆ“µó²tÌí»ùyçFμóh8\ŽÞ$—B/## Ëi»JH®¹02¤N"%å ³<‘p¡µ!À=²Ho#Š%OàØÒ¤2Ò£Ð_0ʲ+1‰Š’uî)²võ?ôwì—î |.ãÛ§gí}'%òõ½Ï©ê˜ÿë°0ᔎùªœÚ‰ÌÎ!bÝÊŠÒ ËÕMíéÖ³êûfa›j;'AÅÀTÊž?ëÝz®›iW5tÑO“#2˜˜ç-•?A®DßaU5ß[õ5ÚzÝÅß»³UǶ›MCOÈÔòÓúƒôü‰Žl-”¨Á`íFœêëIÈŸ1?LÚ´wF‚š>vëIjz{I34}3W¶B‹˜&Ÿ•,œ åȹ2Ç‹Ú/üƒåGdZXú”ÈmÚÄ‘òLÌÌCnÎñĬ<ˆí¢lÌ)=F¸òGm&OqŒyE‚1+ “r;JZ%_¹D@°;»h¾vÄÞ«}Àê µt‡ÅÝš®ê¦µ©¦›‘|œ ¹¥æ4ò“òócJ$Ž;ÎyÈ:2PN¼ÊèúO·ýÔ5=×¢z¹v¾‘ë>FØÔ7‹OqÛQ¦ZÇ0ç5-‰¨~-F·ãUZ±9!Urm¯¹ÏdÏÙœím¯²ò÷2ßG¦n‰§ä.¹¨dRôõ Û6ÄÜyu6³SÅ)k´«ì[uìoO½KÝù> fZÛÁ´ÝWiv9ÚvâÊS§Æ ØÔÎ7|œ¦óªM¤¡ìô£†ei6C*CŒ‰¯rCõ†uØëaÛRl§}Nê¿'P‰~ƒ!åÇY§‚q Ȳ $3!S“ Õ€@ìÌYuxoNýÓ7UôO>½êŽ«·²¶¦>¨b #ÓÝSÅÈ–Ÿ|²WÁ©kË›jääÃL”®"×%Ù_è9èÆãÃÐ0°¶–朲¶.¸]t½tN9ÙúþhÞ<´¥?;lêYþXㄈ¢ÓqZÚF¡µ·ææÙ›üå¡]TGTÌ¡°ÖðV ÚVv zŸ-q/#Ydw|Ù~Žž“fé˜]v®³™ ¡¹rÿNÌ·”WKÕê˜Í ¨Èf1Å_ä‘èÒváÒUj—Ã%{Œî†g*_DUU UÛÐ/é…¡&ä™·:¯oAÓaFLÛK<ŽÉ,™ná*&†˜ª¬ IŽ%Ù{nÝÆ‘žRÚA²vŽ«?Pö4Ì9êûkTÆ®ƒº4(ÇÅÔ ;`jøeÚK­éY¾:„ÈsN²µz”õM‰µmjš&2ëyXâz®ÎÔr*ȹ£ÓZÓz4© Rt”%ã^¤ÑP ³µ‹V¿HwfæÛ›ûNÙ‹&ÕžS*a´Ë E±±Œ|0È´”¥eâóÍåRŸ‹$Dsh-ÞÊÜ©²´ýË–Ø1Ö2ôºË\Ñ$À´é—¥ã#×MÈ™[>*ëøŠø­xM§ˆd„Þ+å‡?Ï'÷z"¢0¬^C"èUv ]ÔxƒfG­L…g2LÜìL˜R9\G1Â<ÅL‘Ú–RYWá’)´ANÞeú߸´º}™¹·Ç¤z†~á=>ÇÇÝž£lÜ-àj[÷AÒ?3Í‘‹ ŽrN­¶%[ànM>LÒÏŒæl•{!H¬°¶ßÝÏÚö£-¢OÕOC[Ý›{´Ž~«“µ±ðp2wÎÈŬ1±²r°ð2²rw†ØÅâ¹Xø£YÒÀTÒ¡_Eôã^ôïSl}Çzc“éǪڪÇpì¬êDe[nîªáän<\ Ø. ˜˜yxÚã~04ciô¡6_©ªÖô—í[×]î‡ÑÛß#ÒÏT}Fڙϡác~FßÐuJãë>²l\š|°Ùòt¼Ü•ß’˜ùnòñ”“¢>Lc5éÊgÈž>øó©q°IÂŒ¬ÆË·šEv‡çÎFrBô6°ó9ᦼ«š­:§Ç¢:cþ£RÖuÚù3K³€€ÌÌÃí™â޶‹bäTUÕy>&p®Ôú+}îz@Þ…zûê'§XÖ+¶mª6éÙ—8Ñ8Ù{+vªn ½•‰Ke‰u~qŸltaC&ó#5Z€cé ‡}dcæ‡TÛ 28aËÖ´~¨§µ•l–¿’…òJ~ÌótaY8(½9ãæb®ŠÙYò‰®VnC7C`õ¤°¼”ñ=)*ùHÓ°òˆ€ïã_¦ì1ƒMY–U+ieã\˜à¨²´è¢n÷qÙfýÿ*‘Ø£;P©£ $žt,Fà­†E€u-@ü}ÏFú‡&f"0­!FÙÂÈÊ"×gQÁ±v n>I6¿+÷ˆؤº_¹K‘G­±³z±pçˆÌcäLͱäZü$ÕY—†¯­ddx^ øwŒh¡™'~q€ I´¸y ¯±ª«;Hýˈ£Úy_Œk“”ÍUd…¥8c¹ŒÚO7¼rQ“Å&ìJªÕYVÇÆÑï]jTËÆj.ÁVY=/LmSJ¹E¤„oøË’î] {"†™£¥p¸]æ#T"”èÞ=Ñ ÒñûEí®¶(þn|Uqa¹˜5ëR•vfÈ-dp-Ac+}*zžÕÌ·‰a]·J64ãX§Šgò®MA³{âshÔ/!CžxE+ôÏFòEu\œ|̵êç¹\YÒõ[þÙti˪ӵLûfå-ߢM5í¿®×)LîÚœóÊpÔu¢×õµ˜lA%4Tê(jÒ#ÉÕj65ö_¬ñÒÓ)~:Æ^œðªYˆÄÍ…ñS¼–¦|Ù'”ÙÖý‘V!&E,LåÍ›Ü+ôû¸ÐÐw"66pªÿN@>E¶ãñGÓÞGO““œ¦A òIŒoâêÁcfnÚÖêKX?((YÖ¹zyÞú_yõ—²È)2Ä+Z´ÃÑÉò4Ý]¼³ZÉô±l¾É~_¢Ô-@:ÚaUh³˜aÁiÎA»þOU úI„•Øsd÷áW&0eÛ®jxäü¢¤]¼³!OÊ…ˆ>£ ó³õxâáèRYxH†¡©²B ¼U”­ƒ°+áùª,¬µ(ê‘“Ôr£HÑR9ŽÏj©Ò=¹å†ÜÒ­–¨­ß£È¤aM#¼¯!' ¼’&ñ¨Q@;lª VŒKŸSz´±±f‹RÈr«Úˆ ŠxUQÝ ÉÛ†phݤ(>Š:^ž×@Öìã«¥HBžÒP—´Â²£)-ãê}ØýG¶Æ‘-1R/”„I²3(ÖíRV•jP°·ZñNÜùK;– )Ä“% ¼¾– ÕŠ…æ\w`dî”°%: <04‹®œ IbŨ»ÁSvA:„ (’]i-þÜŠîìÚÈR±ìXY¦Ÿp“]‹½]hº´UÝS¯W3@õQN\¸¥8BQHB(%Ó§PgjUYBÐl™ÎîK¢ÊG±~ÝÚˆ?)׆,OTf@:'õådb)û]egZRuI‡¯V3Æ%WäÀ²…TWEUä©‘èš|Y–¬Ì]M•êÜ33~§³|LÁ©üüoÕe”#n©,QÏ ‹ò) ÒÑ EÔÉÑagpwn•VEo·Ž[_–ÔkãÄóki¬Þ*Q&žC²„0¦@ä[õÕº°d`8à¯(Ö·e66?ã¬r(Èü·Qì;¸NÌ¡TŸgBǰÐ Ñf“ÆÈ0BôE@PÈ)-Ë!Fff]øà7e÷b¦‹˜¸õ™6uü`)&ìÕqÀfUN|»ðïÌt£,‚Pv ƒB…ÀZ’šã–5ãE‡ŽMîxŸ1dˆmªP­µýö´+o"u’~/Õ¢ÅÏ 2T 4Õ”ÏPœ¨Fç°byàû®<'ê[‡©¼aÓÏóç¹Zƒïº³rx#³•ã¡ak 5u~GvI²ž®Yµx&dŸ‡²€Bû ŸajÓ*)V¨²´ÕæÈHVYò«É œ·,h¾Ü@è>I{tG"žè=¾ÚäY`ÌW­¨…æ_Hu i½±#QwÀ*,ã©ùäYÀØôxÂÉ Á”… Tð¬H!ʆå te }¿·r…¸ú~ÉÓtääèšî›ƒ¬éy³ÊÁÔ1¥—duT(ð²Qx!º«8ç“Ûýþ†:^c½$ëí5þ¥@@y^¼3 öþŸÔ7³‹}´¼à+ÐÍÇ^¡È,QU%yì¿0p=Ôûvú›2E–9#‘‘ƒÃFÁ ¤AåYˆ®5"ý+æá/iãuGV Èɰ ©ña\ü€Aß$_®pÉwøCÐwf›®úÉö¯€šF¿­KYô÷ñ5ä¦U²4uV-Ë36:LŽN;Q]9½ØºÎ¯éîàÑ6VáÀ}?r¾­àåádbçÂo‹ 29Rj¥ÿžuš´Yš?ZYOú[á0 š¸VWvZ …ÝXQ}ø ~`©þA'žG×?ßå÷ü^az•£å}Îú·0çêÐ_÷{Ëm`b™Õzn1ÌÎÆ†=&VÄ‚Vˆ¤v²òÓ¢º¯“ ½§ï·ê0ÃÐ}ÌýÔ”pz‹Í$zEcÉ$ŒdPiV9 J{²QèMúaåfÂÊ"5yißå`žO!¶†¶ îKÄÍç´eZu·†¿Ž}BÜ æ’–¦‹C9Šš~¼\:Þ¤·Zõ §@Õ‚“âs_‡+ÀÈ•´K2wÊj¾6™/ ŸŽ/dÕs–2ò×·ÉŠqÔZŒŽÊÎׂrÜ»ê9Z÷æW bæj:>:džtò盋‡Ÿ•‚ÃÏ$jþDʰ äRëÉdÒ)é:® t-Ê8§!SP|‘™c þmdÈ3ò#³~u]¨+7¢µT¦¼¼C>0ªvä«mdÁ2îH³©ˆqeˆ£VÊoé®âMŠ’¢5UjB¤.€Áî?’*õ4oûVÇ–ïû®ô—n;Çyíúx&R%[on·ºƒF¬ÐÀ¡˜ªóNÉ 0Á±£l¶ —ù•¤Å¨„/Fi å;r^òj…g *¢‘Õ¥È îç&hÞ§¦5è_ÄgÄ|n¨¥{¶2|€ñÃ*vé6(¬\ŸçŸ„œšJY•ÙÂûóP¨;ÆÜÈvR¡\¢y³¥cÌè!J¬ß´u }ÙÚ°f(.œqîïÝJʺ†;­Ç)eo‚Áh_ Gð-,ö— Þ ´q†ä¨`JíÇÉm…žZÉ  úfh8ά€¨'±ŸW4¢Ï€xèÝÐ!èýËnèª2×ö^;Rø½Üº8~f'è\tvƒD^º¨‘ >¬6T…Âò‚hfïÜ;p®þO“pÌVŸf¡,:’ä˜Þn.:ÎËTg“åÙØ€äôR…Gf CÍ3Ï—Pœ1¨d´æÔÉ@Ò›$Š5óbˆõî<ÉÓ]7ó±"¼(M¸ A°Te<7ªo¸vvtŠ8·-È$FFX!?5§7…•Ü:DY¹F}˵µ,'ã¹¢ ½,L¬¡{ä·‘Dïtƒ2Ô‘ØTÌ…§K韤̋«LÐ[»­Ã7G4f=Â3/Å–d©uê‹Ýˆï\бòâ‘I0'äaE˜&˜ÆÌ´D ‘sã ´¤E(•jÊbÊSÈ•´?ÀûöCxòBA¾u¿¯ÕKc‘Yв7‘K­¿6Úêœ+¯P¯LöV>N‡›“fkUæ2ÒÙXÌ¢;÷@TD¤ȉӂ b‚ÖmÝ·õ ïWöž™¡c]rrµl…î«)³Xÿ«0óê:ѹ_ØB0ª#s6¦ ñtÚÆPyEgABÇäíEdUnÖê?ü5ù†<ºM›¨o§·ÿG§»>á¶î_â6LtÚS1êÑU C/ΫB{)6=H‘à…bQ›„Îb÷|;«uÉò܇ '±Rúˆâ ©à÷+b¶§oÉoOÐàa?MtcX!ú‰\0%8YŠ !uzRlÇP¬Tt/葦úe¶°¬*º>,y幊 ±ä°†_ç’÷VrnÓðB{Ù9!Rø T±ߓԱúMµôßõº.:bˆ Px§ÑUPqÏ¿È!^#ù$q% ÑK>!=y_ˆ=Oˆ^~]ý»B€;vúçÆ ù-”À‰$v’ÍFßþTÕ°²Þ¿6AçœÜÖÈŸ'ZY‰4H»bH QøæÇÀâ¢:‹¦<íV¨ø†¡=úדÏóî¿ÇQÉþ–÷ÁßòþFpý ÆÖv¶–£¸ò“2~ëüÐy~BX$È”R÷iœY#ÞªÇTþà=LŽÉÛúÆ[ߨLZ÷á×úõex GûžP¹.[ù,8„û¸Ôu¿^>áµï‘¥àj ’Ci¶9ƒYѯ<³3ºõš!_eIÏ¢¶ý(ö¶'»:ü­ÕŒÑt®™Ödè͘ÆJ= ¡È!”6@5°g¿ktÆ^¦ÐEì±Å‚'RÑ‰Ë¨î• æ" ±D IЗXÖwçÝ&÷Ïõ yέ Õì‘§”FP·ë8І,¯EG)9«NJÔ4è¤émÍ+M”´ü|GåýÎg¶§D9tÞ´&PhL³IäQg@Þ⽕)F³GW%;£D&Ã÷<¢tÉ@äy¦-ݵ`ٲīÏôË>RØq[7úüTN•c¾Æ¶"€ƒTFªØž·þÜQÞÑÂ:…t›  †ñü¨z,ûrÀ± ¨Œ@êW© x¹“ÍØM‚ª°AØÏ¿uqËu,„¢{äLýQo·/¡h½9þ¿ÌÄ#øÛÙ‹‘Þ§•²Ñ*ÔR;}_8~,çîZŸ˜É;"©äù‚ÄQرä:üOn>ër©Ëb Ù•Á.ÁoRÜ IZ*KU§ÇA{‘ˆÍþå`H€Ù#` ù ¬ëd©»ü° …YP£±dr¬¼'$pP#))Ó£ÅMÉ-U·¶© n-_Ô1Ÿ/G×t½[.*­G8Z~|221ƒ©­ñÓ¡ó'=• L‘[iÚÕ`Óçü‰°_Ùí@¨Õp’«À5E,ÆËÍCõ¾3m/QNOcÉL”5)Ü>Nuòr —E`yîz} À˜¦d=¢Ê^R¥P²4lDŽ­£-‹åã!\Ciý®±Ï‘6<€ºL’C"ù ŠJWBQƒ[-Ot@<ë!ȆÒÒw>¹¼·®ÞÎÅÓý8×öÏ­»Ëan}_=ôÍ[vmí3YÑ0Wné´Ítüʾ>Ÿ«Œ!²Qb¦C{ôö{iù—”«–²(h†eÎêËj)@n5,å¶b¥Š›$‹ä]©¦Ð÷˜Ì¨Ò$ŒF¥5®¡uÙ°$ìÛ …  -]JÅÔwnÙŠ¶Ÿ“®éS0T£••ï&<„‡Zv\¢ AÍqÔPÌ߯¹˜µê_£;~øË•¡dé÷ðÃ`*ú–Ÿˆq3)x¿MqqÄÑÏZ16nÕOí¿`·¨^¶ì]«§—¼r5¬Kd•qc¦o=Oeêù…·”Í«ì=Í2¥½Êù¿P ¨LÎÁð3*NÍg’Ôv£Ðä:mïOu]s@ÅË”»nRl\ý"¬¹渒¶-È-=SÍgz<¨¦y­\nÅd+¬÷ö‰¿÷Ÿ§Ú®.•]·†Úý)”Øùˆ_r1HÁb¶VÊÈ:Xü*dÕ(éIºŸ#¡úº~Žk9e'Ÿ™I6·‡l¿Ownq] –@ASÞN5j ùT9R<” UH¿A3cÀ¡ Ð+¨]Ö6 Ý#ÆòJ°UR7¯RŸIwv¡•»6V‹½±²ô]ݲqò±r-¨ñdaÊ:ž>.©'É%ªør|?ÊÈÍk‚¡ýÈaz¸µÞ¦î ®f\íkL}?hi›©yßJÆ3e ¤åÁ—¢‹Jˆ<–—V¢~£×>;³X×pŸšJjÚ]31E<Â+S¨bÎÀ3-ñò¤&W2’P2kIw¥m*ÇöS¨c•“©¨Ô4¿÷2ÜZ}ó`ͧàS/7'óÂøÉq6ŒŒ³-'¦34—†C<ªk(£¯mãA­;&Á@J¬ÊÄHÙ Dµ¬uŠ< fí$Ƕ±¬`Óig’hà’ÉRò<| (Š‚5rz°^°í]¥‰èÓß'LÆ;¯d&~6ˆšµ%ŽË»r6òiÔ†ÑÊy°éªäbc³«‘$›3<Í3ý¥zµ©z»é‡®ßc¾¤m¼í^Û«WËõCÒœ¥Ä°ÌÙ¾¬èÂù9°ûÒ:vâÒðŽ±±Šõ¶ ñcµ32KéßÝÓÁõwíK_ÂÒŽ©¦jš¶âÊÅôٲ둋]OqS˸N°Ê­iâáëY‰—£éï@ùSŒXRŸ¹1e?`ÛÀiÿymKm>ú~æÈõné[ã6ÂÝõüªk-¥ÂO "‰x$Q.ólÐÖŸ- T[2³2fW:äÄc‘Ñáúy\.ÐÐIq§– $,SžÙB=»ô<Œyç&NŸ›ŸÔ Y¡PD¸«õ˜È².ÑŒ(1“H_.=Lm õi¿ÌÖËÍ}ƒþ:=Zm;z–øûNÛcYÉ2iß+;aišG‹óIUCzaj„øiwy™¢Ú¿×(=ÍÊiïÄ!Q2ô4\±,Ë3¸tÊä?V¬"Dá‹@²C4ã€ôšÚOóãê‹•©}´z7¶²gXúCµ7~V½‹ƒ$Ë–“=É«ièRÒðä$0°Öò‹":ÍÑ%Yöñ65z9¤0Ù~¨ê¿ì`%=WÌëÓ!¤¸ú® ÐUh©‘|yIãÜ:\? xÉ›2Â4¨jéúz½í“V®EY2_©@ñ*¸j¢ôT+S-Ò.‘¼ìZ6‘‡ÀIÞ+cðljîëb Ý*›©¯l´ª6CDkº¬@ÙrCp ÞÊ(úÕ_· ý^À3å(çê¸ù VqgÉÌŸ›&n}«@öµG‘«Gâ¤Çeó«î9±4Ÿ^ô|¨Ÿ:äj:FB‡é”ZY窧<µzqy–~„nìš_µcuÄÒô½­œÃkj¹A¼8®qÑËw¢†ãÊ**´^8ëäù_µû¶ÑKõ7hÉ¿}¿NJäYÖëjBù,Dçä›Õ£LŸÉå¨ìLªÏäël_Ù¹Ï7¼2ç•¥×;?À8ªÆÌ®À‘KJ4Û•«‘ës÷FÅíx"DHßãðø4…¹±Ü–ñ>n0R¤úÐF×/UÚX8¹y-—)UâŽôÉÉ}CQÁdÄ…„ÚyjÄ:WµØYfëP×?LÅÅÁÑ—O„qñ|ö·Y@% ºù ‚þá*T†*:À<{ýU?D1]ôó§<çú/‰)߇›‹(2ã…x±¯3³Á€¤jªüõ¢}ZzG›Fql“øù NŠ pÌʬKð«9 X3+²ôqÐî<–=_&!Iv2cþXG #|³2­yÞ§QWË>{c7èx˜´šË"ÊÊ@$‘†Ÿ Ä)ý̤V«â²m>ŸŽ©ŒK /ë›T6ºøÔy\¯&©Õ>}Øòƒ‰öú“"¥$ÿ"­J)~Çò<\$ @R&[ÊŸûåßÝXpʘ“wˆÉ..œüK™¬Ñ‡*¥•T¥“—r{ŸÚjäYÓßþæB €æ?Aî;2™¢—èÍ ÍÏ`»&@¶€Zè k•KqÁªVÀ6¥I,HÏ#.Â@à“CF*Øi‰åÍ­X45:úu”•* PIZ¡_…3—F=É< T)ËUWùò­,2×½˜Nž!Vb@5þ£Æ=¿QB¸ÑšIÇ™b‘º;/‘Ë÷æ¼2»§J8SGOá)ÿä¹'äGnYþ¥Òγc /’Lç°u¥n¨èZ6ºP‡"qæ›"ÐWú%Þ6Ø–¦ ~KY«Ô²ò­r,xðTj07Û\°Y¼kzš%¸Øµ!׆k4}4<¡7VF_xÊ:vYû«PY—äó<ìX~HZelP1E]HB£Ž¹ù7ºQ¸çž}øä)"M&ˆêœ½'"€„<–eêH_*³ÿ—Bp½WµC4ëNÉv3Uììî³T§U™êÉuw躒UU]ß”ìÁb,°…­‘` ¦έÍòÞüüŠEêØä³•ñØ0x¯X®¯ñɉ«8_ÂI4+4˜nÞ2Á˜÷ZT`R‰Ð;vcì²$}6«ÖUS©@[ûQ —ZÚ”bÅÂ~‘Ê1?Aý/'¢¹g uaѺ¯üšÍÔ‰ðኄê®A.̈l t‹¥^bŽã'ŽM]‡cî¤ù(øª©¢§(¡:“ä¡°ëtG.>Ó{kö’<Õ¹SäÊ8¢5+êÐßU!EŸIäkB·mŽ´¨AfO£V‘vYã~ÃÐÍ€@È\·±RÝh\ð½b}ÿàžý"µ*ÝhÕf£oc@ÀÔpy(<ÇܧžBzmx ‡ Î]CE.Ë> þ‰@rì,ˆL-gCÙ»Ì ïÃ/P¼¿*Üäu ‚Wž¯?QÃŽDÊçÇ‚§e²5Y’ØæêøbùÎq¢F ›sÀã|“ñ•åi‚“^‰šuèCvز•äÿ<þI<ö'–=žOÑxùø÷ÆÉU¬mŽò¬ò"«IðgÐŽ¢r8§$ù€x >qÔòËÿ±÷'²'<³ò ÌH'_ˆÿØŸ©ž™~„#<ÜpP9åA#ƒü ä8?M¸‘ÚùVßÅÕÇÈÆÁ» @:–¯²2Ñ*ºÿóö?ìU›²=qþrþÇí›Ö#Õý¡<ý.õWUÔsï-?O mny+jš† ñIÃ6c+P‘©(_ò%ñþÖÇ|mm›)WPô>OæÌK/9S-æøÙÕÎŒRùO‹ åsˆ÷Ãñ¸"Y‹—‹þˆä‡íoKûºûFõ7ÓÅwèö×¶NeŠ`î~“\zÍZ’óÒ-‡WO‘ŽC'VBWëüÕ5WÕt}GýF©ƒ|½/QÖ4œ¸]):.fSbfc9øð’¼ZDt_ÇüA3Eßý—Õ^é §ÔúD²cäIòÒÅ4mØŸ_Ée ;ªeëKö7Wl®˜ÐÍ!2a¼8’ìc¹c1ëŠÎ\1ýHAKR$i1f‘· Àìßø†Æ–_©Þ·oŒx7—MÛžÉYŠn BX²ˆ£+*;Å ŽZEDÛª å±[\_*uÈð˜Q©Èë9[*xè¼ö §‘A~­Ò“&`Yú ËŸðݧÿ­ôÏÔ}Ó”ª?Úo;2#‰ÿß²2¹¡fÉ߀ܒų!–ä]âW\ù_£/Í™üeQÐ+¯Šj1*òh±êªà¨'Ìhœ<Ðð¾>¾dù- —Zø›…gj<]3˜Y*꼨 ã@ýM§p¾H«P0F`<†FfX¾FòÍé!ä⎀ «!jrÏúžhId#vêê(K3™©©^yà« LϹ •D™PbúF—‘¹5l Ýí¨Ñ$ÓŸ Êh²”JR\w§iùÖ“W¨Dës#,bâÊÎOØ…aÅ a°¶äÝX®aë÷NÅ9¹Q"ýŒÊÄ–'E­¹ù¥P¤2­XäøòI['+\ÇLm/ݼ`TÑõ,âA Rnž¨®§ÇÃô }^¿´ŸH5¿¿³·«¦[T„±ñÁeaV6¯FöI¯3œª€&O`„бègÛl¶î“ƒ›©aªÊVfU¯_íä¡ù,êŸìÌdz( Zîl­½……T”L¼¢~IÝžH÷<û˜nnæ~»Ô’|üÅÅgl|¶nã¾À¾Òãd†Š‚€†`~õït¬=7#§à˜¤QŒ1ç–6%u°¹aM3©ðªäè¦"‹‹‰ =v`Iãª)˜‡äõçŽO'·-É*~šµ %Ç-ÿ•¡Ð9¾ µÛZZ½c½/LÙÒ(Õ¤u m‹‘B¯çâÿ?#X‘þR}p¾ßÄm¹£äy5 ŶŒr¿¤T¢÷rJ…_qB ÛŽ(£ëö†ˆš~VN¿Ÿ6¦FBµ²½ÎSÕŒÎ8Y½”Àb²nyUf¶Ÿt^ _Õ?Uuœì¦ÂÀÊɆ$Ëš*õl…ì쮵TEà2/`ł̟ Æꔆ‘„±ã+X£1v¯ò¥ŠV“Wf¢ƒA2¾5=Aì?ì^×ÅÇ•4Êê1¦OPa[´l³š`J•,´iI =?ƒÑF ©?GÄòyHÖ8ñbTÅ#SQ>–i5õ(¶cÁé“—’ÊC&iÇÅW´ÚA ×°eZŠ:rÈÅl9é;_MóæE¿&ñuÀ€$M£ÀBä1*½•›§³!¾–h:(—í ¬Ve§À .7Pf0úñão~Iá8Nyo­r™™5ÄÓÝ(hÎ=fèf;¡<–^@ê ÙCƒ&wÏÉúh¼!ÌTq¢’TX€£Ž9aÍ]&Æy}­D†,ô‚‘jÞš—Ëña†Þ›2µÌ½ËŸYM¤&i×*xð…V¡vò~ÄQÞg†^î«AAìå8~&›Žˆž8Ü-âý …ZU™i>;ª¯.Ü|¨S¹Q_‹×Ò¥6Ìeþ1²ü.M*äÎÈÈÌÎÔj=‰^BÊž%o u$Éq¼Ùy«…øÜ"UKÁÚÎmãSÞ¦>°AÔK!Ñ {2 À‰$™¢E+<2€¤3R§î§òo#Íí@óa:žRãb—ÛÊEŒýä!™Y€ZV«S¨Zµo‚9÷Ø÷¤·‘hÑ;O.OÜÓÆçŒˆ‹V£Ž‡­ (Y3D9=—ýŽçÛYôïlyú#Ç *†NÎÕŒ§¿VêC÷ˆ?0aJ±jýq{·]å­avQ*ËÆÌ?¢š¡£¥šy·¨,¡bCvþ>õ¨j~œhEmØ8Г<Ü:d0šÏÍÑgÛlŸ#ÚázP4ªgÛÎÇg÷RëÓápu6ÀX² .¼dXãRoâÇÛ\Ëî¯ÔéHìVjfbC :Év-øPbèܸ\%®ÒÔbñ ³36>I2ÁÌõVUB¨guþ¼pÇë½G'DûŸÖ άßõ„Õž†O.ŽÒ.=(¼3ÕNÁU'´?ZtËfí}Dð\~-»Ð?nŒé@yoãÈ’©Ë{nz®=ýa„±¾ëµ£®»*ΕèÈÔp¤\¢Ð=(k+·ŸÊG…Tðã<öûýê/&îtéïÇò‚à5kùÕP°oúY úÈÃ5ÊĘü¯Äª„xÞeÁ‚Bñɺšû^i>ÛÑ‚«Ñ[ƒ{òàãM¬\¨ )è5µV­î ¡pVü÷EŒ¼eœ/ Éã³rмôà«QˆWfe yDàg·ÚU(ûGBJ:â㎊ݓ«B^6„_'PyfSîÎh:Mù¢Öªg ÀW‚ŽÌ³ãÇÚ~Ì’çâS“ÙƒºñÆýf0z–B÷Ur'·rÊ¥ŒI¸-  p¡Ã¥½Î€eFÄ£1$cšÿžI,x6}U d™™XŠðÝ ³ü‰ ‹Í ù$2’A¨žµ¥ 4–7eFj¯^ìT³š’¼†³qÔ0n¢œ_«/,mD½s_¢ š ~Ür¬½ydyYUÖ/Lž¶¯p¡—ÈIMC·ˆtþ&¨é0í„’3ÍÈÍøÂM,„£%Öˆ\à'Ô€Àk@³´[¿‰bNÜÜú6´2±4½ »óTÔÿ&®\Öƒ  *Çã$iJùêØ8–(–NB…{bPœÆdVf“Θi«[PFÍ\Fµv àâ ú£;(Im¤Z +f«a\Ä1­›5z¿?mWk}®7M݃_õûÕ Onè&ÜÁiVÛ;BÔuL[ååäÙK]HÁ™š/kTM¦—KUJ÷‘¹³ww«úƽ-,iøk•«`bexãC©¬uz)®>Kʳt=žO6µŸ¨.©I1r£—z]Ì>%ÚvhÚ/YË&YÇ•eD«Ï•ÇÙ—ÞH×·N³¢eÌi>ž×LÌÝSŽÓUÊÓ2àccRjÌ婦yrWˆ])W\ž¸Í)œ—UÃì¢\²:O‘û— p¿ˆÔ±­¨{…"ˆ(=S¿ÇÓäŽ(’A:#Gß™fˆ@Œiœ1È`‘(c@"°$J=Q¶F¥‰³ö÷¢óI]áèþêзæôë 3 ˜:ΚÕCM[ÅÈ•Æ&F¡ΦÍ2ò&å”ûÒ_¶Í3Hõã}ýÎï/KvÆÖÚÞžgbîm¡º0ém:Úön‚5 _/XÒy¶ŸTÛÙ£+;ó&±ñÙÒ1LšLR´W×¼íóéÛëÞ°ú_¡ÃX×ë¶0·Oû«f`nÍ¥›‹îVÌD|Šm­HÃ:Ø”+á–OšÏ±ìòê/¤z~éܾ›è»›míýÍ¥m ׳ÜjØøÍu½;73@ײ2™T×DÏÃl:¥pÃÒ$°øÌªdæÍ «pÍ)ús´]Øešy5„ÊòeÛF™Õ!bÚ˜£[C¤fœ"éºÉl/FRÊf§Ôˆ§š ^9ãŠMäîÃÉå4lU”jÑ÷9÷aö¡ê§¤ž½ú}³vîùߟp^¶ïí»/sëz\±—FÓvÖ£¤ÃNÂÒr*šá66´0cjä_&ÙM'¥>³sjÍ›éÎãÓªq†^¯¸õ.“GkK& àäøª–ÉrËVî Z˜Cº‰‰÷ìo†äûŠû)Üy™¾¡k„ë^‘îÿP×pè{{þƒÈÓ5l#HÈÅM6»½1h¸†[æŒÝ/ÑMO+?Êøê™ «èÛ¦ïÔö§þŸú÷=;'5Ýo½°2ñæ×µZÖ®¡š˜Óð Þ5œi—"ÄšÙnª¹ÒŒÈ•Fb¾Ì.3U:{'Ò+I'§˜Û§W‡Lõˆɪhù—Ø4Lí+3%1 Úƹ+2Ñg‹ZtÄ‹Æâ9*YXT¥å«eT¦5Ó ˜3È iIøP+W švK &•ê‰;äFU¹r:ÑcnÒ9I#*𽪂‘²–î*Hò38°Ïµ¶§32e1ž7ý9<|ÁWÕµXí$ l Z Ã+­lÙ¯¹ÈÅlZÔd‹¢bðŒÉK²x-û¤«K„òRs5®vd «ºŸn>—K[Üë=@Ç"x²)’* Æ“…³òmBó¾KE¡¥Šc•ò0ucQý=Ñí©ë˜Y>?ÈÄ‚¦bÅVoÞö4üE ÜÕìhb]¹Xý–ŽšÙöᵿ×J¹”²P;”R@AË|ûo+º8D*ÔJ|ÂOõ®ËƒÒäÄÀ”«Y]ÝP?€-@?po¡ÿOú YYÿ\àdwuE:2¤KdVØŠ u € 6TÙ¬+FÄdž2ȼéB‚iEºÉC¥g%›öáùjuaÕÜýe·Ü·án/¸]¥M–§%mVNld«›óRñTý˜5˜£YgPR(Åu°cÖk°D 4i¨PõŒ"‘rÎÀõ`_ÇEFnª•UÈÝã9îoº{fÇ&t–ʪ¬X*H1ÿG(9¿,räÑJŠD¿nµY(Ì=‚®:Æ^[>“£çH[È qÙŒ›,ÎO‘»î$§ûÞEþÎbR äåà ÖBC@¡jªH7Dl?h´ÑDñéñËá²N93¨P¨O™ªhJͼ}˜‚Ìz–sR¬Ôâ•úµ&wJ%•æl…‘ÂÐ1J±VyÙ”0YýÉvúzK¥œ]2ñR•(`ÏãH)IO…l8pÍo,©ÑjUÕ×…§Ñê0aLWEò…²§ÅT”jr½¾$xGÇ•,J(~ÙRº´†N©™¨`­0CaJè…=mf¡Ï‰ÕÝ6ô”ítŒÉ*âM»)VbÒêתƒ|ßå<ôø²$ u† ™åÑ š:r]ßÈ(¾ãݨMË‚´*ê´N…,¡9bΊ:ðJP¤˜>E=Áò=c2Îï:-YZŒ]ø_V3vv/û;ö Ö$q>U~,ÕIü2 ³VúÉUÊu=VvøÕ¢‰§ ;¸IÍHV2&É;p@Ôü1¥4 ãÓEYF%(*ìö û”ØUÛŸ"í\°V÷Ç›AçF!Š:(U=ZF†so'ŠpèìXS»"§.ÿ­Œº6©>ê«û€@Wà* §ì=BµCRT’ܳÞ&Kj3û+šLÅ‚«»±à%Ëû© ÝSÜ/PÒ|3*_—%SûJmD Õ uýH¥|\2“íÙ½$€) ‹RMžêu7d‰Rþ@Æ´s±ø !Ve hð¥€êì|px^HZ}VaY*¾.åJƒÔHMØpgÃvq$RŒŠIcDBšé/>bB$RíÕ‡ }Ër;·rn:¯c0HŸJ+Eé’ý}”*N&^ ù:tÊŠ~1І›NFqÿ°(&ybžÌÅ}»ä=ƒôå/7¦D»L’TöIº*‚8²3±VÏÄŸR¡‰ä—§eÙ<+:—ìì¶ §( ¨á•\…à uÜüX¡Q™T‡j òÔ²,€žHhf½g²ªm]¹ãÿOËmU~9kRFß lz?èÏÝg)žæ,}ùîÍ;pX{¨!X‚9=½Á ¬X½¡Ø­8C2ŠB;9FãàG$¨AQß—R ‘ô Ð3£/VêÔ §«½ Š"{¯å–a˜vžz¨Ÿ¢Þ‹@¼yU8Vÿž?i ÜÏö!(μ|€ãùiqT4‹@,4´K©J±¢ ^AMëêÈUÞÁ×V°£µsÇ6ß EšðrŒ‹'&ªP—±Bž‡òÏû/`9þ¤/SƒtUNѹg@ÌIè»0ÿv ðË/òfèy§ä3ÎD!ê¼ûÿî;¼:ûý‰. }¦XV8÷Ëý™ñïÈ#‚}ŠÍ¿žWÜ”,A ¸ËÛÖ? *è“\YH)6MsȲòã. ®v¿æ¸#òOŸÀþ@æýð©;cS¼:øè‡Yxeà ÞÄÏoþãëüàÿÍ? ·ûzûýõO>.Ùõ’õ7mAS®(–äk.®‘PÏ4lmo5ÊN^B¶JÚŠ§ýðîªÃÕJ)ê€J $ŸåÃHföcÇ#åíõÊoÿ´õèRê»;П¸­?<ûw_ÏôïpeÌ( ¥îvÔtÃSä^&5=;ÀŒ&ÔGÊþB9Rýý<Ï?ÞXPÈ@‡­A.†bœ.0ç€xk$“^&ü¶³í̇ÇêˆHú˜â€îâÿ«Iø¸ãÉk‹”¨Sf«?øÎÑŽßûaÙ“¤i6Ü{“pë—ŸÉÂÒ…½ÐøùüN˜0JÊî9çJSÅ+H±íÅ0Î6UY«:àŒ‰MÈQã_Ô³NÜSå×…,i/Ù>ÿOý½ú=§Q!2›[og¿É{«kT:µC8)&>kÍ™wW^ö’½.ÄJåèÕÇtd¢CýŒìª;Q:dŽIò2¦5ÁAà v±P?êó.g¸}ÔÍk7\ÊUf`I #Ý…cm¨TJ¦tDÑÐ=u†6?HŲZ 8‹…/’öÕ¼˜P «±"©z-6ÙêÝ@zð\/i±Z ú„ŠBáYÇn¢mevÜÌ¥óó¼ŠÀ†¯GTêI¡RîÀ:¥ûU]ä\tn’Ï#ÜžxëÀ¹ŽÜ‚X0QÀç“8ÉËXõ ªr Ø-û¹ _,Ct*‹7ŽRHð'åbe’¼“LEZèךæ…]O&8øôbËvþ9þã€y$·±ãù<…úÆo¿Xm…£j:&•r×~àfç»­æˆH =›ÙÍNÁ[e ¨ž¯ném½¹©æ¨ÆÈeýH Ê/tö¤rJ¯,G*@#ë›/\7Õ·¦óÎ9KÀå8ñ0fFèkP¼ Žlõ©bª€ÿ!SÚÇEÂþóî$]Kbà2d8Áˆ{TPò`ò¤ÅE«ú×?¤¾Ü97Už0Ñâ„׹—aù?©³qù ]úÎýwOÍKW/¢ùòmO5‹(FZÐQ[žAœûµr_^ã‘W]—ƒ‘‘‘(ÚHÏY­-š¶ò PD‹ð‡­]厨 »y*^wU¥*,±ÆK•²„4EFwÚwÅœj´ /àl|@¨  |þ•>ÝTDlx‰agI“^á[â‡óËzÜ¿´œžû_n0 °±ê$€(Yþ23GTP'RìÊGY9ì è®1â3VXȆTöê¹¼ø0bÍÀ$’äöÌ¿´,ª£ €òê¸RgR2®²÷<½]U$ ¨ÉâQ¤ØïÞ 6¢†’ûªÁbz† }žeöä¾}Häp ê9wÜêf¿²ê>ZùÇš ʾì½Ô€dÇg‘Þ¥‹P†‰*´adßÏ5ðÖÌÉV ߬én«ÀîQÄz2«‡gY’¨¡¹äµ_õ@cäêzTl-,ëx¾wìÅøw¥¢ d Ný“Æ\ñì…lÜ•üoÕP’;fRÎfªyäÀQÕž‚ UOÖ ØúvNn*”¾"tä•-´˜æjò ëGVñð\!à‰%.’ÑÇÕ0fs¢&D%•fÙ¤“Ä©UòòÅEþhûn,óFI$2ÆHB»ÎË~$ üQ°SüŽú{\¿Xt=/F£¸Ÿ{eÓf9ÀÓ‡áj˜ô¥n¿¼˜«Pö_¬ƒÖ3üxºN ˆ ÄjY,|¬LŒHʶGqjL`‘Œÿù{ÙÙümã‡ÖìýíkÃqz¹°÷F™…“L?KõjäÍçnÕ×e¥¬VëÐÏòg‡V((HäÙC+4ÜaŽëÆŽ¾ØLqï“‹‰…;IÅRÈõž;ÐRZ…µ`ߪÕ-e—äåþˆû'&L¾‰Òß$þŠ ˜2nÚ€ P®94 _¬kܨ`ʘFl„Bê~Ñb‰ÒƒÉ¥š˜‹¶,ÔWlý³¸7N#chZ~Fv§•YÒBJ+ácµ¼™?˜Ëi jÕ¤h*…Œ¼a¤&­B®³¦moMãþ¾šö—¹7+¦OäËL¥L4#¾ž™]¿êUȹŒo0ç½pñ™nýÛ CUÓtvÇL_"~=3'ŒÎ<Qê«\‚œ"Oµ+Qä‚)üÜû.\ùS2„ ~CÖÆn-AURØÑ‹—›U™Â÷¢4’ò’©QFø$Š5âÇ6傃͂jX‘€`DŒP– mvb´SUÙ˜p 5€™6؉w§ÖÍ:³jXìVX¿‘\Ë"2ùi O+ÉšEæ  T,ô>.ÉQgsPëfA-«*—Æloû”Çü¼\XÃ/){þ;V\òÒ ÝkfL·SI‘íµ´³¥âábd,yÌÇ]YÅ2Y*áàÕ.ŸgfVÎÈ=Â*…IÉ|.{…›®ÛÂÃÞ¥²ò)§AÖÖÌv—Ždƒ¹Äb­•N³Å¤jÁ-‘Ú¨’¤é4ÁY‹Ûˆ[2Ð:£Ïoþ:)¢Ôkï¢[ZBê€r)š2_qb2•ü‚:ž&©·òSµëKÇ'öU¡ .JäÖøÝK^<Ôäã¯,yHBÇ©ôõ+E¾váÒ5\ ÿY¼4ëxXÑÉžBþL´mZY5ÇUñ;êsåR}«[ãÓ•.ˆ]÷>å¶n«¡jÑ\¼HÞÄv›¬h­icäŽáCXÒ¯àrn#:´]MÕ(‘Íɯ¶£é0†4c“ÉÌE—9RÙ—ZY0€ÉíF>YØ£2{µ>+£4C¶K·Š¸­FF-òk°Ö¶¦¾+ŸJ’wî+FÅ×NDšƒe›±· X#QdM¶–ÖÂ×w§ÿ›äÇÙ: 2%¹5|\*iƹyã&â°fµGããO‰ Éiã"¯y9\}o®¹JdZ[Ûiå ÇéÎ~|çœÚ6…Óo$¨]¹8øø¹JÑŽMئZ¼ƒÚâ]Žßô3OÚ(¨u¯Tu«ädßâµÂÓ´†—†¼µ]㑪å¶!jªÂ&1Yò‘_ím"z¯‹§îŒíCKÕtùg6Œ¡ÛåÖ¸ŒÐ˜¡PS•˜6òº³Šù¼ß§c¤XB¡TÊÝ]ÙeƒYp ¨Ül§¡¹¾—'*M®!3EòV I Ú«°häø-Jàþÿ훟pg;PôÏ @—©XyÙ[ë`jY«¤Ï¸½1÷¾›‹5Zdc¶W[êšl•㌄¨Ç›Þði¸[‹j´Üš–›¡îó}wWlÝ&VŽÚÜ»gm]¶Äó-•’®F§jøtÝOò†>­“‘º†eg›ª*ÚN“k¥éQ®B9JÙ4ṫ°(Ë2‹Ë0jÛË]õtooU÷~V&VâÝšÖµ¼5zQ2¾v¡™”ØñÇ™¥.'е+Œ‚rðIUÅ_ê? æK8æc)ÏÔ3VJˆáæø˜ÁÛ&Y_ÉÚ™4W?âcPZB‰E`™Úc!ˆH« á" ˆdrrH`©~šIRZÈ¢uõ§áÅ2ããýrÄÙY%³2ÀVïFHíW§’x®ŠÀþÑÔ5ÅZãôùv³¬ÐƒÔdž QŒ¾PèT…æVñdã¿-6ú“í­½›¬®'%ë™Öèëᜇ•¸›Æ¥já2DØÌ…«$Ù‰I ¸1{™L’D ,¤ ™£¶IÀ.Ì»0$)!UA8‘æ–8ÓÅ.”…ùñ±ä³uJyšl(¿I3k+Šôxpý†iF iâ Ztug…–ŒŽÎ JÈÓßa@(;Nß&nË6M;*°y“ãf`YÂŽÌYjLtíã`X0BfìÌŽªÈÄ€Yß· T 'b¤:¯¥]vùUØylHÇjõ+· '†ÔvÍjQZÊý´Gà(Öãi…@êâp&¥•‰ Ábˆ†íÖj®{rY†©®IN³<¯_nx“Õ3H2ÙI! »äòÎadž\"Xxúñgwy±$Tå­:9&ª8<Èî\ª¯ÜL³&d[h€^¬Žü„ ó`à7*÷ ìÁ4Ý)€o¼¶o"[R„°ýÆ«òÞÝE ,t%Á`¼–ü&ʼŠÇ…ÔÇN õº»Y "ÝÜ) ®8áZa••XÐÈòfVo¤»BÈGëWTšWÍ/œüß*t÷ìhàŠ¢¡dTnê„á˜Ñ3‘OÔeÃ?»)ÞŠˆ(jÝ‘O)Õž]ÔQÌÇ(ðRWWVt¢7º)z=;àõn¬ÿÂÚWÑB‡Ú‚’I?$¨Ø€j$Š$ý € ]I’5û“×ð#³ùºÙOñT¾‰nLùN줸gøT_ÔËÇì.Ê&©Ø£v>NI!afõñ1gñ$ý—´”fqbê¼øÐ\pó*Ȥ±úâÕ¦ÉÙ“öò¤Ì §í*þÎUÕÉvcÂ3“uŸé‹ÑãÞìݺªÕÛ¯#’²¹ö`‚ÀóÛž²ù/Òö µÜA½K/΂›RA?J€‡šõŸulXÃ6¤ňZ"ɇ $Qô{Ûy©6èåÒ¥§Áo”þTéʳ‚ÌPêSåÏ¿ã£æ!^ÌY©œéÊ©VW3÷BAá€à{°ì}øú­>¢¸Ãpe"¨È«äfDuPÜ‚]úŽÇÅž¥¾( Ûw/XQ]?Ye_’!c@Î[§º‚²¯°3î}Ø–ûŠõÓ²òáÍÍš&Œ?RÉhÁP݈‘@êárŒ§awl(úéŸqbŽ©‘f÷päÅÇ|WGáñ»*ñ1:èHÌgSùÖ¾Jrfá óåPÚj´§7¨²#ðÕJð\v4Xtñ¾R÷tEv [}˜DtFdú$Þ­ñaß«‰“Ã)Twi}ÂcÐb×35f€* R®M¨Î²Ÿ)ÉNfbé5ug)ãT Õl&ëN©´ÊfRYCu¤¿X/Ë«GVÜþ@E@ů>ñ¶Å ¢ÄòÛ±cøf17uäÞ,T•ô«>&LKlšx‚€X%K)&È®!n¢kb&@£“G õP;”Y¿‰=Ô̓¿‹’ y íÛ¨Ž­0Ósä ái+ô(jüDJòˆ¬ˆ*Ψä0ìCÖ>ôÐó±çLJªöcÃ_ô£sÊãþX»9¯e,¡—Æ|ŸUÛSò kJÍt¬™GÌ+ÚÄ ÈŠ+IR\Æ´+ÌѬ‘‚]IÕ•E rI *ù óÁã!䓹t)gËŸÃQ N¾#犿ò>=A1t—¤Éð3ÒŒÉZ” Y¸Zw£||}J0 !ÉEnႉ€|ôK|äzU¸—9$i‚ï$ºÍкŸ)éó<¯1GWò+ÑKP°ÀI¡íÖ¤…rq•³?{`btìÌ^—€$§xÝÑ´ÙIb@:±¦ÑA;yr,]Tït¶“²5"”t¦DÞ%A`½UxR¬¥;|‚‡#·=‡nJ·:{ƒ\#(ØØ"Ú­ç#‚Ì+@³9‘zÌ©…yö,¯¬ß~ž¤wkè¸ö›;㉑EpJ;1*ÊOWPáäýafùßf~1 f½<]gÝÙèîïßã-Û‰Ó£–z¨Qâ"ó ÿKzlùpdåv™Î^Aí¿ÄÁ6¾!™w4…hà =ì,ú7´ñÞPå8Èeb7dÔ„¥<¹T'PZìƒeA¤›ŸYLË~ K–É£ñ^ÍF†HDFñŽUJW£Ñz«ª7BŒÁŸQÕÛÐÜ FY±šô QâÆ§‰Uî¤1ª¹šÉ…”‚þå§Eºd­õ¼ òA!YÍ‚cã/42NVÊ´‘ªwê œÑêzÓî½rštƒœ,¡'š;„ƒÙ•&ÈbiZ4y +Z²ù‚÷úè,Nœ²&,r­H¯.¥|B€oc`rIÕ¬¬Ð»È­¯qT(Øj8 ³0+VBÒ€G&ÖÕ¦¾Ÿaê;·?'/W”Ê>C:MARl´£%DVDdL€Ü©N;Kª9w?:zDh˜ÀÍqƒ< ¿‘Yª©@Ü7œ¢õ Š(oÒ±iéë6'*²–B¤U–«c9¯N ÐÙ”ø‡Œ§_'bÓìb'®Ñ²²äŠ´ÖFµä΂oGi)ðòõ0õ@̬ÌQ¸cPã÷òm@H£´(5j¡«j`+^ä_áU¥,ÜËŒ‚À´º‚ ¡nh]‘æj%¾AÛZôÅ;xêô½¡Ë3)‹;ø$§¯>&fnáúŸ P)ÚŸ%±t¬|F•Çš–ñ±”]ò·âžŽŠ¦A䋎ΈHåÙÜI:F«=FOþ9‚ÿ¬tíÑË"pA¨ìåèÌ\ù(à}YÞÏ…¥&™ˆ +G¼ªóðÑ©d›ß¯V(Öªti£p2{Nj$ÌõfL`ŵA¶Ä*šÅ«Zº¦K_à 5µ„ì‡.UZ:»µŽUnù"kZ}¦‰Ô“¹y±¬€–N[v)4EyLv ܰ’Ñœ§-NÄŽ@*´|&îˆ\úÛrkµ¯QliÊø˜½B˦ʎ`µRé‘42™I³÷D«Wš¿?U;Ð+LËe·ûLö¥™ŠÆÈ;¸š"*ªIáN\¿Unxf'©–‚}Šm Ow­ió3¡ ¤auf©˜˜J%•Ø£$Å©˜¢”Ÿ¯o¦¬ïqcõ›.EÕȰVRÅf6Éâ›JØ"¬zE÷E|nœÇ!Y¤‰ˆNJøÈÉUP+Ml~I£ÍŽ„5POSÇ`ÝXÓ¯uu Á#‚ÜÌÿ °ºOª»C=‹s›•—…”¨ jáR=‹R” Él X׺L3+ªu+¥K/mötàE'ȃÁ*üI`T/¤éÎGÓû’áC‰ ÙFCÁ¾ð  «ªµ¿gTjíM áÃÇ“vVFTˆE©÷à­ ±Jž_¢²ê•óÇVè½v§ 0!fL¦\+À·¹å¹Ÿ ¼†!òçí•sN—)0²èUË1 ÃQ Ð*Oš¸P¯5 %¨«ênŽŠØHG4=%W²¡T@ °ìÅù÷ù((^÷(Xú†YEkú¬ZÓP•¶èò*Á&ÔìñUìtÌYñäzm±à4?rGÍ…ù³k_ rÈñR–ÂŽ‹!ÔŽºóN{7ʼnø©åà&¶²LYäÒÒƒãÀ'P6;šÐc±$/š½WÔ°÷ž—±÷ÔÝ1áªëº»JY(ÎÃFÃÇ\\,”‘4œÿ&‡Ä‡«ª¯ÿ‹’Ûé'›ëúÊñNXv½Ÿ“j͆$ÛŒ*IY|Êê`êª7E‘BuOî ELJÛÞÆž›25mû¿_ $º²é„Û#¼PH[ Êr‚¼ÐÎŒ¤ù_÷YZÉÇ¥'YËÁÆšÕüF•OE23¼¬ê«âÍ-H£Ð‘:S‰¯×ôoÚ‘ªtµl±Ã{|¬q² i ÑðÏäŸXï¹%lŒÉd}7lì©Ü)¤ dÎË PXø²_µ…¿‹v¥¬¶¥uœÝ›ÿo Ú‚Ü1—'HÉEt`ŠÁBþÙ‚ù† hÃÓeô7+§ ¦îì¢Jñ¦r¡£¶ˆ• ¨’GÙPnêÍMâ¾·×sl‹÷#鎡µ÷æ1ÄÈǦãÙ;Æxí‹´·kÊx‹më‹•ÇÃÖ³YØyyQ¼ñ³)˜Ùd$â~³¿q}«o½#}êšïÃÅÌÛÛ7FÓ¥¥o|I¤³µÝµ¯¼°ôü-M–³LüoÌÉm13a:äh™K,‡ë†Æ3”ý“ýÞêš¶t/TRYú^*í÷Öµ&ÀÎÂÔYçˆw,X c6=%“¨á"69µUd”fÒñé¥÷ǤZ†~ÀÊÂ8˜Y8ù˜˜'Pÿi—¦bå4ßWÑ4¹‡ã7mæ¡eu™®evyNuˆš›’8g Ûh,™(©|™ 7ÝòÂA"}_ÀVÇ… ¼Ÿnõ3‹’>Ÿ“4f)NaŠF ÂábÑ‚âŒr ÌäG-¬ÙÓÿ¶ý{núÍ£íkz·¦éÚE¯Ÿƒ-@`>ØÝ8˜M¦6³‡Ž2r—6­Ò–/d›`bRŒ(ÕeLôï]7¶~Í×ý;¾n-ôÛŽãU¢áÂ9°Ž~¡s' $ ËÇóÒ˜ÙLi¼Ý\q©zFÌÙûŸCßzNŸ‚ÚN9Û˜î=@ž¼cŒš¾‚¹U¾&àÒõããdâa`‡‰•[6kS ±µ8O)|c4Ômyù3{Ö–ž &(È(˜üy—…z /f“ÕyfDΤ²£äÆód“‚8¢;CP P¼n¬£#f‘\ÀQùGDѺqÆžc#ÚR°[~ì†(*le–$w‹HÌ“ª…Ž\0iŠýuÌ%‚ÃAÃÌ›Š¼g•ú©ä•Âo†ô|x-DIIÁm9!•85PPÔ£,ÈbĺccBXâS YO"óglp;•jEÿVC%ü+pÜ}"žfn"ƩɢڌFF>-–¦Ý¤Ýq²hêKÉ&œ«=fÕ`Z« m¾kåf¾?šsü¤+_ $²wG—)ˆ˜¤ ·p=šüÍ›šXjGCîò·fدmÙ´%–6u ¯%xGS+‘÷¨R¡T" *Ȧ06w%ønüì}+˜Žud¨ZMù áŸ+âVœÄNCžj‘¼dY®ÍäGy§ÕÒôhÛ)rÊâ°•¯¦……ZŽE¬ šÍ«¥Õ$õBKp}ŒÕyejéé†Íž»«IrfÃOÓ:d»ÔX$’`DcÍ1©öê|†oÕ +Ï-¨~‡lÌvÈDšG³ÑxÇá&ˆË$ñ‚P~'Z%9Wg.ÝÀ/ûï¯Cƒ†ðÃ"÷¶¿m±µCDS0 @½p'Zg²ú™y1ÈèB4›¶°´¬M‚F´ [¶øU<ÖSÓíEÑp1º£5”½UcŽÂ¥ù RèPJNríÌÜð®Íã–jš¶ÜÒ³õÌܤÇÂÅŵòè^§¦4Áª‹:¨«½gÁ—o'+Õ»Zqá³M4(•1ìÊøØE©ù8˜µzõÆÞà«[ ¦P †­nÜPÔô*ÝÛ©^€*‹Ð{ ÉrPò9 G‰WŠÌ¡ ©ì€p8Z{{¨bµ^T?Ó5ñ˜Hб—°/Õ$ŠìAn‡ÆàMŸ«»{žKÐT»$·q\6ÙHâÃQå¹&¼ZÚÎÀ„ª@)«p ØàÏ!@¢ˆáÇ)ç#Z–¢¨p\…íâaÕ˜:ªL?'ƒ>’¯VfQ/óʈ¤¨FšÄò•Nœ3ÚSCÃ|¨Ý‡v@åùSÂýAeaŒŸ>€b”ÈêS©ê¤Éoâ¨TÓ†e¸94 %ö3-7¡çÉò务Ÿºü>d0$q@²FÜ WMM±P¨)‰O¸¥Q$|C¢#.Èþ!Iº¸­h¥ybe<j eARAK)âª8ìíÀù!%Á_:y _gr³=‡~BuîŒÒy¦æMFÊzù¨`IR­­“åÀ‚‚ô‡Õ1mT” ÎiÚÉZ¢5ñÇ4MŽèͧæ#`žáDØ{ò~ å\Ù ö!P/nTrèɵò¨±nV—Y7‚€¬ÈÁd^‡­«pqòàÍrÐîÎÒV»±i‘ñdWþŽÜ™“¤ fê:0©“GÔ±ÎD5œ¼Tc@9þ½˜2õ<9fý¤°=Gn¼•úW ŸnXëò —Ž6౺ 8 zÊ=Á€Z9#TØòçòÃ@«aÁaÀlÑæËYm»tj¯‹‚…? ¡àösÉffbQ î~ŠúnGy1fàLðݹF#–ÊH$Üv‹)SîYÐlÝz%J°4á¿ò­O_ìÞ>*,8䡸íü´‹²•›rGҰ剀\¤òö*½ŠöúnÁ”ºF@Z¡ñûlŽ(òkîälÅ‘ˆõh;r½Š¢&¿,+/à›ú)c[·E ±SǸžU†<ö§HU•öV÷’`PuO+QÞÜW|»«iµ8Ï’§áx©³Ó³Ìg—©p2z†j&´óu2,Å‘Ùs=AÝÚf´DµR…V0-XÅ‹³QØ•‚¸ìžœžŠŠ”µ¹Õ´;cùLÁòÐљӥ8¢XÑéPd ”•ªó Êàu•”˜ÝH kC" ÕXÍ­ÒwIÍi7™§u˜,݈pÈþíôg&–ø£p¥ƒ(^¶ ¤‚XŽy žoÓ\½¶V-º“©.ÀÊ èÞ#bÄ¡E o€MǨ.Ýnˆ]k•Q9®Jû°Y¦Bœ€¡ ¥ÿp…›ƒ7êì_¼þþš}ëéÿŸàÔ³E²RݲOfÉ“[äÊi r½4ÈÍd ,ï6…õbÝi•lDâBΗ¤i[{ë}NÂY5”"“B½:¯ÅË?°Ufò(nÿTsÛžïËöþDÒM’!È 6bbvXèZDªä4œ—‚‘èÜy²ÃŸÒ11qÖªŠ ©æ™ÈWŽXû‰ä¥Z1ÙûµØ³‘c‚¡/ÙnÃMNÈÍ`|YVŸIQ;ÒsÜ£8÷ò©fûuDE[]ë®ö–ÕÚy¹~¦8t(;Î.zÍ»’¼½A ž£’~^Æ'èÆŸ´¶– d¿ZGmzS‰±§_5—’z–fSŽ@çØ ³ÿ'ŸyÛgÓ¡¨èš~¥•®Þi˞Ēl»¬Ì'Q÷TÆè½2ÊËÏ͉H[í&ÌÜcÓgrAP»1ÿ1zs{‹Ý¿Q(gÅŠMå’@u\xG›±Ç‚‘mNÌVÉ-ë(~ñ~áNN¹«Èg.C¥ì·¢ÑÁCðn,€¨Á,™re6”Ù$¥©Â/4ª’³F™Ôjðò÷êÏѾŽàFlBÐÛŽ9P?ÿ—ÝTÓfˆSè4mEY‰¡ Ùv+ɯ‚9 <¸c³o“~=,lï‹‹žϾQ˜ø´ÛñëQZwSÏaÔIEG‡§Â¥_®Šz ‹¥hzÞK'æ6fop†ž7£ÕÁ ‰±j8ì1P½Œ;ôÔKm¦.—lÊHÚÙj•{!ö³»€ŒžU ·‘+/Ä•J Ÿ{ÒßE· ÈÝØo•œÙV`Jõi:Ë&“*WçGS%˜FìÞÞowD>Häé­Ù}‰R(ŠÅü›%ªÁ²•OqË.gN•,† _žÄàÙü›5°¡Ç®‹´,ùCH iðE ÔRªÎ‰üñبþ`Œ[‚~d0\lÿ"X‹¨¤žQxêzfJ¢†~‘ìÜó™}’E[±r¬ªŽé«ÛR†FÜÆ¡>z64ÙÙûº©ucñVbÝ @þüÏo“rNkýóhRÕ±r)$Ê€\À}‡¶(ìóE4 Ñ—° ç»2 nA)TyÆC`ªÈ $Qñ&¬Ò¨$|Q5Íd徯a¸° :ªRI¶ î€mfêì½AäRo´WUÀÄftãÌžUsÑœµGUybªHëNO3ì>µcF«¦>:¿É pªÎP-ò{"¡w‡ºïÏl–ûSv†><ž…Z†tOT³P€<Ó¡n‚ò#©e%~lü­jÛ¿,H+ªƒÀ'æ­Êä#pIj؉ÿn¬AêO-;éQýÇ15 2²¢KYm¬›?•¨¤H¶µãË]ÐùUøõ4ÓUDªÈx£KƒØêìgt÷bIn¼pÎÍŸ_~–ÊÇôKujx!c›£ÓLÕåjÍJ(ÂÕ1ÅÕ¹FŽjObä¹Eê¿5:‹9" ]üŽÄ§Š ¨ Ô<¸_qÕ›ßÉK¾ì´<}ÇéG¨Z59ºWCÎZŸÖÓÆ³«`®…=§Õ¹vVö(Ä'¶j/sô\—BR.©ÓK¼‹e ÛݼihîR­dUÙY€^¥§J–¸‹ÃŒ«Ô©aU¯í$íë>ð5Q¡zg ­"¦Ÿ£ËNĸ²­µ¸á*ÑfKÖlQÅgå^¨ –eYö|–œó›Š´“[ ååä¦='ÝÅé9p]'5ÇÈŒ¦qåL|‡ n©Á Ž–{×Ró·†ÊØûvóa ½M”¼ø>)h˜ÃO\FÌŠ,iŽö®EˆF=åfë<ŒnùpÓ¯M?"dæ¨LHdA鎵Êli¬K3)‘5¡ÙF5eF­ÛúGÐñ¾¦Æ²{³– M®Å•, .mjÏ‘UëëY/&l«ºß#e%v—¼‘|2šv(«® ³=pE•غfU_JÁuX&­j bþ@¯<:L2‰ñ?"7kdT5!ÔJ4J}9hXω­O¿†9¸Îå£÷8ØP[=lª $yÑl&ÊÄYÙÁà;¦×+VÒrqÅi¦âfÿÚ¤ÚøÖw{*d)/Œèï“Z"Å¡&ájê^в½*˨êY˜KI,sñiî)$ÿã¦XéÚ jÞir©C•5’å=RWVeumŽËÍ6Ü/ 7_ÈñãtÉ „Ø6ÄkØß5óÏ lÄð:°'–]rÃ?;PÆÈ|‹ÒÊnÎYÕœ¿ ÒkûÕñܵ.¨Ê¾Š~˜l¼½h6¥ƒ™ù¶ÌÓ6þ›@2/þßPÔe§Ë JñZX¬¯H+‰ÛÜ]˜PM/¬Ú}tÏQ-…”BáÇlííwM5YÌÑ5+Qµ ç¡Ë“[7%š©_3ë^ ^€Ó2Z×§ØxéÆÁõJÝY™YÆè³Ò êTBØì/>Fâƒy]‰ŠÖH,ü@eØÚÆÄUñà@PjÁ»ó`_¡òÉPK:“¨‚|„CZÉQ™£QÇÁ`_4 £ˆn•£dk>©çhù†Ù˜šö`°Å‚Ú¹ÊÅÊ›UaK¢ª6+ƒøìëæ”GUH—¬›r;kzjq8 ¥ëZ|i¤åyhQ:|å™äjÑh—ïÞi(2Eûžƒå)ÆÁÕñµÏ]÷-o•Õòõéµ08g¶>nJ=éÈÆd¢ÎN Ü^°ñ̳62\¸ßI¶ö½éö«¸q%¨Òú8MÕ ¬4N˜9rÅŽ»Š(‹Y¤1ì°Ìeº+uËw«…ŸS¾<€G:qˆ¥~IjY x“z1QdrIÔ± R/fhá•€2†Pì ƒ*º]ÙÕD¶ŠÞÇZU©¦Û[CÞ~˜în|³¦æhm < ]ÕΛ©âØdàÛ:¦ƒÁ©Í‚w^ЖFl÷ÇJµ¨£DѵMsoî-·WmCvhX¹ôŒ|l¾ÙzÖ›¢$c¸t¦”yµþŸÌMO±)ÒŠ£³G€¿íÖR×w6½¢ÑN£³wF6ÕÜé™ c®n~í·u1Š”°\4Ô¢ºhÊǨ÷Ô¥òLÙ‹aj{›í÷×,]±‘†öß{;p2$õg¢éÚä1k5;w)ÞÎst Ñ£S8¹2´Lò³¼4’bcÛ~0š@c¦²Æˆbˆ"2ĽI÷ 2IÂ'ÙrHGHA’V¢Y¡»j‹£µfP®YA^₺©®Ù–¨ìÝ?1ScgKXۚΫ¸4ÆÄ®¯¤ä–f™Œ“«EòbVÙ£·ÈïØ{spíŸDuW}ÜYí®m½Ñ¶uÝͶ°µÅÅÓñtì _ q~66kø—yääfz eˆ¸œJ¸e¤z•´4Ý qcoLŸRŽÊÜúÆfâÚÚ&PÔ'I¾~k½½<Ô¦òî5©A˜˜A¿üá¤gäW­\)¢_o{bí]Ë®iøú·§›çiꞢ`OÎF§£B•Ðõf8`±\½>‰‹«fOû&.^g†Eí`¤„q¶3Ì¢e%“ô¨È·N#ÏuU’’ÝÕ’RͽRWúHØ,³ï*ÉÙ™c=ëÕçÂdñÕš5xÑ ]&Ý ªlީܪ;oÖýƒ¯ézÛÕ¶fþôÏTÔõ-ß,\ö–éÇÎH°ÈÂÓñ#Mn#¤À _o¿jXÛJñÖõÉÏ?VyLåR‰zÎ4•)9½K#ºô(IV£?!¼ém6W£{naÊxø_ë1È—’Lr¦ˆ&Œdè1Õ×âÁÝ{%|¸Üý¥èÚ|"qqƒuW‰\uB‰—+ã%›±d‘ÈP§· ÉEN¥îìl,:/¶q¤ô籑*È%ÏÎp‚åÌË*ŽÖ´|Q lôÙíY²3"ëâË~­š„4ˆD]??L<8¸ŠÏ*V÷‘šGUÛbàtÐ0§‡ lÍd‹;U?„CowQ2ê¨`ð‰d®«§™×lp[f¯RÌZIa&ä9—ª©`¬þUq׫»(pÁ:1š):wr¤®œïð´Ô…K·(UÚ!ª½ÆX¬ÑÕX:–Ui¬‰ø¦j¦D`Rgx«Õ_ËÈbÊ“›TbT‘rŠ“? Rˆ¡œÛ):M™‡J@<ÖjQ|Œ{p;v£) –5bI­£¦ƒb~ê D]µ°(rÀ²©>@Ùr~=y*Î\×™jpâ­u?'kIo»RjMpÇZ MÅXô*Æe˜3¯U˜R‡Ø…š,û0$"¨ªü*†Ì‹ŽŽ¢`’a¼jsE+ò:òܽ?ýJßæŒÊº¯bÉåj³§EœGO…˜0 ?»?ʼO¤Àå–3¿Á+æíøë Ä›1î¥fBã² >ο‚Õ¹Wôå‰Pœ‚UjØmæ7R5$-àV `y‚V4eèjò(¨!üYOžn²Wñûy$èUêӠìW³UË{iFì H‚T2’ôÛ•†Ô“ØJžE-ß X³4ß’¦L ŽùàŠ2~„ËzJ¨E^ëÕ]Ñ1#€ÏÏ%Yº«P¸‡aô×<¾V‹I²­föMIvP…ÿî:Cд™H¢‰wo,ú@*XξJëH®‡¸ŒÑIqÈñd öO#§ZòŒ‘â, ·³©p½Aù+Lð„ü¤¨èîæ„éýÏo'Õ‘Ô¿Ü(b²û6„ªÀr¯:Ý&ƒVMðÚz]ê0°¢j]IŸ^¾êU„ú¨ã…ú0èÙO"‹Ê( 2œÜ±f埂 {[‡%¿þn>ŽôéDjx „]R*¬5.l_>Òa¾áÄBX ¯µ#Zª< 4lüioŸêÀiÙJë>üpP€9 Á@^[d¹R£© üû}KP–ƒÌ¨ ;ûòòÁ¹ÿˆ_ê’¿Àè]£ç)‚IVsÀà“Â"‡ù4*;NÞÇ苃ciÓ­Ž¡º/qÓØvvr@aVä¯ n?© Y£ÖD!›åhmdýÔ°Ekóð~~â8ÍòDÅ€#FBH³U\ÄŸÏ?çÈZL­ì}?Ô¯Jw¾ÄÕ$•ÃÜû[VÓ(É åaVbêC«Ë#‡CÏu3RŒHeúáïHÄÎÙÛ£pí<žc}¯­jÚ&V=b•sþ»P¾ {ùWñÐ*²Á{¸jW»ù•¬–aÀáx ‚SÙ}•‰€>E€n(nyçŽ/ò7éïÿGþó½F\L)ài{Æx;ßJh‘(;jS\}KØ•›¿û$g©¨~Âåü|#w¢øæçaÑ©ã*+n6 Ú–†üéút~GÇ$Xп§]H‡ê]=˜k41fÆ ðøç±*ò”«‘ o’6xèuþÅm‹%e3«<çS1w “ÐT |UObB1…j˜<çÖQ4¡ŠŠ ‡ŠñÖÞB¯QiÖÔåÜ ‰ù|GúI£jfòÇvðq4ÇåRµ÷@I]×Í@>i_¸ªõ=–›,Ö…æ(ǯ?e ÍúpÔëÕ©IáTö^üŽ)ùPB·?‹j׉&|­€ø­7ë#Pä§` ZìYEµÁ¥¢H†¬Û«j%0d’dÈzÑÔ©bÅÏ#•ŒÁ‰J$Ù<ˆ9,Î û¤‚Z§£úÎSåˆdJ~[ÛÊ+ÖõJgR“Ø*;ôù D¹yQäoNf‚Ù™ƤTK"kѦ)`’àÞ¢SDz½(þ‹ÍQ-‰ýÌÿ=å¯íZmÝ®çÙ øõÏ(Ò-2¤Ä ¨4<Aâºv!D}Ç6{÷ÚýWݾì—'flþÐ|ÂtŽ!ª/vI ƒºÐ—ÓºbÁI¹íÌ̬þ—Hxïâhô«kdî­q2™iYS!Ý‘›Ç.H|ŠuvdF?ŽŠÜjºüŒ™V\8R,i'q\Xä©*ÇÄÙ,L`Ù»¾~G¼’4ªd7ä¦þEhO+âÍEvpË\­ ú?úe´vZe\4›¤rDàT—¢yNCµ&¨Ì¢& ìW²ùOÑ·uf>™§[NÓdJãL½ŒÕ¯Ý‰êÓT Êe©3&õ,´¤»Wo`é¸Ù&hòa%‰âmÑÜ8fIv LU }•à ½…z›>Öýfr ¸¡ë;v( :q'ì`„Q(QåEšÏäB{ƒ¸ÎJ¯ÇDö~êçÿRïâÈô/(<,¶ºWåKXà­ B|ðw$€ª»êN¹=%òë,ŸÞqZêÔ¡Ë“F+(¡‘ Z(t?Æ:¼UäŠ:Ð1›/ZɀέmgøÔ˜¡«E³7z5ʪÑQ‚­ßÞL¥’lå»5“¬¾vj¦CΣ%0ëÝ¥îÈÔŸŽØÔ$—«.æü£´ÝåõÜ»‡%ñ_OJd-ršBÁæá¼hެÎíjw£¯ê$ ;»HîMúhc%vPü)ãäpG5gR~O¨ßˆÎÜiÛMXR òØ7Ü¢ØWÀµõÓõ,\lL\§Ç_2ÜCÊÑ“Iž–¯… •f•]TŒØO‡îhÌn‡ÛþòÔsýBÛšj¼ïæµñ‘È¢sLrVÌŒèÔågÚ¨œÎ|£2÷ðÈP,LŸûhÑ`VT+4RüÑÔ_"Ž)E 1/U=&f¥z’{1²¿n›4ŸZvµ›ö2k2ÃÖ¬Iiô™ZâIüѩ֧“vfÎÃÙ¹6ë ÄSÈ UÈŽlƒÈi óyㆉµ_&^T/Ú6! ù*¾~æb;xôÓHdlPÎn§3K…£¥zÆ‘‹Hð¡_øw*$È)`xú«{¾Š..ÌÔ÷6‘ÚÇOÌ|¼vz/hp½úõ´*±pI Úˆzpº évzÓem,¬p¾ m•Jä.ŸŠ…Xy¾,><·, „ÿsØ¿ý7Þš¥¡ÿOkjÍÃ?_û Ï…Ÿ¿,§cÏ’U‹v¡ç¡Ôò—!r†Œ­2ZxUü°Kl ¡LÀxüVUÑ—éúÞ3¦Û¦p¡wë*•¥àù€åMüãGÛ.4£\I»ŠSÇù(_“bÆ‚} 쬀ü¾<5<*:2°Ö]¸fº|\SãéÉ=WI)ßr¹U$è¿–R}µI1Âb³EìÎÀEfõîÞ4嚢(à‰¨ìÌxUÕ=®#KŒÐ€Ò$¸>Ë%§V±ùÔ)÷oŠ‚¼Ÿ¬WÝÅÇXÌÔîßTåÖêµQ±bÜ€ºÛ;)¬Õz힨áºoLs±+"¨©$¥iÕ­Yä ‰8¿Ž•Ü) DÙ|‹>W9å•I«)þËñ=ˆLÒûúÝûçnú}¨i›AMG+pƘz†Uj’ÇÄuOÉ8‚ ”kdEë9?‰P7ŸÄã(ÜòêÝ{©nYŠ¢‚¬Xu=ƒò©<Ô’;rË—ßûÓ\Ù˜{9téBé¯äëš|ÚŠ®ÑÌ®‘w†K Z~ GˆŸŽYü„ö‘b¿}‰Š™žîéMŠ2Q²’^Ä’IR·àͬRp‹ãÂç¤M•Ú¸õ´Äß*Ìü3ÒÔ Yg¨Ùí}C?pÚ;åîÜôÃÃêŠØøÑÌK‘å’<‡†X“šUdà2–Ç ÑhV´õ]ÍžVó®µ’ø­L–•-l¤‘‘éXÙ1­F´\Añò'&¡–LÉGoè¤&¢…H¤z~JÉKq¯ä/—üx;)ûˆõfª÷²gR_n䀳’BðÖ‰íTAü´g¢é°[§›þ¢²z>W™c"°œ!UrÏLR‹ÉV9 AÜtbäØX™:±¨Ë­ùVÄF†Eÿ"´Éš±±õ#JÝœ·ýÎVDËæ1¨úpÒ°-«e2Y9ƒ?AȺ[Â’_ú–Õ_ &œœI»Å‘0ÔEòžï“âƒ1yŽÚ–-. ™†+|üŠ,lª¥¥yíË´GSÄÊ×1¢÷~¼ÓÇ䢰Q¥íÛåjB‹'‚§æü¶#ø&ˆä±òû=øö$¬€ÉKæu² gb’¡›ŸÉÕVöªoJ4½ßKŠëû cìÝË&e®KmìýNÒÐr½žøÉ¦4šlß LÄULl»sUÕ}8õÏv æÂÄÛW28w¬T)ÕµÇÆÒâ‘™yÏ*¾H›M–Åo<„”™Hœ+MÓòq÷æ±´ôÜX>‰ê7ú¼]OOVUŽv&£|]e…'’þ(>.£E¬iƧe!»D¼ídmÛд–µí,ŒÿWýsÕñrqb«Ljm‹õÙMë9tÕ²Y—ÏÅ¿vü ÒñíŒbå¡dí­N#Ô)5ÚfŠ2v•َŬ$êð1à l¼ø¡‰hXÇr¦V"ЧÆÊDRÒ4áÅô_''Õýˆg”¬s·„t¹¶Të'®;j.‹K&6FS;¶<–¹Sá*Å.ô QµÓÓšbëž²z³è¦áäí­ó·4ÍÁ¥cÙ’“Þ«µ´»kØSš!Ô4š®N4J/gÆ “˜nÃ6}Óñ´Y¶ü]‘u<-ù‰§3.<ëøqÍQ‘ ȳ*ÉÅ#©´DÕE ËFññ/Ñïxî¬Ý;î3Ö FžôZk¸ÛxËL×:˜Î~lÓ‚tÝRRl‚ÖÃÍ´ŒS‹Neº¯÷+³1þávn™¤n]±\}½ê>™’Qe’#¦ág°ÃʪHQŽ&Eš'´ƒ2!›KjÏê6݇Ù¦›É§“©a2æíŒ˜†ü¼-[oë k…ì*ŧŸ¤êš4ŒmäÆ|5ò-FóU›ÿ鲂²4±Q¿k"ªH>\©ÿNÊwÖÄYMz¢®q^pÂyIÁÊ€…ýÞ34¶DŽEbÅ QÆã—=È¿ úΑë¦4ØŸS¦ÞÖ7>FCé;¾Ù ‹¤z±·ñ£•·u¼™5`×\ÃdÑŸ>Jæ¦x0Ín)zßA=eÜ› Uܾšzƒ “©m=bøº›©ÆÿóÞF>zœ¤âØÚž{é–l)cxòòk|€VV=ëG¥û¯Hÿq¯àëzwúƒ¸±³2s°ô§6ƶ\ç麞š¦4ü¡\;#ÊæØôµÚIŽy“–þ×w&‘»ãºµJÇTÊʆÏת-L|J»Ã/GÈͼ¦”|ÜiN’»%1Æšîפ¨Ï6KC<ðµÆŽD±B¶òñoµöߺnâg•öÒdÔ¤ø0ÌvrÆ)VŠÒøä"èò'•ÓÆ6×ɬGŒ²GŸ_4ÝߤjI±6¾›§çz{«£ <ènm‡¶r·WRÓÎn”óʶ‚SRL,„s_õ€RߌØïš`3‹"8”ÎÁÉÉéùxic›Ë`m©NtÈÀak#Da7‡* ^B¾<µ§Ö©íÿ^WIÓ}:õ7^ÒpßÕ~—ëÚpÀžMóo¡Ó'+993'%›+NÔiÈœ¯‰•§ȯ\>ã~ÛöVŸ®êûóÒ\¬ˆí\\¬ëú¥‹<|»ªkQ|ý14Öò"fhº‚ùg:S+"_½T:©‚ eO~!,¢K7*«3ÑåU–8]äµFó) ]cõÑà–YáÁš!æí SD6 4r¬M`ì{«9@„­HÒ¡YëÕ^Ò6Âd’˜c6¦‘‹ijчyùX²ø—ó*ÆM.Ì‘*¶!(özMé^PðÛP½|µš3âyŽ;+2ôRÍ2’ráQ¢ªþ6…~¢~œzfº$q™¯äÎ|%¹™–;ÏÍãë6§i”*<¯6G¤Á^½TÔÑn®ÇÄDÇ·JŠž¢qœÕTIÝjª³V"sAä wåØÑ6ûÏÝ™2³Ã‹.±!ˆÞÛÍBª®ÃƒvB• àÏTû;ÚxØÅ$Â9dP*»3BÛ±FÕA¢ òE¡êo´6V›5­Vy6¤æ¬iÈt½|EB÷¢—$…^;ÍÜ”p4ùiî%4yÂnÊ„¬Ä™ø§Ïi•ePÎ÷èArÈtŒLs½…S‚Èx%[Ó•ê'?NÓlyAmýßÄDÐêìQÁମ‘áŸûºøèÈ<0gA:¤{^4T¹AÐsCËã6 ÕP‚̯É*$“ µ9~ªÕdK¨+Áè䙺òf>`Ç̨Ü 3²nH¸¼ì@oÉ"€b ARÅȺ«öÀ,öì6¶Y#‚l€H VV/‘y5fâk:2t'¸Uö+ÙJ»©F(Q”§u4Y„³Æ¨l„¢õy³9.r0êy%§ÈìËñUnU‘Ñ4h\JpŸSZ±Vñ²¿T)D !ƒ©“r@Ä* áVYX‘B §J{I——DðKÒn…”v nü0Rj—* SQÕi¨v è¤ðG$¨¶Ü•æï[1Ʀ¢µMÎÀJ¡×`ÈP×Rº:E%4gy²ÊÈzZˆî<‡®<Û«!åJ—nÏN>—ãõĬê¿¢lþÞîC‚Ó˜V¯÷b'?!>N[³4É_¦ì/˜*cžÓhòÞÓ%кwbë|Ðõ# ñÇÕ瓎¾O2ùB7½ ªËòö'²MË pÁø,åIúð²0`ä›:dZP tA-¨$Ø”5íøÃ½ÃD’[5¨{$Ž)…l[RÀq#–CÒÈÇ¢ÍRN[£ ó ¡[†î˜²¸ò3ŽWª¿"ÔepΫ>ÔRʤ"1÷ì…yZ ³Ç ÈVúlŽ`Ét,ðñº…yu%güU"xþŒª”*ÒùVó?* nW»+£íìUAÞD£ö+rT«£(V a‰$¯†Ä· ¢©åï’\* IÐVB„"ª…¢”6ƒ[ؚصAGäú‡¡X‡.Š¿âVíán–šª|šh>Å É@@úži”£Ë¬ÝÉóÕº*£p ‚IBž'^ªvN½˜;Œ@A{Ä«jv#äù^LJò™ÕÕYŠÁ”É¢¥«’xf#…?‚,P炎†ì¶Dz·NÁU‡PK=Gô_d+O#rÑJ0ú*èÙt^ðóRŠ‚EAàª)§RVSÊ;3²‚>+È'BÊx0=šœÓ­ð½Ã¡êÅù~*8÷EO+Û¯R¾ÛËö(ÈïE˜bý”rë6^y<ØcÈ`uÌå±Ë+«Ã0Ûf`~h e¢6Öòu¬ƒÜ8§õ\Ñ‚ÀP»}Äßr~ NÕ¯£æƒv¬#CF™‡=É$¯*:ñÔÝÔ øØŸpëÁ*éY¥ö÷ì8'ÛãÊ£IP>@`H‘дj*¤Û–a@ cî[ر ¾çÈŒG?د$n—œµRý‹‡ì–¼¼ù<³9f€€ egÅ“uüx‚XQz‚xþ8>I>²¡Žw> ûø¾hñÿØš« *À$¼L— ú¿UåB˜~¿7“¿=Û±þꊩ÷#žoó±é¾L¿ú3êæ ‘:–fÍÖrøâ³ÈñêkRÝçNádD³³Mšº+ô ‹~`ºÿ2 ¿!ÊrªäÙIaبfHþ8< -þNý,ªßh›ûO^ªmûé[‹K{Ž^Ÿ¨B˜ÑÂ2ô¡=*H PÇÑ\ìu~•‘£’_¦}[–ŽpTþkî g…’Hü~ö¼òaõÞœàY“!0È)°?YÆ£Ç:¼ÑÈ$2«MzäÿifBªÞIºÉ…ErqñjÈ t3,¸ýìr²GÉ&ƒ§jÜ !ëGËÆ8Ó¤¼Œ®ÜD4^yJh \d§yÍ;câ ½ËeåÖ¾iZ¹´/,lÌša_ªU¿ Ò®;ù{äÑ~F‘ £þÚ«HõḦ&¤M¹¬[+/d ‡â¥ÑÙŸÌÙËiM:øRЇZ“B¥iÑœ¹æÀðd¼y $f3äu_`×D-v<©ä+/­ƒÉ‘Ê+j¥Anç>ekÃ`à(g*ÂÐ2ú°ÚV“H¦C!Z?º±=KLÍYØ„ W™É§Éu{]Ÿ€_óò["JÁ]‰[“.¤—àŽ„)A·3-ªÆÂUfŠb&PaáXAƒõý]Yä^4 ¨§Œ?iý²v÷ãàÀ²¥Äû‚’€S Pæ“.ÅÊQ©ó™èò© ª™ï¸úˆ‰–7r­°(/ç€Cš¦¡_ͨŸWÿgtîë uÝ´;)^c ®ß¹FÃo†ÿ¬…`ž¯Šo­Q4=Ïv$h—È^ÍØ‰õL†€˜êôpÜ€F¹›o+Vº$±‹’¿²€éØÌÿ&Šãµ{•+2ßV ¶ç™áå Y·Á€‚ŒóR´§HFEìèÁϲÍ~ˆ˜¹Õ+G!s*¥ hJ‚\ªºÏ•Vn¨„pQŠ„ÜQôô-‹3"þ —ôÖ¶RM °øùƒ£·IIõI]C*#&ÊÄÁ#… ¥£±(>û¬Õ»ìümLŸi©Èž*û«%Ëγ=ê~\’Œ–<­8oªÝ¯hy:†£E=ñ“¨l”gRÎÑ=Ë=C°Q»ÅfÈ„À}ØØ™Y˜M‘­¹FãÆX:¢U¿…wu›/þ—›uc•Ucâ¾òÄÃÒ´¸¬S§ˆ8.ŠÊþI3G 8bò=z±F%…yhÏ–|1ãbv.m‰WSÏ?#cDì,ÄšØ|Αqб™Djª©R¼Ä€J’Ybu­ˆô+ÝÚž&‹¥Û!ÊGÔµ¤1X4a&Ì“ Û ø¥¨œŒ|Zò­“,lšÃ®! ëü[MðÖ“ˆü‚)úú š•-R–æ‹y …ì&¹t)·Ñk×?Rç¡ädãy2y­^fß>÷£4zöñ”¤ÙÀ¡1fJ+=89•½w†v­šéœô›äVSÇh3£ÏÇÕŠ(ò<8¸\eìd¤T~C•iõ¡¾Ÿ†Òö݃P7äò Bª«’9GÏ,@ÁB›åÈS0³ŠÎÀ(VaVćЩUã#P¾P¾u-[øž eôZRvD›ÊL¢¥K[಩i‰='dò/ Ó¤ë[›28šuÎ]³CÁœt~õ&,ÑG´dÎ*Ñ>H³¡§ŽŸ©‘CŽÆÒ³u<ÌS' B‹WÈcÙJÙ’¡Èv ݈ò‡JOñÜ}^ÏO½+ÆÓt¸–ƃg%YæmÂLjUO¯ÿÙpodofo-0.9.5/test/WatermarkTest/0000775000175000017500000000000013044451151016435 5ustar dominikdominikpodofo-0.9.5/test/WatermarkTest/WatermarkTest.vcproj0000664000175000017500000000673110475170454022477 0ustar dominikdominik podofo-0.9.5/test/WatermarkTest/CMakeLists.txt0000664000175000017500000000040210614703752021200 0ustar dominikdominikADD_EXECUTABLE(WatermarkTest WatermarkTest.cpp) TARGET_LINK_LIBRARIES(WatermarkTest ${PODOFO_LIB} ${PODOFO_LIB_DEPENDS}) SET_TARGET_PROPERTIES(WatermarkTest PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(WatermarkTest ${PODOFO_DEPEND_TARGET}) podofo-0.9.5/test/WatermarkTest/WatermarkTest.cpp0000664000175000017500000000556513013650710021747 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "../PdfTest.h" #include using namespace PoDoFo; void WatermarkFile( const char* pszInFilename, const char* pszOutFilename ) { printf("Running watermark test\n"); PdfMemDocument doc( pszInFilename ); PdfPainter painter; PdfPage* pPage; PdfRect rect; int i; for(i=0;iGetPageSize(); painter.SetPage( pPage ); painter.SetStrokingColor( 1.0, 0.0, 0.0 ); painter.SetStrokeWidth( 5 ); painter.DrawLine( 0.0, 0.0, rect.GetWidth(), rect.GetHeight() ); painter.DrawLine( 0, rect.GetHeight(), rect.GetWidth(), 0.0 ); painter.FinishPage(); } printf("writing document back\n"); doc.Write( pszOutFilename ); } int main( int argc, char* argv[] ) { if( argc != 3 ) { printf("Usage: WatermarkTest input_filename output_filename\n"); return 0; } printf("This test tests the PdfWriter and PdfDocument classes.\n"); printf("It opens an existing PDF and draws an X on each page.\n"); printf("---\n"); printf("Watermarking....\n"); try { WatermarkFile( argv[1], argv[2] ); } catch( PdfError & e ) { e.PrintErrorMsg(); return e.GetError(); } return 0; } podofo-0.9.5/test/FilterTest/0000775000175000017500000000000013044451150015724 5ustar dominikdominikpodofo-0.9.5/test/FilterTest/CMakeLists.txt0000664000175000017500000000036310614703752020476 0ustar dominikdominikADD_EXECUTABLE(FilterTest FilterTest.cpp) TARGET_LINK_LIBRARIES(FilterTest ${PODOFO_LIB} ${PODOFO_LIB_DEPENDS}) SET_TARGET_PROPERTIES(FilterTest PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(FilterTest ${PODOFO_DEPEND_TARGET}) podofo-0.9.5/test/FilterTest/FilterTest.cpp0000664000175000017500000002563213013650710020524 0ustar dominikdominik /*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "../PdfTest.h" #include #include using namespace PoDoFo; namespace { const char pTestBuffer1[] = "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure."; // We treat the buffer as _excluding_ the trailing \0 const pdf_long lTestLength1 = strlen(pTestBuffer1); const char pTestBuffer2[] = { 0x01, 0x64, 0x65, static_cast(0xFE), 0x6B, static_cast(0x80), 0x45, 0x32, static_cast(0x88), 0x12, static_cast(0x71), static_cast(0xEA), 0x01, 0x01, 0x64, 0x65, static_cast(0xFE), 0x6B, static_cast(0x80), 0x45, 0x32, static_cast(0x88), 0x12, static_cast(0x71), static_cast(0xEA), 0x03, 0x01, 0x64, 0x65, static_cast(0xFE), 0x6B, static_cast(0x80), 0x45, 0x32, static_cast(0x88), 0x12, static_cast(0x71), static_cast(0xEA), 0x02, 0x01, 0x64, 0x65, static_cast(0xFE), 0x6B, static_cast(0x80), 0x45, 0x32, static_cast(0x88), 0x12, static_cast(0x71), static_cast(0xEA), 0x00, 0x01, 0x64, 0x65, static_cast(0xFE), 0x6B, static_cast(0x80), 0x45, 0x32, static_cast(0x88), 0x12, static_cast(0x71), static_cast(0xEA), 0x00, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const pdf_long lTestLength2 = 6*13; void test_filter( EPdfFilter eFilter, const char * pTestBuffer, const pdf_long lTestLength ) { char* pEncoded; char* pDecoded; pdf_long lEncoded; pdf_long lDecoded; std::auto_ptr pFilter = PdfFilterFactory::Create( eFilter ); if( !pFilter.get() ) { printf("!!! Filter %i not implemented.\n", eFilter); return; } printf("Testing Algorithm %i:\n", eFilter); printf("\t-> Testing Encoding\n"); try { pFilter->Encode( pTestBuffer, lTestLength, &pEncoded, &lEncoded ); } catch( PdfError & e ) { if( e == ePdfError_UnsupportedFilter ) { printf("\t-> Encoding not supported for filter %i.\n", eFilter ); return; } else { e.AddToCallstack( __FILE__, __LINE__ ); throw e; } } printf("\t-> Testing Decoding\n"); try { pFilter->Decode( pEncoded, lEncoded, &pDecoded, &lDecoded ); } catch( PdfError & e ) { if( e == ePdfError_UnsupportedFilter ) { printf("\t-> Decoding not supported for filter %i.\n", eFilter); return; } else { e.AddToCallstack( __FILE__, __LINE__ ); throw e; } } printf("\t-> Original Data Length: %li\n", lTestLength ); printf("\t-> Encoded Data Length: %li\n", lEncoded ); printf("\t-> Decoded Data Length: %li\n", lDecoded ); if( static_cast(lTestLength) != lDecoded ) { fprintf( stderr, "Error: Decoded Length != Original Length\n"); /* fprintf( stderr, "Data:\n%s\n", pEncoded ); fprintf( stderr, "DecodedData:\n%s\n", pDecoded ); */ PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } if( memcmp( pTestBuffer, pDecoded, lTestLength ) != 0 ) { printf("\t-> Original Data: <%s>\n", pTestBuffer ); printf("\t-> Encoded Data: <%s>\n", pEncoded ); printf("\t-> Decoded Data: <%s>\n", pDecoded ); fprintf( stderr, "Error: Decoded Data does not match original data.\n"); PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } printf("\t-> Test succeeded!\n"); } void test_filter_queue( const char* pBuffer, long lLen ) { char* pEncoded; pdf_long lEncoded; char* pDecoded; pdf_long lDecoded; TVecFilters filters; filters.push_back( ePdfFilter_ASCIIHexDecode ); filters.push_back( ePdfFilter_ASCII85Decode ); filters.push_back( ePdfFilter_FlateDecode ); printf("Testing queque of filters:\n"); printf("\tePdfFilter_ASCIIHexDecode\n"); printf("\tePdfFilter_ASCII85Decode\n"); printf("\tePdfFilter_FlateDecode\n"); PdfMemoryOutputStream stream; PdfOutputStream* pEncode = PdfFilterFactory::CreateEncodeStream( filters, &stream ); pEncode->Write( pBuffer, lLen ); pEncode->Close(); delete pEncode; lEncoded = stream.GetLength(); pEncoded = stream.TakeBuffer(); PdfMemoryOutputStream stream2; PdfOutputStream* pDecode = PdfFilterFactory::CreateDecodeStream( filters, &stream2 ); pDecode->Write( pEncoded, lEncoded ); pDecode->Close(); delete pDecode; lDecoded = stream2.GetLength(); pDecoded = stream2.TakeBuffer(); printf("\t-> Original Data Length: %li\n", lLen ); printf("\t-> Encoded Data Length: %li\n", lEncoded ); printf("\t-> Decoded Data Length: %li\n", lDecoded ); if( lDecoded != lLen ) { fprintf( stderr, "Error: Decoded data length does not match original data length.\n"); PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } if( memcmp( pBuffer, pDecoded, lLen ) != 0 ) { printf("\t-> Original Data: <%s>\n", pBuffer ); printf("\t-> Encoded Data: \n<%s>\n", pEncoded ); printf("\t-> Decoded Data: \n<%s>\n", pDecoded ); fprintf( stderr, "Error: Decoded Data does not match original data.\n"); PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } free( pDecoded ); free( pEncoded ); } void test_stream( const char* pBuffer, pdf_long lLen ) { char* pDecoded; pdf_long lDecoded; PdfObject object; PdfMemStream stream( &object ); printf("Testing PdfStream:\n"); stream.Set( const_cast(pBuffer), lLen ); stream.GetFilteredCopy( &pDecoded, &lDecoded ); printf("\t-> Original Data Length: %li\n", lLen ); printf("\t-> Encoded Data Length: %lu\n", stream.GetLength() ); printf("\t-> Decoded Data Length: %li\n", lDecoded ); if( lDecoded != lLen ) { fprintf( stderr, "Error: Decoded data length does not match original data length.\n"); PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } if( memcmp( pBuffer, pDecoded, lLen ) != 0 ) { printf("\t-> Original Data: <%s>\n", pBuffer ); printf("\t-> Decoded Data: \n<%s>\n", pDecoded ); fprintf( stderr, "Error: Decoded Data does not match original data.\n"); PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } free( pDecoded ); } } // end anon namespace int main() { printf("This test tests all filters of PoDoFo\n"); printf("---\n"); printf("ePdfFilter_ASCIIHexDecode = 0\n"); printf("ePdfFilter_ASCII85Decode = 1\n"); printf("ePdfFilter_LZWDecode = 2\n"); printf("ePdfFilter_FlateDecode = 3\n"); printf("ePdfFilter_RunLengthDecode = 4\n"); printf("ePdfFilter_CCITTFaxDecode = 5\n"); printf("ePdfFilter_JBIG2Decode = 6\n"); printf("ePdfFilter_DCTDecode = 7\n"); printf("ePdfFilter_JPXDecode = 8\n"); printf("ePdfFilter_Crypt = 9\n"); // Data from stream of obj 9 0 R const char pszInputAscii85Lzw[] = "J..)6T`?q0\"W37&!thJ^C,m/iL/?:-g&uFOK1b,*F;>>qM[VuU#oJ230p2o6!o^dK\r=tpu7Tr'VZ1gWb9&Im[N#Q~>"; pdf_long lLargeBufer1 = strlen(pszInputAscii85Lzw) * 6; pdf_long lLargeBufer2 = strlen(pszInputAscii85Lzw) * 6; char* pLargeBuffer1 = static_cast(malloc( strlen(pszInputAscii85Lzw) * 6 )); char* pLargeBuffer2 = static_cast(malloc( strlen(pszInputAscii85Lzw) * 6 )); try { std::auto_ptr pFilter = PdfFilterFactory::Create( ePdfFilter_ASCII85Decode ); pFilter->Decode( pszInputAscii85Lzw, strlen(pszInputAscii85Lzw), &pLargeBuffer1, &lLargeBufer1 ); pFilter->Encode( pLargeBuffer1, lLargeBufer1, &pLargeBuffer2, &lLargeBufer2 ); if( memcmp( pszInputAscii85Lzw, pLargeBuffer2, lLargeBufer2 ) != 0 ) { printf("\tROACH -> Original Data: <%s>\n", pszInputAscii85Lzw ); printf("\tROACH -> Encoded Data: <%s>\n", pLargeBuffer1 ); printf("\tROACH -> Decoded Data: <%s>\n", pLargeBuffer2 ); fprintf( stderr, "Error: Decoded Data does not match original data.\n"); PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } if( static_cast(strlen(pszInputAscii85Lzw)) != lLargeBufer2 ) { fprintf( stderr, "ROACH Error: Decoded Length != Original Length\n"); fprintf( stderr, "ROACH Original: %li\n", strlen(pszInputAscii85Lzw) ); fprintf( stderr, "ROACH Encode: %li\n", lLargeBufer2 ); PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } // ASCII 85 decode and re-encode delivers same results printf("ROACH ASCII encode/decode OK\n"); for( int i =0; i<=ePdfFilter_Crypt; i++ ) { test_filter( static_cast(i), pTestBuffer1, lTestLength1 ); test_filter( static_cast(i), pTestBuffer2, lTestLength2 ); } test_filter_queue( pTestBuffer1, lTestLength1 ); test_filter_queue( pTestBuffer2, lTestLength2 ); test_stream( pTestBuffer1, lTestLength1 ); test_stream( pTestBuffer2, lTestLength2 ); } catch( PdfError & e ) { e.PrintErrorMsg(); return e.GetError(); } printf("All tests sucessfull!\n"); return 0; } podofo-0.9.5/test/unit/0000775000175000017500000000000013044451150014616 5ustar dominikdominikpodofo-0.9.5/test/unit/VariantTest.cpp0000664000175000017500000004510211246160175017576 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "VariantTest.h" #include using namespace PoDoFo; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( VariantTest ); static const char* s_pszObjectData = "242 0 obj\n" "<<\n" "/Type /Metadata\n" "/Length 9393\n" "/Subtype /XML\n" ">>\n" "stream\n" "\n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" "\n" "\n" "endstream\n" "endobj\n"; void VariantTest::setUp() { } void VariantTest::tearDown() { } void VariantTest::testEmptyObject() { const char* pszObject = "10 0 obj\nendobj\n"; PdfRefCountedInputDevice device( pszObject, strlen( pszObject ) ); PdfRefCountedBuffer buffer( 1024 ); PdfVecObjects vecObjects; PdfParserObject parser( &vecObjects, device, buffer, 0 ); parser.SetLoadOnDemand( false ); parser.ParseFile( NULL ); CPPUNIT_ASSERT_EQUAL( parser.IsNull(), true ); } void VariantTest::testEmptyStream() { const char* pszObject = "10 0 obj<>stream\nendstream\nendobj\n"; PdfRefCountedInputDevice device( pszObject, strlen( pszObject ) ); PdfRefCountedBuffer buffer( 1024 ); PdfVecObjects vecObjects; PdfParserObject parser( &vecObjects, device, buffer, 0 ); parser.SetLoadOnDemand( false ); parser.ParseFile( NULL ); CPPUNIT_ASSERT_EQUAL( parser.IsDictionary(), true ); CPPUNIT_ASSERT_EQUAL( parser.HasStream(), true ); CPPUNIT_ASSERT_EQUAL( parser.GetStream()->GetLength(), static_cast(0) ); } void VariantTest::testNameObject() { const char* pszObject = "10 0 obj / endobj\n"; PdfRefCountedInputDevice device( pszObject, strlen( pszObject ) ); PdfRefCountedBuffer buffer( 1024 ); PdfVecObjects vecObjects; PdfParserObject parser( &vecObjects, device, buffer, 0 ); parser.SetLoadOnDemand( false ); parser.ParseFile( NULL ); CPPUNIT_ASSERT_EQUAL( parser.IsName(), true ); CPPUNIT_ASSERT_EQUAL( parser.GetName().GetName(), std::string("") ); } void VariantTest::testIsDirtyTrue() { PdfArray array; PdfDictionary dict; PdfVariant varBool( true ); PdfVariant varLong( static_cast(1LL) ); PdfVariant varDouble( 1.0 ); PdfVariant varStr( PdfString("Any") ); PdfVariant varName( PdfName("Name") ); PdfVariant varRef( PdfReference( 0, 0 ) ); PdfVariant varArray( array ); PdfVariant varDict( dict ); PdfVariant varVariant( varBool ); varBool.SetBool( false ); varLong.SetNumber( static_cast(2LL) ); varDouble.SetReal( 2.0 ); varStr = PdfString("Other"); varName = PdfName("Name2"); varRef = PdfReference( 2, 0 ); varArray.GetArray().push_back( varBool ); varDict.GetDictionary().AddKey( varName.GetName(), varStr ); varVariant = varLong; CPPUNIT_ASSERT_EQUAL_MESSAGE( "BOOL IsDirty() == true", true, varBool.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "LONG IsDirty() == true", true, varLong.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "DOUBLE IsDirty() == true", true, varDouble.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "STRING IsDirty() == true", true, varStr.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "REFERENCE IsDirty() == true", true, varRef.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "ARRAY IsDirty() == true", true, varArray.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "DICT IsDirty() == true", true, varDict.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "VARIANT IsDirty() == true", true, varVariant.IsDirty() ); PdfRefCountedInputDevice device( s_pszObjectData, strlen( s_pszObjectData ) ); PdfRefCountedBuffer buffer( 1024 ); PdfVecObjects vecObjects; PdfParserObject parser( &vecObjects, device, buffer, 0 ); parser.SetLoadOnDemand( false ); parser.ParseFile( NULL ); // After reading const stream it has still to be clean PdfStream* pStream = parser.GetStream(); CPPUNIT_ASSERT_EQUAL( static_cast(pStream->GetLength()), 9381L ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "STREAM IsDirty() == true", true, parser.IsDirty() ); } void VariantTest::testIsDirtyFalse() { PdfArray array; PdfDictionary dict; PdfData data("/Name"); PdfVariant varEmpty; PdfVariant varBool( true ); PdfVariant varLong( static_cast(1LL) ); PdfVariant varDouble( 1.0 ); PdfVariant varStr( PdfString("Any") ); PdfVariant varName( PdfName("Name") ); PdfVariant varRef( PdfReference( 0, 0 ) ); PdfVariant varArray( array ); PdfVariant varDict( dict ); PdfVariant varData( data ); PdfVariant varVariant( varBool ); // IsDirty() should be false after construction CPPUNIT_ASSERT_EQUAL_MESSAGE( "EMPTY IsDirty() == false", false, varEmpty.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "BOOL IsDirty() == false", false, varBool.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "LONG IsDirty() == false", false, varLong.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "DOUBLE IsDirty() == false", false, varDouble.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "STRING IsDirty() == false", false, varStr.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "REFERENCE IsDirty() == false", false, varRef.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "ARRAY IsDirty() == false", false, varArray.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "DICT IsDirty() == false", false, varDict.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "DATA IsDirty() == false", false, varData.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "VARIANT IsDirty() == false", false, varVariant.IsDirty() ); // IsDirty() should be false after calling const getter (void)varBool.GetBool(); (void)varLong.GetNumber(); (void)varDouble.GetReal(); (void)varStr.GetString(); (void)varName.GetName(); (void)varRef.GetReference(); (void)static_cast(varArray).GetArray(); (void)static_cast(varDict).GetDictionary(); (void)varVariant.GetBool(); CPPUNIT_ASSERT_EQUAL_MESSAGE( "BOOL IsDirty() == false", false, varBool.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "LONG IsDirty() == false", false, varLong.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "DOUBLE IsDirty() == false", false, varDouble.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "STRING IsDirty() == false", false, varStr.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "REFERENCE IsDirty() == false", false, varRef.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "ARRAY IsDirty() == false", false, varArray.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "DICT IsDirty() == false", false, varDict.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "VARIANT IsDirty() == false", false, varVariant.IsDirty() ); // IsDirty() should be false after calling non const getter, but not modifying object (void) varArray.GetArray(); (void) varDict.GetDictionary(); CPPUNIT_ASSERT_EQUAL_MESSAGE( "ARRAY IsDirty() == false", false, varArray.IsDirty() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "DICT IsDirty() == false", false, varDict.IsDirty() ); // IsDirty() should be false after reading an object PdfRefCountedInputDevice device( s_pszObjectData, strlen( s_pszObjectData ) ); PdfRefCountedBuffer buffer( 1024 ); PdfVecObjects vecObjects; PdfParserObject parser( &vecObjects, device, buffer, 0 ); parser.SetLoadOnDemand( false ); parser.ParseFile( NULL ); // Newly create Object has to be clean CPPUNIT_ASSERT_EQUAL_MESSAGE( "OBJECT IsDirty() == false", false, parser.IsDirty() ); // After reading const stream it has still to be clean const PdfStream* pStream = static_cast(&parser)->GetStream(); CPPUNIT_ASSERT_EQUAL( static_cast(pStream->GetLength()), 9381L ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "STREAM IsDirty() == false", false, parser.IsDirty() ); } podofo-0.9.5/test/unit/PagesTreeTest.h0000664000175000017500000000725211201067720017513 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _PAGES_TREE_TEST_H_ #define _PAGES_TREE_TEST_H_ #include namespace PoDoFo { class PdfMemDocument; class PdfPage; }; /** This test tests the class PdfPagesTree */ class PagesTreeTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( PagesTreeTest ); CPPUNIT_TEST( testEmptyTree ); CPPUNIT_TEST( testEmptyDoc ); CPPUNIT_TEST( testCreateDelete ); CPPUNIT_TEST( testGetPagesCustom ); CPPUNIT_TEST( testGetPagesPoDoFo ); CPPUNIT_TEST( testGetPagesReverseCustom ); CPPUNIT_TEST( testGetPagesReversePoDoFo ); CPPUNIT_TEST( testInsertCustom ); CPPUNIT_TEST( testInsertPoDoFo ); CPPUNIT_TEST( testDeleteAllCustom ); CPPUNIT_TEST( testDeleteAllPoDoFo ); CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown(); void testEmptyTree(); void testEmptyDoc(); void testCreateDelete(); void testGetPagesCustom(); void testGetPagesPoDoFo(); void testGetPagesReverseCustom(); void testGetPagesReversePoDoFo(); void testInsertCustom(); void testInsertPoDoFo(); void testDeleteAllCustom(); void testDeleteAllPoDoFo(); private: void testGetPages( PoDoFo::PdfMemDocument & doc ); void testGetPagesReverse( PoDoFo::PdfMemDocument & doc ); void testInsert( PoDoFo::PdfMemDocument & doc ); void testDeleteAll( PoDoFo::PdfMemDocument & doc ); /** * Create a pages tree with 100 pages, * where every page object has an additional * key PoDoFoTestPageNumber with the original * page number of the page. * * This method uses PoDoFo's build in PdfPagesTree * which creates a flat tree. * * You can check the page number ussing IsPageNumber() * * @see IsPageNumber */ void CreateTestTreePoDoFo( PoDoFo::PdfMemDocument & rDoc ); /** * Create a pages tree with 100 pages, * where every page object has an additional * key PoDoFoTestPageNumber with the original * page number of the page. * * This builds a pages tree manually an makes * sure a real tree structure is build. * * You can check the page number ussing IsPageNumber() * * @see IsPageNumber */ void CreateTestTreeCustom( PoDoFo::PdfMemDocument & rDoc ); bool IsPageNumber( PoDoFo::PdfPage* pPage, int nNumber ); }; #endif // _PAGES_TREE_TEST_H_ podofo-0.9.5/test/unit/BasicTypeTest.h0000664000175000017500000000410111233264622017512 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _BASICTYPE_TEST_H_ #define _BASICTYPE_TEST_H_ #include /** This class tests the basic integer and other types PoDoFo uses * to make sure they satisfy its requirements for behaviour, size, etc. * * We now detect what types to use using CMake, so it's important to * test that detection and make sure it's doing the right thing. */ class BasicTypeTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( BasicTypeTest ); CPPUNIT_TEST( testXrefOffsetTypeSize ); CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown(); void testXrefOffsetTypeSize(); private: }; #endif podofo-0.9.5/test/unit/BasicTypeTest.cpp0000664000175000017500000000360511403202272020045 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "BasicTypeTest.h" #include #include using namespace PoDoFo; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( BasicTypeTest ); void BasicTypeTest::setUp() { } void BasicTypeTest::tearDown() { } void BasicTypeTest::testXrefOffsetTypeSize() { CPPUNIT_ASSERT_MESSAGE("pdf_uint64 is big enough to hold an xref entry", std::numeric_limits::max() >= PODOFO_ULL_LITERAL(9999999999) ); } podofo-0.9.5/test/unit/CMakeLists.txt0000664000175000017500000000151012706437606017371 0ustar dominikdominik IF(PODOFO_HAVE_CPPUNIT) INCLUDE_DIRECTORIES( ${PROJ_SOURCE_DIR}/src ${PROJ_BINARY_DIR}/src ${PROJ_BINARY_DIR}/src/os ${PROJ_BINARY_DIR}/src/os/${OROCOS_TARGET}) ADD_DEFINITIONS("-g") # repeat for each test ADD_EXECUTABLE( podofo-test main.cpp ColorTest.cpp DeviceTest.cpp ElementTest.cpp EncodingTest.cpp EncryptTest.cpp FilterTest.cpp FontTest.cpp NameTest.cpp PagesTreeTest.cpp PageTest.cpp PainterTest.cpp TokenizerTest.cpp StringTest.cpp VariantTest.cpp BasicTypeTest.cpp TestUtils.cpp DateTest.cpp ) ADD_DEPENDENCIES( podofo-test ${PODOFO_DEPEND_TARGET}) TARGET_LINK_LIBRARIES( podofo-test ${PODOFO_LIB} ${PODOFO_LIB_DEPENDS} ${CPPUNIT_LIBRARIES} ) SET_TARGET_PROPERTIES( podofo-test PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_TEST( podofo-test podofo-test ) ENDIF(PODOFO_HAVE_CPPUNIT) podofo-0.9.5/test/unit/DeviceTest.h0000664000175000017500000000342412706437606017047 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2016 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _DEVICE_TEST_H_ #define _DEVICE_TEST_H_ #include class DeviceTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( DeviceTest ); CPPUNIT_TEST( testDevices ); CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown(); void testDevices(); }; #endif // _DEVICE_TEST_H_ podofo-0.9.5/test/unit/FontTest.cpp0000664000175000017500000001342211434740242017076 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2009 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "FontTest.h" #include #include #include FT_FREETYPE_H using namespace PoDoFo; CPPUNIT_TEST_SUITE_REGISTRATION( FontTest ); void FontTest::setUp() { m_pDoc = new PdfMemDocument(); m_pVecObjects = new PdfVecObjects(); m_pFontCache = new PdfFontCache( m_pVecObjects ); } void FontTest::tearDown() { delete m_pDoc; delete m_pFontCache; delete m_pVecObjects; } #if defined(PODOFO_HAVE_FONTCONFIG) void FontTest::testFonts() { FcObjectSet* objectSet = NULL; FcFontSet* fontSet = NULL; FcPattern* pattern = NULL; FcConfig* pConfig = NULL; // Initialize fontconfig CPPUNIT_ASSERT_EQUAL( !FcInit(), false ); pConfig = FcInitLoadConfigAndFonts(); CPPUNIT_ASSERT_EQUAL( !pConfig, false ); // Get all installed fonts pattern = FcPatternCreate(); objectSet = FcObjectSetBuild( FC_FAMILY, FC_STYLE, FC_FILE, FC_SLANT, FC_WEIGHT, NULL ); fontSet = FcFontList( NULL, pattern, objectSet ); FcObjectSetDestroy( objectSet ); FcPatternDestroy( pattern ); if( fontSet ) { printf("Testing %i fonts\n", fontSet->nfont ); int j; for (j = 0; j < fontSet->nfont; j++) { testSingleFont( fontSet->fonts[j], pConfig ); } FcFontSetDestroy( fontSet ); } // Shut fontconfig down // Causes an assertion in fontconfig FcFini(); } void FontTest::testSingleFont(FcPattern* pFont, FcConfig* pConfig) { std::string sFamily; std::string sPath; bool bBold; bool bItalic; if( GetFontInfo( pFont, sFamily, sPath, bBold, bItalic ) ) { std::string sPodofoFontPath = m_pFontCache->GetFontConfigFontPath( pConfig, sFamily.c_str(), bBold, bItalic ); std::string msg = "Font failed: " + sPodofoFontPath; EPdfFontType eFontType = PdfFontFactory::GetFontType( sPath.c_str() ); if( eFontType == ePdfFontType_TrueType ) { // Only TTF fonts can use identity encoding PdfFont* pFont = m_pDoc->CreateFont( sFamily.c_str(), bBold, bItalic, new PdfIdentityEncoding() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( msg, pFont != NULL, true ); } else if( eFontType != ePdfFontType_Unknown ) { PdfFont* pFont = m_pDoc->CreateFont( sFamily.c_str(), bBold, bItalic ); CPPUNIT_ASSERT_EQUAL_MESSAGE( msg, pFont != NULL, true ); } else { printf("Ignoring font: %s\n", sPodofoFontPath.c_str()); } } } void FontTest::testCreateFontFtFace() { FT_Face face; FT_Error error; // TODO: Find font file on disc! error = FT_New_Face( m_pDoc->GetFontLibrary(), "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", 0, &face ); if( !error ) { PdfFont* pFont = m_pDoc->CreateFont( face ); CPPUNIT_ASSERT_MESSAGE( "Cannot create font from FT_Face.", pFont != NULL ); } } bool FontTest::GetFontInfo( FcPattern* pFont, std::string & rsFamily, std::string & rsPath, bool & rbBold, bool & rbItalic ) { FcChar8* family = NULL; FcChar8* file = NULL; int slant; int weight; if( FcPatternGetString(pFont, FC_FAMILY, 0, &family) == FcResultMatch ) { rsFamily = reinterpret_cast(family); if( FcPatternGetString(pFont, FC_FILE, 0, &file) == FcResultMatch ) { rsPath = reinterpret_cast(file); if( FcPatternGetInteger(pFont, FC_SLANT, 0, &slant) == FcResultMatch ) { if(slant == FC_SLANT_ROMAN) rbItalic = false; else if(slant == FC_SLANT_ITALIC) rbItalic = true; else return false; if( FcPatternGetInteger(pFont, FC_WEIGHT, 0, &weight) == FcResultMatch ) { if(weight == FC_WEIGHT_MEDIUM) rbBold = false; else if(weight == FC_WEIGHT_BOLD) rbBold = true; else return false; return true; } } //free( file ); } //free( family ); } return false; } #endif podofo-0.9.5/test/unit/EncryptTest.h0000664000175000017500000000616012774756031017275 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _ENCRYPT_TEST_H_ #define _ENCRYPT_TEST_H_ #include #include namespace PoDoFo { class PdfEncrypt; } /** This test tests the class PdfString */ class EncryptTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( EncryptTest ); CPPUNIT_TEST( testDefault ); #ifndef OPENSSL_NO_RC4 CPPUNIT_TEST( testRC4 ); CPPUNIT_TEST( testRC4v2_40 ); CPPUNIT_TEST( testRC4v2_56 ); CPPUNIT_TEST( testRC4v2_80 ); CPPUNIT_TEST( testRC4v2_96 ); CPPUNIT_TEST( testRC4v2_128 ); #endif // OPENSSL_NO_RC4 CPPUNIT_TEST( testAESV2 ); #ifdef PODOFO_HAVE_LIBIDN CPPUNIT_TEST( testAESV3 ); #endif // PODOFO_HAVE_LIBIDN CPPUNIT_TEST( testLoadEncrypedFilePdfParser ); CPPUNIT_TEST( testLoadEncrypedFilePdfMemDocument ); CPPUNIT_TEST( testEnableAlgorithms ); CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown(); void testDefault(); #ifndef OPENSSL_NO_RC4 void testRC4(); void testRC4v2_40(); void testRC4v2_56(); void testRC4v2_80(); void testRC4v2_96(); void testRC4v2_128(); #endif // OPENSSL_NO_RC4 void testAESV2(); #ifdef PODOFO_HAVE_LIBIDN void testAESV3(); #endif // PODOFO_HAVE_LIBIDN void testLoadEncrypedFilePdfParser(); void testLoadEncrypedFilePdfMemDocument(); void testEnableAlgorithms(); private: void TestAuthenticate( PoDoFo::PdfEncrypt* pEncrypt, int keyLength, int rValue ); void TestEncrypt( PoDoFo::PdfEncrypt* pEncrypt ); /** * Create an encrypted PDF. * * @param pszFilename save the encrypted PDF here. */ void CreateEncryptedPdf( const char* pszFilename ); private: char* m_pEncBuffer; long m_lLen; int m_protection; }; #endif // _ENCRYPT_TEST_H_ podofo-0.9.5/test/unit/DeviceTest.cpp0000664000175000017500000001042412706437606017400 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2016 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "DeviceTest.h" #include #include #include #define BUFFER_SIZE 4096 using namespace PoDoFo; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( DeviceTest ); void DeviceTest::setUp() { } void DeviceTest::tearDown() { } void DeviceTest::testDevices() { const char* pszTestString = "Hello World Buffer!"; long lLen = strlen( pszTestString ); PdfRefCountedBuffer buffer1; PdfRefCountedBuffer buffer2; printf("-> Testing PdfRefCountedBuffer...\n"); // test simple append printf("\t -> Appending\n"); PdfBufferOutputStream stream1( &buffer1 ); stream1.Write( pszTestString, lLen ); stream1.Close(); if( static_cast(buffer1.GetSize()) != lLen ) { fprintf( stderr, "Buffer size does not match! Size=%li should be %li\n", buffer1.GetSize(), lLen ); PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } if( strcmp( buffer1.GetBuffer(), pszTestString ) != 0 ) { fprintf( stderr, "Buffer contents do not match!\n" ); PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } // test assignment printf("\t -> Assignment\n"); buffer2 = buffer1; if( buffer1.GetSize() != buffer2.GetSize() ) { fprintf( stderr, "Buffer sizes does not match! Size1=%li Size2=%li\n", buffer1.GetSize(), buffer2.GetSize() ); PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } if( strcmp( buffer1.GetBuffer(), buffer2.GetBuffer() ) != 0 ) { fprintf( stderr, "Buffer contents do not match after assignment!\n" ); PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } // test detach printf("\t -> Detaching\n"); PdfBufferOutputStream stream( &buffer2 ); stream.Write( pszTestString, lLen ); stream.Close(); if( static_cast(buffer2.GetSize()) != lLen * 2 ) { fprintf( stderr, "Buffer size after detach does not match! Size=%li should be %li\n", buffer2.GetSize(), lLen * 2 ); PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } if( static_cast(buffer1.GetSize()) != lLen ) { fprintf( stderr, "Buffer1 size seems to be modified\n"); PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } if( strcmp( buffer1.GetBuffer(), pszTestString ) != 0 ) { fprintf( stderr, "Buffer1 contents seem to be modified!\n" ); PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } // large appends PdfBufferOutputStream streamLarge( &buffer1 ); for( int i=0;i<100;i++ ) { streamLarge.Write( pszTestString, lLen ); } streamLarge.Close(); if( static_cast(buffer1.GetSize()) != (lLen * 100 + lLen) ) { fprintf( stderr, "Buffer1 size is wrong after 100 attaches: %li\n", buffer1.GetSize() ); PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } } podofo-0.9.5/test/unit/TestUtils.h0000664000175000017500000000375611423516632016750 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _TEST_UTILS_H_ #define _TEST_UTILS_H_ #include /** * This class contains utility methods that are * often needed when writing tests. */ class TestUtils { public: static std::string getTempFilename(); static void deleteFile( const char* pszFilename ); /** * Read a test data file into memory and return a malloc'ed buffer. * * @param pszFilename filename of the data file. The path will be determined automatically. */ static char* readDataFile( const char* pszFilename ); }; #endif // _TEST_UTILS_H_ podofo-0.9.5/test/unit/PainterTest.cpp0000664000175000017500000000520311523003150017555 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2011 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "PainterTest.h" #include "TestUtils.h" #include using namespace PoDoFo; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( PainterTest ); void PainterTest::setUp() { } void PainterTest::tearDown() { } void PainterTest::CompareStreamContent(PdfStream* pStream, const char* pszExpected) { char* pBuffer; pdf_long lLen; pStream->GetFilteredCopy( &pBuffer, &lLen ); std::string str(pBuffer, lLen); CPPUNIT_ASSERT_EQUAL( std::string(pszExpected), str ); free( pBuffer ); } void PainterTest::testAppend() { const char* pszExample1 = "BT (Hallo) Tj ET"; const char* pszColor = " 1.000 1.000 1.000 rg\n"; PdfMemDocument doc; PdfPage* pPage = doc.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); pPage->GetContents()->GetStream()->Set(pszExample1) ; this->CompareStreamContent(pPage->GetContents()->GetStream(), pszExample1); PdfPainter painter; painter.SetPage( pPage ); painter.SetColor( 1.0, 1.0, 1.0 ); painter.FinishPage(); std::string newContent = pszExample1; newContent += pszColor; this->CompareStreamContent(pPage->GetContents()->GetStream(), newContent.c_str()); } podofo-0.9.5/test/unit/FilterTest.h0000664000175000017500000000376710736717750017111 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _FILTER_TEST_H_ #define _FILTER_TEST_H_ #include #include /** This test tests the various PdfFilter classes */ class FilterTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( FilterTest ); CPPUNIT_TEST( testFilters ); CPPUNIT_TEST( testCCITT ); CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown(); void testFilters(); void testCCITT(); private: void TestFilter( PoDoFo::EPdfFilter eFilter, const char * pTestBuffer, const long lTestLength ); }; #endif // _FILTER_TEST_H_ podofo-0.9.5/test/unit/EncryptTest.cpp0000664000175000017500000003444213040216442017614 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "EncryptTest.h" #include "TestUtils.h" #include using namespace PoDoFo; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( EncryptTest ); void EncryptTest::setUp() { const char* pBuffer1 = "Somekind of drawing \001 buffer that possibly \003 could contain PDF drawing commands"; const char* pBuffer2 = " possibly could contain PDF drawing\003 commands"; m_lLen = strlen( pBuffer1 ) + 2 * strlen( pBuffer2 ); m_pEncBuffer = static_cast(malloc( sizeof(char) * m_lLen )); memcpy( m_pEncBuffer, pBuffer1, strlen( pBuffer1 ) * sizeof(char) ); memcpy( m_pEncBuffer + strlen(pBuffer1), pBuffer2, strlen( pBuffer2 ) ); memcpy( m_pEncBuffer + strlen(pBuffer1) + strlen( pBuffer2 ), pBuffer2, strlen( pBuffer2 ) ); m_protection = PdfEncrypt::ePdfPermissions_Print | PdfEncrypt::ePdfPermissions_Edit | PdfEncrypt::ePdfPermissions_Copy | PdfEncrypt::ePdfPermissions_EditNotes | PdfEncrypt::ePdfPermissions_FillAndSign | PdfEncrypt::ePdfPermissions_Accessible | PdfEncrypt::ePdfPermissions_DocAssembly | PdfEncrypt::ePdfPermissions_HighPrint; } void EncryptTest::tearDown() { free( m_pEncBuffer ); } void EncryptTest::testDefault() { PdfEncrypt* pEncrypt = PdfEncrypt::CreatePdfEncrypt( "user", "podofo" ); TestAuthenticate( pEncrypt, 40, 2 ); TestEncrypt( pEncrypt ); delete pEncrypt; } #ifndef OPENSSL_NO_RC4 void EncryptTest::testRC4() { PdfEncrypt* pEncrypt = PdfEncrypt::CreatePdfEncrypt( "user", "podofo", m_protection, PdfEncrypt::ePdfEncryptAlgorithm_RC4V1, PdfEncrypt::ePdfKeyLength_40 ); TestAuthenticate( pEncrypt, 40, 3 ); TestEncrypt( pEncrypt ); delete pEncrypt; } void EncryptTest::testRC4v2_40() { PdfEncrypt* pEncrypt = PdfEncrypt::CreatePdfEncrypt( "user", "podofo", m_protection, PdfEncrypt::ePdfEncryptAlgorithm_RC4V2, PdfEncrypt::ePdfKeyLength_40 ); TestAuthenticate( pEncrypt, 40, 3 ); TestEncrypt( pEncrypt ); delete pEncrypt; } void EncryptTest::testRC4v2_56() { PdfEncrypt* pEncrypt = PdfEncrypt::CreatePdfEncrypt( "user", "podofo", m_protection, PdfEncrypt::ePdfEncryptAlgorithm_RC4V2, PdfEncrypt::ePdfKeyLength_56 ); TestAuthenticate( pEncrypt, 56, 3 ); TestEncrypt( pEncrypt ); delete pEncrypt; } void EncryptTest::testRC4v2_80() { PdfEncrypt* pEncrypt = PdfEncrypt::CreatePdfEncrypt( "user", "podofo", m_protection, PdfEncrypt::ePdfEncryptAlgorithm_RC4V2, PdfEncrypt::ePdfKeyLength_80 ); TestAuthenticate( pEncrypt, 80, 3 ); TestEncrypt( pEncrypt ); delete pEncrypt; } void EncryptTest::testRC4v2_96() { PdfEncrypt* pEncrypt = PdfEncrypt::CreatePdfEncrypt( "user", "podofo", m_protection, PdfEncrypt::ePdfEncryptAlgorithm_RC4V2, PdfEncrypt::ePdfKeyLength_96 ); TestAuthenticate( pEncrypt, 96, 3 ); TestEncrypt( pEncrypt ); delete pEncrypt; } void EncryptTest::testRC4v2_128() { PdfEncrypt* pEncrypt = PdfEncrypt::CreatePdfEncrypt( "user", "podofo", m_protection, PdfEncrypt::ePdfEncryptAlgorithm_RC4V2, PdfEncrypt::ePdfKeyLength_128 ); TestAuthenticate( pEncrypt, 128, 3 ); TestEncrypt( pEncrypt ); delete pEncrypt; } #endif // OPENSSL_NO_RC4 void EncryptTest::testAESV2() { PdfEncrypt* pEncrypt = PdfEncrypt::CreatePdfEncrypt( "user", "podofo", m_protection, PdfEncrypt::ePdfEncryptAlgorithm_AESV2, PdfEncrypt::ePdfKeyLength_128 ); TestAuthenticate( pEncrypt, 128, 4 ); // AES decryption is not yet implemented. // Therefore we have to disable this test. // TestEncrypt( pEncrypt ); delete pEncrypt; } #ifdef PODOFO_HAVE_LIBIDN void EncryptTest::testAESV3() { PdfEncrypt* pEncrypt = PdfEncrypt::CreatePdfEncrypt( "user", "podofo", m_protection, PdfEncrypt::ePdfEncryptAlgorithm_AESV3, PdfEncrypt::ePdfKeyLength_256 ); TestAuthenticate( pEncrypt, 256, 5 ); // AES decryption is not yet implemented. // Therefore we have to disable this test. // TestEncrypt( pEncrypt ); delete pEncrypt; } #endif // PODOFO_HAVE_LIBIDN void EncryptTest::TestAuthenticate( PdfEncrypt* pEncrypt, int PODOFO_UNUSED_PARAM(keyLength), int PODOFO_UNUSED_PARAM(rValue) ) { PdfString documentId; documentId.SetHexData( "BF37541A9083A51619AD5924ECF156DF", 32 ); pEncrypt->GenerateEncryptionKey( documentId ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "authenticate using user password", pEncrypt->Authenticate(std::string("user"), documentId), true ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "authenticate using wrong user password", pEncrypt->Authenticate(std::string("wrongpassword"), documentId), false ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "authenticate using owner password", pEncrypt->Authenticate(std::string("podofo"), documentId), true ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "authenticate using wrong owner password", pEncrypt->Authenticate(std::string("wrongpassword"), documentId), false ); } void EncryptTest::TestEncrypt( PdfEncrypt* pEncrypt ) { pEncrypt->SetCurrentReference( PdfReference( 7, 0 ) ); pdf_long nOutputLen = pEncrypt->CalculateStreamLength(m_lLen); unsigned char *pEncryptedBuffer = new unsigned char[nOutputLen]; unsigned char *pDecryptedBuffer = new unsigned char[m_lLen]; // Encrypt buffer try { pEncrypt->Encrypt( reinterpret_cast(m_pEncBuffer), m_lLen, pEncryptedBuffer, nOutputLen ); } catch (PdfError &e) { CPPUNIT_FAIL(e.ErrorMessage(e.GetError())); } // Decrypt buffer try { pEncrypt->Decrypt( pEncryptedBuffer, nOutputLen, pDecryptedBuffer, m_lLen ); } catch (PdfError &e) { CPPUNIT_FAIL(e.ErrorMessage(e.GetError())); } CPPUNIT_ASSERT_EQUAL_MESSAGE( "compare encrypted and decrypted buffers", 0, memcmp( m_pEncBuffer, pDecryptedBuffer, m_lLen ) ); delete[] pEncryptedBuffer; delete[] pDecryptedBuffer; } void EncryptTest::testLoadEncrypedFilePdfParser() { std::string sFilename = TestUtils::getTempFilename(); try { CreateEncryptedPdf( sFilename.c_str() ); // Try loading with PdfParser PdfVecObjects objects; PdfParser parser( &objects ); try { parser.ParseFile( sFilename.c_str(), true ); // Must throw an exception CPPUNIT_FAIL("Encrypted file not recognized!"); } catch( PdfError & e ) { if( e.GetError() != ePdfError_InvalidPassword ) { CPPUNIT_FAIL("Invalid encryption exception thrown!"); } } parser.SetPassword( "user" ); } catch( PdfError & e ) { e.PrintErrorMsg(); printf("Removing temp file: %s\n", sFilename.c_str()); TestUtils::deleteFile(sFilename.c_str()); throw e; } printf("Removing temp file: %s\n", sFilename.c_str()); TestUtils::deleteFile(sFilename.c_str()); } void EncryptTest::testLoadEncrypedFilePdfMemDocument() { std::string sFilename = TestUtils::getTempFilename(); try { CreateEncryptedPdf( sFilename.c_str() ); // Try loading with PdfParser PdfMemDocument document; try { document.Load( sFilename.c_str() ); // Must throw an exception CPPUNIT_FAIL("Encrypted file not recognized!"); } catch( PdfError & e ) { if( e.GetError() != ePdfError_InvalidPassword ) { CPPUNIT_FAIL("Invalid encryption exception thrown!"); } } document.SetPassword( "user" ); } catch( PdfError & e ) { e.PrintErrorMsg(); printf("Removing temp file: %s\n", sFilename.c_str()); TestUtils::deleteFile(sFilename.c_str()); throw e; } printf("Removing temp file: %s\n", sFilename.c_str()); TestUtils::deleteFile(sFilename.c_str()); } void EncryptTest::CreateEncryptedPdf( const char* pszFilename ) { PdfMemDocument writer; PdfPage* pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); PdfPainter painter; painter.SetPage( pPage ); PdfFont* pFont = writer.CreateFont( "Arial", PdfEncodingFactory::GlobalWinAnsiEncodingInstance(), false ); if( !pFont ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } pFont->SetFontSize( 16.0 ); painter.SetFont( pFont ); painter.DrawText( 100, 100, "Hello World" ); painter.FinishPage(); writer.SetEncrypted( "user", "owner" ); writer.Write( pszFilename ); printf( "Wrote: %s (R=%i)\n", pszFilename, writer.GetEncrypt()->GetRevision() ); } void EncryptTest::testEnableAlgorithms() { int nDefault = PdfEncrypt::GetEnabledEncryptionAlgorithms(); // By default every algorithms should be enabled #ifndef OPENSSL_NO_RC4 CPPUNIT_ASSERT( PdfEncrypt::IsEncryptionEnabled( PdfEncrypt::ePdfEncryptAlgorithm_RC4V1 ) ); CPPUNIT_ASSERT( PdfEncrypt::IsEncryptionEnabled( PdfEncrypt::ePdfEncryptAlgorithm_RC4V2 ) ); #endif // OPENSSL_NO_RC4 CPPUNIT_ASSERT( PdfEncrypt::IsEncryptionEnabled( PdfEncrypt::ePdfEncryptAlgorithm_AESV2 ) ); #ifdef PODOFO_HAVE_LIBIDN CPPUNIT_ASSERT( PdfEncrypt::IsEncryptionEnabled( PdfEncrypt::ePdfEncryptAlgorithm_AESV3 ) ); #endif // PODOFO_HAVE_LIBIDN CPPUNIT_ASSERT_EQUAL( #ifndef OPENSSL_NO_RC4 PdfEncrypt::ePdfEncryptAlgorithm_RC4V1 | PdfEncrypt::ePdfEncryptAlgorithm_RC4V2 | #endif // OPENSSL_NO_RC4 PdfEncrypt::ePdfEncryptAlgorithm_AESV2 #ifdef PODOFO_HAVE_LIBIDN | PdfEncrypt::ePdfEncryptAlgorithm_AESV3 #endif // PODOFO_HAVE_LIBIDN , PdfEncrypt::GetEnabledEncryptionAlgorithms() ); // Disable AES #ifndef OPENSSL_NO_RC4 PdfEncrypt::SetEnabledEncryptionAlgorithms( PdfEncrypt::ePdfEncryptAlgorithm_RC4V1 | PdfEncrypt::ePdfEncryptAlgorithm_RC4V2 ); CPPUNIT_ASSERT( PdfEncrypt::IsEncryptionEnabled( PdfEncrypt::ePdfEncryptAlgorithm_RC4V1 ) ); CPPUNIT_ASSERT( PdfEncrypt::IsEncryptionEnabled( PdfEncrypt::ePdfEncryptAlgorithm_RC4V2 ) ); #endif // OPENSSL_NO_RC4 CPPUNIT_ASSERT( !PdfEncrypt::IsEncryptionEnabled( PdfEncrypt::ePdfEncryptAlgorithm_AESV2 ) ); #ifndef OPENSSL_NO_RC4 CPPUNIT_ASSERT_EQUAL( PdfEncrypt::ePdfEncryptAlgorithm_RC4V1 | PdfEncrypt::ePdfEncryptAlgorithm_RC4V2, PdfEncrypt::GetEnabledEncryptionAlgorithms() ); #endif // OPENSSL_NO_RC4 PdfObject object; object.GetDictionary().AddKey(PdfName("Filter"), PdfName("Standard")); object.GetDictionary().AddKey(PdfName("V"), static_cast(4L)); object.GetDictionary().AddKey(PdfName("R"), static_cast(4L)); object.GetDictionary().AddKey(PdfName("P"), static_cast(1L)); object.GetDictionary().AddKey(PdfName("O"), PdfString("")); object.GetDictionary().AddKey(PdfName("U"), PdfString("")); try { (void)PdfEncrypt::CreatePdfEncrypt( &object ); CPPUNIT_ASSERT( false ); } catch( PdfError & rError ) { CPPUNIT_ASSERT_EQUAL( rError.GetError(), ePdfError_UnsupportedFilter ); } // Restore default PdfEncrypt::SetEnabledEncryptionAlgorithms( nDefault ); } /* PdfMemoryOutputStream mem( lLen ); PdfOutputStream* pStream = enc.CreateEncryptionOutputStream( &mem ); pStream->Write( pBuffer1, strlen( pBuffer1 ) ); pStream->Write( pBuffer2, strlen( pBuffer2 ) ); pStream->Write( pBuffer2, strlen( pBuffer2 ) ); pStream->Close(); printf("Result: %i \n", memcmp( pEncBuffer, mem.TakeBuffer(), lLen ) ); enc.Encrypt( reinterpret_cast(pEncBuffer), lLen ); printf("Decrypted buffer: %s\n", pEncBuffer ); */ podofo-0.9.5/test/unit/ColorTest.h0000664000175000017500000000660311472721772016727 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _COLOR_TEST_H_ #define _COLOR_TEST_H_ #include class ColorTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( ColorTest ); CPPUNIT_TEST( testDefaultConstructor ); CPPUNIT_TEST( testGreyConstructor ); CPPUNIT_TEST( testGreyConstructorInvalid ); CPPUNIT_TEST( testRGBConstructor ); CPPUNIT_TEST( testRGBConstructorInvalid ); CPPUNIT_TEST( testCMYKConstructor ); CPPUNIT_TEST( testCMYKConstructorInvalid ); CPPUNIT_TEST( testCopyConstructor ); CPPUNIT_TEST( testAssignmentOperator ); CPPUNIT_TEST( testEqualsOperator ); CPPUNIT_TEST( testHexNames ); CPPUNIT_TEST( testNamesGeneral ); CPPUNIT_TEST( testNamesOneByOne ); CPPUNIT_TEST( testColorGreyConstructor ); CPPUNIT_TEST( testColorRGBConstructor ); CPPUNIT_TEST( testColorCMYKConstructor ); CPPUNIT_TEST( testColorSeparationAllConstructor ); CPPUNIT_TEST( testColorSeparationNoneConstructor ); CPPUNIT_TEST( testColorSeparationConstructor ); CPPUNIT_TEST( testColorCieLabConstructor ); CPPUNIT_TEST( testRGBtoCMYKConversions ); CPPUNIT_TEST_SUITE_END(); public: virtual void setUp(); virtual void tearDown(); protected: void testDefaultConstructor(); void testGreyConstructor(); void testGreyConstructorInvalid(); void testRGBConstructor(); void testRGBConstructorInvalid(); void testCMYKConstructor(); void testCMYKConstructorInvalid(); void testCopyConstructor(); void testAssignmentOperator(); void testEqualsOperator(); void testHexNames(); void testNamesGeneral(); void testNamesOneByOne(); void testColorGreyConstructor(); void testColorRGBConstructor(); void testColorCMYKConstructor(); void testColorSeparationAllConstructor(); void testColorSeparationNoneConstructor(); void testColorSeparationConstructor(); void testColorCieLabConstructor(); void testRGBtoCMYKConversions(); }; #endif podofo-0.9.5/test/unit/ElementTest.h0000664000175000017500000000406711403202272017223 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _ELEMENT_TEST_H_ #define _ELEMENT_TEST_H_ #include class ElementTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( ElementTest ); CPPUNIT_TEST( testTypeToIndexAnnotation ); CPPUNIT_TEST( testTypeToIndexAction ); CPPUNIT_TEST( testTypeToIndexAnnotationUnknown ); CPPUNIT_TEST( testTypeToIndexActionUnknown ); CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown(); void testTypeToIndexAnnotation(); void testTypeToIndexAction(); void testTypeToIndexAnnotationUnknown(); void testTypeToIndexActionUnknown(); private: }; #endif // _ELEMENT_TEST_H_ podofo-0.9.5/test/unit/VariantTest.h0000664000175000017500000000410611245541723017243 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _VARIANT_TEST_H_ #define _VARIANT_TEST_H_ #include /** This test tests the class PdfVariant */ class VariantTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( VariantTest ); CPPUNIT_TEST( testEmptyObject ); CPPUNIT_TEST( testEmptyStream ); CPPUNIT_TEST( testNameObject ); CPPUNIT_TEST( testIsDirtyTrue ); CPPUNIT_TEST( testIsDirtyFalse ); CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown(); void testEmptyObject(); void testEmptyStream(); void testNameObject(); void testIsDirtyTrue(); void testIsDirtyFalse(); private: }; #endif // _VARIANT_TEST_H_ podofo-0.9.5/test/unit/TokenizerTest.cpp0000664000175000017500000002274011455342347020154 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "TokenizerTest.h" #include using namespace PoDoFo; CPPUNIT_TEST_SUITE_REGISTRATION( TokenizerTest ); void TokenizerTest::Test( const char* pszString, EPdfDataType eDataType, const char* pszExpected ) { PdfVariant variant; std::string ret; std::string expected; expected = pszExpected ? pszExpected : pszString; printf("Testing with value: %s\n", pszString ); PdfTokenizer tokenizer( pszString, strlen( pszString ) ); tokenizer.GetNextVariant( variant, NULL ); printf(" -> Expected Datatype: %i\n", eDataType ); printf(" -> Got Datatype: %i\n", variant.GetDataType() ); CPPUNIT_ASSERT_EQUAL( variant.GetDataType(), eDataType ); variant.ToString( ret ); printf(" -> Convert To String: %s\n", ret.c_str() ); CPPUNIT_ASSERT_EQUAL( expected, ret ); } void TokenizerTest::setUp() { // Nothing todo here } void TokenizerTest::tearDown() { // Nothing todo here } void TokenizerTest::testArrays() { Test( "[]", ePdfDataType_Array, "[ ]" ); Test( "[ ]", ePdfDataType_Array ); Test( "[ / ]", ePdfDataType_Array, "[ / ]" ); // empty names are legal, too! Test( "[ / [ ] ]", ePdfDataType_Array, "[ / [ ] ]" ); // empty names are legal, too! Test( "[/[]]", ePdfDataType_Array, "[ / [ ] ]" ); // empty names are legal, too! Test( "[ 1 2 3 4 ]", ePdfDataType_Array ); Test( "[1 2 3 4]", ePdfDataType_Array, "[ 1 2 3 4 ]" ); Test( "[ 2 (Hallo Welt!) 3.500000 /FMC ]", ePdfDataType_Array ); Test( "[ [ 1 2 ] (Hallo Welt!) 3.500000 /FMC ]", ePdfDataType_Array ); Test( "[/ImageA/ImageB/ImageC]", ePdfDataType_Array, "[ /ImageA /ImageB /ImageC ]" ); Test( "[<530464995927cef8aaf46eb953b93373><530464995927cef8aaf46eb953b93373>]", ePdfDataType_Array, "[ <530464995927CEF8AAF46EB953B93373> <530464995927CEF8AAF46EB953B93373> ]" ); Test( "[ 2 0 R (Test Data) 4 << /Key /Data >> 5 0 R ]", ePdfDataType_Array, "[ 2 0 R (Test Data) 4 <<\n/Key /Data\n>> 5 0 R ]" ); Test( "[<>2 0 R]", ePdfDataType_Array, "[ <<\n/key /name\n>> 2 0 R ]" ); Test( "[<>2 0 R]", ePdfDataType_Array,"[ <<\n/ /name\n>> 2 0 R ]" ); Test( "[ 27.673200 27.673200 566.256000 651.295000 ]", ePdfDataType_Array ); } void TokenizerTest::testBool() { Test( "false", ePdfDataType_Bool); Test( "true", ePdfDataType_Bool); } void TokenizerTest::testHexString() { Test( "", ePdfDataType_HexString ); Test( "", ePdfDataType_HexString, "" ); Test( "<>", ePdfDataType_HexString ); } void TokenizerTest::testName() { Test( "/Type", ePdfDataType_Name ); Test( "/Length", ePdfDataType_Name ); Test( "/Adobe#20Green", ePdfDataType_Name ); Test( "/$$", ePdfDataType_Name ); Test( "/1.2", ePdfDataType_Name ); Test( "/.notdef", ePdfDataType_Name ); Test( "/@pattern", ePdfDataType_Name ); Test( "/A;Name_With-Various***Characters?", ePdfDataType_Name ); Test( "/", ePdfDataType_Name ); // empty names are legal, too! // Some additional tests, which cause errors for Sebastian Loch const char* pszString = "/CheckBox#C3#9Cbersetzungshinweis"; PdfVariant variant; PdfTokenizer tokenizer( pszString, strlen( pszString ) ); tokenizer.GetNextVariant( variant, NULL ); PdfName name2( variant.GetName() ); std::ostringstream oss; PdfOutputDevice output(&oss); name2.Write(&output, ePdfWriteMode_Default); CPPUNIT_ASSERT_EQUAL( variant.GetName().GetName(), name2.GetName() ); CPPUNIT_ASSERT_EQUAL( oss.str(), std::string(pszString) ); printf("!!! Name=[%s]\n", variant.GetName().GetName().c_str() ); printf("!!! Name2=[%s]\n", name2.GetName().c_str() ); printf("!!! oss=[%s]\n", oss.str().c_str() ); } void TokenizerTest::testNull() { Test( "null", ePdfDataType_Null ); } void TokenizerTest::testNumbers() { Test( "145", ePdfDataType_Number ); Test( "-12", ePdfDataType_Number ); Test( "3.141230", ePdfDataType_Real ); Test( "-2.970000", ePdfDataType_Real ); Test( "0", ePdfDataType_Number ); Test( "4.", ePdfDataType_Real, "4.000000" ); } void TokenizerTest::testReference() { Test( "2 0 R", ePdfDataType_Reference ); Test( "3 0 R", ePdfDataType_Reference ); Test( "4 1 R", ePdfDataType_Reference ); } void TokenizerTest::testString() { // testing strings Test( "(Hallo Welt!)", ePdfDataType_String ); Test( "(Hallo \\(schöne\\) Welt!)", ePdfDataType_String ); Test( "(Balanced () brackets are (ok ()) in PDF Strings)", ePdfDataType_String, "(Balanced \\(\\) brackets are \\(ok \\(\\)\\) in PDF Strings)" ); Test( "()", ePdfDataType_String ); // Test octal strings Test( "(Test: \\064)", ePdfDataType_String, "(Test: \064)" ); Test( "(Test: \\064\\064)", ePdfDataType_String, "(Test: \064\064)" ); Test( "(Test: \\0645)", ePdfDataType_String, "(Test: 45)" ); Test( "(Test: \\478)", ePdfDataType_String, "(Test: '8)" ); // Test line breaks Test( "(Hallo\nWelt!)", ePdfDataType_String, "(Hallo\\nWelt!)" ); Test( "(These \\\ntwo strings \\\nare the same.)", ePdfDataType_String, "(These two strings are the same.)" ); // Test escape sequences Test( "(Hallo\\nWelt!)", ePdfDataType_String, "(Hallo\\nWelt!)" ); Test( "(Hallo\\rWelt!)", ePdfDataType_String, "(Hallo\\rWelt!)" ); Test( "(Hallo\\tWelt!)", ePdfDataType_String, "(Hallo\\tWelt!)" ); Test( "(Hallo\\bWelt!)", ePdfDataType_String, "(Hallo\\bWelt!)" ); Test( "(Hallo\\fWelt!)", ePdfDataType_String, "(Hallo\\fWelt!)" ); } void TokenizerTest::testDictionary() { const char* pszDictIn = "<< /CheckBox#C3#9Cbersetzungshinweis(False)/Checkbox#C3#9Cbersetzungstabelle(False) >>"; const char* pszDictOut = "<<\n/CheckBox#C3#9Cbersetzungshinweis (False)\n/Checkbox#C3#9Cbersetzungstabelle (False)\n>>"; Test( pszDictIn, ePdfDataType_Dictionary, pszDictOut ); } void TokenizerTest::TestStream( const char* pszBuffer, const char* pszTokens[] ) { long lLen = strlen( pszBuffer ); PdfTokenizer tokenizer( pszBuffer, lLen ); EPdfTokenType eType; const char* pszCur; int i = 0; while( pszTokens[i] ) { CPPUNIT_ASSERT_EQUAL( tokenizer.GetNextToken( pszCur, &eType ), true ); std::string sCur( pszCur ); std::string sToken( pszTokens[i] ); CPPUNIT_ASSERT_EQUAL( sCur, sToken ); ++i; } // We are at the end, so GetNextToken has to return false! CPPUNIT_ASSERT_EQUAL( tokenizer.GetNextToken( pszCur, &eType ), false ); } void TokenizerTest::TestStreamIsNextToken( const char* pszBuffer, const char* pszTokens[] ) { long lLen = strlen( pszBuffer ); PdfTokenizer tokenizer( pszBuffer, lLen ); int i = 0; while( pszTokens[i] ) CPPUNIT_ASSERT_EQUAL( tokenizer.IsNextToken( pszTokens[i++] ), true ); } void TokenizerTest::testTokens() { const char* pszBuffer = "613 0 obj" "<< /Length 141 /Filter [ /ASCII85Decode /FlateDecode ] >>" "endobj"; const char* pszTokens[] = { "613", "0", "obj", "<<", "/", "Length", "141", "/", "Filter", "[", "/", "ASCII85Decode", "/", "FlateDecode", "]", ">>", "endobj", NULL }; TestStream( pszBuffer, pszTokens ); TestStreamIsNextToken( pszBuffer, pszTokens ); } void TokenizerTest::testComments() { const char* pszBuffer = "613 0 obj\n" "% A comment that should be ignored\n" "<< /Length 141 /Filter\n% A comment in a dictionary\n[ /ASCII85Decode /FlateDecode ] >>" "endobj"; const char* pszTokens[] = { "613", "0", "obj", "<<", "/", "Length", "141", "/", "Filter", "[", "/", "ASCII85Decode", "/", "FlateDecode", "]", ">>", "endobj", NULL }; TestStream( pszBuffer, pszTokens ); TestStreamIsNextToken( pszBuffer, pszTokens ); } void TokenizerTest::testLocale() { // Test with a locale thate uses "," instead of "." for doubles char *old = setlocale( LC_ALL, "de_DE" ); const char* pszNumber = "3.140000"; Test( pszNumber, ePdfDataType_Real, pszNumber ); setlocale( LC_ALL, old ); } podofo-0.9.5/test/unit/ColorTest.cpp0000664000175000017500000024511411473153124017253 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "ColorTest.h" #include #include "cppunitextensions.h" #include #include #include using namespace PoDoFo; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( ColorTest ); //#define DEBUG_INFO void ColorTest::setUp() { } void ColorTest::tearDown() { } void ColorTest::testDefaultConstructor() { #ifdef DEBUG_INFO std::cout << "testDefaultConstructor" << std::endl; #endif PdfColor color; ASSERT_FALSE(color.IsGrayScale()); ASSERT_FALSE(color.IsRGB()); ASSERT_FALSE(color.IsCMYK()); ASSERT_FALSE(color.IsSeparation()); ASSERT_FALSE(color.IsCieLab()); ASSERT_EQ(color.GetColorSpace(), ePdfColorSpace_Unknown); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetAlternateColorSpace(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetGrayScale(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetRed(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetGreen(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetBlue(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetCyan(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetMagenta(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetYellow(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetBlack(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetName(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetDensity(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetCieL(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetCieA(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetCieB(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.ConvertToGrayScale(), PdfError, ePdfError_CannotConvertColor); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.ConvertToRGB(), PdfError, ePdfError_CannotConvertColor); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.ConvertToCMYK(), PdfError, ePdfError_CannotConvertColor); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.ToArray(), PdfError, ePdfError_CannotConvertColor); } void ColorTest::testGreyConstructor() { #ifdef DEBUG_INFO std::cout << "testGreyConstructor" << std::endl; #endif const double GREY_VALUE = 0.123; PdfColor color(GREY_VALUE); ASSERT_TRUE(color.IsGrayScale()); ASSERT_FALSE(color.IsRGB()); ASSERT_FALSE(color.IsCMYK()); ASSERT_FALSE(color.IsSeparation()); ASSERT_FALSE(color.IsCieLab()); ASSERT_EQ(color.GetColorSpace(), ePdfColorSpace_DeviceGray); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetAlternateColorSpace(), PdfError, ePdfError_InternalLogic); ASSERT_EQ(color.GetGrayScale(), GREY_VALUE); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetRed(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetGreen(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetBlue(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetCyan(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetMagenta(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetYellow(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetBlack(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetName(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetDensity(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetCieL(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetCieA(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetCieB(), PdfError, ePdfError_InternalLogic); ASSERT_TRUE(color == color.ConvertToGrayScale()); ASSERT_TRUE(PdfColor(GREY_VALUE, GREY_VALUE, GREY_VALUE) == color.ConvertToRGB()); ASSERT_TRUE(color.ConvertToRGB().ConvertToCMYK() == color.ConvertToCMYK()); const PdfArray COLOR_ARRAY = color.ToArray(); ASSERT_TRUE(1 == COLOR_ARRAY.GetSize()); ASSERT_TRUE(PdfObject(GREY_VALUE) == COLOR_ARRAY[0]); } void ColorTest::testGreyConstructorInvalid() { #ifdef DEBUG_INFO std::cout << "testGreyConstructorInvalid" << std::endl; #endif { const double GREY_VALUE = 1.01; CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( const PdfColor TEST_COLOR(GREY_VALUE), PdfError, ePdfError_ValueOutOfRange); } { const double GREY_VALUE = -0.01; CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( const PdfColor TEST_COLOR(GREY_VALUE), PdfError, ePdfError_ValueOutOfRange); } } void ColorTest::testRGBConstructor() { #ifdef DEBUG_INFO std::cout << "testRGBConstructor" << std::endl; #endif const double R_VALUE = 0.023; const double G_VALUE = 0.345; const double B_VALUE = 0.678; PdfColor color(R_VALUE, G_VALUE, B_VALUE); ASSERT_FALSE(color.IsGrayScale()); ASSERT_TRUE(color.IsRGB()); ASSERT_FALSE(color.IsCMYK()); ASSERT_FALSE(color.IsSeparation()); ASSERT_FALSE(color.IsCieLab()); ASSERT_EQ(color.GetColorSpace(), ePdfColorSpace_DeviceRGB); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetAlternateColorSpace(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetGrayScale(), PdfError, ePdfError_InternalLogic); ASSERT_EQ(color.GetRed(), R_VALUE); ASSERT_EQ(color.GetGreen(), G_VALUE); ASSERT_EQ(color.GetBlue(), B_VALUE); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetCyan(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetMagenta(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetYellow(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetBlack(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetName(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetDensity(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetCieL(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetCieA(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetCieB(), PdfError, ePdfError_InternalLogic); ASSERT_TRUE(PdfColor(0.299*R_VALUE + 0.587*G_VALUE + 0.114*B_VALUE) == color.ConvertToGrayScale()); ASSERT_TRUE(PdfColor(R_VALUE, G_VALUE, B_VALUE) == color.ConvertToRGB()); { double dBlack = PDF_MIN( 1.0-R_VALUE, PDF_MIN( 1.0-G_VALUE, 1.0-B_VALUE )); double dCyan = (1.0-R_VALUE-dBlack) /(1.0-dBlack); double dMagenta = (1.0-G_VALUE-dBlack)/(1.0-dBlack); double dYellow = (1.0-B_VALUE-dBlack) /(1.0-dBlack); ASSERT_TRUE(PdfColor( dCyan, dMagenta, dYellow, dBlack ) == color.ConvertToCMYK()); } const PdfArray COLOR_ARRAY = color.ToArray(); ASSERT_TRUE(3 == COLOR_ARRAY.GetSize()); ASSERT_TRUE(PdfObject(R_VALUE) == COLOR_ARRAY[0]); ASSERT_TRUE(PdfObject(G_VALUE) == COLOR_ARRAY[1]); ASSERT_TRUE(PdfObject(B_VALUE) == COLOR_ARRAY[2]); } void ColorTest::testRGBConstructorInvalid() { #ifdef DEBUG_INFO std::cout << "testRGBConstructorInvalid" << std::endl; #endif { const double R_VALUE = 1.023; const double G_VALUE = 0.345; const double B_VALUE = 0.678; CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( const PdfColor TEST_COLOR(R_VALUE, G_VALUE, B_VALUE), PdfError, ePdfError_ValueOutOfRange); } { const double R_VALUE = 0.023; const double G_VALUE = 1.345; const double B_VALUE = 0.678; CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( const PdfColor TEST_COLOR(R_VALUE, G_VALUE, B_VALUE), PdfError, ePdfError_ValueOutOfRange); } { const double R_VALUE = 0.023; const double G_VALUE = 0.345; const double B_VALUE = 2.678; CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( const PdfColor TEST_COLOR(R_VALUE, G_VALUE, B_VALUE), PdfError, ePdfError_ValueOutOfRange); } { const double R_VALUE = -0.023; const double G_VALUE = 0.345; const double B_VALUE = 0.678; CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( const PdfColor TEST_COLOR(R_VALUE, G_VALUE, B_VALUE), PdfError, ePdfError_ValueOutOfRange); } { const double R_VALUE = 0.023; const double G_VALUE = -0.345; const double B_VALUE = 0.678; CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( const PdfColor TEST_COLOR(R_VALUE, G_VALUE, B_VALUE), PdfError, ePdfError_ValueOutOfRange); } { const double R_VALUE = 0.023; const double G_VALUE = 0.345; const double B_VALUE = -0.678; CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( const PdfColor TEST_COLOR(R_VALUE, G_VALUE, B_VALUE), PdfError, ePdfError_ValueOutOfRange); } } void ColorTest::testCMYKConstructor() { #ifdef DEBUG_INFO std::cout << "testCMYKConstructor" << std::endl; #endif const double C_VALUE = 0.1; const double M_VALUE = 0.2; const double Y_VALUE = 0.3; const double B_VALUE = 0.4; PdfColor color(C_VALUE, M_VALUE, Y_VALUE, B_VALUE); ASSERT_FALSE(color.IsGrayScale()); ASSERT_FALSE(color.IsRGB()); ASSERT_TRUE(color.IsCMYK()); ASSERT_FALSE(color.IsSeparation()); ASSERT_FALSE(color.IsCieLab()); ASSERT_EQ(color.GetColorSpace(), ePdfColorSpace_DeviceCMYK); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetAlternateColorSpace(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetGrayScale(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetRed(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetGreen(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetBlue(), PdfError, ePdfError_InternalLogic); ASSERT_EQ(color.GetCyan(), C_VALUE); ASSERT_EQ(color.GetMagenta(), M_VALUE); ASSERT_EQ(color.GetYellow(), Y_VALUE); ASSERT_EQ(color.GetBlack(), B_VALUE); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetName(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetDensity(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetCieL(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetCieA(), PdfError, ePdfError_InternalLogic); CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( color.GetCieB(), PdfError, ePdfError_InternalLogic); ASSERT_TRUE(color.ConvertToRGB().ConvertToGrayScale() == color.ConvertToGrayScale()); { double dRed = C_VALUE * (1.0 - B_VALUE) + B_VALUE; double dGreen = M_VALUE * (1.0 - B_VALUE) + B_VALUE; double dBlue = Y_VALUE * (1.0 - B_VALUE) + B_VALUE; ASSERT_TRUE(PdfColor( 1.0 - dRed, 1.0 - dGreen, 1.0 - dBlue ) == color.ConvertToRGB()); } ASSERT_TRUE(PdfColor(C_VALUE, M_VALUE, Y_VALUE, B_VALUE) == color.ConvertToCMYK()); const PdfArray COLOR_ARRAY = color.ToArray(); ASSERT_TRUE(4 == COLOR_ARRAY.GetSize()); ASSERT_TRUE(PdfObject(C_VALUE) == COLOR_ARRAY[0]); ASSERT_TRUE(PdfObject(M_VALUE) == COLOR_ARRAY[1]); ASSERT_TRUE(PdfObject(Y_VALUE) == COLOR_ARRAY[2]); ASSERT_TRUE(PdfObject(B_VALUE) == COLOR_ARRAY[3]); } void ColorTest::testCMYKConstructorInvalid() { #ifdef DEBUG_INFO std::cout << "testCMYKConstructorInvalid" << std::endl; #endif { const double C_VALUE = 1.1; const double M_VALUE = 0.2; const double Y_VALUE = 0.3; const double B_VALUE = 0.4; CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( const PdfColor TEST_COLOR(C_VALUE, M_VALUE, Y_VALUE, B_VALUE), PdfError, ePdfError_ValueOutOfRange); } { const double C_VALUE = 0.1; const double M_VALUE = 1.2; const double Y_VALUE = 0.3; const double B_VALUE = 0.4; CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( const PdfColor TEST_COLOR(C_VALUE, M_VALUE, Y_VALUE, B_VALUE), PdfError, ePdfError_ValueOutOfRange); } { const double C_VALUE = 0.1; const double M_VALUE = 0.2; const double Y_VALUE = 1.3; const double B_VALUE = 0.4; CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( const PdfColor TEST_COLOR(C_VALUE, M_VALUE, Y_VALUE, B_VALUE), PdfError, ePdfError_ValueOutOfRange); } { const double C_VALUE = 0.1; const double M_VALUE = 0.2; const double Y_VALUE = 0.3; const double B_VALUE = 1.4; CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( const PdfColor TEST_COLOR(C_VALUE, M_VALUE, Y_VALUE, B_VALUE), PdfError, ePdfError_ValueOutOfRange); } { const double C_VALUE = -0.1; const double M_VALUE = 0.2; const double Y_VALUE = 0.3; const double B_VALUE = 0.4; CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( const PdfColor TEST_COLOR(C_VALUE, M_VALUE, Y_VALUE, B_VALUE), PdfError, ePdfError_ValueOutOfRange); } { const double C_VALUE = 0.1; const double M_VALUE = -0.2; const double Y_VALUE = 0.3; const double B_VALUE = 0.4; CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( const PdfColor TEST_COLOR(C_VALUE, M_VALUE, Y_VALUE, B_VALUE), PdfError, ePdfError_ValueOutOfRange); } { const double C_VALUE = 0.1; const double M_VALUE = 0.2; const double Y_VALUE = -0.3; const double B_VALUE = 0.4; CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( const PdfColor TEST_COLOR(C_VALUE, M_VALUE, Y_VALUE, B_VALUE), PdfError, ePdfError_ValueOutOfRange); } { const double C_VALUE = 0.1; const double M_VALUE = 0.2; const double Y_VALUE = 0.3; const double B_VALUE = -0.4; CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( const PdfColor TEST_COLOR(C_VALUE, M_VALUE, Y_VALUE, B_VALUE), PdfError, ePdfError_ValueOutOfRange); } } void ColorTest::testCopyConstructor() { #ifdef DEBUG_INFO std::cout << "testCopyConstructor" << std::endl; #endif { const double GREY_VALUE = 0.123; PdfColor initialColor(GREY_VALUE); PdfColor color(initialColor); ASSERT_TRUE(color.IsGrayScale()); ASSERT_FALSE(color.IsRGB()); ASSERT_FALSE(color.IsCMYK()); ASSERT_FALSE(color.IsSeparation()); ASSERT_FALSE(color.IsCieLab()); ASSERT_EQ(color.GetColorSpace(), ePdfColorSpace_DeviceGray); ASSERT_EQ(color.GetGrayScale(), GREY_VALUE); } { const double R_VALUE = 0.023; const double G_VALUE = 0.345; const double B_VALUE = 0.678; PdfColor initialColor(R_VALUE, G_VALUE, B_VALUE); PdfColor color(initialColor); ASSERT_FALSE(color.IsGrayScale()); ASSERT_TRUE(color.IsRGB()); ASSERT_FALSE(color.IsCMYK()); ASSERT_FALSE(color.IsSeparation()); ASSERT_FALSE(color.IsCieLab()); ASSERT_EQ(color.GetColorSpace(), ePdfColorSpace_DeviceRGB); ASSERT_EQ(color.GetRed(), R_VALUE); ASSERT_EQ(color.GetGreen(), G_VALUE); ASSERT_EQ(color.GetBlue(), B_VALUE); } { const double C_VALUE = 0.1; const double M_VALUE = 0.2; const double Y_VALUE = 0.3; const double B_VALUE = 0.4; PdfColor initialColor(C_VALUE, M_VALUE, Y_VALUE, B_VALUE); PdfColor color(initialColor); ASSERT_FALSE(color.IsGrayScale()); ASSERT_FALSE(color.IsRGB()); ASSERT_TRUE(color.IsCMYK()); ASSERT_FALSE(color.IsSeparation()); ASSERT_FALSE(color.IsCieLab()); ASSERT_EQ(color.GetColorSpace(), ePdfColorSpace_DeviceCMYK); ASSERT_EQ(color.GetCyan(), C_VALUE); ASSERT_EQ(color.GetMagenta(), M_VALUE); ASSERT_EQ(color.GetYellow(), Y_VALUE); ASSERT_EQ(color.GetBlack(), B_VALUE); } } void ColorTest::testAssignmentOperator() { #ifdef DEBUG_INFO std::cout << "testAssignmentOperator" << std::endl; #endif { const double GREY_VALUE = 0.123; PdfColor initialColor(GREY_VALUE); PdfColor color; color = initialColor; ASSERT_TRUE(color.IsGrayScale()); ASSERT_FALSE(color.IsRGB()); ASSERT_FALSE(color.IsCMYK()); ASSERT_FALSE(color.IsSeparation()); ASSERT_FALSE(color.IsCieLab()); ASSERT_EQ(color.GetColorSpace(), ePdfColorSpace_DeviceGray); ASSERT_EQ(color.GetGrayScale(), GREY_VALUE); } { const double R_VALUE = 0.023; const double G_VALUE = 0.345; const double B_VALUE = 0.678; PdfColor initialColor(R_VALUE, G_VALUE, B_VALUE); PdfColor color; color = initialColor; ASSERT_FALSE(color.IsGrayScale()); ASSERT_TRUE(color.IsRGB()); ASSERT_FALSE(color.IsCMYK()); ASSERT_FALSE(color.IsSeparation()); ASSERT_FALSE(color.IsCieLab()); ASSERT_EQ(color.GetColorSpace(), ePdfColorSpace_DeviceRGB); ASSERT_EQ(color.GetRed(), R_VALUE); ASSERT_EQ(color.GetGreen(), G_VALUE); ASSERT_EQ(color.GetBlue(), B_VALUE); } { const double C_VALUE = 0.1; const double M_VALUE = 0.2; const double Y_VALUE = 0.3; const double B_VALUE = 0.4; PdfColor initialColor(C_VALUE, M_VALUE, Y_VALUE, B_VALUE); PdfColor color; color = initialColor; ASSERT_FALSE(color.IsGrayScale()); ASSERT_FALSE(color.IsRGB()); ASSERT_TRUE(color.IsCMYK()); ASSERT_FALSE(color.IsSeparation()); ASSERT_FALSE(color.IsCieLab()); ASSERT_EQ(color.GetColorSpace(), ePdfColorSpace_DeviceCMYK); ASSERT_EQ(color.GetCyan(), C_VALUE); ASSERT_EQ(color.GetMagenta(), M_VALUE); ASSERT_EQ(color.GetYellow(), Y_VALUE); ASSERT_EQ(color.GetBlack(), B_VALUE); } } void ColorTest::testEqualsOperator() { #ifdef DEBUG_INFO std::cout << "testEqualsOperator" << std::endl; #endif //Grey test { //Positive const double GREY_VALUE = 0.123; PdfColor lColor(GREY_VALUE); PdfColor rColor(GREY_VALUE); ASSERT_TRUE(lColor == rColor); } { //Negative const double L_GREY_VALUE = 0.123; PdfColor lColor(L_GREY_VALUE); const double R_GREY_VALUE = 0.124; PdfColor rColor(R_GREY_VALUE); ASSERT_FALSE(L_GREY_VALUE == R_GREY_VALUE); ASSERT_FALSE(lColor == rColor); } //RGB tests { //Positive const double L_R_VALUE = 0.023; const double L_G_VALUE = 0.345; const double L_B_VALUE = 0.678; PdfColor lColor(L_R_VALUE, L_G_VALUE, L_B_VALUE); const double R_R_VALUE = 0.023; const double R_G_VALUE = 0.345; const double R_B_VALUE = 0.678; PdfColor rColor(R_R_VALUE, R_G_VALUE, R_B_VALUE); ASSERT_TRUE(L_R_VALUE == R_R_VALUE); ASSERT_TRUE(L_G_VALUE == R_G_VALUE); ASSERT_TRUE(L_B_VALUE == R_B_VALUE); ASSERT_TRUE(lColor == rColor); } { //Negative const double L_R_VALUE = 0.023; const double L_G_VALUE = 0.345; const double L_B_VALUE = 0.678; PdfColor lColor(L_R_VALUE, L_G_VALUE, L_B_VALUE); const double R_R_VALUE = 0.100; const double R_G_VALUE = 0.345; const double R_B_VALUE = 0.678; PdfColor rColor(R_R_VALUE, R_G_VALUE, R_B_VALUE); ASSERT_FALSE(L_R_VALUE == R_R_VALUE); ASSERT_TRUE(L_G_VALUE == R_G_VALUE); ASSERT_TRUE(L_B_VALUE == R_B_VALUE); ASSERT_FALSE(lColor == rColor); } { //Negative const double L_R_VALUE = 0.023; const double L_G_VALUE = 0.345; const double L_B_VALUE = 0.678; PdfColor lColor(L_R_VALUE, L_G_VALUE, L_B_VALUE); const double R_R_VALUE = 0.023; const double R_G_VALUE = 0.340; const double R_B_VALUE = 0.678; PdfColor rColor(R_R_VALUE, R_G_VALUE, R_B_VALUE); ASSERT_TRUE(L_R_VALUE == R_R_VALUE); ASSERT_FALSE(L_G_VALUE == R_G_VALUE); ASSERT_TRUE(L_B_VALUE == R_B_VALUE); ASSERT_FALSE(lColor == rColor); } { //Negative const double L_R_VALUE = 0.023; const double L_G_VALUE = 0.345; const double L_B_VALUE = 0.678; PdfColor lColor(L_R_VALUE, L_G_VALUE, L_B_VALUE); const double R_R_VALUE = 0.023; const double R_G_VALUE = 0.345; const double R_B_VALUE = 0.677; PdfColor rColor(R_R_VALUE, R_G_VALUE, R_B_VALUE); ASSERT_TRUE(L_R_VALUE == R_R_VALUE); ASSERT_TRUE(L_G_VALUE == R_G_VALUE); ASSERT_FALSE(L_B_VALUE == R_B_VALUE); ASSERT_FALSE(lColor == rColor); } //CMYB tests { //Positive const double L_C_VALUE = 0.1; const double L_M_VALUE = 0.2; const double L_Y_VALUE = 0.3; const double L_B_VALUE = 0.4; PdfColor lColor(L_C_VALUE, L_M_VALUE, L_Y_VALUE, L_B_VALUE); const double R_C_VALUE = 0.1; const double R_M_VALUE = 0.2; const double R_Y_VALUE = 0.3; const double R_B_VALUE = 0.4; PdfColor rColor(R_C_VALUE, R_M_VALUE, R_Y_VALUE, R_B_VALUE); ASSERT_TRUE(L_C_VALUE == R_C_VALUE); ASSERT_TRUE(L_M_VALUE == R_M_VALUE); ASSERT_TRUE(L_Y_VALUE == R_Y_VALUE); ASSERT_TRUE(L_B_VALUE == R_B_VALUE); ASSERT_TRUE(lColor == rColor); } { //Negative const double L_C_VALUE = 0.1; const double L_M_VALUE = 0.2; const double L_Y_VALUE = 0.3; const double L_B_VALUE = 0.4; PdfColor lColor(L_C_VALUE, L_M_VALUE, L_Y_VALUE, L_B_VALUE); const double R_C_VALUE = 0.11; const double R_M_VALUE = 0.2; const double R_Y_VALUE = 0.3; const double R_B_VALUE = 0.4; PdfColor rColor(R_C_VALUE, R_M_VALUE, R_Y_VALUE, R_B_VALUE); ASSERT_FALSE(L_C_VALUE == R_C_VALUE); ASSERT_TRUE(L_M_VALUE == R_M_VALUE); ASSERT_TRUE(L_Y_VALUE == R_Y_VALUE); ASSERT_TRUE(L_B_VALUE == R_B_VALUE); ASSERT_FALSE(lColor == rColor); } { //Negative const double L_C_VALUE = 0.1; const double L_M_VALUE = 0.2; const double L_Y_VALUE = 0.3; const double L_B_VALUE = 0.4; PdfColor lColor(L_C_VALUE, L_M_VALUE, L_Y_VALUE, L_B_VALUE); const double R_C_VALUE = 0.1; const double R_M_VALUE = 0.21; const double R_Y_VALUE = 0.3; const double R_B_VALUE = 0.4; PdfColor rColor(R_C_VALUE, R_M_VALUE, R_Y_VALUE, R_B_VALUE); ASSERT_TRUE(L_C_VALUE == R_C_VALUE); ASSERT_FALSE(L_M_VALUE == R_M_VALUE); ASSERT_TRUE(L_Y_VALUE == R_Y_VALUE); ASSERT_TRUE(L_B_VALUE == R_B_VALUE); ASSERT_FALSE(lColor == rColor); } { //Negative const double L_C_VALUE = 0.1; const double L_M_VALUE = 0.2; const double L_Y_VALUE = 0.31; const double L_B_VALUE = 0.4; PdfColor lColor(L_C_VALUE, L_M_VALUE, L_Y_VALUE, L_B_VALUE); const double R_C_VALUE = 0.1; const double R_M_VALUE = 0.2; const double R_Y_VALUE = 0.3; const double R_B_VALUE = 0.4; PdfColor rColor(R_C_VALUE, R_M_VALUE, R_Y_VALUE, R_B_VALUE); ASSERT_TRUE(L_C_VALUE == R_C_VALUE); ASSERT_TRUE(L_M_VALUE == R_M_VALUE); ASSERT_FALSE(L_Y_VALUE == R_Y_VALUE); ASSERT_TRUE(L_B_VALUE == R_B_VALUE); ASSERT_FALSE(lColor == rColor); } { //Negative const double L_C_VALUE = 0.1; const double L_M_VALUE = 0.2; const double L_Y_VALUE = 0.3; const double L_B_VALUE = 0.4; PdfColor lColor(L_C_VALUE, L_M_VALUE, L_Y_VALUE, L_B_VALUE); const double R_C_VALUE = 0.1; const double R_M_VALUE = 0.2; const double R_Y_VALUE = 0.3; const double R_B_VALUE = 0.45; PdfColor rColor(R_C_VALUE, R_M_VALUE, R_Y_VALUE, R_B_VALUE); ASSERT_TRUE(L_C_VALUE == R_C_VALUE); ASSERT_TRUE(L_M_VALUE == R_M_VALUE); ASSERT_TRUE(L_Y_VALUE == R_Y_VALUE); ASSERT_FALSE(L_B_VALUE == R_B_VALUE); ASSERT_FALSE(lColor == rColor); } } void ColorTest::testHexNames() { #ifdef DEBUG_INFO std::cout << "testHexNames" << std::endl; #endif { PdfColor rgb = PdfColor::FromString( "#FF0AEF"); ASSERT_TRUE(rgb.IsRGB()); ASSERT_EQ(static_cast(rgb.GetRed() * 255.0), 0xFF); ASSERT_EQ(static_cast(rgb.GetGreen() * 255.0), 0x0A); ASSERT_EQ(static_cast(rgb.GetBlue() * 255.0), 0xEF); } { PdfColor rgb = PdfColor::FromString( "#012345"); ASSERT_TRUE(rgb.IsRGB()); ASSERT_EQ(static_cast(rgb.GetRed() * 255.0), 0x01); ASSERT_EQ(static_cast(rgb.GetGreen() * 255.0), 0x23); ASSERT_EQ(static_cast(rgb.GetBlue() * 255.0), 0x45); } { PdfColor rgb = PdfColor::FromString( "#ABCDEF"); ASSERT_TRUE(rgb.IsRGB()); ASSERT_EQ(static_cast(rgb.GetRed() * 255.0), 0xAB); ASSERT_EQ(static_cast(rgb.GetGreen() * 255.0), 0xCD); ASSERT_EQ(static_cast(rgb.GetBlue() * 255.0), 0xEF); } { PdfColor rgb = PdfColor::FromString( "#abcdef"); ASSERT_TRUE(rgb.IsRGB()); ASSERT_EQ(static_cast(rgb.GetRed() * 255.0), 0xAB); ASSERT_EQ(static_cast(rgb.GetGreen() * 255.0), 0xCD); ASSERT_EQ(static_cast(rgb.GetBlue() * 255.0), 0xEF); } { PdfColor invalidColour = PdfColor::FromString( "#01"); ASSERT_TRUE(invalidColour == PdfColor()); } { PdfColor invalidColour = PdfColor::FromString( "#123456789"); ASSERT_TRUE(invalidColour == PdfColor()); } { CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( PdfColor::FromString( "#12345g" ), PdfError, ePdfError_CannotConvertColor); } { CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( PdfColor::FromString( "#1234g5" ), PdfError, ePdfError_CannotConvertColor); } PdfColor cmyk = PdfColor::FromString( "#ABCDEF01"); ASSERT_TRUE(cmyk.IsCMYK()); ASSERT_EQ(static_cast(cmyk.GetCyan() * 255.0), 0xAB); ASSERT_EQ(static_cast(cmyk.GetMagenta() * 255.0), 0xCD); ASSERT_EQ(static_cast(cmyk.GetYellow() * 255.0), 0xEF); ASSERT_EQ(static_cast(cmyk.GetBlack() * 255.0), 0x01); } void ColorTest::testNamesGeneral() { #ifdef DEBUG_INFO std::cout << "testNames" << std::endl; #endif PdfColor aliceBlue = PdfColor::FromString( "aliceblue"); ASSERT_TRUE(aliceBlue == PdfColor::FromString("#F0F8FF")); ASSERT_EQ(aliceBlue.GetRed(), static_cast(0xF0)/255.0); ASSERT_EQ(aliceBlue.GetGreen(), static_cast(0xF8)/255.0); ASSERT_EQ(aliceBlue.GetBlue(), static_cast(0xFF)/255.0); PdfColor lime = PdfColor::FromString( "lime"); ASSERT_TRUE(lime == PdfColor(0.000, 1.000, 0.000)); PdfColor yellowGreen = PdfColor::FromString( "yellowgreen"); ASSERT_TRUE(yellowGreen == PdfColor::FromString("#9ACD32")); { // Test a not existing color PdfColor notExist = PdfColor::FromString( "asfaf9q341"); ASSERT_TRUE(notExist == PdfColor()); } { // Test a not existing color PdfColor notExist = PdfColor::FromString( "A"); ASSERT_TRUE(notExist == PdfColor()); } { // Test a not existing color PdfColor notExist = PdfColor::FromString( ""); ASSERT_TRUE(notExist == PdfColor()); } { // Test a not existing color PdfColor notExist = PdfColor::FromString( "yellowgree"); ASSERT_TRUE(notExist == PdfColor()); } { // Test a not existing color PdfColor notExist = PdfColor::FromString( "yellowgreem"); ASSERT_TRUE(notExist == PdfColor()); } { // Test a not existing color PdfColor notExist = PdfColor::FromString( "yellowgreen "); ASSERT_TRUE(notExist == PdfColor()); } } namespace { class TestColor { public: TestColor(int r, int g, int b, const char* colorName) : m_r(static_cast(r)/255.0), m_g(static_cast(g)/255.0), m_b(static_cast(b)/255.0), m_colorName(colorName) { //do nothing } ~TestColor() {} double getR() const { return m_r; } double getG() const { return m_g; } double getB() const { return m_b; } const char* getColorName() const { return m_colorName; } TestColor(const TestColor& rhs) : m_r(rhs.m_r), m_g(rhs.m_g), m_b(rhs.m_b), m_colorName(rhs.m_colorName) { //do nothing } private: TestColor(); TestColor& operator=(const TestColor&); double m_r; double m_g; double m_b; const char* m_colorName; }; } void ColorTest::testNamesOneByOne() { #ifdef DEBUG_INFO std::cout << "testNames" << std::endl; #endif //Copied and adjusted from http://cvsweb.xfree86.org/cvsweb/xc/programs/rgb/rgb.txt?rev=1.2 const TestColor TABLE_OF_TEST_COLORS[] = { TestColor(255, 250, 250, "snow"), TestColor(248, 248, 255, "GhostWhite"), TestColor(245, 245, 245, "WhiteSmoke"), TestColor(220, 220, 220, "gainsboro"), TestColor(255, 250, 240, "FloralWhite"), TestColor(253, 245, 230, "OldLace"), TestColor(250, 240, 230, "linen"), TestColor(250, 235, 215, "AntiqueWhite"), TestColor(255, 239, 213, "PapayaWhip"), TestColor(255, 235, 205, "BlanchedAlmond"), TestColor(255, 228, 196, "bisque"), TestColor(255, 218, 185, "PeachPuff"), TestColor(255, 222, 173, "NavajoWhite"), TestColor(255, 228, 181, "moccasin"), TestColor(255, 248, 220, "cornsilk"), TestColor(255, 255, 240, "ivory"), TestColor(255, 250, 205, "LemonChiffon"), TestColor(255, 245, 238, "seashell"), TestColor(240, 255, 240, "honeydew"), TestColor(245, 255, 250, "MintCream"), TestColor(240, 255, 255, "azure"), TestColor(240, 248, 255, "AliceBlue"), TestColor(230, 230, 250, "lavender"), TestColor(255, 240, 245, "LavenderBlush"), TestColor(255, 228, 225, "MistyRose"), TestColor(255, 255, 255, "white"), TestColor(0, 0, 0, "black"), TestColor(47, 79, 79, "DarkSlateGray"), TestColor(47, 79, 79, "DarkSlateGrey"), TestColor(105, 105, 105, "DimGray"), TestColor(105, 105, 105, "DimGrey"), TestColor(112, 128, 144, "SlateGray"), TestColor(112, 128, 144, "SlateGrey"), TestColor(119, 136, 153, "LightSlateGray"), TestColor(119, 136, 153, "LightSlateGrey"), TestColor(190, 190, 190, "gray"), TestColor(190, 190, 190, "grey"), TestColor(211, 211, 211, "LightGrey"), TestColor(211, 211, 211, "LightGray"), TestColor(25, 25, 112, "MidnightBlue"), TestColor(0, 0, 128, "navy"), TestColor(0, 0, 128, "NavyBlue"), TestColor(100, 149, 237, "CornflowerBlue"), TestColor(72, 61, 139, "DarkSlateBlue"), TestColor(106, 90, 205, "SlateBlue"), TestColor(123, 104, 238, "MediumSlateBlue"), TestColor(132, 112, 255, "LightSlateBlue"), TestColor(0, 0, 205, "MediumBlue"), TestColor(65, 105, 225, "RoyalBlue"), TestColor(0, 0, 255, "blue"), TestColor(30, 144, 255, "DodgerBlue"), TestColor(0, 191, 255, "DeepSkyBlue"), TestColor(135, 206, 235, "SkyBlue"), TestColor(135, 206, 250, "LightSkyBlue"), TestColor(70, 130, 180, "SteelBlue"), TestColor(176, 196, 222, "LightSteelBlue"), TestColor(173, 216, 230, "LightBlue"), TestColor(176, 224, 230, "PowderBlue"), TestColor(175, 238, 238, "PaleTurquoise"), TestColor(0, 206, 209, "DarkTurquoise"), TestColor(72, 209, 204, "MediumTurquoise"), TestColor(64, 224, 208, "turquoise"), TestColor(0, 255, 255, "cyan"), TestColor(224, 255, 255, "LightCyan"), TestColor(95, 158, 160, "CadetBlue"), TestColor(102, 205, 170, "MediumAquamarine"), TestColor(127, 255, 212, "aquamarine"), TestColor(0, 100, 0, "DarkGreen"), TestColor(85, 107, 47, "DarkOliveGreen"), TestColor(143, 188, 143, "DarkSeaGreen"), TestColor(46, 139, 87, "SeaGreen"), TestColor(60, 179, 113, "MediumSeaGreen"), TestColor(32, 178, 170, "LightSeaGreen"), TestColor(152, 251, 152, "PaleGreen"), TestColor(0, 255, 127, "SpringGreen"), TestColor(124, 252, 0, "LawnGreen"), TestColor(0, 255, 0, "green"), TestColor(127, 255, 0, "chartreuse"), TestColor(0, 250, 154, "MediumSpringGreen"), TestColor(173, 255, 47, "GreenYellow"), TestColor(50, 205, 50, "LimeGreen"), TestColor(154, 205, 50, "YellowGreen"), TestColor(34, 139, 34, "ForestGreen"), TestColor(107, 142, 35, "OliveDrab"), TestColor(189, 183, 107, "DarkKhaki"), TestColor(240, 230, 140, "khaki"), TestColor(238, 232, 170, "PaleGoldenrod"), TestColor(250, 250, 210, "LightGoldenrodYellow"), TestColor(255, 255, 224, "LightYellow"), TestColor(255, 255, 0, "yellow"), TestColor(255, 215, 0, "gold"), TestColor(238, 221, 130, "LightGoldenrod"), TestColor(218, 165, 32, "goldenrod"), TestColor(184, 134, 11, "DarkGoldenrod"), TestColor(188, 143, 143, "RosyBrown"), TestColor(205, 92, 92, "IndianRed"), TestColor(139, 69, 19, "SaddleBrown"), TestColor(160, 82, 45, "sienna"), TestColor(205, 133, 63, "peru"), TestColor(222, 184, 135, "burlywood"), TestColor(245, 245, 220, "beige"), TestColor(245, 222, 179, "wheat"), TestColor(244, 164, 96, "SandyBrown"), TestColor(210, 180, 140, "tan"), TestColor(210, 105, 30, "chocolate"), TestColor(178, 34, 34, "firebrick"), TestColor(165, 42, 42, "brown"), TestColor(233, 150, 122, "DarkSalmon"), TestColor(250, 128, 114, "salmon"), TestColor(255, 160, 122, "LightSalmon"), TestColor(255, 165, 0, "orange"), TestColor(255, 140, 0, "DarkOrange"), TestColor(255, 127, 80, "coral"), TestColor(240, 128, 128, "LightCoral"), TestColor(255, 99, 71, "tomato"), TestColor(255, 69, 0, "OrangeRed"), TestColor(255, 0, 0, "red"), TestColor(255, 105, 180, "HotPink"), TestColor(255, 20, 147, "DeepPink"), TestColor(255, 192, 203, "pink"), TestColor(255, 182, 193, "LightPink"), TestColor(219, 112, 147, "PaleVioletRed"), TestColor(176, 48, 96, "maroon"), TestColor(199, 21, 133, "MediumVioletRed"), TestColor(208, 32, 144, "VioletRed"), TestColor(255, 0, 255, "magenta"), TestColor(238, 130, 238, "violet"), TestColor(221, 160, 221, "plum"), TestColor(218, 112, 214, "orchid"), TestColor(186, 85, 211, "MediumOrchid"), TestColor(153, 50, 204, "DarkOrchid"), TestColor(148, 0, 211, "DarkViolet"), TestColor(138, 43, 226, "BlueViolet"), TestColor(160, 32, 240, "purple"), TestColor(147, 112, 219, "MediumPurple"), TestColor(216, 191, 216, "thistle"), TestColor(255, 250, 250, "snow1"), TestColor(238, 233, 233, "snow2"), TestColor(205, 201, 201, "snow3"), TestColor(139, 137, 137, "snow4"), TestColor(255, 245, 238, "seashell1"), TestColor(238, 229, 222, "seashell2"), TestColor(205, 197, 191, "seashell3"), TestColor(139, 134, 130, "seashell4"), TestColor(255, 239, 219, "AntiqueWhite1"), TestColor(238, 223, 204, "AntiqueWhite2"), TestColor(205, 192, 176, "AntiqueWhite3"), TestColor(139, 131, 120, "AntiqueWhite4"), TestColor(255, 228, 196, "bisque1"), TestColor(238, 213, 183, "bisque2"), TestColor(205, 183, 158, "bisque3"), TestColor(139, 125, 107, "bisque4"), TestColor(255, 218, 185, "PeachPuff1"), TestColor(238, 203, 173, "PeachPuff2"), TestColor(205, 175, 149, "PeachPuff3"), TestColor(139, 119, 101, "PeachPuff4"), TestColor(255, 222, 173, "NavajoWhite1"), TestColor(238, 207, 161, "NavajoWhite2"), TestColor(205, 179, 139, "NavajoWhite3"), TestColor(139, 121, 94, "NavajoWhite4"), TestColor(255, 250, 205, "LemonChiffon1"), TestColor(238, 233, 191, "LemonChiffon2"), TestColor(205, 201, 165, "LemonChiffon3"), TestColor(139, 137, 112, "LemonChiffon4"), TestColor(255, 248, 220, "cornsilk1"), TestColor(238, 232, 205, "cornsilk2"), TestColor(205, 200, 177, "cornsilk3"), TestColor(139, 136, 120, "cornsilk4"), TestColor(255, 255, 240, "ivory1"), TestColor(238, 238, 224, "ivory2"), TestColor(205, 205, 193, "ivory3"), TestColor(139, 139, 131, "ivory4"), TestColor(240, 255, 240, "honeydew1"), TestColor(224, 238, 224, "honeydew2"), TestColor(193, 205, 193, "honeydew3"), TestColor(131, 139, 131, "honeydew4"), TestColor(255, 240, 245, "LavenderBlush1"), TestColor(238, 224, 229, "LavenderBlush2"), TestColor(205, 193, 197, "LavenderBlush3"), TestColor(139, 131, 134, "LavenderBlush4"), TestColor(255, 228, 225, "MistyRose1"), TestColor(238, 213, 210, "MistyRose2"), TestColor(205, 183, 181, "MistyRose3"), TestColor(139, 125, 123, "MistyRose4"), TestColor(240, 255, 255, "azure1"), TestColor(224, 238, 238, "azure2"), TestColor(193, 205, 205, "azure3"), TestColor(131, 139, 139, "azure4"), TestColor(131, 111, 255, "SlateBlue1"), TestColor(122, 103, 238, "SlateBlue2"), TestColor(105, 89, 205, "SlateBlue3"), TestColor(71, 60, 139, "SlateBlue4"), TestColor(72, 118, 255, "RoyalBlue1"), TestColor(67, 110, 238, "RoyalBlue2"), TestColor(58, 95, 205, "RoyalBlue3"), TestColor(39, 64, 139, "RoyalBlue4"), TestColor(0, 0, 255, "blue1"), TestColor(0, 0, 238, "blue2"), TestColor(0, 0, 205, "blue3"), TestColor(0, 0, 139, "blue4"), TestColor(30, 144, 255, "DodgerBlue1"), TestColor(28, 134, 238, "DodgerBlue2"), TestColor(24, 116, 205, "DodgerBlue3"), TestColor(16, 78, 139, "DodgerBlue4"), TestColor(99, 184, 255, "SteelBlue1"), TestColor(92, 172, 238, "SteelBlue2"), TestColor(79, 148, 205, "SteelBlue3"), TestColor(54, 100, 139, "SteelBlue4"), TestColor(0, 191, 255, "DeepSkyBlue1"), TestColor(0, 178, 238, "DeepSkyBlue2"), TestColor(0, 154, 205, "DeepSkyBlue3"), TestColor(0, 104, 139, "DeepSkyBlue4"), TestColor(135, 206, 255, "SkyBlue1"), TestColor(126, 192, 238, "SkyBlue2"), TestColor(108, 166, 205, "SkyBlue3"), TestColor(74, 112, 139, "SkyBlue4"), TestColor(176, 226, 255, "LightSkyBlue1"), TestColor(164, 211, 238, "LightSkyBlue2"), TestColor(141, 182, 205, "LightSkyBlue3"), TestColor(96, 123, 139, "LightSkyBlue4"), TestColor(198, 226, 255, "SlateGray1"), TestColor(185, 211, 238, "SlateGray2"), TestColor(159, 182, 205, "SlateGray3"), TestColor(108, 123, 139, "SlateGray4"), TestColor(202, 225, 255, "LightSteelBlue1"), TestColor(188, 210, 238, "LightSteelBlue2"), TestColor(162, 181, 205, "LightSteelBlue3"), TestColor(110, 123, 139, "LightSteelBlue4"), TestColor(191, 239, 255, "LightBlue1"), TestColor(178, 223, 238, "LightBlue2"), TestColor(154, 192, 205, "LightBlue3"), TestColor(104, 131, 139, "LightBlue4"), TestColor(224, 255, 255, "LightCyan1"), TestColor(209, 238, 238, "LightCyan2"), TestColor(180, 205, 205, "LightCyan3"), TestColor(122, 139, 139, "LightCyan4"), TestColor(187, 255, 255, "PaleTurquoise1"), TestColor(174, 238, 238, "PaleTurquoise2"), TestColor(150, 205, 205, "PaleTurquoise3"), TestColor(102, 139, 139, "PaleTurquoise4"), TestColor(152, 245, 255, "CadetBlue1"), TestColor(142, 229, 238, "CadetBlue2"), TestColor(122, 197, 205, "CadetBlue3"), TestColor(83, 134, 139, "CadetBlue4"), TestColor(0, 245, 255, "turquoise1"), TestColor(0, 229, 238, "turquoise2"), TestColor(0, 197, 205, "turquoise3"), TestColor(0, 134, 139, "turquoise4"), TestColor(0, 255, 255, "cyan1"), TestColor(0, 238, 238, "cyan2"), TestColor(0, 205, 205, "cyan3"), TestColor(0, 139, 139, "cyan4"), TestColor(151, 255, 255, "DarkSlateGray1"), TestColor(141, 238, 238, "DarkSlateGray2"), TestColor(121, 205, 205, "DarkSlateGray3"), TestColor(82, 139, 139, "DarkSlateGray4"), TestColor(127, 255, 212, "aquamarine1"), TestColor(118, 238, 198, "aquamarine2"), TestColor(102, 205, 170, "aquamarine3"), TestColor(69, 139, 116, "aquamarine4"), TestColor(193, 255, 193, "DarkSeaGreen1"), TestColor(180, 238, 180, "DarkSeaGreen2"), TestColor(155, 205, 155, "DarkSeaGreen3"), TestColor(105, 139, 105, "DarkSeaGreen4"), TestColor(84, 255, 159, "SeaGreen1"), TestColor(78, 238, 148, "SeaGreen2"), TestColor(67, 205, 128, "SeaGreen3"), TestColor(46, 139, 87, "SeaGreen4"), TestColor(154, 255, 154, "PaleGreen1"), TestColor(144, 238, 144, "PaleGreen2"), TestColor(124, 205, 124, "PaleGreen3"), TestColor(84, 139, 84, "PaleGreen4"), TestColor(0, 255, 127, "SpringGreen1"), TestColor(0, 238, 118, "SpringGreen2"), TestColor(0, 205, 102, "SpringGreen3"), TestColor(0, 139, 69, "SpringGreen4"), TestColor(0, 255, 0, "green1"), TestColor(0, 238, 0, "green2"), TestColor(0, 205, 0, "green3"), TestColor(0, 139, 0, "green4"), TestColor(127, 255, 0, "chartreuse1"), TestColor(118, 238, 0, "chartreuse2"), TestColor(102, 205, 0, "chartreuse3"), TestColor(69, 139, 0, "chartreuse4"), TestColor(192, 255, 62, "OliveDrab1"), TestColor(179, 238, 58, "OliveDrab2"), TestColor(154, 205, 50, "OliveDrab3"), TestColor(105, 139, 34, "OliveDrab4"), TestColor(202, 255, 112, "DarkOliveGreen1"), TestColor(188, 238, 104, "DarkOliveGreen2"), TestColor(162, 205, 90, "DarkOliveGreen3"), TestColor(110, 139, 61, "DarkOliveGreen4"), TestColor(255, 246, 143, "khaki1"), TestColor(238, 230, 133, "khaki2"), TestColor(205, 198, 115, "khaki3"), TestColor(139, 134, 78, "khaki4"), TestColor(255, 236, 139, "LightGoldenrod1"), TestColor(238, 220, 130, "LightGoldenrod2"), TestColor(205, 190, 112, "LightGoldenrod3"), TestColor(139, 129, 76, "LightGoldenrod4"), TestColor(255, 255, 224, "LightYellow1"), TestColor(238, 238, 209, "LightYellow2"), TestColor(205, 205, 180, "LightYellow3"), TestColor(139, 139, 122, "LightYellow4"), TestColor(255, 255, 0, "yellow1"), TestColor(238, 238, 0, "yellow2"), TestColor(205, 205, 0, "yellow3"), TestColor(139, 139, 0, "yellow4"), TestColor(255, 215, 0, "gold1"), TestColor(238, 201, 0, "gold2"), TestColor(205, 173, 0, "gold3"), TestColor(139, 117, 0, "gold4"), TestColor(255, 193, 37, "goldenrod1"), TestColor(238, 180, 34, "goldenrod2"), TestColor(205, 155, 29, "goldenrod3"), TestColor(139, 105, 20, "goldenrod4"), TestColor(255, 185, 15, "DarkGoldenrod1"), TestColor(238, 173, 14, "DarkGoldenrod2"), TestColor(205, 149, 12, "DarkGoldenrod3"), TestColor(139, 101, 8, "DarkGoldenrod4"), TestColor(255, 193, 193, "RosyBrown1"), TestColor(238, 180, 180, "RosyBrown2"), TestColor(205, 155, 155, "RosyBrown3"), TestColor(139, 105, 105, "RosyBrown4"), TestColor(255, 106, 106, "IndianRed1"), TestColor(238, 99, 99, "IndianRed2"), TestColor(205, 85, 85, "IndianRed3"), TestColor(139, 58, 58, "IndianRed4"), TestColor(255, 130, 71, "sienna1"), TestColor(238, 121, 66, "sienna2"), TestColor(205, 104, 57, "sienna3"), TestColor(139, 71, 38, "sienna4"), TestColor(255, 211, 155, "burlywood1"), TestColor(238, 197, 145, "burlywood2"), TestColor(205, 170, 125, "burlywood3"), TestColor(139, 115, 85, "burlywood4"), TestColor(255, 231, 186, "wheat1"), TestColor(238, 216, 174, "wheat2"), TestColor(205, 186, 150, "wheat3"), TestColor(139, 126, 102, "wheat4"), TestColor(255, 165, 79, "tan1"), TestColor(238, 154, 73, "tan2"), TestColor(205, 133, 63, "tan3"), TestColor(139, 90, 43, "tan4"), TestColor(255, 127, 36, "chocolate1"), TestColor(238, 118, 33, "chocolate2"), TestColor(205, 102, 29, "chocolate3"), TestColor(139, 69, 19, "chocolate4"), TestColor(255, 48, 48, "firebrick1"), TestColor(238, 44, 44, "firebrick2"), TestColor(205, 38, 38, "firebrick3"), TestColor(139, 26, 26, "firebrick4"), TestColor(255, 64, 64, "brown1"), TestColor(238, 59, 59, "brown2"), TestColor(205, 51, 51, "brown3"), TestColor(139, 35, 35, "brown4"), TestColor(255, 140, 105, "salmon1"), TestColor(238, 130, 98, "salmon2"), TestColor(205, 112, 84, "salmon3"), TestColor(139, 76, 57, "salmon4"), TestColor(255, 160, 122, "LightSalmon1"), TestColor(238, 149, 114, "LightSalmon2"), TestColor(205, 129, 98, "LightSalmon3"), TestColor(139, 87, 66, "LightSalmon4"), TestColor(255, 165, 0, "orange1"), TestColor(238, 154, 0, "orange2"), TestColor(205, 133, 0, "orange3"), TestColor(139, 90, 0, "orange4"), TestColor(255, 127, 0, "DarkOrange1"), TestColor(238, 118, 0, "DarkOrange2"), TestColor(205, 102, 0, "DarkOrange3"), TestColor(139, 69, 0, "DarkOrange4"), TestColor(255, 114, 86, "coral1"), TestColor(238, 106, 80, "coral2"), TestColor(205, 91, 69, "coral3"), TestColor(139, 62, 47, "coral4"), TestColor(255, 99, 71, "tomato1"), TestColor(238, 92, 66, "tomato2"), TestColor(205, 79, 57, "tomato3"), TestColor(139, 54, 38, "tomato4"), TestColor(255, 69, 0, "OrangeRed1"), TestColor(238, 64, 0, "OrangeRed2"), TestColor(205, 55, 0, "OrangeRed3"), TestColor(139, 37, 0, "OrangeRed4"), TestColor(255, 0, 0, "red1"), TestColor(238, 0, 0, "red2"), TestColor(205, 0, 0, "red3"), TestColor(139, 0, 0, "red4"), TestColor(255, 20, 147, "DeepPink1"), TestColor(238, 18, 137, "DeepPink2"), TestColor(205, 16, 118, "DeepPink3"), TestColor(139, 10, 80, "DeepPink4"), TestColor(255, 110, 180, "HotPink1"), TestColor(238, 106, 167, "HotPink2"), TestColor(205, 96, 144, "HotPink3"), TestColor(139, 58, 98, "HotPink4"), TestColor(255, 181, 197, "pink1"), TestColor(238, 169, 184, "pink2"), TestColor(205, 145, 158, "pink3"), TestColor(139, 99, 108, "pink4"), TestColor(255, 174, 185, "LightPink1"), TestColor(238, 162, 173, "LightPink2"), TestColor(205, 140, 149, "LightPink3"), TestColor(139, 95, 101, "LightPink4"), TestColor(255, 130, 171, "PaleVioletRed1"), TestColor(238, 121, 159, "PaleVioletRed2"), TestColor(205, 104, 137, "PaleVioletRed3"), TestColor(139, 71, 93, "PaleVioletRed4"), TestColor(255, 52, 179, "maroon1"), TestColor(238, 48, 167, "maroon2"), TestColor(205, 41, 144, "maroon3"), TestColor(139, 28, 98, "maroon4"), TestColor(255, 62, 150, "VioletRed1"), TestColor(238, 58, 140, "VioletRed2"), TestColor(205, 50, 120, "VioletRed3"), TestColor(139, 34, 82, "VioletRed4"), TestColor(255, 0, 255, "magenta1"), TestColor(238, 0, 238, "magenta2"), TestColor(205, 0, 205, "magenta3"), TestColor(139, 0, 139, "magenta4"), TestColor(255, 131, 250, "orchid1"), TestColor(238, 122, 233, "orchid2"), TestColor(205, 105, 201, "orchid3"), TestColor(139, 71, 137, "orchid4"), TestColor(255, 187, 255, "plum1"), TestColor(238, 174, 238, "plum2"), TestColor(205, 150, 205, "plum3"), TestColor(139, 102, 139, "plum4"), TestColor(224, 102, 255, "MediumOrchid1"), TestColor(209, 95, 238, "MediumOrchid2"), TestColor(180, 82, 205, "MediumOrchid3"), TestColor(122, 55, 139, "MediumOrchid4"), TestColor(191, 62, 255, "DarkOrchid1"), TestColor(178, 58, 238, "DarkOrchid2"), TestColor(154, 50, 205, "DarkOrchid3"), TestColor(104, 34, 139, "DarkOrchid4"), TestColor(155, 48, 255, "purple1"), TestColor(145, 44, 238, "purple2"), TestColor(125, 38, 205, "purple3"), TestColor(85, 26, 139, "purple4"), TestColor(171, 130, 255, "MediumPurple1"), TestColor(159, 121, 238, "MediumPurple2"), TestColor(137, 104, 205, "MediumPurple3"), TestColor(93, 71, 139, "MediumPurple4"), TestColor(255, 225, 255, "thistle1"), TestColor(238, 210, 238, "thistle2"), TestColor(205, 181, 205, "thistle3"), TestColor(139, 123, 139, "thistle4"), TestColor(0, 0, 0, "gray0"), TestColor(0, 0, 0, "grey0"), TestColor(3, 3, 3, "gray1"), TestColor(3, 3, 3, "grey1"), TestColor(5, 5, 5, "gray2"), TestColor(5, 5, 5, "grey2"), TestColor(8, 8, 8, "gray3"), TestColor(8, 8, 8, "grey3"), TestColor(10, 10, 10, "gray4"), TestColor(10, 10, 10, "grey4"), TestColor(13, 13, 13, "gray5"), TestColor(13, 13, 13, "grey5"), TestColor(15, 15, 15, "gray6"), TestColor(15, 15, 15, "grey6"), TestColor(18, 18, 18, "gray7"), TestColor(18, 18, 18, "grey7"), TestColor(20, 20, 20, "gray8"), TestColor(20, 20, 20, "grey8"), TestColor(23, 23, 23, "gray9"), TestColor(23, 23, 23, "grey9"), TestColor(26, 26, 26, "gray10"), TestColor(26, 26, 26, "grey10"), TestColor(28, 28, 28, "gray11"), TestColor(28, 28, 28, "grey11"), TestColor(31, 31, 31, "gray12"), TestColor(31, 31, 31, "grey12"), TestColor(33, 33, 33, "gray13"), TestColor(33, 33, 33, "grey13"), TestColor(36, 36, 36, "gray14"), TestColor(36, 36, 36, "grey14"), TestColor(38, 38, 38, "gray15"), TestColor(38, 38, 38, "grey15"), TestColor(41, 41, 41, "gray16"), TestColor(41, 41, 41, "grey16"), TestColor(43, 43, 43, "gray17"), TestColor(43, 43, 43, "grey17"), TestColor(46, 46, 46, "gray18"), TestColor(46, 46, 46, "grey18"), TestColor(48, 48, 48, "gray19"), TestColor(48, 48, 48, "grey19"), TestColor(51, 51, 51, "gray20"), TestColor(51, 51, 51, "grey20"), TestColor(54, 54, 54, "gray21"), TestColor(54, 54, 54, "grey21"), TestColor(56, 56, 56, "gray22"), TestColor(56, 56, 56, "grey22"), TestColor(59, 59, 59, "gray23"), TestColor(59, 59, 59, "grey23"), TestColor(61, 61, 61, "gray24"), TestColor(61, 61, 61, "grey24"), TestColor(64, 64, 64, "gray25"), TestColor(64, 64, 64, "grey25"), TestColor(66, 66, 66, "gray26"), TestColor(66, 66, 66, "grey26"), TestColor(69, 69, 69, "gray27"), TestColor(69, 69, 69, "grey27"), TestColor(71, 71, 71, "gray28"), TestColor(71, 71, 71, "grey28"), TestColor(74, 74, 74, "gray29"), TestColor(74, 74, 74, "grey29"), TestColor(77, 77, 77, "gray30"), TestColor(77, 77, 77, "grey30"), TestColor(79, 79, 79, "gray31"), TestColor(79, 79, 79, "grey31"), TestColor(82, 82, 82, "gray32"), TestColor(82, 82, 82, "grey32"), TestColor(84, 84, 84, "gray33"), TestColor(84, 84, 84, "grey33"), TestColor(87, 87, 87, "gray34"), TestColor(87, 87, 87, "grey34"), TestColor(89, 89, 89, "gray35"), TestColor(89, 89, 89, "grey35"), TestColor(92, 92, 92, "gray36"), TestColor(92, 92, 92, "grey36"), TestColor(94, 94, 94, "gray37"), TestColor(94, 94, 94, "grey37"), TestColor(97, 97, 97, "gray38"), TestColor(97, 97, 97, "grey38"), TestColor(99, 99, 99, "gray39"), TestColor(99, 99, 99, "grey39"), TestColor(102, 102, 102, "gray40"), TestColor(102, 102, 102, "grey40"), TestColor(105, 105, 105, "gray41"), TestColor(105, 105, 105, "grey41"), TestColor(107, 107, 107, "gray42"), TestColor(107, 107, 107, "grey42"), TestColor(110, 110, 110, "gray43"), TestColor(110, 110, 110, "grey43"), TestColor(112, 112, 112, "gray44"), TestColor(112, 112, 112, "grey44"), TestColor(115, 115, 115, "gray45"), TestColor(115, 115, 115, "grey45"), TestColor(117, 117, 117, "gray46"), TestColor(117, 117, 117, "grey46"), TestColor(120, 120, 120, "gray47"), TestColor(120, 120, 120, "grey47"), TestColor(122, 122, 122, "gray48"), TestColor(122, 122, 122, "grey48"), TestColor(125, 125, 125, "gray49"), TestColor(125, 125, 125, "grey49"), TestColor(127, 127, 127, "gray50"), TestColor(127, 127, 127, "grey50"), TestColor(130, 130, 130, "gray51"), TestColor(130, 130, 130, "grey51"), TestColor(133, 133, 133, "gray52"), TestColor(133, 133, 133, "grey52"), TestColor(135, 135, 135, "gray53"), TestColor(135, 135, 135, "grey53"), TestColor(138, 138, 138, "gray54"), TestColor(138, 138, 138, "grey54"), TestColor(140, 140, 140, "gray55"), TestColor(140, 140, 140, "grey55"), TestColor(143, 143, 143, "gray56"), TestColor(143, 143, 143, "grey56"), TestColor(145, 145, 145, "gray57"), TestColor(145, 145, 145, "grey57"), TestColor(148, 148, 148, "gray58"), TestColor(148, 148, 148, "grey58"), TestColor(150, 150, 150, "gray59"), TestColor(150, 150, 150, "grey59"), TestColor(153, 153, 153, "gray60"), TestColor(153, 153, 153, "grey60"), TestColor(156, 156, 156, "gray61"), TestColor(156, 156, 156, "grey61"), TestColor(158, 158, 158, "gray62"), TestColor(158, 158, 158, "grey62"), TestColor(161, 161, 161, "gray63"), TestColor(161, 161, 161, "grey63"), TestColor(163, 163, 163, "gray64"), TestColor(163, 163, 163, "grey64"), TestColor(166, 166, 166, "gray65"), TestColor(166, 166, 166, "grey65"), TestColor(168, 168, 168, "gray66"), TestColor(168, 168, 168, "grey66"), TestColor(171, 171, 171, "gray67"), TestColor(171, 171, 171, "grey67"), TestColor(173, 173, 173, "gray68"), TestColor(173, 173, 173, "grey68"), TestColor(176, 176, 176, "gray69"), TestColor(176, 176, 176, "grey69"), TestColor(179, 179, 179, "gray70"), TestColor(179, 179, 179, "grey70"), TestColor(181, 181, 181, "gray71"), TestColor(181, 181, 181, "grey71"), TestColor(184, 184, 184, "gray72"), TestColor(184, 184, 184, "grey72"), TestColor(186, 186, 186, "gray73"), TestColor(186, 186, 186, "grey73"), TestColor(189, 189, 189, "gray74"), TestColor(189, 189, 189, "grey74"), TestColor(191, 191, 191, "gray75"), TestColor(191, 191, 191, "grey75"), TestColor(194, 194, 194, "gray76"), TestColor(194, 194, 194, "grey76"), TestColor(196, 196, 196, "gray77"), TestColor(196, 196, 196, "grey77"), TestColor(199, 199, 199, "gray78"), TestColor(199, 199, 199, "grey78"), TestColor(201, 201, 201, "gray79"), TestColor(201, 201, 201, "grey79"), TestColor(204, 204, 204, "gray80"), TestColor(204, 204, 204, "grey80"), TestColor(207, 207, 207, "gray81"), TestColor(207, 207, 207, "grey81"), TestColor(209, 209, 209, "gray82"), TestColor(209, 209, 209, "grey82"), TestColor(212, 212, 212, "gray83"), TestColor(212, 212, 212, "grey83"), TestColor(214, 214, 214, "gray84"), TestColor(214, 214, 214, "grey84"), TestColor(217, 217, 217, "gray85"), TestColor(217, 217, 217, "grey85"), TestColor(219, 219, 219, "gray86"), TestColor(219, 219, 219, "grey86"), TestColor(222, 222, 222, "gray87"), TestColor(222, 222, 222, "grey87"), TestColor(224, 224, 224, "gray88"), TestColor(224, 224, 224, "grey88"), TestColor(227, 227, 227, "gray89"), TestColor(227, 227, 227, "grey89"), TestColor(229, 229, 229, "gray90"), TestColor(229, 229, 229, "grey90"), TestColor(232, 232, 232, "gray91"), TestColor(232, 232, 232, "grey91"), TestColor(235, 235, 235, "gray92"), TestColor(235, 235, 235, "grey92"), TestColor(237, 237, 237, "gray93"), TestColor(237, 237, 237, "grey93"), TestColor(240, 240, 240, "gray94"), TestColor(240, 240, 240, "grey94"), TestColor(242, 242, 242, "gray95"), TestColor(242, 242, 242, "grey95"), TestColor(245, 245, 245, "gray96"), TestColor(245, 245, 245, "grey96"), TestColor(247, 247, 247, "gray97"), TestColor(247, 247, 247, "grey97"), TestColor(250, 250, 250, "gray98"), TestColor(250, 250, 250, "grey98"), TestColor(252, 252, 252, "gray99"), TestColor(252, 252, 252, "grey99"), TestColor(255, 255, 255, "gray100"), TestColor(255, 255, 255, "grey100"), TestColor(169, 169, 169, "DarkGrey"), TestColor(169, 169, 169, "DarkGray"), TestColor(0, 0, 139, "DarkBlue"), TestColor(0, 139, 139, "DarkCyan"), TestColor(139, 0, 139, "DarkMagenta"), TestColor(139, 0, 0, "DarkRed"), TestColor(144, 238, 144, "LightGreen") }; const size_t SIZE_OF_TABLE_OF_TEST_COLORS = sizeof(TABLE_OF_TEST_COLORS)/sizeof(TestColor); for (size_t i=0; i TPairOfColors; typedef std::map TMapOfColors; TMapOfColors colorTable; colorTable["red"] = TPairOfColors(PdfColor(1.0, 0.0, 0.0), PdfColor(0.0, 1.0, 1.0, 0.0)); colorTable["green"] = TPairOfColors(PdfColor(0.0, 1.0, 0.0), PdfColor(1.0, 0.0, 1.0, 0.0)); colorTable["blue"] = TPairOfColors(PdfColor(0.0, 0.0, 1.0), PdfColor(1.0, 1.0, 0.0, 0.0)); colorTable["white"] = TPairOfColors(PdfColor(1.0, 1.0, 1.0), PdfColor(0.0, 0.0, 0.0, 0.0)); colorTable["black"] = TPairOfColors(PdfColor(0.0, 0.0, 0.0), PdfColor(0.0, 0.0, 0.0, 1.0)); colorTable["cyan"] = TPairOfColors(PdfColor(0.0, 1.0, 1.0), PdfColor(1.0, 0.0, 0.0, 0.0)); colorTable["magenta"]= TPairOfColors(PdfColor(1.0, 0.0, 1.0), PdfColor(0.0, 1.0, 0.0, 0.0)); colorTable["yellow"] = TPairOfColors(PdfColor(1.0, 1.0, 0.0), PdfColor(0.0, 0.0, 1.0, 0.0)); for(TMapOfColors::const_iterator iter(colorTable.begin()), iterEnd(colorTable.end()); iter != iterEnd; ++iter) { const std::string COLOR_NAME(iter->first); PdfColor namedColor(PdfColor::FromString(COLOR_NAME.c_str())); PdfColor rgbColor(iter->second.first); PdfColor cmykColor(iter->second.second); ASSERT_TRUE(namedColor.ConvertToRGB() == rgbColor); ASSERT_TRUE(rgbColor.ConvertToCMYK() == cmykColor); ASSERT_TRUE(rgbColor == cmykColor.ConvertToRGB()); } } podofo-0.9.5/test/unit/FilterTest.cpp0000664000175000017500000001243412715163311017416 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "FilterTest.h" #include #include using namespace PoDoFo; CPPUNIT_TEST_SUITE_REGISTRATION( FilterTest ); static const char s_pTestBuffer1[] = "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure."; // We treat the buffer as _excluding_ the trailing \0 static const long s_lTestLength1 = strlen(s_pTestBuffer1); const char s_pTestBuffer2[] = { 0x01, 0x64, 0x65, static_cast(0xFE), 0x6B, static_cast(0x80), 0x45, 0x32, static_cast(0x88), 0x12, static_cast(0x71), static_cast(0xEA), 0x01, 0x01, 0x64, 0x65, static_cast(0xFE), 0x6B, static_cast(0x80), 0x45, 0x32, static_cast(0x88), 0x12, static_cast(0x71), static_cast(0xEA), 0x03, 0x01, 0x64, 0x65, static_cast(0xFE), 0x6B, static_cast(0x80), 0x45, 0x32, static_cast(0x88), 0x12, static_cast(0x71), static_cast(0xEA), 0x02, 0x01, 0x64, 0x65, static_cast(0xFE), 0x6B, static_cast(0x80), 0x45, 0x32, static_cast(0x88), 0x12, static_cast(0x71), static_cast(0xEA), 0x00, 0x01, 0x64, 0x65, static_cast(0xFE), 0x6B, static_cast(0x80), 0x45, 0x32, static_cast(0x88), 0x12, static_cast(0x71), static_cast(0xEA), 0x00, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const long s_lTestLength2 = 6*13; void FilterTest::setUp() { } void FilterTest::tearDown() { } void FilterTest::TestFilter( EPdfFilter eFilter, const char * pTestBuffer, const long lTestLength ) { char* pEncoded; char* pDecoded; pdf_long lEncoded; pdf_long lDecoded; std::auto_ptr pFilter = PdfFilterFactory::Create( eFilter ); if( !pFilter.get() ) { printf("!!! Filter %i not implemented.\n", eFilter); return; } printf("Testing Algorithm %i:\n", eFilter); printf("\t-> Testing Encoding\n"); try { pFilter->Encode( pTestBuffer, lTestLength, &pEncoded, &lEncoded ); } catch( PdfError & e ) { if( e == ePdfError_UnsupportedFilter ) { printf("\t-> Encoding not supported for filter %i.\n", eFilter ); return; } else { e.AddToCallstack( __FILE__, __LINE__ ); throw e; } } printf("\t-> Testing Decoding\n"); try { pFilter->Decode( pEncoded, lEncoded, &pDecoded, &lDecoded ); } catch( PdfError & e ) { if( e == ePdfError_UnsupportedFilter ) { printf("\t-> Decoding not supported for filter %i.\n", eFilter); return; } else { e.AddToCallstack( __FILE__, __LINE__ ); throw e; } } printf("\t-> Original Data Length: %li\n", lTestLength ); printf("\t-> Encoded Data Length: %li\n", lEncoded ); printf("\t-> Decoded Data Length: %li\n", lDecoded ); CPPUNIT_ASSERT_EQUAL( static_cast(lTestLength), static_cast(lDecoded) ); CPPUNIT_ASSERT_EQUAL( memcmp( pTestBuffer, pDecoded, lTestLength ), 0 ); free( pEncoded ); free( pDecoded ); printf("\t-> Test succeeded!\n"); } void FilterTest::testFilters() { for( int i =0; i<=ePdfFilter_Crypt; i++ ) { TestFilter( static_cast(i), s_pTestBuffer1, s_lTestLength1 ); TestFilter( static_cast(i), s_pTestBuffer2, s_lTestLength2 ); } } void FilterTest::testCCITT() { std::auto_ptr pFilter = PdfFilterFactory::Create( ePdfFilter_CCITTFaxDecode ); if( !pFilter.get() ) { printf("!!! ePdfFilter_CCITTFaxDecode not implemented skipping test!\n"); return; } } podofo-0.9.5/test/unit/StringTest.cpp0000664000175000017500000003423412716127356017453 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "StringTest.h" #include #ifndef __clang__ using namespace PoDoFo; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( StringTest ); inline std::ostream& operator<<(std::ostream& o, const PdfString& s) { return o << s.GetStringUtf8(); } void StringTest::setUp() { } void StringTest::tearDown() { } void StringTest::testGetStringUtf8() { const std::string src1 = "Hello World!"; const std::string src2 = src1; const std::string src3 = "「Po\tDoFoã€ã¯ä»Šã‹ã‚‰æ—¥æœ¬èªžã‚‚話ã›ã¾ã™ã€‚"; // Normal ascii string should be converted to UTF8 PdfString str1( src1.c_str() ); std::string res1 = str1.GetStringUtf8(); CPPUNIT_ASSERT_EQUAL_MESSAGE( "testing const char* ASCII -> UTF8", src1, res1 ); // Normal std::string string should be converted to UTF8 PdfString str2( src2 ); std::string res2 = str2.GetStringUtf8(); CPPUNIT_ASSERT_EQUAL_MESSAGE( "testing std::string ASCII -> UTF8", src2, res2 ); // UTF8 data in std::string cannot be converted as we do not know it is UTF8 PdfString str3( src3 ); std::string res3 = str3.GetStringUtf8(); CPPUNIT_ASSERT_EQUAL_MESSAGE( "testing std::string UTF8 -> UTF8", (res3 != src3) , true ); // UTF8 data as pdf_utf8* must be convertible PdfString str4( reinterpret_cast(src3.c_str()) ); std::string res4 = str4.GetStringUtf8(); CPPUNIT_ASSERT_EQUAL_MESSAGE( "testing pdf_utf8* UTF8 -> UTF8", res4, src3 ); } void StringTest::testUtf16beContructor() { const char* pszStringJapUtf8 = "「PoDoFoã€ã¯ä»Šã‹ã‚‰æ—¥æœ¬èªžã‚‚話ã›ã¾ã™ã€‚"; // The same string as a NULL-terminated UTF-8 string. This is a UTF-8 literal, so your editor // must be configured to handle this file as UTF-8 to see something sensible below. // The same string in UTF16BE encoding const char psStringJapUtf16BE[44] = { 0x30, 0x0c, 0x00, 0x50, 0x00, 0x6f, 0x00, 0x44, 0x00, 0x6f, 0x00, 0x46, 0x00, 0x6f, 0x30, 0x0d, 0x30, 0x6f, 0x4e, static_cast(0xca), 0x30, 0x4b, 0x30, static_cast(0x89), 0x65, static_cast(0xe5), 0x67, 0x2c, static_cast(0x8a), static_cast(0x9e), 0x30, static_cast(0x82), static_cast(0x8a), static_cast(0x71), 0x30, 0x5b, 0x30, static_cast(0x7e), 0x30, 0x59, 0x30, 0x02, 0x00, 0x00 }; PdfString strUtf8( reinterpret_cast(pszStringJapUtf8) ); PdfString strUtf16( reinterpret_cast(psStringJapUtf16BE), 21 ); PdfString strUtf16b( reinterpret_cast(psStringJapUtf16BE), 21 ); /* std::cout << std::endl; std::cout << "utf8 :" << strUtf8 << " " << strUtf8.GetCharacterLength() << std::endl; std::cout << "utf16:" << strUtf16 << " " << strUtf16.GetCharacterLength() << std::endl; std::cout << "wide : "; for( int i=0;i<=strUtf16.GetCharacterLength();i++ ) printf("%04x ", strUtf16.GetUnicode()[i]); std::cout << std::endl; std::cout << "wide : "; for( int i=0;i<=strUtf16.GetCharacterLength();i++ ) printf("%4i ", i ); std::cout << std::endl; */ // Compare UTF16 to UTF8 string CPPUNIT_ASSERT_EQUAL_MESSAGE( "Comparing string length", strUtf8.GetCharacterLength(), strUtf16.GetCharacterLength() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Comparing UTF8 and UTF16 string converted to UTF8", strUtf8.GetStringUtf8(), strUtf16.GetStringUtf8() ); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Comparing UTF8 and UTF16 string", strUtf8, strUtf16 ); // Compare two UTF16 strings CPPUNIT_ASSERT_EQUAL( strUtf16.GetCharacterLength(), strUtf16b.GetCharacterLength() ); CPPUNIT_ASSERT_EQUAL( strUtf16.GetStringUtf8(), strUtf16b.GetStringUtf8() ); CPPUNIT_ASSERT_EQUAL( strUtf16, strUtf16b ); } void StringTest::testWCharConstructor() { CPPUNIT_ASSERT_EQUAL( PdfString("Hallo World"), PdfString(L"Hallo World") ); CPPUNIT_ASSERT_EQUAL( PdfString(L"Hallo World"), PdfString(L"Hallo World") ); } void StringTest::testEscapeBrackets() { // Test balanced brackets ansi const char* pszAscii = "Hello (balanced) World"; const char* pszAsciiExpect = "(Hello \\(balanced\\) World)"; PdfString sAscii( pszAscii ); PdfVariant varAscii( sAscii ); std::string strAscii; varAscii.ToString( strAscii ); CPPUNIT_ASSERT_EQUAL( strAscii == pszAsciiExpect, true ); // Test un-balanced brackets ansi const char* pszAscii2 = "Hello ((unbalanced World"; const char* pszAsciiExpect2 = "(Hello \\(\\(unbalanced World)"; PdfString sAscii2( pszAscii2 ); PdfVariant varAscii2( sAscii2 ); std::string strAscii2; varAscii2.ToString( strAscii2 ); CPPUNIT_ASSERT_EQUAL( strAscii2 == pszAsciiExpect2, true ); // Test balanced brackets unicode const char* pszUnic = "Hello (balanced) World"; const char pszUnicExpect[]= { 0x28, static_cast(0xFE), static_cast(0xFF), 0x00, 0x48, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x20, 0x00, 0x5C, 0x28, 0x00, 0x62, 0x00, 0x61, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x6E, 0x00, 0x63, 0x00, 0x65, 0x00, 0x64, 0x00, 0x5C, 0x29, 0x00, 0x20, 0x00, 0x57, 0x00, 0x6F, 0x00, static_cast(0x72), 0x00, 0x6C, 0x00, 0x64, 0x29, 0x00, 0x00 }; // Force unicode string PdfString sUnic( reinterpret_cast(pszUnic) ); PdfVariant varUnic( sUnic ); std::string strUnic; varUnic.ToString( strUnic ); CPPUNIT_ASSERT_EQUAL( memcmp( strUnic.c_str(), pszUnicExpect, strUnic.length() ) == 0, true ); // Test un-balanced brackets unicode const char* pszUnic2 = "Hello ((unbalanced World"; const char pszUnicExpect2[]= { 0x28, static_cast(0xFE), static_cast(0xFF), 0x00, 0x48, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x20, 0x00, 0x5C, 0x28, 0x00, 0x5C, 0x28, 0x00, 0x75, 0x00, 0x6E, 0x00, 0x62, 0x00, 0x61, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x6E, 0x00, 0x63, 0x00, 0x65, 0x00, 0x64, 0x00, 0x20, 0x00, 0x57, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x6C, 0x00, 0x64, 0x29 }; // Force unicode string PdfString sUnic2( reinterpret_cast(pszUnic2) ); PdfVariant varUnic2( sUnic2 ); std::string strUnic2; varUnic2.ToString( strUnic2 ); CPPUNIT_ASSERT_EQUAL( memcmp( strUnic2.c_str(), pszUnicExpect2, strUnic2.length() ) == 0, true ); // Test reading the unicode string back in PdfVariant varRead; PdfTokenizer tokenizer( strUnic2.c_str(), strUnic2.length() ); tokenizer.GetNextVariant( varRead, NULL ); CPPUNIT_ASSERT_EQUAL( varRead.GetString() == sUnic2, true ); } void StringTest::testWriteEscapeSequences() { TestWriteEscapeSequences("(Hello\\nWorld)", "(Hello\\nWorld)"); TestWriteEscapeSequences("(Hello\nWorld)", "(Hello\\nWorld)"); TestWriteEscapeSequences("(Hello\012World)", "(Hello\\nWorld)"); TestWriteEscapeSequences("(Hello\\012World)", "(Hello\\nWorld)"); TestWriteEscapeSequences("(Hello\\rWorld)", "(Hello\\rWorld)"); TestWriteEscapeSequences("(Hello\rWorld)", "(Hello\\rWorld)"); TestWriteEscapeSequences("(Hello\015World)", "(Hello\\rWorld)"); TestWriteEscapeSequences("(Hello\\015World)", "(Hello\\rWorld)"); TestWriteEscapeSequences("(Hello\\tWorld)", "(Hello\\tWorld)"); TestWriteEscapeSequences("(Hello\tWorld)", "(Hello\\tWorld)"); TestWriteEscapeSequences("(Hello\011World)", "(Hello\\tWorld)"); TestWriteEscapeSequences("(Hello\\011World)", "(Hello\\tWorld)"); TestWriteEscapeSequences("(Hello\\fWorld)", "(Hello\\fWorld)"); TestWriteEscapeSequences("(Hello\fWorld)", "(Hello\\fWorld)"); TestWriteEscapeSequences("(Hello\014World)", "(Hello\\fWorld)"); TestWriteEscapeSequences("(Hello\\014World)", "(Hello\\fWorld)"); TestWriteEscapeSequences("(Hello\\(World)", "(Hello\\(World)"); TestWriteEscapeSequences("(Hello\\050World)", "(Hello\\(World)"); TestWriteEscapeSequences("(Hello\\)World)", "(Hello\\)World)"); TestWriteEscapeSequences("(Hello\\051World)", "(Hello\\)World)"); TestWriteEscapeSequences("(Hello\\\\World)", "(Hello\\\\World)"); TestWriteEscapeSequences("(Hello\\\134World)", "(Hello\\\\World)"); // Special case, \ at end of line TestWriteEscapeSequences("(Hello\\\nWorld)", "(HelloWorld)"); TestWriteEscapeSequences("(Hello\003World)", "(Hello\003World)"); } void StringTest::TestWriteEscapeSequences(const char* pszSource, const char* pszExpected) { PdfVariant variant; std::string ret; std::string expected = pszExpected; printf("Testing with value: %s\n", pszSource ); PdfTokenizer tokenizer( pszSource, strlen( pszSource ) ); tokenizer.GetNextVariant( variant, NULL ); CPPUNIT_ASSERT_EQUAL( variant.GetDataType(), ePdfDataType_String ); variant.ToString( ret ); printf(" -> Convert To String: %s\n", ret.c_str() ); CPPUNIT_ASSERT_EQUAL( expected, ret ); } void StringTest::testEmptyString() { const char* pszEmpty = ""; std::string sEmpty; std::string sEmpty2( pszEmpty ); PdfString str1; PdfString str2( sEmpty ); PdfString str3( sEmpty2 ); PdfString str4( pszEmpty ); PdfString str5( pszEmpty, 0, false ); PdfString str6( reinterpret_cast(pszEmpty) ); PdfString str7( reinterpret_cast(pszEmpty), 0 ); PdfString str8( reinterpret_cast(L""), 0 ); CPPUNIT_ASSERT( !str1.IsValid() ); CPPUNIT_ASSERT( str2.IsValid() ); CPPUNIT_ASSERT_EQUAL( static_cast(0), str2.GetLength() ); CPPUNIT_ASSERT_EQUAL( static_cast(0), str2.GetCharacterLength() ); CPPUNIT_ASSERT_EQUAL( std::string(), str2.GetStringUtf8() ); CPPUNIT_ASSERT_EQUAL( std::string(""), str2.GetStringUtf8() ); CPPUNIT_ASSERT( str3.IsValid() ); CPPUNIT_ASSERT_EQUAL( static_cast(0), str3.GetLength() ); CPPUNIT_ASSERT_EQUAL( static_cast(0), str3.GetCharacterLength() ); CPPUNIT_ASSERT_EQUAL( std::string(), str3.GetStringUtf8() ); CPPUNIT_ASSERT_EQUAL( std::string(""), str3.GetStringUtf8() ); CPPUNIT_ASSERT( str4.IsValid() ); CPPUNIT_ASSERT_EQUAL( static_cast(0), str4.GetLength() ); CPPUNIT_ASSERT_EQUAL( static_cast(0), str4.GetCharacterLength() ); CPPUNIT_ASSERT_EQUAL( std::string(), str4.GetStringUtf8() ); CPPUNIT_ASSERT_EQUAL( std::string(""), str4.GetStringUtf8() ); CPPUNIT_ASSERT( str5.IsValid() ); CPPUNIT_ASSERT_EQUAL( static_cast(0), str5.GetLength() ); CPPUNIT_ASSERT_EQUAL( static_cast(0), str5.GetCharacterLength() ); CPPUNIT_ASSERT_EQUAL( std::string(), str5.GetStringUtf8() ); CPPUNIT_ASSERT_EQUAL( std::string(""), str5.GetStringUtf8() ); CPPUNIT_ASSERT( str6.IsValid() ); CPPUNIT_ASSERT_EQUAL( static_cast(0), str6.GetLength() ); CPPUNIT_ASSERT_EQUAL( static_cast(0), str6.GetCharacterLength() ); CPPUNIT_ASSERT_EQUAL( std::string(), str6.GetStringUtf8() ); CPPUNIT_ASSERT_EQUAL( std::string(""), str6.GetStringUtf8() ); CPPUNIT_ASSERT( str7.IsValid() ); CPPUNIT_ASSERT_EQUAL( static_cast(0), str7.GetLength() ); CPPUNIT_ASSERT_EQUAL( static_cast(0), str7.GetCharacterLength() ); CPPUNIT_ASSERT_EQUAL( std::string(), str7.GetStringUtf8() ); CPPUNIT_ASSERT_EQUAL( std::string(""), str7.GetStringUtf8() ); CPPUNIT_ASSERT( str8.IsValid() ); CPPUNIT_ASSERT_EQUAL( static_cast(0), str8.GetLength() ); CPPUNIT_ASSERT_EQUAL( static_cast(0), str8.GetCharacterLength() ); CPPUNIT_ASSERT_EQUAL( std::string(), str8.GetStringUtf8() ); CPPUNIT_ASSERT_EQUAL( std::string(""), str8.GetStringUtf8() ); } void StringTest::testInitFromUtf8() { const char* pszUtf8 = "This string contains UTF-8 Characters: ÄÖÜ."; const PdfString str( reinterpret_cast(pszUtf8) ); CPPUNIT_ASSERT_EQUAL( true, str.IsUnicode() ); CPPUNIT_ASSERT_EQUAL( static_cast(43*2), str.GetLength() ); CPPUNIT_ASSERT_EQUAL( static_cast(43), str.GetCharacterLength() ); CPPUNIT_ASSERT_EQUAL( std::string(pszUtf8), str.GetStringUtf8() ); } #endif // __clang__ podofo-0.9.5/test/unit/EncodingTest.h0000664000175000017500000000451313035002227017355 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _ENCODING_TEST_H_ #define _ENCODING_TEST_H_ #include namespace PoDoFo { class PdfEncoding; }; /** This test tests the various class PdfEncoding classes */ class EncodingTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( EncodingTest ); CPPUNIT_TEST( testDifferences ); CPPUNIT_TEST( testDifferencesEncoding ); CPPUNIT_TEST( testDifferencesObject ); CPPUNIT_TEST( testUnicodeNames ); CPPUNIT_TEST( testGetCharCode ); CPPUNIT_TEST( testToUnicodeParse ); CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown(); void testDifferences(); void testDifferencesObject(); void testDifferencesEncoding(); void testUnicodeNames(); void testGetCharCode(); void testToUnicodeParse(); private: bool outofRangeHelper( PoDoFo::PdfEncoding* pEncoding, std::string & rMsg, const char* pszName ); }; #endif // _STRING_TEST_H_ podofo-0.9.5/test/unit/PainterTest.h0000664000175000017500000000440311523003150017223 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2011 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _PAINTER_TEST_H_ #define _PAINTER_TEST_H_ #include namespace PoDoFo { class PdfPage; class PdfStream; }; /** This test tests the class PdfPainter */ class PainterTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( PainterTest ); CPPUNIT_TEST( testAppend ); CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown(); /** * Test if contents are appended correctly * to pages with existing contents. */ void testAppend(); private: /** * Compare the filtered contents of a PdfStream object * with a string and assert if the contents do not match! * * @param pStream PdfStream object * @param pszContent expected contents */ void CompareStreamContent(PoDoFo::PdfStream* pStream, const char* pszExpected); }; #endif // _PAINTER_TEST_H_ podofo-0.9.5/test/unit/StringTest.h0000664000175000017500000000462612716127356017122 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _STRING_TEST_H_ #define _STRING_TEST_H_ #include #ifndef __clang__ /** This test tests the class PdfString */ class StringTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( StringTest ); CPPUNIT_TEST( testGetStringUtf8 ); CPPUNIT_TEST( testUtf16beContructor ); CPPUNIT_TEST( testWCharConstructor ); CPPUNIT_TEST( testEscapeBrackets ); CPPUNIT_TEST( testWriteEscapeSequences ); CPPUNIT_TEST( testEmptyString ); CPPUNIT_TEST( testInitFromUtf8 ); CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown(); void testGetStringUtf8(); void testUtf16beContructor(); void testWCharConstructor(); void testEscapeBrackets(); void testWriteEscapeSequences(); void testEmptyString(); void testInitFromUtf8(); private: void TestWriteEscapeSequences(const char* pszSource, const char* pszExpected); }; #endif // __clang__ #endif // _STRING_TEST_H_ podofo-0.9.5/test/unit/ElementTest.cpp0000664000175000017500000000627211403202272017556 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "ElementTest.h" #include using namespace PoDoFo; CPPUNIT_TEST_SUITE_REGISTRATION( ElementTest ); void ElementTest::setUp() { } void ElementTest::tearDown() { } void ElementTest::testTypeToIndexAnnotation() { // Check last entry in the type names array of PdfAnnotation PdfObject object; object.GetDictionary().AddKey( PdfName("Type"), PdfName("Annot") ); object.GetDictionary().AddKey( PdfName("Subtype"), PdfName("RichMedia") ); PdfAnnotation annot(&object, NULL); CPPUNIT_ASSERT_EQUAL( ePdfAnnotation_RichMedia, annot.GetType() ); } void ElementTest::testTypeToIndexAction() { // Check last entry in the type names array of PdfAction PdfObject object; object.GetDictionary().AddKey( PdfName("Type"), PdfName("Action") ); object.GetDictionary().AddKey( PdfName("S"), PdfName("GoTo3DView") ); PdfAction action(&object); CPPUNIT_ASSERT_EQUAL( ePdfAction_GoTo3DView, action.GetType() ); } void ElementTest::testTypeToIndexAnnotationUnknown() { // Check last entry in the type names array of PdfAnnotation PdfObject object; object.GetDictionary().AddKey( PdfName("Type"), PdfName("Annot") ); object.GetDictionary().AddKey( PdfName("Subtype"), PdfName("PoDoFoRocksUnknownType") ); PdfAnnotation annot(&object, NULL); CPPUNIT_ASSERT_EQUAL( ePdfAnnotation_Unknown, annot.GetType() ); } void ElementTest::testTypeToIndexActionUnknown() { // Check last entry in the type names array of PdfAction PdfObject object; object.GetDictionary().AddKey( PdfName("Type"), PdfName("Action") ); object.GetDictionary().AddKey( PdfName("S"), PdfName("PoDoFoRocksUnknownType") ); PdfAction action(&object); CPPUNIT_ASSERT_EQUAL( ePdfAction_Unknown, action.GetType() ); } podofo-0.9.5/test/unit/TestUtils.cpp0000664000175000017500000000555311705105566017303 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "TestUtils.h" #include #include #include #include #if defined(_WIN32) || defined(_WIN64) #include #ifdef CreateFont #undef CreateFont #endif // CreateFont #ifdef DrawText #undef DrawText #endif // DrawText #endif // _WIN32 || _WIN64 #include std::string TestUtils::getTempFilename() { const long lLen = 256; char tmpFilename[lLen]; #if defined(_WIN32) || defined(_WIN64) char tmpDir[lLen]; GetTempPathA(lLen, tmpDir); GetTempFileNameA(tmpDir, "podofo", 0, tmpFilename); #else strncpy( tmpFilename, "/tmp/podofoXXXXXX", lLen); int handle = mkstemp(tmpFilename); close(handle); #endif // _WIN32 || _WIN64 printf("Created tempfile: %s\n", tmpFilename); std::string sFilename = tmpFilename; return sFilename; } void TestUtils::deleteFile( const char* pszFilename ) { #if defined(_WIN32) || defined(_WIN64) _unlink(pszFilename); #else unlink(pszFilename); #endif // _WIN32 || _WIN64 } char* TestUtils::readDataFile( const char* pszFilename ) { // TODO: determine correct prefix during runtime std::string sFilename = "/home/dominik/podofotmp/test/unit/data/"; sFilename = sFilename + pszFilename; PoDoFo::PdfFileInputStream stream( sFilename.c_str() ); long lLen = stream.GetFileLength(); char* pBuffer = static_cast(malloc(sizeof(char) * lLen)); stream.Read(pBuffer, lLen); return pBuffer; } podofo-0.9.5/test/unit/DateTest.h0000664000175000017500000000352111763153744016523 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2012 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _DATE_TEST_H_ #define _DATE_TEST_H_ #include class DateTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( DateTest ); CPPUNIT_TEST( testCreateDateFromString ); CPPUNIT_TEST( testDateValue ); CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown(); void testCreateDateFromString(); void testDateValue(); }; #endif podofo-0.9.5/test/unit/NameTest.h0000664000175000017500000000514111067226502016514 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _NAME_TEST_H_ #define _NAME_TEST_H_ #include /** This test tests the class PdfName */ class NameTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( NameTest ); CPPUNIT_TEST( testParseAndWrite ); CPPUNIT_TEST( testNameEncoding ); CPPUNIT_TEST( testEncodedNames ); CPPUNIT_TEST( testEquality ); CPPUNIT_TEST( testWrite ); CPPUNIT_TEST( testFromEscaped ); CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown(); void testParseAndWrite(); void testNameEncoding(); void testEncodedNames(); void testEquality(); void testWrite(); void testFromEscaped(); private: void TestName( const char* pszString, const char* pszExpectedEncoded ); void TestEncodedName( const char* pszString, const char* pszExpected ); /** Tests if both names are equal */ void TestNameEquality( const char * pszName1, const char* pszName2 ); /** Test if pszName interpreted as PdfName and written * to a PdfOutputDevice equals pszResult */ void TestWrite( const char * pszName, const char* pszResult ); void TestFromEscape( const char* pszName1, const char* pszName2 ); }; #endif // _NAME_TEST_H_ podofo-0.9.5/test/unit/TokenizerTest.h0000664000175000017500000000675211205021044017603 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _TOKENIZER_TEST_H_ #define _TOKENIZER_TEST_H_ #include #include /** This test tests the class PdfTokenizer * * Currently the following methods are tested * - void PdfTokenizer::GetNextVariant( PdfVariant& rVariant, PdfEncrypt* pEncrypt ); * - bool PdfTokenizer::GetNextToken( const char *& pszToken, EPdfTokenType* peType = NULL); * - void PdfTokenizer::IsNextToken( const char* pszToken ); */ class TokenizerTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( TokenizerTest ); CPPUNIT_TEST( testArrays ); CPPUNIT_TEST( testBool ); CPPUNIT_TEST( testHexString ); CPPUNIT_TEST( testName ); CPPUNIT_TEST( testNull ); CPPUNIT_TEST( testNumbers ); CPPUNIT_TEST( testReference ); CPPUNIT_TEST( testString ); CPPUNIT_TEST( testTokens ); CPPUNIT_TEST( testComments ); CPPUNIT_TEST( testDictionary ); CPPUNIT_TEST( testLocale ); CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown(); void testArrays(); void testBool(); void testHexString(); void testName(); void testNull(); void testNumbers(); void testReference(); void testString(); void testDictionary(); void testTokens(); void testComments(); void testLocale(); private: void Test( const char* pszString, PoDoFo::EPdfDataType eDataType, const char* pszExpected = NULL ); /** Test parsing a stream. * * \param pszBuffer a string buffer that will be parsed * \param pszTokens a NULL terminated list of all tokens in the * order PdfTokenizer should read them from pszBuffer */ void TestStream( const char* pszBuffer, const char* pszTokens[] ); /** Test parsing a stream. As above but this time using PdfTokenizer::IsNextToken() * * \param pszBuffer a string buffer that will be parsed * \param pszTokens a NULL terminated list of all tokens in the * order PdfTokenizer should read them from pszBuffer */ void TestStreamIsNextToken( const char* pszBuffer, const char* pszTokens[] ); }; #endif // _TOKENIZER_TEST_H_ podofo-0.9.5/test/unit/PageTest.cpp0000664000175000017500000000602511523003150017032 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2000 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "PageTest.h" #include "TestUtils.h" #include using namespace PoDoFo; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( PageTest ); void PageTest::setUp() { } void PageTest::tearDown() { } void PageTest::testEmptyContents() { PdfVecObjects vecObjects; PdfObject object( PdfReference( 1, 0 ), "Page" ); vecObjects.push_back( &object ); const std::deque parents; PdfPage page( &object, parents ); CPPUNIT_ASSERT( NULL != page.GetContents() ); } void PageTest::testEmptyContentsStream() { PdfMemDocument doc; PdfPage* pPage = doc.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); PdfAnnotation* pAnnot = pPage->CreateAnnotation( ePdfAnnotation_Popup, PdfRect( 300.0, 20.0, 250.0, 50.0 ) ); PdfString sTitle("Author: Dominik Seichter"); pAnnot->SetContents( sTitle ); pAnnot->SetOpen( true ); std::string sFilename = TestUtils::getTempFilename(); doc.Write( sFilename.c_str() ); // Read annotation again PdfMemDocument doc2( sFilename.c_str() ); CPPUNIT_ASSERT_EQUAL( 1, doc2.GetPageCount() ); PdfPage* pPage2 = doc2.GetPage( 0 ); CPPUNIT_ASSERT( NULL != pPage2 ); CPPUNIT_ASSERT_EQUAL( 1, pPage2->GetNumAnnots() ); PdfAnnotation* pAnnot2 = pPage2->GetAnnotation( 0 ); CPPUNIT_ASSERT( NULL != pAnnot2 ); CPPUNIT_ASSERT( sTitle == pAnnot2->GetContents() ); PdfObject* pPageObject = pPage2->GetObject(); CPPUNIT_ASSERT( !pPageObject->GetDictionary().HasKey("Contents") ); TestUtils::deleteFile( sFilename.c_str() ); } podofo-0.9.5/test/unit/DateTest.cpp0000664000175000017500000000612212347347566017064 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2012 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "DateTest.h" #include using namespace PoDoFo; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( DateTest ); void DateTest::setUp() { } void DateTest::tearDown() { } void checkExpected(const char *pszDate, bool bExpected) { PdfString tmp(pszDate); PdfDate date(tmp); CPPUNIT_ASSERT_EQUAL(bExpected,date.IsValid()); } void DateTest::testCreateDateFromString() { checkExpected(NULL,false); checkExpected("D:2012",true); checkExpected("D:20120",false); checkExpected("D:201201",true); checkExpected("D:2012010",false); checkExpected("D:20120101",true); checkExpected("D:201201012",false); checkExpected("D:2012010123",true); checkExpected("D:20120101235",false); checkExpected("D:201201012359",true); checkExpected("D:2012010123595",false); checkExpected("D:20120101235959",true); checkExpected("D:20120120135959Z",false); checkExpected("D:20120120135959Z0",false); checkExpected("D:20120120135959Z00",true); checkExpected("D:20120120135959Z00'",false); checkExpected("D:20120120135959Z00'0",false); checkExpected("D:20120120135959Z00'00",false); checkExpected("D:20120120135959Z00'00'",true); } void DateTest::testDateValue() { PdfDate date(PdfString("D:20120530235959Z00'00'")); CPPUNIT_ASSERT_EQUAL(true,date.IsValid()); const time_t &time = date.GetTime(); struct tm _tm; memset (&_tm, 0, sizeof(struct tm)); _tm.tm_year = 2012-1900; _tm.tm_mon = 4; _tm.tm_mday = 30; _tm.tm_hour = 23; _tm.tm_min = 59; _tm.tm_sec = 59; time_t time2 = mktime(&_tm); CPPUNIT_ASSERT_EQUAL(true,time==time2); } podofo-0.9.5/test/unit/NameTest.cpp0000664000175000017500000001634611455342347017067 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "NameTest.h" #include using namespace PoDoFo; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( NameTest ); void NameTest::setUp() { } void NameTest::tearDown() { } void NameTest::testParseAndWrite() { const char* pszData = "/#E5#8A#A8#E6#80#81#E8#BF#9E#E6#8E#A5#E7#BA#BF"; PdfTokenizer tokenizer(pszData, strlen(pszData)); const char* pszToken; EPdfTokenType eType; bool bGotToken = tokenizer.GetNextToken( pszToken, &eType ); CPPUNIT_ASSERT_EQUAL( bGotToken, true ); CPPUNIT_ASSERT_EQUAL( eType, ePdfTokenType_Delimiter ); bGotToken = tokenizer.GetNextToken( pszToken, &eType ); CPPUNIT_ASSERT_EQUAL( bGotToken, true ); CPPUNIT_ASSERT_EQUAL( eType, ePdfTokenType_Token ); // Test with const char* constructor PdfName name = PdfName::FromEscaped( pszToken ); PdfVariant var( name ); std::string str; var.ToString( str ); CPPUNIT_ASSERT_EQUAL( str == pszData, true ); // str.c_str() + 1 <- ignore leading slash CPPUNIT_ASSERT_EQUAL( name.GetEscapedName() == (str.c_str() + 1), true ); // Test with std::string constructor std::string sToken = pszToken; PdfName name2 = PdfName::FromEscaped( sToken ); PdfVariant var2( name ); std::string str2; var.ToString( str2 ); CPPUNIT_ASSERT_EQUAL( str2 == pszData, true ); // str.c_str() + 1 <- ignore leading slash CPPUNIT_ASSERT_EQUAL( name2.GetEscapedName() == (str2.c_str() + 1), true ); } void NameTest::testNameEncoding() { // Test some names. The first argument is the unencoded representation, the second // is the expected encoded result. The result must not only be /a/ correct encoded // name for the unencoded form, but must be the exact one PoDoFo should produce. TestName( "Length With Spaces", "Length#20With#20Spaces" ); TestName( "Length\001\002\003Spaces\177", "Length#01#02#03Spaces#7F" ); TestName( "Length#01#02#03Spaces#7F", "Length#2301#2302#2303Spaces#237F" ); TestName( "Tab\tTest", "Tab#09Test" ); } void NameTest::testEncodedNames() { // Test some pre-encoded names. The first argument is the encoded name that'll be // read from the PDF; the second is the expected representation. TestEncodedName( "PANTONE#205757#20CV", "PANTONE 5757 CV"); TestEncodedName( "paired#28#29parentheses", "paired()parentheses"); TestEncodedName( "The_Key_of_F#23_Minor", "The_Key_of_F#_Minor"); TestEncodedName( "A#42", "AB"); TestEncodedName( "ANPA#20723-0#20AdPro", "ANPA 723-0 AdPro" ); } void NameTest::testEquality() { // Make sure differently encoded names compare equal if their decoded values // are equal. TestNameEquality( "With Spaces", "With#20Spaces" ); TestNameEquality( "#57#69#74#68#20#53#70#61#63#65#73", "With#20Spaces" ); } void NameTest::testWrite() { // Make sure all names are written correctly to an output device! TestWrite( "Length With Spaces", "/Length#20With#20Spaces" ); TestWrite( "Length\001\002\003Spaces\177", "/Length#01#02#03Spaces#7F" ); TestWrite( "Tab\tTest", "/Tab#09Test" ); TestWrite( "ANPA 723-0 AdPro", "/ANPA#20723-0#20AdPro" ); } void NameTest::testFromEscaped() { TestFromEscape( "ANPA#20723-0#20AdPro", "ANPA 723-0 AdPro" ); TestFromEscape( "Length#20With#20Spaces", "Length With Spaces" ); } // // Test encoding of names. // pszString : internal representation, ie unencoded name // pszExpectedEncoded: the encoded string PoDoFo should produce // void NameTest::TestName( const char* pszString, const char* pszExpectedEncoded ) { printf("Testing name: %s\n", pszString ); PdfName name( pszString ); printf(" -> Expected Value: %s\n", pszExpectedEncoded ); printf(" -> Got Value: %s\n", name.GetEscapedName().c_str() ); printf(" -> Unescaped Value: %s\n", name.GetName().c_str() ); CPPUNIT_ASSERT_EQUAL( strcmp( pszExpectedEncoded, name.GetEscapedName().c_str() ), 0 ); // Ensure the encoded string compares equal to its unencoded // variant CPPUNIT_ASSERT_EQUAL( name == PdfName::FromEscaped(pszExpectedEncoded), true ); } void NameTest::TestEncodedName( const char* pszString, const char* pszExpected ) { PdfName name( PdfName::FromEscaped(pszString) ); printf("Testing encoded name: %s\n", pszString ); printf(" -> Expected Value: %s\n", pszExpected ); printf(" -> Got Value: %s\n", name.GetName().c_str() ); printf(" -> Escaped Value: %s\n", name.GetEscapedName().c_str() ); if ( strcmp( pszExpected, name.GetName().c_str() ) != 0 ) { PODOFO_RAISE_ERROR( ePdfError_TestFailed ); } // Ensure the name compares equal with one constructed from the // expected unescaped form CPPUNIT_ASSERT_EQUAL( name == PdfName(pszExpected), true ); } void NameTest::TestNameEquality( const char * pszName1, const char* pszName2 ) { PdfName name1( PdfName::FromEscaped(pszName1) ); PdfName name2( PdfName::FromEscaped(pszName2) ); printf("Testing equality of encoded names '%s' and '%s'\n", pszName1, pszName2); printf(" -> Name1 Decoded Value: %s\n", name1.GetName().c_str()); printf(" -> Name2 Decoded Value: %s\n", name2.GetName().c_str()); CPPUNIT_ASSERT_EQUAL( name1 == name2, true ); // use operator== CPPUNIT_ASSERT_EQUAL( name1 != name2, false ); // use operator!= } void NameTest::TestWrite( const char * pszName, const char* pszResult ) { std::ostringstream oss; PdfName name( pszName ); PdfOutputDevice device( &oss ); name.Write( &device, ePdfWriteMode_Default ); CPPUNIT_ASSERT_EQUAL( oss.str() == pszResult, true ); } void NameTest::TestFromEscape( const char* pszName1, const char* pszName2 ) { PdfName name = PdfName::FromEscaped( pszName1, strlen( pszName1 ) ); CPPUNIT_ASSERT_EQUAL( name.GetName() == pszName2, true ); } podofo-0.9.5/test/unit/cppunitextensions.h0000664000175000017500000001407212347312510020576 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( ColorTest ); /** Added by RG to check if a suitable error message is returned * Asserts that the given expression throws an exception of the specified type. * \ingroup Assertions * Example of usage: * \code * std::vector v; * CPPUNIT_ASSERT_THROW( v.at( 50 ), std::out_of_range ); * \endcode */ # define CPPUNIT_ASSERT_THROW_WITH_ERROR_TYPE( expression, ExceptionType, errorType ) \ CPPUNIT_ASSERT_THROW_MESSAGE_WITH_ERROR_TYPE( CPPUNIT_NS::AdditionalMessage(), \ expression, \ ExceptionType, \ errorType) /** Added by RG to check if a suitable error message is returned * Asserts that the given expression throws an exception of the specified type, * setting a user supplied message in case of failure. * \ingroup Assertions * Example of usage: * \code * std::vector v; * CPPUNIT_ASSERT_THROW_MESSAGE( "- std::vector v;", v.at( 50 ), std::out_of_range ); * \endcode */ # define CPPUNIT_ASSERT_THROW_MESSAGE_WITH_ERROR_TYPE( message, expression, ExceptionType, errorType ) \ do { \ bool cpputCorrectExceptionThrown_ = false; \ CPPUNIT_NS::Message cpputMsg_( "expected exception not thrown" ); \ cpputMsg_.addDetail( message ); \ cpputMsg_.addDetail( "Expected: " \ CPPUNIT_GET_PARAMETER_STRING( ExceptionType ) ); \ \ try { \ expression; \ } catch ( const ExceptionType &e) { \ if (e.GetError() == errorType) \ { \ cpputCorrectExceptionThrown_ = true; \ } \ else \ { \ cpputMsg_.addDetail( "Error type mismatch. Actual: " #errorType ); \ cpputMsg_.addDetail( std::string("What() : ") + e.ErrorName(e.GetError()) ); \ } \ } catch ( const std::exception &e) { \ cpputMsg_.addDetail( "Actual : " + \ CPPUNIT_EXTRACT_EXCEPTION_TYPE_( e, \ "std::exception or derived") ); \ cpputMsg_.addDetail( std::string("What() : ") + e.what() ); \ } catch ( ... ) { \ cpputMsg_.addDetail( "Actual : unknown."); \ } \ \ if ( cpputCorrectExceptionThrown_ ) \ break; \ \ CPPUNIT_NS::Asserter::fail( cpputMsg_, \ CPPUNIT_SOURCELINE() ); \ } while ( false ) //GoogleTest compatible macros #define ASSERT_TRUE(x) CPPUNIT_ASSERT(x) #define ASSERT_FALSE(x) CPPUNIT_ASSERT(!(x)) #define EXPECT_TRUE(x) CPPUNIT_ASSERT(x) #define EXPECT_FALSE(x) CPPUNIT_ASSERT(!(x)) #define EXPECT_EQ(expected, actual) CPPUNIT_ASSERT_EQUAL(expected, actual) #define ASSERT_EQ(expected, actual) CPPUNIT_ASSERT_EQUAL(expected, actual) #define EXPECT_NE(expected, actual) CPPUNIT_ASSERT(expected != actual) #define ASSERT_NE(expected, actual) CPPUNIT_ASSERT(expected != actual) #define EXPECT_DOUBLE_EQ(expected, actual, delta) CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta) #define ASSERT_DOUBLE_EQ(expected, actual, delta) CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, delta) podofo-0.9.5/test/unit/PagesTreeTest.cpp0000664000175000017500000002570712715161264020064 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "PagesTreeTest.h" #include #define PODOFO_TEST_PAGE_KEY "PoDoFoTestPageNumber" #define PODOFO_TEST_NUM_PAGES 100 using namespace PoDoFo; // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( PagesTreeTest ); void PagesTreeTest::setUp() { } void PagesTreeTest::tearDown() { } void PagesTreeTest::testEmptyTree() { PdfMemDocument writer; // Empty document must have page count == 0 CPPUNIT_ASSERT_EQUAL( writer.GetPageCount(), 0 ); // Retrieving any page from an empty document must be NULL PdfPage* pPage = writer.GetPagesTree()->GetPage( 0 ); CPPUNIT_ASSERT_EQUAL( pPage, static_cast(NULL) ); pPage = writer.GetPagesTree()->GetPage( -1 ); CPPUNIT_ASSERT_EQUAL( pPage, static_cast(NULL) ); pPage = writer.GetPagesTree()->GetPage( 1 ); CPPUNIT_ASSERT_EQUAL( pPage, static_cast(NULL) ); } void PagesTreeTest::testEmptyDoc() { // PdfPagesTree does not throw exceptions but PdfDocument does PdfMemDocument writer; // Empty document must have page count == 0 CPPUNIT_ASSERT_EQUAL( writer.GetPageCount(), 0 ); // Retrieving any page from an empty document must be NULL CPPUNIT_ASSERT_THROW( writer.GetPage( 0 ), PdfError ); CPPUNIT_ASSERT_THROW( writer.GetPage( -1 ), PdfError ); CPPUNIT_ASSERT_THROW( writer.GetPage( 1 ), PdfError ); } void PagesTreeTest::testCreateDelete() { PdfMemDocument writer; PdfPage* pPage; PdfPainter painter; PdfFont * pFont; // create font pFont = writer.CreateFont( "Arial" ); if( !pFont ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } pFont->SetFontSize( 16.0 ); // write 1. page pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); painter.SetPage( pPage ); painter.SetFont( pFont ); painter.DrawText( 200, 200, "Page 1" ); painter.FinishPage(); CPPUNIT_ASSERT_EQUAL( writer.GetPageCount(), 1 ); // write 2. page pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); painter.SetPage( pPage ); painter.DrawText( 200, 200, "Page 2" ); painter.FinishPage(); CPPUNIT_ASSERT_EQUAL( writer.GetPageCount(), 2 ); // try to delete second page, index is 0 based writer.DeletePages( 1, 1 ); CPPUNIT_ASSERT_EQUAL( writer.GetPageCount(), 1 ); // write 3. page pPage = writer.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); painter.SetPage( pPage ); painter.DrawText( 200, 200, "Page 3" ); painter.FinishPage(); CPPUNIT_ASSERT_EQUAL( writer.GetPageCount(), 2 ); } void PagesTreeTest::testGetPagesCustom() { PdfMemDocument doc; CreateTestTreeCustom( doc ); testGetPages( doc ); } void PagesTreeTest::testGetPagesPoDoFo() { PdfMemDocument doc; CreateTestTreePoDoFo( doc ); testGetPages( doc ); } void PagesTreeTest::testGetPages( PdfMemDocument & doc ) { for(int i=0; iDeletePage( 0 ); for(int i=0; iDeletePage( DELETED_PAGE ); for(int i=0; i=0; i--) { PdfPage* pPage = doc.GetPage( i ); CPPUNIT_ASSERT_EQUAL( pPage != NULL, true ); CPPUNIT_ASSERT_EQUAL( IsPageNumber( pPage, i ), true ); } // Now delete first page doc.GetPagesTree()->DeletePage( 0 ); for(int i=PODOFO_TEST_NUM_PAGES-2; i>=0; i--) { PdfPage* pPage = doc.GetPage( i ); CPPUNIT_ASSERT_EQUAL( pPage != NULL, true ); CPPUNIT_ASSERT_EQUAL( IsPageNumber( pPage, i + 1 ), true ); } } void PagesTreeTest::testInsertCustom() { PdfMemDocument doc; CreateTestTreeCustom( doc ); testInsert( doc ); } void PagesTreeTest::testInsertPoDoFo() { PdfMemDocument doc; CreateTestTreePoDoFo( doc ); testInsert( doc ); } void PagesTreeTest::testInsert( PdfMemDocument & doc ) { const int INSERTED_PAGE_FLAG= 1234; const int INSERTED_PAGE_FLAG1= 1234 + 1; const int INSERTED_PAGE_FLAG2= 1234 + 2; PdfPage* pPage = new PdfPage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ), &(doc.GetObjects()) ); pPage->GetObject()->GetDictionary().AddKey( PODOFO_TEST_PAGE_KEY, static_cast(INSERTED_PAGE_FLAG) ); // Insert page at the beginning doc.GetPagesTree()->InsertPage( ePdfPageInsertionPoint_InsertBeforeFirstPage, pPage ); delete pPage; // Find inserted page (beginning) pPage = doc.GetPage( 0 ); CPPUNIT_ASSERT_EQUAL( IsPageNumber( pPage, INSERTED_PAGE_FLAG ), true ); // Find old first page pPage = doc.GetPage( 1 ); CPPUNIT_ASSERT_EQUAL( IsPageNumber( pPage, 0 ), true ); // Insert at end pPage = doc.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); pPage->GetObject()->GetDictionary().AddKey( PODOFO_TEST_PAGE_KEY, static_cast(INSERTED_PAGE_FLAG1) ); pPage = doc.GetPage( doc.GetPageCount() - 1 ); CPPUNIT_ASSERT_EQUAL( IsPageNumber( pPage, INSERTED_PAGE_FLAG1 ), true ); // Insert in middle pPage = new PdfPage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ), &(doc.GetObjects()) ); pPage->GetObject()->GetDictionary().AddKey( PODOFO_TEST_PAGE_KEY, static_cast(INSERTED_PAGE_FLAG2) ); const int INSERT_POINT = 50; doc.GetPagesTree()->InsertPage( INSERT_POINT, pPage ); delete pPage; pPage = doc.GetPage( INSERT_POINT + 1 ); CPPUNIT_ASSERT_EQUAL( IsPageNumber( pPage, INSERTED_PAGE_FLAG2 ), true ); } void PagesTreeTest::testDeleteAllCustom() { PdfMemDocument doc; CreateTestTreeCustom( doc ); testDeleteAll( doc ); } void PagesTreeTest::testDeleteAllPoDoFo() { PdfMemDocument doc; CreateTestTreePoDoFo( doc ); testDeleteAll( doc ); } void PagesTreeTest::testDeleteAll( PdfMemDocument & doc ) { for(int i=0; iDeletePage(0); CPPUNIT_ASSERT_EQUAL( doc.GetPageCount(), PODOFO_TEST_NUM_PAGES - (i + 1) ); } CPPUNIT_ASSERT_EQUAL( doc.GetPageCount(), 0 ); } void PagesTreeTest::CreateTestTreePoDoFo( PoDoFo::PdfMemDocument & rDoc ) { for(int i=0; iGetObject()->GetDictionary().AddKey( PODOFO_TEST_PAGE_KEY, static_cast(i) ); CPPUNIT_ASSERT_EQUAL( rDoc.GetPageCount(), i + 1 ); } } void PagesTreeTest::CreateTestTreeCustom( PoDoFo::PdfMemDocument & rDoc ) { const int COUNT = PODOFO_TEST_NUM_PAGES / 10; PdfObject* pRoot = rDoc.GetPagesTree()->GetObject(); PdfArray rootKids; for(int z=0; zGetObject()->GetDictionary().AddKey( PODOFO_TEST_PAGE_KEY, static_cast(z * COUNT + i) ); //printf("Creating page %i z=%i i=%i\n", z * COUNT + i, z, i ); nodeKids.push_back( pPage->GetObject()->Reference() ); } pNode->GetDictionary().AddKey( PdfName("Kids"), nodeKids ); pNode->GetDictionary().AddKey( PdfName("Count"), static_cast(COUNT) ); rootKids.push_back( pNode->Reference() ); } pRoot->GetDictionary().AddKey( PdfName("Kids"), rootKids ); pRoot->GetDictionary().AddKey( PdfName("Count"), static_cast(PODOFO_TEST_NUM_PAGES) ); } bool PagesTreeTest::IsPageNumber( PoDoFo::PdfPage* pPage, int nNumber ) { pdf_int64 lPageNumber = pPage->GetObject()->GetDictionary().GetKeyAsLong( PODOFO_TEST_PAGE_KEY, -1 ); if( lPageNumber != static_cast(nNumber) ) { printf("PagesTreeTest: Expected page number %i but got %" PDF_FORMAT_INT64 ".\n", nNumber, lPageNumber); return false; } else return true; } podofo-0.9.5/test/unit/main.cpp0000664000175000017500000000752711232616441016264 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #include void show_help() { std::cout << "podofo-test" << std::endl << std::endl; std::cout << "Supported commandline switches:" << std::endl; std::cout << "\t --help\t So this help message." << std::endl; std::cout << "\t --selftest\t Output in compiler compatible format." << std::endl; std::cout << "\t --test [name]\t Run only the test case [name]." << std::endl; std::cout << std::endl; } int main(int argc, char* argv[]) { // Get the top level suite from the registry CppUnit::Test *suite = CppUnit::TestFactoryRegistry::getRegistry().makeTest(); // Adds the test to the list of test to run CppUnit::TextUi::TestRunner runner; runner.addTest( suite ); // check some commandline arguments std::string sTestName = ""; bool bSelfTest = false; if( argc > 1 ) { for(int i=1;i #include using namespace PoDoFo; inline std::ostream& operator<<(std::ostream& o, const PdfVariant& s) { std::string str; s.ToString(str); return o << str; } // Needs to be included after the redifition of operator<< // or it won't compile using clang #include "EncodingTest.h" // Registers the fixture into the 'registry' CPPUNIT_TEST_SUITE_REGISTRATION( EncodingTest ); void EncodingTest::setUp() { } void EncodingTest::tearDown() { } void EncodingTest::testDifferences() { PdfEncodingDifference difference; // Newly created encoding should be empty CPPUNIT_ASSERT_EQUAL( static_cast(difference.GetCount()), 0 ); // Adding 0 should work difference.AddDifference( 0, 0, PdfName("A") ); CPPUNIT_ASSERT_EQUAL( static_cast(difference.GetCount()), 1 ); // Adding 255 should work difference.AddDifference( 255, 0, PdfName("B") ); CPPUNIT_ASSERT_EQUAL( static_cast(difference.GetCount()), 2 ); // Adding out of range should throw exception CPPUNIT_ASSERT_THROW( difference.AddDifference( -1, 0, PdfName("C") );, PdfError ); CPPUNIT_ASSERT_THROW( difference.AddDifference( 256, 0, PdfName("D") );, PdfError ); CPPUNIT_ASSERT_EQUAL( static_cast(difference.GetCount()), 2 ); // Convert to array PdfArray data; PdfArray expected; expected.push_back( static_cast(0LL) ); expected.push_back( PdfName("A") ); expected.push_back( static_cast(255LL) ); expected.push_back( PdfName("B") ); difference.ToArray( data ); CPPUNIT_ASSERT_EQUAL( data.GetSize(), expected.GetSize() ); for( unsigned int i=0;i(0LL) ); expected.push_back( PdfName("A") ); expected.push_back( static_cast(255LL) ); expected.push_back( PdfName("X") ); difference.AddDifference( 255, 0, PdfName("X") ); difference.ToArray( data ); CPPUNIT_ASSERT_EQUAL( data.GetSize(), expected.GetSize() ); for( unsigned int i=0;i(0LL) ); expected.push_back( PdfName("A") ); expected.push_back( PdfName("B") ); expected.push_back( PdfName("C") ); expected.push_back( static_cast(4LL) ); expected.push_back( PdfName("D") ); expected.push_back( PdfName("E") ); expected.push_back( static_cast(9LL) ); expected.push_back( PdfName("F") ); expected.push_back( static_cast(255LL) ); expected.push_back( PdfName("X") ); difference.AddDifference( 1, 0, PdfName("B") ); difference.AddDifference( 2, 0, PdfName("C") ); difference.AddDifference( 4, 0, PdfName("D") ); difference.AddDifference( 5, 0, PdfName("E") ); difference.AddDifference( 9, 0, PdfName("F") ); difference.ToArray( data ); CPPUNIT_ASSERT_EQUAL( data.GetSize(), expected.GetSize() ); for( unsigned int i=0;i(value), 0x4100 ); #else CPPUNIT_ASSERT_EQUAL( static_cast(value), 0x0041 ); #endif //PODOFO_IS_LITTLE_ENDIAN CPPUNIT_ASSERT_EQUAL( difference.Contains( 9, name, value ), true ); CPPUNIT_ASSERT_EQUAL( name, PdfName("F") ); #ifdef PODOFO_IS_LITTLE_ENDIAN CPPUNIT_ASSERT_EQUAL( static_cast(value), 0x4600 ); #else CPPUNIT_ASSERT_EQUAL( static_cast(value), 0x0046 ); #endif //PODOFO_IS_LITTLE_ENDIAN CPPUNIT_ASSERT_EQUAL( difference.Contains( 255, name, value ), true ); CPPUNIT_ASSERT_EQUAL( name, PdfName("X") ); #ifdef PODOFO_IS_LITTLE_ENDIAN CPPUNIT_ASSERT_EQUAL( static_cast(value), 0x5800 ); #else CPPUNIT_ASSERT_EQUAL( static_cast(value), 0x0058 ); #endif //PODOFO_IS_LITTLE_ENDIAN CPPUNIT_ASSERT_EQUAL( difference.Contains( 100, name,value ), false ); } void EncodingTest::testDifferencesObject() { PdfMemDocument doc; PdfEncodingDifference difference; difference.AddDifference( 1, 0, PdfName("B") ); difference.AddDifference( 2, 0, PdfName("C") ); difference.AddDifference( 4, 0, PdfName("D") ); difference.AddDifference( 5, 0, PdfName("E") ); difference.AddDifference( 9, 0, PdfName("F") ); PdfDifferenceEncoding encoding( difference, PdfDifferenceEncoding::eBaseEncoding_MacRoman, &doc ); // Check for encoding key PdfObject* pObj = doc.GetObjects().CreateObject(); encoding.AddToDictionary( pObj->GetDictionary() ); CPPUNIT_ASSERT_EQUAL( true, pObj->GetDictionary().HasKey( PdfName("Encoding") ) ); PdfObject* pKey = pObj->GetDictionary().GetKey( PdfName("Encoding") ); CPPUNIT_ASSERT_EQUAL( true, pKey->IsReference() ); PdfObject* pEncoding = doc.GetObjects().GetObject( pKey->GetReference() ); // Test BaseEncoding PdfObject* pBase = pEncoding->GetDictionary().GetKey( PdfName("BaseEncoding" ) ); CPPUNIT_ASSERT_EQUAL( pBase->GetName(), PdfName("MacRomanEncoding") ); // Test differences PdfObject* pDiff = pEncoding->GetDictionary().GetKey( PdfName("Differences" ) ); PdfArray expected; expected.push_back( static_cast(1LL) ); expected.push_back( PdfName("B") ); expected.push_back( PdfName("C") ); expected.push_back( static_cast(4LL) ); expected.push_back( PdfName("D") ); expected.push_back( PdfName("E") ); expected.push_back( static_cast(9LL) ); expected.push_back( PdfName("F") ); const PdfArray & data = pDiff->GetArray(); CPPUNIT_ASSERT_EQUAL( data.GetSize(), expected.GetSize() ); for( unsigned int i=0;i(5), encodingStr.GetSize() ); PdfString str(reinterpret_cast(encodingStr.GetBuffer()), encodingStr.GetSize()); CPPUNIT_ASSERT_EQUAL( memcmp("BAABC", encodingStr.GetBuffer(), encodingStr.GetSize()), 0 ); } void EncodingTest::testUnicodeNames() { // List of items which are defined twice and cause // other ids to be returned than those which where send in const char* pszDuplicated[] = { "Delta", "fraction", "hyphen", "macron", "mu", "Omega", "periodcentered", "scedilla", "Scedilla", "space", "tcommaaccent", "Tcommaaccent", "exclamsmall", "dollaroldstyle", "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "ampersandsmall", "questionsmall", NULL }; int nCount = 0; for( int i = 0;i<=0xFFFF; i++ ) { PdfName name = PdfDifferenceEncoding::UnicodeIDToName( static_cast(i) ); pdf_utf16be id = PdfDifferenceEncoding::NameToUnicodeID( name ); bool bFound = false; const char** pszDup = pszDuplicated; while( *pszDup ) { if( PdfName( *pszDup ) == name ) { bFound = true; break; } ++pszDup; } if( !bFound ) { // Does not work because of 2 many duplicates... //CPPUNIT_ASSERT_EQUAL_MESSAGE( name.GetName(), id, static_cast(i) ); if( id == static_cast(i) ) ++nCount; } } CPPUNIT_ASSERT_EQUAL_MESSAGE( "Compared codes count", 65422, nCount ); } void EncodingTest::testGetCharCode() { std::string msg; bool ret; PdfWinAnsiEncoding cWinAnsiEncoding; ret = outofRangeHelper( &cWinAnsiEncoding, msg, "PdfWinAnsiEncoding" ); CPPUNIT_ASSERT_EQUAL_MESSAGE( msg, ret, true ); PdfMacRomanEncoding cMacRomanEncoding; ret = outofRangeHelper( &cMacRomanEncoding, msg, "PdfMacRomanEncoding" ); CPPUNIT_ASSERT_EQUAL_MESSAGE( msg, ret, true ); PdfIdentityEncoding cIdentityEncoding; ret = outofRangeHelper( &cIdentityEncoding, msg, "PdfIdentityEncoding" ); CPPUNIT_ASSERT_EQUAL_MESSAGE( msg, ret, true ); PdfVecObjects vec; vec.SetAutoDelete( true ); PdfEncodingDifference difference; difference.AddDifference( 0x0041, 0, PdfName("B") ); difference.AddDifference( 0x0042, 0, PdfName("A") ); PdfDifferenceEncoding cDifferenceEncoding( difference, PdfDifferenceEncoding::eBaseEncoding_WinAnsi, &vec ); ret = outofRangeHelper( &cDifferenceEncoding, msg, "PdfDifferenceEncoding" ); CPPUNIT_ASSERT_EQUAL_MESSAGE( msg, ret, true ); #ifdef PODOFO_IS_LITTLE_ENDIAN CPPUNIT_ASSERT_EQUAL( static_cast(0x4200), cDifferenceEncoding.GetCharCode( 0x0041 ) ); CPPUNIT_ASSERT_EQUAL( static_cast(0x4100), cDifferenceEncoding.GetCharCode( 0x0042 ) ); #else CPPUNIT_ASSERT_EQUAL( static_cast(0x0042), cDifferenceEncoding.GetCharCode( 0x0041 ) ); CPPUNIT_ASSERT_EQUAL( static_cast(0x0041), cDifferenceEncoding.GetCharCode( 0x0042 ) ); #endif // PODOFO_IS_LITTLE_ENDIAN } void EncodingTest::testToUnicodeParse() { const char *toUnicode = "3 beginbfrange\n" "<0001> <0004> <1001>\n" "<0005> <000A> [<000A> <0009> <0008> <0007> <0006> <0005>]\n" "<000B> <000F> <100B>\n" "endbfrange\n"; const pdf_utf16be *encodedStr = reinterpret_cast< const pdf_utf16be *>( "\x0\x1\x0\x2\x0\x3\x0\x4\x0\x5\x0\x6\x0\x7\x0\x8\x0\x9\x0\xA\x0\xB\x0\xC\x0\xD\x0\xE\x0\xF\x0\x0" ); const pdf_utf16be expected[] = { 0x1001, 0x1002, 0x1003, 0x1004, 0x000A, 0x0009, 0x0008, 0x0007, 0x0006, 0x0005, 0x100B, 0x100C, 0x100D, 0x100E, 0x100F, 0 }; PdfVecObjects vec; PdfObject *strmObject; vec.SetAutoDelete( true ); strmObject = vec.CreateObject( PdfVariant( PdfDictionary() ) ); strmObject->GetStream()->Set( toUnicode, strlen( toUnicode ) ); PdfIdentityEncoding encoding(0x0001, 0x000F, true, strmObject); PdfString unicodeString = encoding.ConvertToUnicode( PdfString( encodedStr ), NULL ); const pdf_utf16be *unicodeStr = reinterpret_cast( unicodeString.GetString() ); int ii; for( ii = 0; expected[ii]; ii++ ) { pdf_utf16be expects = expected[ii]; #ifdef PODOFO_IS_LITTLE_ENDIAN expects = (expects << 8) | (expects >> 8 ); #endif CPPUNIT_ASSERT_EQUAL( expects, unicodeStr[ii] ); } } bool EncodingTest::outofRangeHelper( PdfEncoding* pEncoding, std::string & rMsg, const char* pszName ) { bool exception = false; try { pEncoding->GetCharCode( pEncoding->GetFirstChar() ); } catch( PdfError & rError ) { // This may not throw! rMsg = "pEncoding->GetCharCode( pEncoding->GetFirstChar() ) failed"; return false; } try { pEncoding->GetCharCode( pEncoding->GetFirstChar() - 1 ); } catch( PdfError & rError ) { // This has to throw! exception = true; } if( !exception ) { rMsg = "pEncoding->GetCharCode( pEncoding->GetFirstChar() - 1 ); failed"; return false; } try { pEncoding->GetCharCode( pEncoding->GetLastChar() ); } catch( PdfError & rError ) { // This may not throw! rMsg = "pEncoding->GetCharCode( pEncoding->GetLastChar() ); failed"; return false; } exception = false; try { pEncoding->GetCharCode( pEncoding->GetLastChar() + 1 ); } catch( PdfError & rError ) { // This has to throw! exception = true; } if( !exception ) { rMsg = "pEncoding->GetCharCode( pEncoding->GetLastChar() + 1 ); failed"; return false; } PdfEncoding::const_iterator it = pEncoding->begin(); int nCount = pEncoding->GetFirstChar(); while( it != pEncoding->end() ) { CPPUNIT_ASSERT_EQUAL_MESSAGE( pszName, *it, pEncoding->GetCharCode( nCount ) ); ++nCount; ++it; } return true; } podofo-0.9.5/test/unit/FontTest.h0000664000175000017500000000466711326377431016564 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2009 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _FONT_TEST_H_ #define _FONT_TEST_H_ #include #include #if defined(PODOFO_HAVE_FONTCONFIG) #include #endif /** This test tests the various PdfFont classes */ class FontTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( FontTest ); #if defined(PODOFO_HAVE_FONTCONFIG) CPPUNIT_TEST( testFonts ); CPPUNIT_TEST( testCreateFontFtFace ); #endif CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown(); #if defined(PODOFO_HAVE_FONTCONFIG) void testFonts(); void testCreateFontFtFace(); #endif private: #if defined(PODOFO_HAVE_FONTCONFIG) void testSingleFont(FcPattern* pFont, FcConfig* pConfig); bool GetFontInfo( FcPattern* pFont, std::string & rsFamily, std::string & rsPath, bool & rbBold, bool & rbItalic ); #endif private: PoDoFo::PdfMemDocument* m_pDoc; PoDoFo::PdfVecObjects* m_pVecObjects; PoDoFo::PdfFontCache* m_pFontCache; }; #endif // _FONT_TEST_H_ podofo-0.9.5/test/unit/PageTest.h0000664000175000017500000000366011403002240016475 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2009 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _PAGE_TEST_H_ #define _PAGE_TEST_H_ #include namespace PoDoFo { class PdfPage; }; /** This test tests the class PdfPagesTree */ class PageTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( PageTest ); CPPUNIT_TEST( testEmptyContents ); CPPUNIT_TEST( testEmptyContentsStream ); CPPUNIT_TEST_SUITE_END(); public: void setUp(); void tearDown(); void testEmptyContents(); void testEmptyContentsStream(); }; #endif // _PAGE_TEST_H_ podofo-0.9.5/test/pdfs/0000775000175000017500000000000013044451150014573 5ustar dominikdominikpodofo-0.9.5/test/pdfs/inline-image.pdf0000664000175000017500000001120711231233340017620 0ustar dominikdominik%PDF-1.4 %Çì¢ 5 0 obj <> stream xœ]T 4|wËe”ŠK&—Ä2k³¹”KCy1 •”¨¹4›Ûæš¼hJ$ÄëÑ+…‘F¹öF%c³)¯ëGÍ06Þ½Ä0ßê¼ß÷óçœç÷ûÿï9Ï9ÏsžÐÔ4ýÿ &vGƒˆ€‡áÇáp8€@Íþ'ñÿH ÓÿÈŸæÿ“ÿ5_†"€0¨©ÉñŸmàpˆˆA 03 ‘ÍìˆZŸr€‘`¤ëEgø‚ÈŸyàSh$Ðv;â`{ô‰`4!À‹‰ #!f¢¢0|TH(ñg…ˆ‡DÔÚàdŒ-Áø«uͬO°ûËl:Ø`+¥® Íë2Ó’ÈnЦæb‰ñ,jüæÚ;V.cƒlw4@ɰýèU45¿pŸƒs½¤UµÏœž–Xy`‡Í™ùÝ]K)¼§hIõ.6w”Úì:àÙôtG¸½©Ú ™ŽÙiv¿¬ãæö"‹ŒèŸçØË¢+8‡­1š£Õ_G%|¾¿ׂ)R;XÔT_³Þ½Ô~oì=0Çq‘–¶¾rHèTE´=›øuh‚<2XžRûøQ>ÖónØV]»bhß• ¡DNÁ8‡}^Ø„áM3Ú×´&Óµ‹waA ×êíI©É£Ä1áöÎNV*À¯Ç9Ëx›Ïæ•a‰k_=R¡¤=ÇYg§t:,ƵZ°TXͳ—]Ž|õØÐ ®çÑvIïLz{IÝ^z³ë¡úüEÏæ¿$î¿jD•öv–×=®¹P\àžë1Z¸Åâ4÷§ *Ú^kn%L”Þ2RoçÛü*ØJ¶dúûíݧ²ŸF~tVRánjVÙäGų,PÕ¢ó]ŠŒ_8»*Xr¦•ôvvvwÓà”ŠhæÌN¶U”Д"¸û\ÙVßáWÇS}ÆRN»=: ¤ç¡Ñ>9ŸÿZþôg¼óù’ÓéÖ9Á¦Q53µ³Moæ£aSíŽÅJ:ÀÃ=GP>çÎ’)D®êNÏC*õYÉòñýÞƒ kïò<žÌ™A]ÒäéLã0ÔÆ Ÿ­è¾d@£ij­ê+©Ô›~ÿ×'ø´Oººú:ßЖ”–¶“|î¡,ÞQ¨º—±ŒÝä’6-Žw*ó5Aq{}Vù.¾Ń×àŽ8Ô™ %[wê1}Û¢ç\ù”jñW£ ΂¬GæñáüÌŽ!%kÆà°±¼<ÎäE[I{ì*ÌË¢F£Iã&“ƒí©bÁ/Í £AUç®Uᦧñœ à‘ =q<ŒN\¹üDµsv–tÚ+®ax‰YÒqsÆf¯B!æþîȾ_øî¸äºØSÁÉKßžMä"r½o%´8<Öþœ²}¾L©®… y)¥ ÐâxKH¿:aQN¡¥jˆÍ`™€Cî«·ŠK޶æ=ˆáÙ´¹Ö\iÐÔ×kÌã>¨P•bú¼¾¼QÌwúL• n¾¥&誶æÿ©~ùõÍmÐÝ@|Ý1®$ÊÐòËéœÛ–S ¯îMrP2µx¡Dö¤5ÊØÂÒ1‰‰‡†m°‚<°oÇ@O‘lç{í™]I÷AÜmT ÞŒ7ˆ7èv4Œ“ï„ꜧ¢v}èGQ;­?%úÍV¶éÚÝ–‘—‡Žd*jÛlƒ« Íeb@PúØ#®Ós¬¤FSâ¦ñŠeÓ«jú™Ëž)ûF¶6C Òzx­Xa—Z,ï gž²ÚÔ;˵5²\/ëCB¤oÒñRÀXnÎ2¤r-¢vø1eU\´Zö¾é ð—¦‹”“© =š6÷ RS§E¹RPg2ý£“£zooï²€¡q§¢ ìxÕ/i—Åà?ö׋ð*ÍÍ.²9‡x·3­;òX½a¿Bq MpÜÝåÍcatÆÎ! ÀÄZ1n>KÞóYÌòoj–¶BÜ—jØßîZ<‚k!ò´Ï8¼@Vêw¬Ø_Ñ™÷¶œ’ '|­Z0né´ã:‡µ}i~3$&¥Ü¥)žŽ¢jÄp·äû¯­ñK ío”®Äùî†Èãt6ðÚ]uÊè}êûæ”o²K4“äƒ[Í:w®®\ê}“Ö7û}ä’߸§ÅIdØú_?ÿó+Ht!¡¡²N0]7MÙŒo¼Ø:Rªæ™¹+ñ>l‡“%+ÇhÅ9ÄŠL­(•k!ØÉEhcg½â vÒVP MslhÌ,¯ÿü6ÔÔ¨R[˜;œ™< 96êBˆ«4öÔ2ooÔâfjŸÖµïÁ——Au€ƒSP£#ÇšüW»—èOû¼ÇI Ôi¯š’×oU4P¬Ê~»-?(ÁŒÎçF±Z—F®©¼§\M¾ùrâàdq`ú›Ë ùÊÅ z°O¢Ž'ázM—~Õ|h`ð#üDÕÓ—Ï¡ª qZ'“ªîfÇ!¿è¡g­çG±þ­:,/1£L³g'àYÀø7MOF~endstream endobj 6 0 obj 2280 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 /Rotate 0>> endobj 1 0 obj <> endobj 7 0 obj <>endobj 8 0 obj <> endobj 9 0 obj <>stream Adobe InDesign CS4 \(6.0.3\) Untitled-1tranngocthachs endstream endobj 2 0 obj <>endobj xref 0 10 0000000000 65535 f 0000002601 00000 n 0000004185 00000 n 0000002533 00000 n 0000002385 00000 n 0000000015 00000 n 0000002365 00000 n 0000002665 00000 n 0000002706 00000 n 0000002735 00000 n trailer << /Size 10 /Root 1 0 R /Info 2 0 R /ID [<78550EE016C4CCDE53835B0AED8D62D1><78550EE016C4CCDE53835B0AED8D62D1>] >> startxref 4390 %%EOF podofo-0.9.5/test/pdfs/inline-image.txt0000664000175000017500000000123411231233340017665 0ustar dominikdominikThis PDF contains an inline image, defined according to the PDF Spec (4.8.6 Inline Images). test/ContentParser/ContentParser -p test/pdfs/inline-image.pdf should parse it fine, with output including: 37 Keyword: BI 38 Variant: /CS 39 Variant: /CMYK 40 Variant: /W 41 Variant: 43 42 Variant: /H 43 Variant: 66 44 Variant: /BPC 45 Variant: 8 46 Variant: /F 47 Variant: /Fl 48 Variant: /DP 49 Variant: << /Colors 4 /Columns 43 /Predictor 15 >> 50 Keyword: ID Inline image data: 560 bytes 51 Keyword: EI podofo-0.9.5/test/pdfs/README.txt0000664000175000017500000000042411231233340016264 0ustar dominikdominikThis directory stores SMALL sample PDFs for use with unit tests and with PoDoFo's general test programs. PDFs used in examples may also go here. Any PDF added here must be freely redistributable under the same license as PoDoFo its self (See README.html in the source root). podofo-0.9.5/test/PdfTest.h0000664000175000017500000000100711460071654015366 0ustar dominikdominik #include /* Common defines needed in all tests */ #define TEST_SAFE_OP( x ) try { x; } catch( PdfError & e ) { \ e.AddToCallstack( __FILE__, __LINE__, NULL ); \ e.PrintErrorMsg();\ return e.GetError();\ } #define TEST_SAFE_OP_IGNORE( x ) try { x; } catch( PdfError & e ) { \ e.AddToCallstack( __FILE__, __LINE__, NULL ); \ e.PrintErrorMsg();\ } podofo-0.9.5/CMakeLists.txt0000664000175000017500000005210013044450667015432 0ustar dominikdominikCMAKE_MINIMUM_REQUIRED(VERSION 2.6) #***************** IMPORTANT ************* IMPORTANT ********************** # Look at http://www.vtk.org/Wiki/CMake_HowToDoPlatformChecks # and the other wiki entries before you add anything. You might not need to. #**************************************************************************** # # Project name and version # PROJECT(PoDoFo) SET(PODOFO_VERSION_MAJOR "0" CACHE STRING "Major part of PoDoFo version number") SET(PODOFO_VERSION_MINOR "9" CACHE STRING "Minor part of PoDoFo version number") SET(PODOFO_VERSION_PATCH "5" CACHE STRING "Patchlevel part of PoDoFo version number") SET(PODOFO_SOVERSION "${PODOFO_VERSION_MAJOR}.${PODOFO_VERSION_MINOR}.${PODOFO_VERSION_PATCH}") SET(PODOFO_LIBVERSION "${PODOFO_SOVERSION}") # # Main includes # INCLUDE(CheckIncludeFile) INCLUDE(CheckLibraryExists) INCLUDE(TestBigEndian) INCLUDE(CheckTypeSize) # # Setup CMake Policies # # Prefer files in CMAKE_MODULE_PATH over shipped ones in module directory CMAKE_POLICY(SET CMP0017 NEW) # https://cmake.org/cmake/help/v3.0/policy/CMP0017.html # Do not use export_library_dependencies() anymore CMAKE_POLICY(SET CMP0033 NEW) # https://cmake.org/cmake/help/v3.0/policy/CMP0033.html # Load modules from our source tree too SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules") # Builds must use this CMakeLists.txt, not the one in src/ or somewhere else. # If users try to use something else the results can be confusing. We set a # variable here that we require to be set elsewhere, otherwise we'll complain. SET(PODOFO_MAIN_CMAKELISTS_READ TRUE) # If the user hasn't told use specifically what they want, build only # a static library or only a shared library on Windows. IF(NOT DEFINED PODOFO_BUILD_SHARED AND NOT DEFINED PODOFO_BUILD_STATIC) IF(WIN32) SET(PODOFO_BUILD_STATIC FALSE) SET(PODOFO_BUILD_SHARED TRUE) ELSE(WIN32) SET(PODOFO_BUILD_STATIC TRUE) SET(PODOFO_BUILD_SHARED FALSE) ENDIF(WIN32) ENDIF(NOT DEFINED PODOFO_BUILD_SHARED AND NOT DEFINED PODOFO_BUILD_STATIC) IF(DEFINED PODOFO_BUILD_SHARED AND NOT DEFINED PODOFO_BUILD_STATIC) IF(PODOFO_BUILD_SHARED) SET(PODOFO_BUILD_STATIC FALSE) ELSE(PODOFO_BUILD_SHARED) SET(PODOFO_BUILD_STATIC TRUE) ENDIF(PODOFO_BUILD_SHARED) ENDIF(DEFINED PODOFO_BUILD_SHARED AND NOT DEFINED PODOFO_BUILD_STATIC) IF(NOT DEFINED PODOFO_BUILD_SHARED AND DEFINED PODOFO_BUILD_STATIC) IF(PODOFO_BUILD_STATIC) SET(PODOFO_BUILD_SHARED FALSE) ELSE(PODOFO_BUILD_STATIC) SET(PODOFO_BUILD_SHARED TRUE) ENDIF(PODOFO_BUILD_STATIC) ENDIF(NOT DEFINED PODOFO_BUILD_SHARED AND DEFINED PODOFO_BUILD_STATIC) IF(DEFINED LIB_SUFFIX) SET(LIBDIRNAME "lib${LIB_SUFFIX}") ELSE(DEFINED LIB_SUFFIX) # Some 64 bit linux distros use /usr/lib64 for 64 bit libraries. # on these platforms we must IF(NOT DEFINED WANT_LIB64) # TODO: detect 64-bit build and existance of /usr/lib64 and set to TRUE. MESSAGE("WANT_LIB64 unset; assuming normal library directory names") SET(WANT_LIB64 FALSE) ENDIF(NOT DEFINED WANT_LIB64) IF(WANT_LIB64) SET(LIBDIRNAME "lib64") ELSE(WANT_LIB64) SET(LIBDIRNAME "lib") ENDIF(WANT_LIB64) ENDIF(DEFINED LIB_SUFFIX) MESSAGE("Will install libraries to ${CMAKE_INSTALL_PREFIX}/${LIBDIRNAME}") # Some headers that tend to vary a bit CHECK_INCLUDE_FILE("strings.h" PODOFO_HAVE_STRINGS_H) CHECK_INCLUDE_FILE("arpa/inet.h" PODOFO_HAVE_ARPA_INET_H) CHECK_INCLUDE_FILE("winsock2.h" PODOFO_HAVE_WINSOCK2_H) CHECK_INCLUDE_FILE("mem.h" PODOFO_HAVE_MEM_H) CHECK_INCLUDE_FILE("ctype.h" PODOFO_HAVE_CTYPE_H) # Do some type size detection and provide yet another set of typedefs for fixed # font sizes. We can't use the c99 / c++0x uint32_t etc, because people use # ancient compilers that don't and will never support the standard. CHECK_INCLUDE_FILE("sys/types.h" PODOFO_HAVE_SYS_TYPES_H) CHECK_INCLUDE_FILE("stdint.h" PODOFO_HAVE_STDINT_H) # See: http://msdn.microsoft.com/en-us/library/aa384264(VS.85).aspx CHECK_INCLUDE_FILE("BaseTsd.h" PODOFO_HAVE_BASETSD_H) CHECK_TYPE_SIZE("long int" SZ_LONG) # We cache integer type detection results, and don't repeat them # (and overwrite the user's manual changes) if they've been done already. IF(NOT PDF_INT64_TYPENAME) # I hate old compilers. IF(PODOFO_HAVE_STDINT_H) SET(pdfint8 "int8_t") SET(pdfint16 "int16_t") SET(pdfint32 "int32_t") SET(pdfint64 "int64_t") SET(pdfuint8 "uint8_t") SET(pdfuint16 "uint16_t") SET(pdfuint32 "uint32_t") SET(pdfuint64 "uint64_t") CHECK_TYPE_SIZE("int64_t" SZ_INT64) ELSE(PODOFO_HAVE_STDINT_H) # No stdint.h . Try BaseTsd.h windows types. IF(PODOFO_HAVE_BASETSD_H) # We have BaseTsd.h, so use those types. SET(pdfint8 "signed char") SET(pdfint16 "short") SET(pdfint32 "INT32") SET(pdfint64 "INT64") SET(pdfuint8 "unsigned char") SET(pdfuint16 "unsigned short") SET(pdfuint32 "UINT32") SET(pdfuint64 "UINT64") CHECK_TYPE_SIZE("INT64" SZ_INT64) ELSE(PODOFO_HAVE_BASETSD_H) # No BaseTsd.h either. Assume the standard types, and go poking # for a sane 64-bit integer. # # First, though, make sure sizeof(int) = 4 and if not, scream, because # hopefully this case will never be hit and we'll never have to write # the horrible code check for CHECK_TYPE_SIZE("signed char" SZ_TINY_INT) CHECK_TYPE_SIZE("unsigned char" SZ_TINY_UINT) CHECK_TYPE_SIZE("short int" SZ_SHORT_INT) CHECK_TYPE_SIZE("int" SZ_INT) CHECK_TYPE_SIZE("unsigned short int" SZ_UINT) CHECK_TYPE_SIZE("unsigned int" SZ_SHORT_UINT) SET(smallintsok SZ_INT == 4 AND SZ_UINT == 4 AND SZ_SHORT_INT == 2 AND SZ_SHORT_UINT == 2 AND SZ_TINY_INT == 1 AND SZ_TINY_UINT == 1) IF(NOT smallintsok) MESSAGE(FATAL "sizeof(int) != 4 and/or sizeof(short) != 2 and no stdint.h or BaseTsd.h found. We don't know how to cope with this.") ENDIF(NOT smallintsok) SET(pdfint8 "signed char") SET(pdfint16 "short") SET(pdfint32 "int") SET(pdfuint8 "unsigned char") SET(pdfuint16 "unsigned short") SET(pdfuint32 "unsigned int") # Now we just have to figure out what 64-bit integer type we can use. # # Do we have VC >= 6's __uint64 and __int64? # See: http://icfun.blogspot.com/2008/04/use-of-int64-variable-in-c.html CHECK_TYPE_SIZE("__int64" SZ___INT64) CHECK_TYPE_SIZE("__uint64" SZ___UINT64) IF(SZ___INT64 == 8 AND SZ___UINT64 == 8) # MS compiler, VC6 or newer without BaseTsd.h in SDK SET(pdfint64 "__int64") SET(pdfuint64 "__uint64") CHECK_TYPE_SIZE("__int64" SZ_INT64) ELSE(SZ___INT64 AND SZ___UINT64) # Still no luck. Old unix compiler, Borland, or some other monster? # Are we lucky and sizeof(long) == 8? CHECK_TYPE_SIZE("unsigned long int" SZ_ULONG) IF(SZ_LONG == 8 AND SZ_ULONG == 8) # Must be on a LP64 platform, sizeof(long) = 8 SET(pdfint64 "long int") SET(pdfuint64 "unsigned long int") CHECK_TYPE_SIZE("long int" SZ_INT64) ELSE(SZ_LONG == 8 AND SZ_ULONG == 8) # See if the compiler implements "long long int", int64_t, int64, # or _int64 (in this order, __int64 check already done) IF(PODOFO_HAVE_SYS_TYPES_H) SET(CMAKE_EXTRA_INCLUDE_FILES "sys/types.h") ENDIF(PODOFO_HAVE_SYS_TYPES_H) CHECK_TYPE_SIZE("long long int" SZ_LONG_LONG) CHECK_TYPE_SIZE("unsigned long long int" SZ_UNSIGNED_LONG_LONG) IF(SZ_LONG_LONG == 8 AND SZ_UNSIGNED_LONG_LONG == 8) SET(pdfint64 "long long int") SET(pdfuint64 "unsigned long long int") CHECK_TYPE_SIZE("long long int" SZ_INT64) ELSE(SZ_LONG_LONG == 8 AND SZ_UNSIGNED_LONG_LONG == 8) # The standard type int64_t is normally found in stdint.h, # but use a type of this name anyway if present CHECK_TYPE_SIZE("int64_t" SZ_INT64_T) CHECK_TYPE_SIZE("uint64_t" SZ_UINT64_T) IF(SZ_INT64_T AND SZ_UINT64_T) SET(pdfint64 "int64_t") SET(pdfuint64 "uint64_t") CHECK_TYPE_SIZE("int64_t" SZ_INT64) ELSE(SZ_INT64_T AND SZ_UINT64_T) CHECK_TYPE_SIZE("int64" SZ_INT64) CHECK_TYPE_SIZE("uint64" SZ_UINT64) IF(SZ_INT64 AND SZ_UINT64) SET(pdfint64 "int64") SET(pdfuint64 "uint64") CHECK_TYPE_SIZE("int64" SZ_INT64) ELSE(SZ_INT64 AND SZ_UINT64) CHECK_TYPE_SIZE("_int64" SZ__INT64) CHECK_TYPE_SIZE("_uint64" SZ__UINT64) IF(SZ__INT64 AND SZ__UINT64) SET(pdfint64 "_int64") SET(pdfuint64 "_uint64") CHECK_TYPE_SIZE("_int64" SZ_INT64) ELSE(SZ__INT64 AND SZ__UINT64) MESSAGE("Oh my lord, your compiler doesn't seem to support any of the int64 type flavours we tried.") MESSAGE(WARNING "You must set the PDF_INTxx_TYPENAME and PDF_UINTxx_TYPENAME variables manually") ENDIF(SZ__INT64 AND SZ__UINT64) ENDIF(SZ_INT64 AND SZ_UINT64) ENDIF(SZ_INT64_T AND SZ_UINT64_T) ENDIF(SZ_LONG_LONG == 8 AND SZ_UNSIGNED_LONG_LONG == 8) ENDIF(SZ_LONG == 8 AND SZ_ULONG == 8) ENDIF(SZ___INT64 AND SZ___UINT64) ENDIF(PODOFO_HAVE_BASETSD_H) ENDIF(PODOFO_HAVE_STDINT_H) SET(CMAKE_EXTRA_INCLUDE_FILES) ENDIF(NOT PDF_INT64_TYPENAME) IF(NOT PDF_INT64_TYPENAME AND pdfint64) SET(PDF_INT64_TYPENAME "${pdfint64}" CACHE STRING "Name of detected 64-bit signed integer type to use") SET(PDF_INT32_TYPENAME "${pdfint32}" CACHE STRING "Name of detected 32-bit signed integer type to use") SET(PDF_INT16_TYPENAME "${pdfint16}" CACHE STRING "Name of detected 16-bit signed integer type to use") SET(PDF_INT8_TYPENAME "${pdfint8}" CACHE STRING "Name of detected 8-bit signed integer type to use") SET(PDF_UINT64_TYPENAME "${pdfuint64}" CACHE STRING "Name of detected 64-bit unsigned integer type to use") SET(PDF_UINT32_TYPENAME "${pdfuint32}" CACHE STRING "Name of detected 32-bit unsigned integer type to use") SET(PDF_UINT16_TYPENAME "${pdfuint16}" CACHE STRING "Name of detected 16-bit unsigned integer type to use") SET(PDF_UINT8_TYPENAME "${pdfuint8}" CACHE STRING "Name of detected 8-bit unsigned integer type to use") ENDIF(NOT PDF_INT64_TYPENAME AND pdfint64) # Linux packagers want an uninstall target. CONFIGURE_FILE( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") # Check if we are big endian TEST_BIG_ENDIAN(TEST_BIG) IF(WIN32) # We must explicitly link to the core win32 libraries, and we need winsock2 # to get some byte-order conversion routines too. SET(PLATFORM_SYSTEM_LIBRARIES kernel32 user32 gdi32 winspool comdlg32 advapi32 shell32 ole32 oleaut32 uuid ws2_32) # Microsoft deprecate certain POSIX functions that we use. # for now, turn off these warnings. ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE) # We need a fake unistd.h for some libraries to build. They try to include # which is not available under win32 with MSVC++, but everything in unistd.h is defined, # so an empty file solves the issue. SET(EXTRA_INCLUDES ${PoDoFo_SOURCE_DIR}/vcincludes) ELSE(WIN32) SET(PLATFORM_SYSTEM_LIBRARIES) SET(EXTRA_INCLUDES) ENDIF(WIN32) IF(UNIX AND NOT PODOFO_NO_FONTMANAGER) SET(WANT_FONTCONFIG TRUE CACHE INTERNAL "True if PoDoFo should be built with fontconfig support") ELSE(UNIX AND NOT PODOFO_NO_FONTMANAGER) SET(WANT_FONTCONFIG FALSE CACHE INTERNAL "True if PoDoFo should be built with fontconfig support") ENDIF(UNIX AND NOT PODOFO_NO_FONTMANAGER) IF(CMAKE_COMPILER_IS_GNUCXX) MESSAGE("Using gcc specific compiler options") # We can be more specific about what we want out of g++ # than with most other compilers. # Attempt to detect the gcc version. You must not rely on # this; use the detected version as a guide only. EXEC_PROGRAM(gcc ARGS --version OUTPUT_VARIABLE GCC_VERSION) IF(GCC_VERSION MATCHES ".*\\(GCC\\) 4\\.[0-9].*") MESSAGE("Have gcc 4.x") SET(PODOFO_HAVE_GCC4 1) ELSE(GCC_VERSION MATCHES ".*\\(GCC\\) 4\\.[0-9].*") SET(PODOFO_HAVE_GCC4 0) ENDIF(GCC_VERSION MATCHES ".*\\(GCC\\) 4\\.[0-9].*") # If the user hasn't specifically said whether they want # -fvisibility=hidden or not, turn it on for gcc4 and off # for other gcc versions. IF(NOT DEFINED PODOFO_USE_VISIBILITY) SET(PODOFO_USE_VISIBILITY ${PODOFO_HAVE_GCC4}) ENDIF(NOT DEFINED PODOFO_USE_VISIBILITY) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++98") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Woverloaded-virtual -Wswitch-enum -Wcast-qual -Wwrite-strings -Wredundant-decls -Wreorder") # # Note that we do not need debug definitions here. Set # -DCMAKE_BUILD_TYPE=debug or (if you want an optimised # release build with debug info) -DCMAKE_CXX_FLAGS="-g3" # # We add -W unless we're using gcc on win32, where it produces # spurious warnings about dllimport of inlines because of a dllimport # declaration on the whole class. IF(NOT WIN32) ADD_DEFINITIONS(-W) ENDIF(NOT WIN32) # If they've enabled the use of gcc4 symbol visibility, use it. IF(PODOFO_USE_VISIBILITY) ADD_DEFINITIONS( -DPODOFO_HAVE_GCC_SYMBOL_VISIBILITY -fvisibility=hidden ) ENDIF(PODOFO_USE_VISIBILITY) ENDIF(CMAKE_COMPILER_IS_GNUCXX) FIND_PACKAGE(ZLIB REQUIRED) MESSAGE("Found zlib headers in ${ZLIB_INCLUDE_DIR}, library at ${ZLIB_LIBRARIES}") FIND_PACKAGE(LIBCRYPTO) IF(LIBCRYPTO_FOUND) SET(PODOFO_HAVE_OPENSSL TRUE) INCLUDE_DIRECTORIES(${LIBCRYPTO_INCLUDE_DIR}) MESSAGE("Found OpenSSL's libCrypto headers in ${LIBCRYPTO_INCLUDE_DIR}, library at ${LIBCRYPTO_LIBRARIES}") ELSE(LIBCRYPTO_FOUND) MESSAGE("OpenSSL's libCrypto not found. Encryption support will be disabled") ENDIF(LIBCRYPTO_FOUND) FIND_PACKAGE(LIBIDN) IF(LIBIDN_FOUND) MESSAGE("Found libidn headers in ${LIBIDN_INCLUDE_DIR}, library at ${LIBIDN_LIBRARIES}") ENDIF(LIBIDN_FOUND) IF(LIBIDN_FOUND) SET(PODOFO_HAVE_LIBIDN TRUE) INCLUDE_DIRECTORIES(${LIBIDN_INCLUDE_DIR}) MESSAGE("Libidn found. AES-256 Encryption support will be enabled") ELSE(LIBIDN_FOUND) MESSAGE("Libidn not found. AES-256 Encryption support will be disabled") ENDIF(LIBIDN_FOUND) FIND_PACKAGE(LIBJPEG) IF(LIBJPEG_FOUND) MESSAGE("Found libjpeg headers in ${LIBJPEG_INCLUDE_DIR}, library at ${LIBJPEG_LIBRARIES}") SET(PODOFO_HAVE_JPEG_LIB TRUE) INCLUDE_DIRECTORIES(${LIBJPEG_INCLUDE_DIR}) ELSE(LIBJPEG_FOUND) MESSAGE("Libjpeg not found. JPEG support will be disabled") ENDIF(LIBJPEG_FOUND) FIND_PACKAGE(TIFF) IF(TIFF_FOUND) MESSAGE("Found libtiff headers in ${TIFF_INCLUDE_DIR}, library at ${TIFF_LIBRARIES}") SET(PODOFO_HAVE_TIFF_LIB TRUE) INCLUDE_DIRECTORIES(${TIFF_INCLUDE_DIR}) ELSE(TIFF_FOUND) MESSAGE("Libtiff not found. TIFF support will be disabled") ENDIF(TIFF_FOUND) FIND_PACKAGE(PNG) IF(PNG_FOUND) MESSAGE("Found LibPng headers in ${PNG_INCLUDE_DIR}, library at ${PNG_LIBRARIES}") SET(PODOFO_HAVE_PNG_LIB TRUE) INCLUDE_DIRECTORIES(${PNG_INCLUDE_DIR}) ELSE(PNG_FOUND) MESSAGE("LibPng not found. PNG support will be disabled") ENDIF(PNG_FOUND) IF(NOT PODOFO_BUILD_LIB_ONLY) FIND_PACKAGE(CppUnit) IF(CppUnit_FOUND) MESSAGE("Found cppunit. Unit tests will be built.") SET(PODOFO_HAVE_CPPUNIT CppUnit_FOUND) INCLUDE_DIRECTORIES(${CPPUNIT_INCLUDE_DIR}) ELSE(CppUnit_FOUND) MESSAGE("Cppunit not found. No unit tests will be built.") ENDIF(CppUnit_FOUND) ENDIF(NOT PODOFO_BUILD_LIB_ONLY) FIND_PACKAGE(OpenSSL) FIND_PACKAGE(FREETYPE REQUIRED) MESSAGE("Found freetype library at ${FREETYPE_LIBRARIES}, headers ${FREETYPE_INCLUDE_DIR}") FIND_PACKAGE(LIBSTLPORT) SET(stlport_libraries_if_use_stlport) IF(USE_STLPORT) IF(LIBSTLPORT_FOUND) MESSAGE("Using STLPort") INCLUDE_DIRECTORIES(${LIBSTLPORT_HEADERS}) LINK_DIRECTORIES(${LIBSTLPORT_LIB}) SET(stlport_libraries_if_use_stlport stlport) # Use the threaded STLPort ADD_DEFINITIONS(-D_PTHREADS) ELSE(LIBSTLPORT_FOUND) MESSAGE(FATAL_ERROR "STLPort use requested, but STLPort not found.") ENDIF(LIBSTLPORT_FOUND) ENDIF(USE_STLPORT) IF(WANT_FONTCONFIG) FIND_PACKAGE(FONTCONFIG REQUIRED) SET(PODOFO_HAVE_FONTCONFIG TRUE) SET(PODOFO_LIB_FONTCONFIG:STRING fontconfig) IF(FONTCONFIG_FOUND) MESSAGE("Found fontconfig headers in ${FONTCONFIG_INCLUDE_DIR}, library at ${FONTCONFIG_LIBRARIES}") ELSE(FONTCONFIG_FOUND) MESSAGE("Could not find fontconfig.") ENDIF(FONTCONFIG_FOUND) ELSE(WANT_FONTCONFIG) # Might as well look for it anyway. This also sets the appropriate # variables to empty values. FIND_PACKAGE(FONTCONFIG) SET(PODOFO_LIB_FONTCONFIG:STRING) ENDIF(WANT_FONTCONFIG) IF(NOT PODOFO_BUILD_LIB_ONLY) FIND_PACKAGE(LUA) IF(LUA_FOUND) # If we have lua, we can build podofoimpose. MESSAGE("Lua found - PoDoFoImpose and PoDoFoColor will be built with Lua support") MESSAGE(" * Lua include directory: ${LUA_INCLUDE_DIR}") MESSAGE(" * Lua libraries: ${LUA_LIBRARIES}") INCLUDE_DIRECTORIES(${LUA_INCLUDE_DIR}) SET(PODOFO_HAVE_LUA TRUE) ELSE(LUA_FOUND) MESSAGE("Lua not found - PoDoFoImpose and PoDoFoColor will be built without Lua support") ENDIF(LUA_FOUND) ENDIF(NOT PODOFO_BUILD_LIB_ONLY) # Check if we should build a multithreaded version of PoDoFo IF(DEFINED PODOFO_NO_MULTITHREAD) MESSAGE("Building non multithreaded version of PoDoFo.") SET(PODOFO_MULTI_THREAD FALSE) ELSE(DEFINED PODOFO_NO_MULTITHREAD) MESSAGE("Building multithreaded version of PoDoFo.") SET(PODOFO_MULTI_THREAD TRUE) FIND_PACKAGE(Threads) SET(PLATFORM_SYSTEM_LIBRARIES ${CMAKE_THREAD_LIBS_INIT} ${PLATFORM_SYSTEM_LIBRARIES}) ENDIF(DEFINED PODOFO_NO_MULTITHREAD) IF(WANT_BOOST) MESSAGE("Looking optional for Boost.") MESSAGE("Boost is optional, so don't worry if it is not found.") MESSAGE("Set the BOOST_ROOT env var if you have problems.") FIND_PACKAGE(Boost) IF(BOOST_FOUND) SET(PODOFO_HAVE_BOOST TRUE) INCLUDE_DIRECTORIES(${BOOST_INCLUDE_DIR}) ELSE(BOOST_FOUND) MESSAGE("If you don't need graph support you can ignore the above error.") ENDIF(BOOST_FOUND) ENDIF(WANT_BOOST) INCLUDE_DIRECTORIES(BEFORE # before toolchain include dir (to ignore installed) ${PoDoFo_SOURCE_DIR} # order will be reversed, so this is the second dir ${PoDoFo_BINARY_DIR} # because of BEFORE, this is the first include dir ) INCLUDE_DIRECTORIES( ${PoDoFo_SOURCE_DIR}/src ${FREETYPE_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} ${EXTRA_INCLUDES} ) LINK_DIRECTORIES( ${PoDoFo_BINARY_DIR}/src/ ) # # The PoDoFo library needs to be linked to these libraries, # as do any apps or libraries linking to PoDoFo. PODOFO_LIB # will include these and the correct podofo target, so clients # should specify only PODOFO_LIB . # # The LIBCRYPTO_LDFLAGS is defined only if the libcrypto was found # by pkg-config, otherwise it will be empty. It can contain proper # path for the libcrypto too, thus it's added here. # SET(PODOFO_LIB_DEPENDS ${ZLIB_LIBRARIES} ${LIBIDN_LIBRARIES} ${LIBCRYPTO_LDFLAGS} ${LIBCRYPTO_LIBRARIES} ${LIBJPEG_LIBRARIES} ${PLATFORM_SYSTEM_LIBRARIES} ${stlport_libraries_if_use_stlport} ${FREETYPE_LIBRARIES} ${PNG_LIBRARIES} ${TIFF_LIBRARIES} ) IF(FONTCONFIG_FOUND AND WANT_FONTCONFIG) SET(PODOFO_LIB_DEPENDS ${FONTCONFIG_LIBRARIES} ${PODOFO_LIB_DEPENDS}) INCLUDE_DIRECTORIES(${FONTCONFIG_INCLUDE_DIR}) ENDIF(FONTCONFIG_FOUND AND WANT_FONTCONFIG) SET(PODOFO_LIB podofo ${PODOFO_LIB_DEPENDS} ) # # Setup directories we will need # SET(MANDIR "share/man/") # Create the config file. It'll be appended to as the subdirs run though # then dependency information will be written to it at the end of the # build. FILE(WRITE "${PoDoFo_BINARY_DIR}/PoDoFoConfig.cmake" "# CMake module for PoDoFo\n" ) FILE(APPEND "${PoDoFo_BINARY_DIR}/PoDoFoConfig.cmake" "SET(PODOFO_INCLUDES ${PoDoFo_SOURCE_DIR}/src)\n" ) ADD_SUBDIRECTORY(src) IF(NOT PODOFO_BUILD_LIB_ONLY) ADD_SUBDIRECTORY(test) ADD_SUBDIRECTORY(tools) ADD_SUBDIRECTORY(examples) ADD_SUBDIRECTORY(debian) ENDIF(NOT PODOFO_BUILD_LIB_ONLY) # Generate our configure file CONFIGURE_FILE(${PoDoFo_SOURCE_DIR}/podofo_config.h.in ${PoDoFo_BINARY_DIR}/podofo_config.h) # Export some variables into the config file so it's easier for others # to build and link against PoDoFo # To use these dependencies set PODOFO_DIR to the podofo BUILD directory in # your build (eg -DPODOFO_DIR=/path/to/podofo when running cmake to configure # the app that'll use podofo). See: FIND_PACKAGE(...) in the cmake docs. IF(PODOFO_BUILD_SHARED) EXPORT(TARGETS podofo_shared FILE "${CMAKE_CURRENT_BINARY_DIR}/PoDoFoConfig.cmake") ENDIF(PODOFO_BUILD_SHARED) IF(PODOFO_BUILD_STATIC) EXPORT(TARGETS podofo_static FILE "${CMAKE_CURRENT_BINARY_DIR}/PoDoFoConfig.cmake") ENDIF(PODOFO_BUILD_STATIC) podofo-0.9.5/podofo/0000775000175000017500000000000013044451157014155 5ustar dominikdominikpodofo-0.9.5/podofo/base/0000775000175000017500000000000013044451157015067 5ustar dominikdominikpodofo-0.9.5/podofo/base/PdfMutexImpl_noop.h0000664000175000017500000000073011535255326020654 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFMUTEXIMPLNOOPH #define PODOFO_WRAPPER_PDFMUTEXIMPLNOOPH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/util/PdfMutexImpl_noop.h" #endif podofo-0.9.5/podofo/base/PdfColor.h0000664000175000017500000000066111535255326016756 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFCOLORH #define PODOFO_WRAPPER_PDFCOLORH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfColor.h" #endif podofo-0.9.5/podofo/base/PdfEncoding.h0000664000175000017500000000067511535255326017433 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFENCODINGH #define PODOFO_WRAPPER_PDFENCODINGH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfEncoding.h" #endif podofo-0.9.5/podofo/base/PdfFileStream.h0000664000175000017500000000070511535255326017732 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFFILESTREAMH #define PODOFO_WRAPPER_PDFFILESTREAMH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfFileStream.h" #endif podofo-0.9.5/podofo/base/PdfLocale.h0000664000175000017500000000066511535255326017103 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFLOCALEH #define PODOFO_WRAPPER_PDFLOCALEH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfLocale.h" #endif podofo-0.9.5/podofo/base/PdfDataType.h0000664000175000017500000000067511535255326017420 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFDATATYPEH #define PODOFO_WRAPPER_PDFDATATYPEH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfDataType.h" #endif podofo-0.9.5/podofo/base/PdfXRef.h0000664000175000017500000000065511535255326016547 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFXREFH #define PODOFO_WRAPPER_PDFXREFH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfXRef.h" #endif podofo-0.9.5/podofo/base/PdfData.h0000664000175000017500000000065511535255326016554 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFDATAH #define PODOFO_WRAPPER_PDFDATAH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfData.h" #endif podofo-0.9.5/podofo/base/PdfObject.h0000664000175000017500000000066511535255326017112 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFOBJECTH #define PODOFO_WRAPPER_PDFOBJECTH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfObject.h" #endif podofo-0.9.5/podofo/base/PdfCompilerCompat.h0000664000175000017500000000072511535255326020617 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFCOMPILERCOMPATH #define PODOFO_WRAPPER_PDFCOMPILERCOMPATH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfCompilerCompat.h" #endif podofo-0.9.5/podofo/base/PdfTokenizer.h0000664000175000017500000000070111535255326017645 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFTOKENIZERH #define PODOFO_WRAPPER_PDFTOKENIZERH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfTokenizer.h" #endif podofo-0.9.5/podofo/base/PdfCanvas.h0000664000175000017500000000066511535255326017117 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFCANVASH #define PODOFO_WRAPPER_PDFCANVASH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfCanvas.h" #endif podofo-0.9.5/podofo/base/PdfRefCountedBuffer.h0000664000175000017500000000073511535255326021072 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFREFCOUNTEDBUFFERH #define PODOFO_WRAPPER_PDFREFCOUNTEDBUFFERH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfRefCountedBuffer.h" #endif podofo-0.9.5/podofo/base/PdfMutexImpl_pthread.h0000664000175000017500000000074411535255326021335 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFMUTEXIMPLPTHREADH #define PODOFO_WRAPPER_PDFMUTEXIMPLPTHREADH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/util/PdfMutexImpl_pthread.h" #endif podofo-0.9.5/podofo/base/PdfParserObject.h0000664000175000017500000000071511535255326020263 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFPARSEROBJECTH #define PODOFO_WRAPPER_PDFPARSEROBJECTH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfParserObject.h" #endif podofo-0.9.5/podofo/base/PdfXRefStream.h0000664000175000017500000000070511535255326017717 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFXREFSTREAMH #define PODOFO_WRAPPER_PDFXREFSTREAMH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfXRefStream.h" #endif podofo-0.9.5/podofo/base/PdfVecObjects.h0000664000175000017500000000070511535255326017726 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFVECOBJECTSH #define PODOFO_WRAPPER_PDFVECOBJECTSH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfVecObjects.h" #endif podofo-0.9.5/podofo/base/PdfEncodingFactory.h0000664000175000017500000000073111535255326020754 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFENCODINGFACTORYH #define PODOFO_WRAPPER_PDFENCODINGFACTORYH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfEncodingFactory.h" #endif podofo-0.9.5/podofo/base/PdfExtension.h0000664000175000017500000000070112320241722017633 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFEXTENSIONH #define PODOFO_WRAPPER_PDFEXTENSIONH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfExtension.h" #endif podofo-0.9.5/podofo/base/PdfEncrypt.h0000664000175000017500000000067111535255326017325 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFENCRYPTH #define PODOFO_WRAPPER_PDFENCRYPTH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfEncrypt.h" #endif podofo-0.9.5/podofo/base/PdfOutputDevice.h0000664000175000017500000000071511535255326020320 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFOUTPUTDEVICEH #define PODOFO_WRAPPER_PDFOUTPUTDEVICEH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfOutputDevice.h" #endif podofo-0.9.5/podofo/base/PdfDefines.h0000664000175000017500000000067111535255326017256 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFDEFINESH #define PODOFO_WRAPPER_PDFDEFINESH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfDefines.h" #endif podofo-0.9.5/podofo/base/PdfDate.h0000664000175000017500000000065511535255326016560 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFDATEH #define PODOFO_WRAPPER_PDFDATEH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfDate.h" #endif podofo-0.9.5/podofo/base/PdfXRefStreamParserObject.h0000664000175000017500000000076511535255326022231 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFXREFSTREAMPARSEROBJECTH #define PODOFO_WRAPPER_PDFXREFSTREAMPARSEROBJECTH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfXRefStreamParserObject.h" #endif podofo-0.9.5/podofo/base/PdfRefCountedInputDevice.h0000664000175000017500000000076111535255326022077 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFREFCOUNTEDINPUTDEVICEH #define PODOFO_WRAPPER_PDFREFCOUNTEDINPUTDEVICEH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfRefCountedInputDevice.h" #endif podofo-0.9.5/podofo/base/PdfArray.h0000664000175000017500000000066111535255326016756 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFARRAYH #define PODOFO_WRAPPER_PDFARRAYH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfArray.h" #endif podofo-0.9.5/podofo/base/PdfInputStream.h0000664000175000017500000000071111535255326020147 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFINPUTSTREAMH #define PODOFO_WRAPPER_PDFINPUTSTREAMH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfInputStream.h" #endif podofo-0.9.5/podofo/base/PdfRijndael.h0000664000175000017500000000067511535255326017435 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFRIJNDAELH #define PODOFO_WRAPPER_PDFRIJNDAELH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfRijndael.h" #endif podofo-0.9.5/podofo/base/PdfMutexWrapper.h0000664000175000017500000000072211535255326020341 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFMUTEXWRAPPERH #define PODOFO_WRAPPER_PDFMUTEXWRAPPERH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/util/PdfMutexWrapper.h" #endif podofo-0.9.5/podofo/base/PdfReference.h0000664000175000017500000000070111535255326017571 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFREFERENCEH #define PODOFO_WRAPPER_PDFREFERENCEH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfReference.h" #endif podofo-0.9.5/podofo/base/PdfError.h0000664000175000017500000000066111535255326016771 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFERRORH #define PODOFO_WRAPPER_PDFERRORH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfError.h" #endif podofo-0.9.5/podofo/base/PdfOutputStream.h0000664000175000017500000000071511535255326020354 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFOUTPUTSTREAMH #define PODOFO_WRAPPER_PDFOUTPUTSTREAMH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfOutputStream.h" #endif podofo-0.9.5/podofo/base/PdfCompilerCompatPrivate.h0000664000175000017500000000076111535255326022152 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFCOMPILERCOMPATPRIVATEH #define PODOFO_WRAPPER_PDFCOMPILERCOMPATPRIVATEH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfCompilerCompatPrivate.h" #endif podofo-0.9.5/podofo/base/PdfMutex.h0000664000175000017500000000066611535255326017007 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFMUTEXH #define PODOFO_WRAPPER_PDFMUTEXH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/util/PdfMutex.h" #endif podofo-0.9.5/podofo/base/PdfInputDevice.h0000664000175000017500000000071111535255326020113 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFINPUTDEVICEH #define PODOFO_WRAPPER_PDFINPUTDEVICEH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfInputDevice.h" #endif podofo-0.9.5/podofo/base/podofoapi.h0000664000175000017500000000066511535255326017232 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PODOFOAPIH #define PODOFO_WRAPPER_PODOFOAPIH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/podofoapi.h" #endif podofo-0.9.5/podofo/base/PdfFilter.h0000664000175000017500000000066511535255326017131 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFFILTERH #define PODOFO_WRAPPER_PDFFILTERH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfFilter.h" #endif podofo-0.9.5/podofo/base/PdfMutexImpl_win32.h0000664000175000017500000000073411535255326020647 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFMUTEXIMPLWIN32H #define PODOFO_WRAPPER_PDFMUTEXIMPLWIN32H /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/util/PdfMutexImpl_win32.h" #endif podofo-0.9.5/podofo/base/PdfWriter.h0000664000175000017500000000066511535255326017160 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFWRITERH #define PODOFO_WRAPPER_PDFWRITERH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfWriter.h" #endif podofo-0.9.5/podofo/base/Pdf3rdPtyForwardDecl.h0000664000175000017500000000074111535255326021201 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDF3RDPTYFORWARDDECLH #define PODOFO_WRAPPER_PDF3RDPTYFORWARDDECLH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/Pdf3rdPtyForwardDecl.h" #endif podofo-0.9.5/podofo/base/util/0000775000175000017500000000000013044451157016044 5ustar dominikdominikpodofo-0.9.5/podofo/base/util/PdfMutexImpl_noop.h0000664000175000017500000000073311535255326021634 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFMUTEXIMPLNOOPH #define PODOFO_WRAPPER_PDFMUTEXIMPLNOOPH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../../src/base/util/PdfMutexImpl_noop.h" #endif podofo-0.9.5/podofo/base/util/PdfMutexImpl_pthread.h0000664000175000017500000000074711535255326022315 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFMUTEXIMPLPTHREADH #define PODOFO_WRAPPER_PDFMUTEXIMPLPTHREADH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../../src/base/util/PdfMutexImpl_pthread.h" #endif podofo-0.9.5/podofo/base/util/PdfMutexWrapper.h0000664000175000017500000000072511535255326021321 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFMUTEXWRAPPERH #define PODOFO_WRAPPER_PDFMUTEXWRAPPERH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../../src/base/util/PdfMutexWrapper.h" #endif podofo-0.9.5/podofo/base/util/PdfMutex.h0000664000175000017500000000067111535255326017760 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFMUTEXH #define PODOFO_WRAPPER_PDFMUTEXH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../../src/base/util/PdfMutex.h" #endif podofo-0.9.5/podofo/base/util/PdfMutexImpl_win32.h0000664000175000017500000000073711535255326021627 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFMUTEXIMPLWIN32H #define PODOFO_WRAPPER_PDFMUTEXIMPLWIN32H /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../../src/base/util/PdfMutexImpl_win32.h" #endif podofo-0.9.5/podofo/base/PdfName.h0000664000175000017500000000065511535255326016563 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFNAMEH #define PODOFO_WRAPPER_PDFNAMEH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfName.h" #endif podofo-0.9.5/podofo/base/PdfParser.h0000664000175000017500000000066511535255326017140 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFPARSERH #define PODOFO_WRAPPER_PDFPARSERH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfParser.h" #endif podofo-0.9.5/podofo/base/PdfMemStream.h0000664000175000017500000000070111535255326017565 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFMEMSTREAMH #define PODOFO_WRAPPER_PDFMEMSTREAMH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfMemStream.h" #endif podofo-0.9.5/podofo/base/PdfImmediateWriter.h0000664000175000017500000000073111535255326020771 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFIMMEDIATEWRITERH #define PODOFO_WRAPPER_PDFIMMEDIATEWRITERH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfImmediateWriter.h" #endif podofo-0.9.5/podofo/base/PdfStream.h0000664000175000017500000000066511535255326017137 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFSTREAMH #define PODOFO_WRAPPER_PDFSTREAMH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfStream.h" #endif podofo-0.9.5/podofo/base/create_forward_headers.sh0000775000175000017500000000217711535255326022122 0ustar dominikdominik#!/bin/bash function create_header { HEADER=$1 FILENAME=$(basename $HEADER) DEFINE=$(echo $FILENAME | tr '[:lower:]' '[:upper:]' | tr -d '[:punct:]' ) echo "Creating forward header $FILENAME" echo "" > $FILENAME echo "#ifndef PODOFO_WRAPPER_$DEFINE" >> $FILENAME echo "#define PODOFO_WRAPPER_$DEFINE" >> $FILENAME echo "/*" >> $FILENAME echo " * This is a simple wrapper include file that lets you include" >> $FILENAME echo " * when building against a podofo build directory" >> $FILENAME echo " * rather than an installed copy of podofo. You'll probably need" >> $FILENAME echo " * this if you're including your own (probably static) copy of podofo" >> $FILENAME echo " * using a mechanism like svn:externals ." >> $FILENAME echo " */" >> $FILENAME echo "#include \"$HEADER\"" >> $FILENAME echo "#endif" >> $FILENAME } HEADERS=$(find ../../src/base -name '*.h') for HEADER in $HEADERS; do create_header $HEADER done cd util UTIL_HEADERS=$(find ../../../src/base/util -name '*.h') for HEADER in $UTIL_HEADERS; do create_header $HEADER done cd .. podofo-0.9.5/podofo/base/PdfObjectStreamParserObject.h0000664000175000017500000000077511535255326022574 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFOBJECTSTREAMPARSEROBJECTH #define PODOFO_WRAPPER_PDFOBJECTSTREAMPARSEROBJECTH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfObjectStreamParserObject.h" #endif podofo-0.9.5/podofo/base/PdfFiltersPrivate.h0000664000175000017500000000072511535255326020644 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFFILTERSPRIVATEH #define PODOFO_WRAPPER_PDFFILTERSPRIVATEH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfFiltersPrivate.h" #endif podofo-0.9.5/podofo/base/PdfVariant.h0000664000175000017500000000067111535255326017305 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFVARIANTH #define PODOFO_WRAPPER_PDFVARIANTH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfVariant.h" #endif podofo-0.9.5/podofo/base/PdfRect.h0000664000175000017500000000065511535255326016600 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFRECTH #define PODOFO_WRAPPER_PDFRECTH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfRect.h" #endif podofo-0.9.5/podofo/base/PdfDefinesPrivate.h0000664000175000017500000000072511535255326020611 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFDEFINESPRIVATEH #define PODOFO_WRAPPER_PDFDEFINESPRIVATEH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfDefinesPrivate.h" #endif podofo-0.9.5/podofo/base/PdfString.h0000664000175000017500000000066511535255326017152 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFSTRINGH #define PODOFO_WRAPPER_PDFSTRINGH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfString.h" #endif podofo-0.9.5/podofo/base/PdfContentsTokenizer.h0000664000175000017500000000074111535255326021367 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFCONTENTSTOKENIZERH #define PODOFO_WRAPPER_PDFCONTENTSTOKENIZERH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfContentsTokenizer.h" #endif podofo-0.9.5/podofo/base/PdfVersion.h0000664000175000017500000000067111535255326017326 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFVERSIONH #define PODOFO_WRAPPER_PDFVERSIONH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfVersion.h" #endif podofo-0.9.5/podofo/base/PdfDictionary.h0000664000175000017500000000070511535255326020004 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFDICTIONARYH #define PODOFO_WRAPPER_PDFDICTIONARYH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfDictionary.h" #endif podofo-0.9.5/podofo/base/PdfMemoryManagement.h0000664000175000017500000000073511535255326021147 0ustar dominikdominik #ifndef PODOFO_WRAPPER_PDFMEMORYMANAGEMENTH #define PODOFO_WRAPPER_PDFMEMORYMANAGEMENTH /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../../src/base/PdfMemoryManagement.h" #endif podofo-0.9.5/podofo/podofo.h0000664000175000017500000000063510614711122015607 0ustar dominikdominik#ifndef PODOFO_WRAPPER_PODOFO_H #define PODOFO_WRAPPER_PODOFO_H /* * This is a simple wrapper include file that lets you include * when building against a podofo build directory * rather than an installed copy of podofo. You'll probably need * this if you're including your own (probably static) copy of podofo * using a mechanism like svn:externals . */ #include "../src/podofo.h" #endif podofo-0.9.5/podofo/compilercompat/0000775000175000017500000000000013044451157017173 5ustar dominikdominikpodofo-0.9.5/podofo/compilercompat/borland/0000775000175000017500000000000013044451157020614 5ustar dominikdominikpodofo-0.9.5/podofo/compilercompat/borland/ctime0000664000175000017500000000002211231022232021612 0ustar dominikdominik#include podofo-0.9.5/podofo/compilercompat/borland/cstdio0000664000175000017500000000002311231022232021777 0ustar dominikdominik#include podofo-0.9.5/TODO0000664000175000017500000000330110715632607013357 0ustar dominikdominikPoDoFo 0.5 - Do not inherit from PdfTokenizer - Interactive forms support PoDoFo 0.6: - convert PdfDocument / PdfStreamedDocument such that: + PdfDocument becomes PdfMemDocument + Common code moves to new shared base PdfDocument + PdfStreamedDocument does not depend on PdfMemDocument for base implementation + Most output-oriented tasks can be performed on any PdfDocument without caring what kind it is. - PdfString supports now unicode strings and conversions + PdfDocEncoding to UTF16 + UTF8 to UTF16 + UTF16 to UTF8 - Simple content stream parsing was added - Support for reading & writing encrypted PDFs FUTURE: - More filters (read & write) - Support for attaching an ICC profile to an image or content stream - Some more drawing routines (tiles, save and rstore?) also finish cleanup the existing ones revamp color support to be more general & support more types - PNG predictor functions in filters - CMYK image handling for podofoimgextract, images in different colour spaces in general. - Semi-streamed writing mode using normal in-memory document and a PdfStream class that can read input from a file / PdfInputStream on ::write() calls. (like PdfFileStream, but with support for user-supplied input files). - Streamline core datatypes to reduce repeated initialization, copy-construction, etc. Focus on limiting memory allocation/deallocation and heap fragmentation. Known trouble areas: + Small strings on heap in PdfString. Use an in-object buffer for small PdfStrings/PdfRefCountedBuffers since these are the most common type. podofo-0.9.5/FAQ.html0000664000175000017500000003174312623656054014201 0ustar dominikdominik PoDoFo FAQ

PoDoFo FAQ

General

What platforms are supported by PoDoFo?

PoDoFo has been tested on Linux, Mac OS X and Windows. It is developed in a platform-independent way so that porting to any other system should be no problem.

Can I use PoDoFo in my commercial application?

Yes, though you must follow the terms of the LGPL license for PoDoFo. The license permits you to use PoDoFo in any commercial application, though the LGPL obliges you to provide source to PoDoFo itself and any changes you made to it under the LGPL. That means that you may link code to PoDoFo that is not GPL- or LGPL-licensed so long as you follow the LGPL's rules. You need not fear "viral code" here - not unless you start copying chunks of PoDoFo into your own application, of course. The inlining done by the compiler is considered "linking" for the purposes of the license and thus not an issue.

The PoDoFo developers would be happy if you would credit them for using PoDoFo in your application, though this is not a license obligation.

What language is PoDoFo written in?

PoDoFo is written entirely in C++. If you're interested in using it from other languages, see the section on those below.

Does PoDoFo offer a stable API or ABI?

PoDoFo is not presently able to provider either a stable API or ABI. The library is being developed quickly and still requires a lot of changes to its interfaces as it is enhanced.

At present the best option for many users will be to target a snapshot of PoDoFo or a particular release. An in-tree copy of the library is not an unreasonable option, though care must be taken to ensure that your copy doesn't end up as an increasingly unmaintainable fork. The svn:externals mechanism is probably ideal for projects that use svn, since it lets you specify a particular tag or revision that's versioned along with your project. See PoDoFoBrowser for an example of this.

The README offers some more information on how to minimise the impact of API changes on your application.

The PoDoFo developers are interested in offering a stable, maintained release at some point, but the library is not yet at a point where that is practical.

Does PoDoFo have a mailing list?

Yes. See our support pages. You're very welcome on the lists, and they're not high-traffic. If you have a question, make sure to tell us your compiler and version, platform / OS and version, PoDoFo version, where you got PoDoFo / how it was built, and the details of any error messages. If possible, upload a problem PDF document somewhere so that we can get to it, too.

My question isn't answered here. Where do I go next?

Your best bet is to email the podofo-users mailing list.

Other Programming Languages

My program is written in C. Can I use PoDoFo?

PoDoFo can not be used directly from a basic C program, but if you have access to a C++ compiler there are acceptable workarounds.

The cleanest approach is probably to write your PoDoFo-using code as C++ and have it expose a pure C interface (using extern "C" and the nothrow() qualifier) that can be used by the rest of your program/library/plugin. With proper care and attention to memory handling and exception safety in the code that works directly with podofo, this approach should work extremely well. You need to be careful not to allow exceptions to unroll past your interface functions and into their pure-C callers, and it's also necessary to be careful to use the C library memory allocator when allocating memory that'll be free()'d in your pure C code (or vice versa).

As an alternative, if your program compiles as C++ (most C programs are legal C++), you may simply switch to building it with a C++ compiler. You may then use PoDoFo directly, though you'll still need to pay attention to cleaning up after an exception is thrown to avoid leaking resources or leaving your program in an invalid state. This is a reasonable approach for stand-alone programs, but is unattractive for library authors, plugin writers for C programs, and some other users.

Is there a C wrapper for PoDoFo?

Not as yet.

As PoDoFo does not make heavy use of templates in its general public API, it would be possible to write a fairly full-featured C wrapper around PoDoFo's public C++ APIs. Most of what'd be needed would be to:

  • provide factory functions for PoDoFo objects
  • provide deletion functions for PoDoFo objects
  • write wrappers for methods that take an instance as their first argument (also expanding overloaded methods) and translate thrown exceptions into error codes.

The PoDoFo authors would be interested in hearing about any such effort, but are not working on anything along those lines themselves.

I'm a Java developer. Can I use PoDoFo?

Not with Java, no, though we don't discriminate if you've used it but want to move to another language ;-) . In all seriousness a wrapper for Java may be possible, but nobody has been in touch with the PoDoFo developers to express an interest in writing one. Java users will probably want to look at iText.

I'm a C# or other .NET developer. Can I use PoDoFo?

Not easily. Since PoDoFo is unmanaged C++ code, you can use it with P/Invoke and a glue layer, but I wouldn't recommend this as a pleasant way to use a library. If writing your PDF output code in C++ is an option, you may well be able to use PoDoFo.

Are any other languages supported?

No. Python bindings would be a fun Boost.Python project, though.

Troubleshooting

Sometimes my program crashes in a call to PoDoFo and produces a traceback including a call to std::terminate(). Why?

If you're seeing a traceback including a call to std::terminate(), like the (simplified) one shown below, the problem is probably that you're not catching an exception being thrown by PoDoFo.

raise()
abort()
std::set_unexpected()
std::terminate()
PoDoFo::SomePoDoFoMethod()
main()

PoDoFo uses exceptions to indicate error conditions to the caller, and your program is not handling an exception that is thrown by PoDoFo. Your program should call all PoDoFo methods that are not annotated `nothrow()' in a try/catch block, or be prepared to handle the exception further up the call chain. Code that calls PoDoFo should also be exception-safe.

In simplified terms, if you fail to catch an exception and allow it to unroll the stack past your main() function, the runtime will call std::terminate() for you. This in turn will call abort(). On Linux, a SIGABRT (Signal #6) will be generated and your program will be terminated. Windows users may be informed that their program has asked the runtime to terminate it in an unusual way, or may get a crash dialog.

Why does my program crash with a SIGABRT (Signal #6) in a call to PoDoFo?

You're probably not catching an exception being thrown by PoDoFo. See the answer for std::terminate. Alternately, you might be hitting an internal assertion in PoDoFo, indicating you've found a library bug. If your problem isn't covered by the answer for std::terminate, please report a bug and include the full PoDoFo library version, a backtrace of the crash (this is critical), the code that causes the crash if possible, the PDF document that causes the crash if possible, and full information about your platform (OS/distro and version, what the CPU is, etc).

Why does my program exit with the message "Application has requested runtime to terminate it in an unusual way" ?

This is the Windows equivalent of a crash on a signal. This could easily be an error in your code, or an error from PoDoFo crashing your program. You need to attach a debugger to find out. If you're using MinGW, install GDB from this page under "GNU Source Level Debugger", then run gdb --args myprogram.exe. Visual Studio users should use the integrated debugger. If the crash does appear to come from PoDoFo, make sure that you are correctly catching and handling exceptions thrown by PoDoFo - see the answer to std::terminate.

PoDoFo creates invalid PDF files because , is used in floats instead of . Why?

PDF files use floating point numbers for almost all drawing operations as coordinates. Those floating point numbers have to be written in the English format with a . (point) as a separator. Some languages like German use a , (comma) instead.
Earlier versions of PoDoFo used the current locale's C++ library formatting operations to output values, causing these issues. Upgrade to a recent PoDoFo, or run in the `C' locale.

Where can I get test PDF files?

podofo-0.9.5/doc/0000775000175000017500000000000013044451162013430 5ustar dominikdominikpodofo-0.9.5/doc/latex/0000775000175000017500000000000013044451162014545 5ustar dominikdominikpodofo-0.9.5/doc/podofo_architecture.png0000664000175000017500000004220011460071654020170 0ustar dominikdominik‰PNG  IHDRªAà5sRGB®ÎébKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEÚ   ‡¤ IDATxÚíÝwtUðg{vÓPB RBï½DšHQQTAÅOº‚¤wPz‘ÞIhRB =¤mzÝÝùþØ$d“ÝdÓ7Éó;‡sÈ´÷Î;wß;3+ |.€ˆˆˆˆÈˆYDDDDÄD•ˆˆˆˆˆ‰*1Q%""""b¢JDDDDLT‰ˆˆˆˆ˜¨1Q%""""&ªDDDDDLT‰ˆˆˆˆ‰*U""""b¢JDDDDÄD•ˆˆˆˆˆ‰*1Q%""""b¢JDDDDLT‰ˆˆˆˆ …´8V+ˆ0ûûïxÔˆˆˆˆŠ €é3¦çnÝÀWáBqÙÑE¾‹±÷ÐqÔiÞ•Gˆˆˆ¨xà -zcÊ´9^WZÜvÖë¦è2|*:Q1pL¬„à\­Ë{T‰ˆˆˆÈ"1Q%""""&ªDDDDDLT‰ˆˆˆˆ‰*U""""b¢JDDDDÄD•ˆˆˆˆˆ‰*1Q%""""b¢JDDDDLT‰ˆˆˆˆ˜¨Qi#eQQšÖÅÙèt‘H±T¹+\+7@ÍvÃвS;HDS,ƒ\eÛ2^¨X¯ |úAWU¡ì¯)³†MýB]e‡WT‰È" ‚mr"âÕÏðÄÿošß §Ï†F(À˜ºd$Æ„"ôáEøíø+GÔÅÁo•Îúg]‘àU"²Æ® Ú$$D¿B๵صÌêK °þÀ;Þ­jÄÔi’†°Gþ¸ºû'œ;{ §æ¶ƒÄé:Ö+[àûkIõ_˜uADd ¯¨‘ÅIäP:x»Û×÷U_@àš%×!JåPÚ—ƒG½èùí) y§Aƒ“³F ^+”ªºg]‘%àU"*ÿ`;’£vXd0/ñùIü»þÜö¿ˆÈÈXÈÊ£bƒîh5t *•µÉuÌZ#wÁçX\¾„W_â݆)¨Ø¦v¶2^G!"^Q%¢bB@,@$¶2˜qa~Ó§D˜Z . ñápçÈ2üþN_}•û ")ÚMhx¼æB¦ÙۈŽgn]ä¦\ÁG¦bî„wqæßã …V“ˆ˜ ›¸²õk,71=1Q%¢â!ôØ4€ÂedÚ4MÜy¬ø~>â5Z¸¶œ€±«þÃwû^`êª}hÕ²tÉ!8øMgyýb|Z‚”F$EË/âĘåPÿÈeò&’8m¤Áôˆ]”ñÌ­‹Ü”ëê©§ŸñogŠ¡pÙGð„ "&ªDd¹ô/üWÁƵÊUo†:G¡~ÚËD'—³5º +÷÷,‡&öH®Ë¡Ó§ä\Nù;§¯§*Œ}ÍM]ä¦\w¢õ]¬ÙЉˆ‰*Y¾Ü¼W4õG™ñ®L,Õ?™žñjhNhcO$ªf…;/ñ²ºBÛw¸«‹ÜÔC´F °•HØð‰(K|˜ŠˆŠ-©¾ S'kŒÎ×%D·\Ljº¼ òê_豋2ž¹u‘›r)SÖ‰ÖjÙˆ‰(K¼¢JDÅV [+\ ÅÅQè^É)Óü„çê;:Ûö¹ $ãȪ+ïÑ 7v÷5ßùÊD]䦪Y+p%"×ÂãѶŒ 2™Ä+ªDTl5lí ¸úó2è2þX’ Áéyú§Æš ÎÕöïüÕ×#â wìî^Î…»°÷5·u‘›rù4*¸üûáLq’ÕÛ0­‹3¾}»/81Q%¢â«Üðù°‘I{ß‹˜…'O‚ Ñ&!êÉEü¡%N<ƒXê‚^£êšµ=A›„øˆ§x|qvÛk7œ…H¬B§}!lìÂÞ×üª‹Ü”Ëcô,ÈÅbDœ kÖC Aà›{±ùÓ/e{Ïd'"ˆ_…›m^ä»·_&à­ñÿã‘#*!RúÉíPµúÂ<,ÿnâŒü’‘Hb¶3Ž£cÓ FcfûM^æ†ö_íA»^ù;7û››xæÖ^ê"7åzuà ,óýZ!óGªê|ºØ* ¯¥•ÇÖþNB0¦L›‘ãuy*kŽM&ã³_áèú¸ãÑÑqPºxÀ³a_40^î¶æsK ³v‚cùš¨Ü õ²öŠB‰]ØûšŸu‘›r¹uýŸy4ÆáM¿ãÞ훈Oж\-x·‰ŽƒÞ…2ã%l"*•xE•ˆˆˆˆ ¯¨Q±5Æçõ•³•—Îç|""&ªDdIjúä„óï¬þ&¢Ò‡CÿDdIjúé©8Ÿó‰¨øËËÐ?U""""²ÈD•ïþ """"‹ÄD•ˆˆˆˆ˜¨1Q%""""&ªDDDDDLT‰ˆˆˆˆ‰*U"""""&ªDDDDÄD•ˆˆˆˆ(¤Å©°"pßÿö.ŸZdeHˆ… ÓAimËÖúâq¡|£PZ#1>–m‚ˆm¼ÄyxãZ7kXòÕ‰ŸL„\"iÎñCbb"¶ïÀ–Ǻâq¡üKTr$&êØ&ˆØÆKœZåÛcÜøOJ~¢ ×;š_A@tTT‘—£8`]ñ¸ÛÛ8åïQ%""""&ªDDDDDLT‰ˆˆˆˆ‰*U""""b¢JDDDDÄD•ˆˆˆˆˆ‰*1Q%""""b¢JDDDDLT‰ˆˆˆˆ˜¨U"""""&ªDDDDDLT‰ˆˆˆˆ‰*U""""b¢JDDDDÄD•ˆˆˆˆ˜¨1Q%""""b¢JDDDDLT‰ˆˆˆˆ˜¨U"""""&ªDDDDDLT‰ˆˆˆˆ‰*QNHYDDDTRÜ ¸ƒÄÄDƒiA/_".67®_3˜îî^Î..¬4&ªDDDDï—%‹°cëf£ó¶nÚhð÷ö=˜¨Z8ýQ‰Ñ½W³–+çîŽ>XaLT‰ˆˆˆ Gëvíakg—írÝzöH$b…1Q%"""*r¹ºtËv¹½û°²˜¨®ì†ÿ9ìÏD•ˆˆˆ¨Hd7üÏa&ªDDDDE"»áû3Q%"""*2¦†ÿ9ìÏD•ˆˆˆ¨H™þç°?U"""¢"ejøŸÃþLT‰ˆˆˆŠ\Æáû3Q%"""²‡ÿ9ìÏD•ˆˆˆÈ"dþç°?U""""‹‘:üÏa&ªDDDD%uøŸÃþLT‰ˆˆˆ,Jêð?‡ý‹')«€ˆˆ¨`ifÿ+¢ˆ$CŒ=û`ïþƒ¬Œ"ðÕ7ßB&Ö1Q%""²DK-ÂéóWP§yWVF•uC$«¡HøǬYßã‡YÓ˜¨Y*¯7š¢Ëð©¬*UA4¡¹^Ÿ÷¨‘Eb¢JDDDDLT‰ˆˆˆˆ˜¨U""""¢“¨VrsB%7§Y©%y߈ˆˆˆ _OU DEEá÷_—ãà¾=x¨P±:wëŽÆ} {{{V1Q¥Âuïn†€ÏŸL¸} ·oaûæMX³i+ªU¯ÁÊ"""¢…÷¨Z°ø¸8Œ6/ž?ƒw­ÚX½q n>|‚[Ÿâ¯ÍÛP«v¼xþ £‡ A|\+Œˆˆˆ˜¨æÄÓÇ1zøxWöÀU+aʧcrù[·à¾=ñFÕJ¨æá†ÖàÇYß"**Ê`¹Ôû@cb¢ñÅ'ãQ§JEÔªì‰1#ÞÃÓ'Oòe»Ÿ~<5+•G½šUðÓ÷³ô¿®‹}‹Áì™ÓѲQ=T-_uªTÄoá衬sx㺿øè!ªV«Žm{ö£mûް¶¶ÊÚ­Û¶ÇÖö¡JÕj|ô›Ö¯Íõ~Y¢úW‡‡c@Ÿzù"mÚ– ë–ù§´AÀ¤Æb÷ŽmÓŸ<ÄÊåKpìèaìØ{¶¶vó'}4GHûûÐþ}¸~õ*;GÇ\o÷³ñâÐþ}€„øxü²tʹ»çjß¾ødöý³;íhœ9ygNž@à«p“õw`ï?€O&OµµM¦ùÖÖ6ødòL7öþƒ‘£ÇfZÆÔ~ 5š­Ÿˆˆˆ,Z^Qýeéb½| +a×þøû4;öÄÛ·2-»yýZìÞ± *`åêu¸~/÷ž½Â?‡þEÃFMp/à–ù.Ì´ÞÝ;wÒ¶½sß!xT¨€ —/°bÉ¢ðÜy™–Mº^¶òtîÖvvvÉdxãÍzX¶êw¯¯0¦—~Ûõú¤m;59Ìívgÿ¼•*{A©Ra§“÷ïÝÍÕ¾9»¸Žÿ{¿ÿ²Wü.£n½úøåÏ¿²¬¿˜èh€ƒ££Éeõ¯ÁŠÎp ƒ¹ûADDDd© tèÿé“Ç€ÆMšLoÒ´y¦eS¯DöéÚÑäöž=Í|ï©©m§ÆÎívkz×Jû¿‹«>ÑLÿÀRNömöÏóñɇcpìÈ!;r¾óæ b¥ÊXñÇÔª]Çd¹llmµ:­ E¨Õ[;;£ó³Û""*Þ¦uq6:]$A,•Cnã ×Ê P³Ý0´ìÔQÆË WÙöŒ*ÖëŸ~cPÁUU(ûkÊìƒaESÿb d*G8zÖFõƒÐ¦ß(ó£òK‹yêßœ|4M¡mW"‘äÛ¾µëÐ ®ÞÄÊÕë0jì‡([Îaê§³\¯FMoÀ¹3§L.“:/uÙ‚Ü""*>A€69ñêgxâÿ7Íï…ÓgCS€ÏÓ ºd$Æ„"ôáEøíø+GÔÅÁo•Îú×i‘ŠW·OàÔobþø«Ñ±aæP^Qõ¬PîßÃÅ çкmû´éΟʹlõ5qãÚU<~5Ò]ÌŽ©m{V¨˜§íæç¾€R¥BçnÝѹ[wŒ?ßðÆÍ×!D"ãß°ºöè…‹çÏaÑüŸÑ¡S¨¬­ æÇÅÆbñ‚yiËQéeìÊ¡ MBBô+ž[‹]Ë|¡¾´ë¼ƒáݪHL& ‰±a{ä«»¹³·pjn;Hœ®¡c½²¾¿–Tÿ:m"£Cñ*à/˜ŠÀ‡›ñçê÷1þ6Ö(Ð+ª»tLŸú®úû!99Wü.㛩“3-;tä(ÀÈ!ƒ°}Ë&¼xþ ‰‰‰xøà>6®]ƒ~=ºdZ/ã¶§ù Cç®yÚn~îÛðApêø1ÄÅÆ"66GSÞR “ÉL&©0hÈPT¬T÷ï`@Ÿ8yü_ÄÅÆ">.§OÇ€>=pÿn*Uö !CÙš‰ˆÈ€H"‡ÒÁÞݾƸ¯ú×,)¸¤B*‡Ò¾<êõ@ÏoOaÈ;Í œœ5ñÚÒõjD±D¥CyTjòÞ[ð% xßL6Ê*Ð+ªãÆOÄîÛð8ðúvë”.ÉëŠgÞu:pðܼqk~_…Ï'|dvŒªÕ«lÊ–sLJ>ÉÓvósßN;ŠÇŽfÚFvWAUÖÖømí {§?nÞ¸ŽaïôÏ´L9÷òXõ×z(U*¶f""2É¡ñ¶#9j7€EóŸŸÄ¿ëÁmÿ‹ˆŒŒ…Ì¡<*6èŽVC§ RY›\Ǭ5r|ŽUÁåàKØyõ%Þmèži™‚ŠmJaÇ+÷ÑfB%Ó7ÛÍÏ}Û¸ãotíÑ ŽŽH$ð¨PN˜„9 e§Zõ8pü4&~þjxׂ•R +¥ÕkzcÂg“qàøiþ|*eK@,@$¶2˜qa~Ó§D˜Z . ñápçÈ2üþN_}•û ")ÚMÐ?düxÍ…L³ 4¶…/URð€ÔÎðµ”Br¶|Ô›WúâþíÛˆO€ Ó 1*O.mÅŽ©pè?Ã2%<߈EôÉý#èå+h’µÐ$E#üáE\X?‹†öÅ‹„dƒubïü ßáÝqâÀ„††B£MB|ÄSÜ=¶ «Ç6À‰KÏ-¶ÝJ :€gÅŠøí¯ ™¦›zÑ}‹ÖmТu³·okk‡¹¾K0×7ë¡ s·kª\©ÓW,ñÍñ¾5kÑÍRÞwšöööølÊWølÊWf¯“Ý~Qézl@á22mš&îþ'ËDU$q ¿3½Âˆ]”ñ2|e€úþ1<ëŠéî}û Ó šM[}½iÔÓ+ZËp?:+§~ˆv½û¡Rí¦(㪯c™C_Ì>Ø×`ù+{îú ll4N…“}c¡>±`¢JDDD…AÿÂl\+ \õf¨Óyê7¬i°L@t q9[£Û°rÀrhbä>EÓ§ä‚Nù;§¯§*è}ÍTA‹¤85ÔO®áÚž8qd Ö;‹ACm§Œ@ ˆ @Ðã;xqç2žÞñË7õsÃw½÷Ý lCÔÍíØ}s;@éZ^õÛ¢FÓî¨Ó¬é2ñÿ"õû½¬OÖ¯ÓD´Èv\lUÞkIDD”ûÄ bR^@ï(3žˆ¥î)9Wd®Ë¥=¨šzì¼ÄËê µYu-’@ní7ïèìÝ•ËvÁêu—ñ÷ÌM¨½øý´Å^_ˆ].Ƴ (³öå˯øÈªmþ÷è¯LJàæ¡Ü<ô+ö¸¶Àe[QÕ^ˆÖhÍÚ®  ³ÈvÍ+ªDDD¥”TŒ¨d-Ôɸy¥‘.)0%çrËuŒ¨Ë*¯þ…»(ãeTeÐ/À:Ä=\@Ÿ¨ªÏLƲŸVCX{6ÆmzÁÝÍ Vv®p®PKFÖ5º­òm&`d› H¾WOáÑñäæY<ö I!g°å«Uøzùx€R*FL²“÷ÃQZü~­’‰*Q)UÃÖ —ÂcqñEºWrÊ4?áùŸúdÁ¶}îÉ8²JÿîPïÑ 7v÷5ßùJ¤¢^ÐE§MÚï» ‚  áäCè×ÉðþPMÜù×ÿ©‘ß²*ãÚ½Q»ó}âûßbÌû|â/ OT«Û(௎ÃÙ§‘èQ٩صQ1OS""¢Ò©akOÀÕŸ—A—ñ‡£ NÏÛph68WÛ¿óW?\ˆƒÜ±º{9jìÂÞ×ì„;J›£¿´K»ú™–´å›×I´V—öÿßßvÇ´.θ®ŽÏ´Ž}”ÉÒ¦5j­ÿÁ€«ÿ› ù×ÁÔ§bZgü8~U"""²å†Ï‡L‚Øû¾XüÃ,¹€³ôOüÛx¶¼ûˆ…°•I÷x~5÷î=‚&9A×÷àðâX2óˆÄVè:}¸E¶Qý•RRUSŒ›>Ë¿›ƒÓ‹ñëéÅóE{´™~^Ö £ëg÷J,±Ì í¿Úƒæ^Nù»°÷5;æ¼̽Ë\¼ÝÜ3íïî£{àÎüíx²s2æíœl°¬÷°MvÀ¨\}ÊUõåòµ5Ï6Ç ÃØ<5ó/kJmëcà·o§ÛïÆøðÛ¯°læÿqe5V_m¸ß"1ê}¼ Ül,³ò4%""*½›LÆg¿6ÂÑõ+pÇÿ2¢£ã tñ€gþh6`¼ÜmÍÞ–H,ÌÚ Žåk¢rƒnhÔwÊÚ+ %vaï«9Ä2%¬=P¶ZSÔéô>|š^­uî¼c„ª8´k3ž?} Aæ·-ÑhÀ44jXjÏ~¸3{n/Z‡·–LÒoSZC~;ƒókçáÚù~ñ(`W¦*ª6ï‹ïŽC•Ì Ž}£OñùªÆ8¶ñÜö¿ˆµ"…#ܪ·€Ï€éhäSÙr¿Lñ%""*¾òã¡¥GôœÚ= 1fQÅÎi¼‚.OÅ.S0ºËã‰uë%˜Ýz‰‘ØÍß÷Eó÷Í£po®Ÿ·@×bÖ¾™¨cc|^ßü¹ò²ÀùœŸ¯ó™¨Q®“ÔôÉÿæßùù7U"""Ê—$Ð_Ëê çs¾9ó-)Ye¢JDDT ™J&²K28Ÿóó2¿°ñ=ªDDDDd‘˜¨U"""""&ªDDDDÄD•ˆˆˆˆˆ‰*˜‡7Îã®ÿ V!U"""²,wýŽãæÙ¬C&ªDDDDDLT‰ˆˆˆˆ‰*Q^ñ'T‰ˆˆ ˜HÜ÷?†½Ë§Z|Yï]?ä¤ÄbQVsÙØ9"&J]jÚ›%Ã{×Ï£qãFLT‰ˆˆ,ÕÄO&B.ŠEY#eHLÔ¡VyeÉITmdˆ±U–šöfIǰVùv7þ&ªDDD–,/Ö…IDGE›òRÉ>†¼G•ˆˆˆˆ,’dÀàwgjµ:XYY!**¡¡Á‰DÉdˆˆPC±X ‰Dµ:QH¥áa¡ˆ‰…T&ƒF£AXX(âã!W(ÐÐh’5P(䈉EHH0´Z”J%""Ô 1+<< Ñ‘Q&c…†† 1!r¹Üh¬àWÐét°²2K"‘@$›Œ%“Ë‘””„°°Ð´XΞF„Zz | P(,b©ÕáˆP«!‚¸Ø8Èd²L±âã V“e,±H ©L µZm4–T&ƒV«Exx¨ÑX …ñqqÍ&VXX¨éXa¡ˆŽŽ†T*M‹uùÂh4ø4nŠÐÐ$'%An"VppD"är"##ŒÆ’Jôêð°L±âbã —Ë‘”˜h2–••¢££üÊd¬ðð”6.‘•ÚÆe&b…¿Bêùd*–D,1<Ÿ2Ä’e8Ÿ2ÆRX) Î'c±Lž» ü._Bd„µêÔÍtî¦Å 6zî¦%‹ ´Ÿ0§OÊk?aNŸ”›~"§}RQ÷Ïž…F£AãfÍ ½ŸH+»~"$äA€BQpý„9}R^û sú¤¼öæôI¦ÎÝ×®"11 5½½ž»9é“òÚO˜Ó'±ŸÈÜO\<jÔ­WßH¬‚Ë'LõI±11+‹sw}TPY[ 7î=\]Ë„*U« gü® J•J‰DB³–­„-»ö ++A"‘CG¾/|÷ÓÏ‚\.d2™0eÚ á£ “©L&È á÷¿6»vÄb± T*…ýÇN uëÕRc¾ ¬ml²Ž¥PR©Ôd,‰T*(VYƲ¶±É2Vç®Ý„ßÿÚ`2Öw?ý, ù¾A¬jÕ« ¥Ÿÿ É IDATR)œñ»&T©Z-ËXVJ¥ ‹MÆ’Éå‚L.7«s×n‚H$T*U–±êÖ«'ì?vÊd¬&L¦L›a2Ö–]{„f-[eKeme¬Ô:KK,‘­Ú¶ÓÇ’H++e–±ÜÊ–nÜ{d2Ö[ý ¾Ë1K&— ¾ËÞê?Ðd¬÷ neËe+µ›Š•ÚÆMÅJ>™Š•ñ|Ê+ãù”1VÆóÉX,Sçî[ý =û¼%ˆÅâ,c™:wÓÇ*è~¬>)ú‰ìú¤Üô9퓊ºŸ‹ÅBƒ†>EÒOÄ2£Ÿp-S¦@û sú¤¼öæôIyí'Ìé“L»µë¼!tìÜ%_ú¤¼öæôIì'2÷õú"‘Èh¬‚Ì'LõIvöö–]{„ÀWá9þ'U(ppp„X,“‹ ""Ôprv†T&ƒƒƒ#Ô:ÎÎÎPªT°·w@ll agg[èt:ØÛÛC*‘@¥RA&•AecGgXYYÁÖÎ …NÎ.HNNNHJL4ËÎÞ ñ ¦c)UPXY™Œ%“Éàèè”e,Gg¨llLƲ³³ƒ££³A,¥ÊR©vöÊdprvÆ“ÇYÄr@Td¤ÉXÖÖÖ‰ÄFc9:»@ae{Çlb¥Ö­ñXŽŽ°¶±1K©RÁÙÙ9ËXŽŽNÐj4&cÙÚÙ!99Ù VbB"ra¥TÂÚÚÚd¬Çàäì ±Xb:–“3llìŒÆ‰Ä°±±ƒ£“éXb±NÎÎ 1+­›ˆ•ÚÆMÆJ>™ˆ•é|Ê+ãù”1VÆóÉX,“箓3"#ÔËå°²RšŽeâÜÍ« û sú¤¼öæôI¹é'rÞ'm? EJ{(ì~"}¬ìú‰'áèT°ý„9}Ržû 3ú¤¼öæôI¦Î]¥J™\aòÜÍiŸ”—~¬>‰ýD¦~B©TA&“ÁÖÎ.S¬‚Ì'LõI‰‰‰PªT¹ºš* |.ðó­Xâ‹è¨(L™6ƒ•Áºâq!¶ b{ Ãć©ˆˆˆˆˆ‰*U""""b¢JDDDDÄD•ˆˆˆˆ˜¨1Q%""""b¢JDDDDLT‰ˆˆˆˆ˜¨U"""""&ªDDDDÄD•ˆˆˆˆˆ‰*U""""b¢JDDDDÄD•ˆˆˆˆ˜¨Qà«pÕ`Ü’…óc0Íßï2’Ñ´y ƒéƒ† CÅÊ•Km]ݽs;·m1«®0æã l`… ðáClÞ°Ö¬ãbmc‹ñ“>c¥•`:óçüVkV›1z,ÜÜʲâJ°m›7âÁ½»fµ‡6í;fšFüüe¢Z„&Œ…víÌv9++%üoÝ…ÊÚºÔÖUxX×õ†F£ÉvÙÁï Ãÿæû²‚ؘ4¨U‰‰ Ù.Ûû­·±ø—U¬´nHÿ·pæÔ‰l—svvÁÅ·!‘HXi%تË0{æt³–ݵÿ0ê5hÈJãço¡âк÷êkÖrm;t,ÕI*89;£ió–f-Û³Ï[l\…ÄÚÆmÚw0kÙ½û²ÂJž}Ì;Î]º÷`’Z tëÙ "‘(ÛåÜ=<ðfý¬0~þ2Qµ$í:v‚µ hÞ}XYfÖƒ““3š¶hÉʲ°ãbccƒ¶:²²J.Ý{š•€ò‹KéàáYÁ¬´G¯>f%´ÄÏ_&ª…ÈÊÊ í;uÎf%:têÂÊJù”J¥Ù,ë4…­cç®P(¬²\¦}§.P(¬¬RÀœ«/ÎÎ.üBYª’œ¾ù² ñó—‰jÈnøŸÃþ9ûä°á3gøŸB¥KvÃÿüBYºd7üÏa~þ2Qµ`Ù ÿsØßüúà°¿eû—>Ù ÿó‹Ké’Ýð?‡ýùùËDÕ‚e5üÏa〦†x•¦èd5üÏaÿÒ'««/ö/­IN_~qáç/ÕâÊÔð?‡ýsöÈaÿ¢“Õð??„J'SÃÿüBY:™þç°??‹šÔ 5ç‡YUF™L†äädƒéZ¦ÐË:õ›o-¾î$’Ì߬¬”8yü_œ>yÜbO†âP·y‘ñ%ï “Épùây\õ¿\ê;ùìŽIhéÅÇÇC$A _¥U¢ö3¿Û@IúlËȵŒ‚_Ns-ƒ¹³¿ãñ-&Ç·¸|þæäXX\¢ºb‰/.?‹F>,*›¯X±"îß¿ÿzšTŠŠž€&¹ÐÊqåÚUÌý¦L›atþÒ…óqþôI4mÚ¬Hë«rÅŠ8™á°råÊë´€Nk‘صëײ¬ÛK|qáÌi4iÒ¤ØvÒ== ‘H M—°V¬X R…ÚŽ-‘¿¿?~ú~&¾œ>Óä2‹~þÉ"ίü¢”Iáî^ÏŸ?3ø@sws+•íáúYöyµðçŸphßÔôö¶Ø:pvrÌ”¨Ú¨”xòèA±?¾C$ØñÿÓl‹8¾r©$ÓP×2®xöø‘Å‹û÷ï#)) Ó¿›]<U¨Sç ¼óÎ@‹*S¹re1cÆëÞ¼ys¼÷ÞÂ-D¶÷² ðöö¶ˆº»qã:üüüÒþþàƒQhØÐrÑD,• »Ÿh«U»–ŵ˜ ¸ƒÓ§O§ý=|ø0´jÕ ¥V›ý/º‚Îbίü¢R)1þü´¿;uêˆÁƒ•Ê6 •Ë¡-Àßit:”+W||,¶ªU­ŠÛ·o§ýmooŽ;–ˆ©Ä¢‚½ÓQ§µœãûàÁ<|ø0íïvmÛÂËËËbŽEbBÎüc2K“&M T*ÓþnÛ¶-+% éëÇÞÞõêÕc¥XØqQ©TÅú 1å]«V­ ‹Ù¯ÀÁÁåË—Oû»víÚ|Ú¿ª]»¶A?_©R¥âý%ƒ‡Ô< …Íš5Ëô2ý˜ú@FúÿSÑjÞ¼9är9 Y³fiÿ§Ò›˜Ô¯_?íÿüBI铜Zµj±BŠ¡š5k¦}õöö6ø2ÊDµ„K½Úñê*ÿLýÐk×®+ÄB¨T*4nÜØ =û5~¡¤ŒÉ©½½½ÁÕU*>¬­­Ó®¢¦ÿâÁDµHMPùoþ ‡ý-ó¸pØŸR¥ÿ³_£Ô‹ åË—ç°1W»ví1ìXèÃT–J¡P M›6öÏÁàýû÷y•ÆÂ4oÞ~~~ö§´Ä¤mÛ¶üBIIN… XÅXÍš5Tì‡ý™¨æÂ¸qã8쟃À‘#G²",ŒJ¥ÂرcY”fâĉüBIiÞ|óM¨T*VD1fmm]bFI˜¨æ"ù"Ö ±=PINrˆÇÑRðU""""b¢JDDDDÄD•ˆˆˆˆ˜¨1Q%""""&ªdHû„•@l¯Ä¶BDTHJÌë©ú¿Ý°mûŽ,§e5=+7Ž¬ÃŠ?þÆò [ÌŠ€?–­Á…[“ …ÒÖ ƒç/FI Ñé]%¦®J;SǾ0qVíµ8ÖÝo .–íÐÚBIm+A×cÛ¾qón "bâ!UÚÀÃË-;öA5J\¿²tÉbÀø ³œ–ÕôœnŸØV˜¨#³Väìró´Ù8ü"&íïØÈTWJ°ù ãÓ©ä0uì-¹½²îJïþǶreãøq»Axý¥ &÷®ŸÇ½ëçqâòHüôI/•%:Q-¬«/ÆâŠ ŸµÝj¹ÚHeRÌ01½´ÔUipÀBqq®»âÚ>Ùò_ô£-˜½í2Äb+t|w4z´öAYgÔ¯pùØ.¬Úô/žüsëøàËåJt]äçU0^IÛŠ…âÎ’ ÓzÕ)©X©L™åt*ùÇžJ_ݱ-ä¿ Ë÷|8cûµƒ‡‹-¤" lœÜÑöíðÓØ†€ë7³²ˆJ€ýÕÞœû+ŸœÝ…?¶ĽáPغ fýÆèöÖ@¼QNi°ŒÛL¿Ýôq²Z>»í÷º2¶­ûÇ7ãÏGððedÖN¨Z×½¾‹zÖ&׉ ¼€ÕmÅ•{O‘(V¡bÍúèÖoZÖÈü3ñ/¯cÃÆ¸|ãÔñ\=½ÑcðèÚ l¡ß_kN[Ñ—ù¶nù¯ ,* {gÔ|³ ú¼3Þe”Y›ìêÆÜ2D=òÃŽ¿÷àÒÍ@„EÆÁÚ¹<ê7ë€!ƒ»ÃQ*2RÏWfsÊÕ±´¤6“¶:mãš0ï[_\‡òÞm1oÆiË&…ßöÍ;qþÊm„DÄAaã€ju¡×ÀwQ×Ýøo±›»NVe\·j4Þ½ rÛFذú«Ì1¢/àÝs Ux`ÝúÅHm2¹9÷sºŸ{ŸÇÞoíntÿË· ¬¸„äè %þÜœû ÃîùáÔ¥Šˆ…ÔÊî«à†áé Ïv[é§½º}§ün"$"…5Ü<+£~ãf¨à”ù~kML.]ôÃÇ/—©B…²ž^¨×¸)<³¸?;)â)Ο÷ã§AˆM`ëTo6mº•Jõ=´©ûž•ìê%?Û ÕBôüØRL^v º”ûœÃ_ââÑݸ|ü(MóE¿7øU&uõhïÏøòsi'G‡àú™ýøïüI øÊê;gZ'îå¿ølêr„kt)S"pù8îùŸC”ïoè^þõ‡\ÄíÝølæZD¥- ¼|èßÿ7/&/µÈz õÛŒÉs·"&]™“ÕA¸||7üÏÇÐi Ðë G£ëæ¤n²òìø*|±ì’u¯ïï‹|ˆã»~Ç¥‹X¼ðSاKV-¡Ì¦Ç6Ñö™?Ã/0Rÿ"éõC@Q÷bêôß’¬}]ï‘!¸rj®;…ASç£_ƒmåfc¬œº¡žíj\¾„³QIhngøA|f'À®ê»0ò½&Gç~N˼0»‡¾„$€HêXêûmõí#ØtäRÏtMl$ÞòÇ£;7Ѥ×øT°1k;!W÷aë©ûik¢ñôÞu<{€Æ=‡ QÅ×Û‰º-;N ZûúœÔÆGãñÝkxr?M{ FÃJ¶™ûŠþذó Ò÷K!8¹ç "º ã‡pDb+‹i+LTóÙ´_ŽÃ©Ng|4ü-xWpBLÐìÛ¸;Ï=Å–93Ðhõ"£WM³’ÝòÅõ)zsêÊSnøÈ7«/À®ZkŒÿ`ި삘 سn v_|ms¦¡É𥍠0l‚¿Ïú>Ý0¶w¼QÅÁ÷ü±záR\ KÀÖ'Ñ}~7€.ùf}¿QÜ÷Åø!½àUÎê§Øõ×Xðu¡×QvÇ^_þ¬OøÊ7í‹÷D•r¶ˆzù{7.Ãîóϱî‡/Qsõ2TSf>5Í©›lË{Ó–D²N@í®#0ê­¶pwáeÀe¬ö]Žk/Ncö–>˜ûn•B+³9ugŒ%¶sÛBz»C=0cÉ"Ôrð"AuZ›ô3¾ý¡{½ÝZÃÓYW·qæÈì8z›æ|‰Ú«A”zÏé:Ù•qPÛr¸úÏüsêš÷ð4˜wj÷3@õAÆŸ®7÷ÜÏÍ~fû{kÀ¶òÛ¥>ÙöïmX{¼-ÂÝÙ ‘Á¸~þ(üî‡ãâÞ¨<ú=8K³¿pûé°r«ŽmšÀÓÕ ‘Á¸vö0üFàÒÞmð=Î2 t5v싯†èج\¬öWÎÆ[Kõq4v4Èo¶Õ¿VîÎïXL[)¥ûÕ²±øÛ1¨[¹ d)Ë×Àɾè_ÍšÄXöÏS~UËC]‰šcÑìOРjÙ´u†NY„·¼ì¡MÆÒ¿3¯sïÍ0÷‹QhXÃr©<¼›ãÓY½õßÔ_ìI[îÅ‘Exš¨W?,œ2 Õ=!•ÈàZ©FO_‚.e“,® múÉ:ØyõÂÉÃPÃà R‰ N51t²¯¾^4!X¾ñ‘ÑõÍ­›,˰ù7Äjupi0³F÷F;H¥JxÖn…É?Ž<=¸Ö¢ÊlJqlÆÔ?uÝí UÚ£‚£þÊå³|ñ,Qƒ*ýgaʈž¨ìf©TòUëaà¸o0­ƒ;tšpüºéu½çf¬xöí xþÏqƒéÚ¤§ø;4"± ƒ«Úÿ`1óÜÏï2ë4aX¾ð<Ä2Œú¼%ûmû7ð^ß¶ðtµƒD,µc94ë6Ü”Ði"pôj˜yW쬫aHÿÎ¨äæ¶æÝßCCW%tÚ(¹¿rje÷C÷Võàj¯„D"ƒ£[E4nß½j9BÐÅâø…ƒíGÜ<„pV®>x·{ ”u²†D,«ÚôŠ7ì5<–é$„ßÀÎsú$Õ­~/´®fo1m…‰j>kõé ÈEÇ­Dè9¾­¾ƒ>p„gDêªñ¤‘°•dXG$AŸ‰m/ŸÈ´ÎÛCeš¦tí¬ÿ€Ô„¦M;û·þ$m;±/$™Š%ÇÀI­,®ÿ= hm´Ì¯ë%øô£ë›[7Y9qNÿÑáƒVF·µmûl\3Ó¢ÊlJqlÆt®™ùÞë_Æö5~Ųƻôõ~æHžÖɊ¡#ÛÊú_' ê›ë¬ tê‰òrã¯Ú2÷ÜÏÏ2 B6ý0·4n÷ýB4sV ´«Ñµ ¤Fúí7;zëåõ[fm§J—VPŠ3O1êwª™’hÞü§´kPÖèvÊ5k ˆºk÷þ}äݩęŠ+Eã.5@)_Æ´Q8°ý$´ ro„~-*[T[)¥zè¿»»ñûã”e:ØÄès>à™‘Ëºêéek|²]ü¤¨sFÌkh-Ëüm*å^3A—œ6íT„þjYç²Æ(Q•ï`¿EÕ¡_´¾Ì]ÜŒ?ù­J©—ä8£óÍ­›¬Ë _®³U±)³)ű ã­ÊÜ Ÿ‹ÒïÛCf¹nRÌå<­“þÝqq{ 6ÜPãkWÀõwõIG×Ö&×3÷ÜÏ·2 IØ9oö–ÅŒ¥3à]ÄXŠºÆ“u¹]þÐ$ÜÐ&Ûí¼éj¼¿;ÔpÚøûZá~¼þ>ãÍ¿,Ër{šÄ‡Ú§ý«ÿ"TÇÄq“;¾ à:(€ÿldz-¤ªŠx»o“Ì_Ò‹¸­„R}EÕUfüj€D¦¿q_ÐFó¬ÈC]yÈ’HS¾ª3ͳ1zÖež¢Ñwˆ.&ÈÊX\Fj…,ëRœR/‚6Îè|së&+ê”‡Žœ$âbSfSŠc0šP‹E&SvMTžÖÉŽGÏ>€ûýSŽs Ö?ÑŸëÛ–5½ž™ç~~”YÐÅcëÜIØt9ç}Ã$5[ç¹Xb›Rw fmÇIjâüë/`ètú71ÄjÍ<žZøÑ)¯q³›*¯&õƒ8ù0b± :ì{‰ØâÚJA(ÕWTÃ5:”‘e>8ÚäW)ª+ÏŒ<Ô•Z«CiëÈÊæº<b1BuZ'kándøQ›jquh/!\# $Ykð AÆzK ¬ ÖR"“¨µ:¸šqc¼%”¹$µœ§å›·=‡òkìÈíÚ …Ý/8ûäoƒFI›™¬ƒLY³x͹ç~^ˬ‰†5sfaÿ0Ôü3šºX^‹Õé`g$Ñi#SMÛ¹dwæv$hñwJ½¸4j—÷ÛD{íØ@?ôztmæ{J“"N¢ÿÛý0xØ·ERæÒÐÌÕ©¹þ¶…“ 7#Iȼw!þ«Ðÿí~õÅßyZÇœ¾Í½«þ5O`ýâk€Z«fY~sÏýÜ–9Ô+&L[†Àx[ ž²Ÿh’O7””,ÿ½aô8\:pª_ݼDõèu#ÛÑâòýýÊnMªjWÓѼ‘ãxK—,Æï› ûŸ)ýң׌žË׎Ü.ÕÇñáÉm¸•ÛJ-뱇E·&ªùÌúîFLõÝŒ{/ÕÐh“x«¾Ÿ€ýÏb UUŧ]^ÿòIê=};¯>Fm2ëÊD]¥Š¸½“lÀ½—Ðè4}|þo"þ Œ†Üö Ljé–ëò”ïò¼¬dˆ¼» Ÿ/\‡€çjht¨Ÿ`ýüIØþHbquXyð8ØËĈz¸ŸÍ[‹»ÏÔÐh5P? Àºy“°óQÄR{|0Ô+ϱLµ×*ÆÃJ,F𙘷ñ(‚£ h’ðìÎø~½P1Ý˵ ³Ì¥¡ ˜ËëÝà(#úé>|òÝJ\{„$M2ß¼€¿þŒÏ:‘XŽ¡S:åisú6¹]3´³W@§‰Æ‘‡Q‹\9ëa@sÏýÜ”9Q}_ÌÙŒD‰>›¿ý»3#5At[^@PD,´: ¢BŸâÄßkq]±¼ ºÔ1ï–¸ç°éÀ9EÄA«Ó":ôNíY‡«¡ Xy Su}‚êÚ´T¯aýîãx V‹ÐçpþØ>lÚ{Iм{ƒí;Öé W™ñA°éàY¼TÇB«Ó"Výç¬ÇåÒ›ªÄ<=‹ý7 ·«†Ýزüj+¡t¿ðÿ³®øø§-øê”áoBK­<ññ3 ÒhSF‰í/b°é‡IØ”2­¸½´¿°ê*Õ÷_ŽÂòkðÕ™m†ëXWÂÄŸ¾Ìüúšœ|Ã’º`ú÷£ðé×+ñäôL;ýúXˆDtùt1,ø"±å4q©Ò?}ñ¦ÌÝŒççwâëó; ÷Ib~_ÌAUÞï=2Õ^åvðã¸Î˜²â Îo[†óÛ ŸÎµõê€ozI™KC0¿­ÔÀÿ¦ Æ”9rý ¾ŸrÐ`¾H$F›~D[WežÖ1·oëÕÛÇÖê™HéÚÏäl9=÷sSæcsV"Z£ðó>še9JSmL¯®u±vÏl»køs²b™:ôïkòšŒúõhƒ£NaÛ½K†ÛQ¸ óÀži¯®’ÈËa@÷fؼ÷¢ŸÞÀß›odØ’5Û€w†_:Klѧ_lØv aw/cûÝË×ÓÞèònü •¾„Õÿ°~#)êþX~ÏäryýiÙüj+LTó™‹ÏûX0Ù+7ïÇýáÛ¹¢ŽOkôü*Ú~ð¾ýýT„.þ~wž"6Y€ƒ ëÊD]¥ònÔsy`éÂßqõa(ìʸ£^‹èÝ·ÊYå½éÙzuÆÒÅظi.^ @DLËWG÷AcÑ£¡-‰-ëiQ׆°ta lÞú._» uLlœ\Q­^stïóê”SæKœ¬Úk…c°Ô½&6ìØ«ˆIÔÁÑ­"µê‚ÁýÚÃ:ÈÂ*siifŸs ÞÆ²E5±mÛ?¸t-!‘Ñ+láY¥6:ô}ê•Í—uÌéÛÊu¬ýP¾w³lËž“s?§eÞòˆÖ˜}~TnÁÝlpüâu¼RÇBª´…Gåðiê¥ù#î^oâ÷qôà <ŽÒΪ×Fýµáá ¶•|0ì½²¸|é*>y‰èøˆ¤Vp*ãÚ š£vEã/§·*SCßsÄù þxøä%â4P9–Å›MÛáÍJV¸q‰”¥î&h‹U[)¢ÀWáu×åŠ%¾xõüF çoûf´yˈ¤rL™6Ãèü¥ çáÅ“@Œ3¦HËi ?›sƒ‡¹mclXýe¶Ëoݾ‚Hb²nW,ñÅóÇðÁ¨QlˆÅDNÚÀ†  –[áËé3M.ã;÷G¿|QäçWQHŠ:wGÎ…H$Æä?7¢‰‰'Ž‹ëODÀö» `²È«s~„ÿÅóèØ±£î½€¥K–aü„ ¯?S–,Η«uy¥MxŒ«vCbå…G÷ÌÕ6üüüáYÙ«ÀŽïϳ¿Ç5ÿKz|-ËéÓ§Q¡rÌøáf-_b®¨¶iÛ6íÿ'Ž/vóKR]…„éNmÛx]Îÿç0|2|h¦ÎPû Ûb žïêì„/Wo6héçÃÙ 6m@yrAÿ0“CÍQ&“T*XßÎ|ý%jÖÌ™ù:_§zÝoÏœ™ïÛÏnþÊeKð<$Ìäü +gSÊ̼ltû<ö;¿(ë¼D$ªm2$DÅíï’VW®ÎNiWU *Þ†‡bGP,BzuÂOKÿDÝêžPI€¶:â«Ñ½ðçγÐ>ýNà8Ûb ü{ÃÇCró)*O÷÷ gèIDATÅØú£nuOtïÜ»6ÿ GvâÏg†OF×a–“KaqÉPÅ?Æïë@$cð§íX)E”¨¤OòëoM\ÄJf}¿®ÎN*½1îƒNÏÔßÏCÂàêì…SU´kÓkgÎÄÌÓ†‡·ü°í`\Ðtðhø¸(yì‹ðï¢Pì‡þÛÂU;K¹Âš×¡ÿª«ŒÃQW±/ŽaògË’¬}}% å  £éàøüíºiëgUÏù1ô_RÛ¢¥ÎOm·‚B2ÿômàï%³=þú7.õ\€2Í&bùä¶f-Ï¡ÿÌr;ôÿm!\áL=oÜÆ€&®…~ïëOÞÁ¦Gî—­ ûugTmÚ]yæºþ‹ãÐÿ·EpuÛœùy•Ó¡Þ£ZŒðUCI‘±gÇ?8õ^¼R#I'‚µƒ3ªx×CÇîýÑ´†“ÙÛâ=ªÅS~µ&ªÆ}:z(‚bE¨Ö¨3&O;©ˆ‰j!'ªEÐ%aÓš5ˆˆM€Xaƒ 5ê£cË7!K÷“¾…yª&.Wý®âÁãçˆˆŠ…FA¡²A÷Ѝ]×UÊåí%÷¼GÕr”Ú{TÉrÖ‡”ÜÞ ýF~‚~¬òR‹m `-\µÖ"Ï}Ê;‘XŽÁ#Gg¹La>D%U•O«ÎðiÅcC†Ä¬""""b¢JDDDDÄD•ˆˆˆˆ˜¨1Q%""""&ªDDDDDLT‰ˆˆˆˆ˜¨U""""¢œ³È_¦º|ù’,¢,¶¶¶ˆŽŽ¶ˆ²Ü¾}ÍZµÉr™«W¯båÊ•ÙØT*âââ,²lwдEÖ?‰rÅß+µÚRÓ9Èd2$''—Š}½yóf¶ç–¥Ÿ_%¹ï+ wï¢Ió–#00GŽaP‚‚‚àYÙ«Ô_¥R‰øøx‹*ÓÓ§OQ¡r³—¾ ,­A­Xì A°ŒbYÛØ 6&Æbêæ£O>ÍrþòE -¶£°R*‘`a'LI©[~0üñt:¬X²¨ÔÔ‡¥õ}M$áÉ“ lû:KÌ+¶õ#W(”˜X|¯X„‰Ÿ}Q`Û×jµXºp>Ïc3Møl2Äbóõ-2Q%""""â=ªDDDDÄD•ˆˆˆˆˆ‰*1Q%""""b¢JDDDDLT‰ˆˆˆˆ˜¨1Q%""""&ªDDDDDLT‰ˆˆˆˆ‰*U""""b¢JDDDDÄD•ˆˆˆˆˆ‰*1Q%""""b¢JDDDDLT‰ˆˆˆˆ˜¨U"""""&ªDDDDDÙú?òçŒ x„iIEND®B`‚podofo-0.9.5/doc/html/0000775000175000017500000000000013044451161014373 5ustar dominikdominikpodofo-0.9.5/examples/0000775000175000017500000000000013044451162014501 5ustar dominikdominikpodofo-0.9.5/examples/CMakeLists.txt0000664000175000017500000000022611366377460017256 0ustar dominikdominikIF(BOOST_FOUND) SET(graph pdfcontentsgraph) ELSE(BOOST_FOUND) SET(graph) ENDIF(BOOST_FOUND) SUBDIRS( helloworld helloworld-base14 ${graph} ) podofo-0.9.5/examples/helloworld-base14/0000775000175000017500000000000013044451162017731 5ustar dominikdominikpodofo-0.9.5/examples/helloworld-base14/CMakeLists.txt0000664000175000017500000000133111366377460022504 0ustar dominikdominik# This is not a full standalone CMake configuration for the hello world # example. # # To build it outside the PoDoFo source tree, you must set your build system # make the PoDoFo headers available and must link to the PoDoFo library # and any libraries it depends on (see the README, # "5. Using PoDoFo in Your Application") . # # Note that you don't need the headers for PoDoFo's dependencies in your # header search path. ADD_EXECUTABLE(helloworld-base14 helloworld-base14.cpp) TARGET_LINK_LIBRARIES(helloworld-base14 ${PODOFO_LIB}) SET_TARGET_PROPERTIES(helloworld-base14 PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(helloworld-base14 ${PODOFO_DEPEND_TARGET}) INCLUDE_DIRECTORIES(${PoDoFo_SOURCE_DIR}) podofo-0.9.5/examples/helloworld-base14/helloworld-base14.cpp0000664000175000017500000002557213013650710023674 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ /* * Include the standard headers for cout to write * some output to the console. */ #include /* * Now include all podofo header files, to have access * to all functions of podofo and so that you do not have * to care about the order of includes. * * You should always use podofo.h and not try to include * the required headers on your own. */ #include /* * All podofo classes are member of the PoDoFo namespace. */ using namespace PoDoFo; void PrintHelp() { std::cout << "This is a example application for the PoDoFo PDF library." << std::endl << "It creates a small PDF file containing the text >Hello World!<" << std::endl << "Please see http://podofo.sf.net for more information" << std::endl << std::endl; std::cout << "Usage:" << std::endl; std::cout << " examplehelloworld [outputfile.pdf]" << std::endl << std::endl; } const char * GetBase14FontName(int i); void DemoBase14Fonts(PdfPainter& painter, PdfPage* pPage, PdfStreamedDocument& document); void HelloWorld( const char* pszFilename ) { /* * PdfStreamedDocument is the class that can actually write a PDF file. * PdfStreamedDocument is much faster than PdfDocument, but it is only * suitable for creating/drawing PDF files and cannot modify existing * PDF documents. * * The document is written directly to pszFilename while being created. */ PdfStreamedDocument document( pszFilename ); /* * PdfPainter is the class which is able to draw text and graphics * directly on a PdfPage object. */ PdfPainter painter; /* * This pointer will hold the page object later. * PdfSimpleWriter can write several PdfPage's to a PDF file. */ PdfPage* pPage; /* * A PdfFont object is required to draw text on a PdfPage using a PdfPainter. * PoDoFo will find the font using fontconfig on your system and embedd truetype * fonts automatically in the PDF file. */ PdfFont* pFont; try { /* * The PdfDocument object can be used to create new PdfPage objects. * The PdfPage object is owned by the PdfDocument will also be deleted automatically * by the PdfDocument object. * * You have to pass only one argument, i.e. the page size of the page to create. * There are predefined enums for some common page sizes. */ pPage = document.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); /* * If the page cannot be created because of an error (e.g. ePdfError_OutOfMemory ) * a NULL pointer is returned. * We check for a NULL pointer here and throw an exception using the RAISE_ERROR macro. * The raise error macro initializes a PdfError object with a given error code and * the location in the file in which the error ocurred and throws it as an exception. */ if( !pPage ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } /* * Set the page as drawing target for the PdfPainter. * Before the painter can draw, a page has to be set first. */ painter.SetPage( pPage ); /* * Create a PdfFont object using the font "Arial". * The font is found on the system using fontconfig and embedded into the * PDF file. If Arial is not available, a default font will be used. * * The created PdfFont will be deleted by the PdfDocument. */ pFont = document.CreateFont( "Helvetica" ); /* * If the PdfFont object cannot be allocated return an error. */ if( !pFont ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } /* * Set the font size */ pFont->SetFontSize( 18.0 ); /* * Set the font as default font for drawing. * A font has to be set before you can draw text on * a PdfPainter. */ painter.SetFont( pFont ); /* * You could set a different color than black to draw * the text. * * SAFE_OP( painter.SetColor( 1.0, 0.0, 0.0 ) ); */ /* * Actually draw the line "Hello World!" on to the PdfPage at * the position 2cm,2cm from the top left corner. * Please remember that PDF files have their origin at the * bottom left corner. Therefore we substract the y coordinate * from the page height. * * The position specifies the start of the baseline of the text. * * All coordinates in PoDoFo are in PDF units. * You can also use PdfPainterMM which takes coordinates in 1/1000th mm. * */ painter.DrawText( 56.69, pPage->GetPageSize().GetHeight() - 56.69, "Hello World!" ); DemoBase14Fonts(painter, pPage, document); painter.FinishPage(); /* * The last step is to close the document. */ document.Close(); } catch ( PdfError & e ) { /* * All PoDoFo methods may throw exceptions * make sure that painter.FinishPage() is called * or who will get an assert in its destructor */ try { painter.FinishPage(); } catch( ... ) { /* * Ignore errors this time */ } throw e; } } int main( int argc, char* argv[] ) { /* * Check if a filename was passed as commandline argument. * If more than 1 argument or no argument is passed, * a help message is displayed and the example application * will quit. */ if( argc != 2 ) { PrintHelp(); return -1; } /* * All podofo functions will throw an exception in case of an error. * * You should catch the exception to either fix it or report * back to the user. * * All exceptions podofo throws are objects of the class PdfError. * Thats why we simply catch PdfError objects. */ try { /* * Call the drawing routing which will create a PDF file * with the filename of the output file as argument. */ HelloWorld( argv[1] ); } catch( PdfError & eCode ) { /* * We have to check if an error has occurred. * If yes, we return and print an error message * to the commandline. */ eCode.PrintErrorMsg(); return eCode.GetError(); } /* * The PDF was created sucessfully. */ std::cout << std::endl << "Created a PDF file containing the line \"Hello World!\": " << argv[1] << std::endl << std::endl; return 0; } // Base14 + other non-Base14 fonts for comparison #define NUM_BASE14_FONTS 17 const char * GetBase14FontName(int i) { const char *base14fonts[NUM_BASE14_FONTS] = { "Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique", "Helvetica", "Helvetica-Bold", "Helvetica-Oblique", "Helvetica-BoldOblique", "Times-Roman", "Times-Bold", "Times-Italic", "Times-BoldItalic", "Symbol", "ZapfDingbats", "Arial", "Times New Roman", "Verdana" }; if (i >= 0 && i < NUM_BASE14_FONTS) return base14fonts[i]; else return NULL; } void DrawRedFrame(PdfPainter& painter, double x, double y, double width, double height) { // draw red box painter.SetColor(1.0f, 0.0f, 0.0f); painter.SetStrokingColor(1.0f, 0.0f, 0.0f); painter.DrawLine(x, y, x+width, y); if ( height > 0.0f ) { painter.DrawLine(x, y, x, y+height); painter.DrawLine(x+width, y, x+width, y+height); painter.DrawLine(x, y+height, x+width, y+height); } // restore to black painter.SetColor(0.0f, 0.0f, 0.0f); painter.SetStrokingColor(0.0f, 0.0f, 0.0f); } void DemoBase14Fonts(PdfPainter& painter, PdfPage* pPage, PdfStreamedDocument& document) { double x = 56,y = pPage->GetPageSize().GetHeight() - 56.69; char text[255]; const char *demo_text = "abcdefgABCDEFG12345!#$%&+-@? "; double height=0.0f, width=0.0f; int i; // draw sample of all types for(i = 0; i < NUM_BASE14_FONTS; ++i) { x = 56; y = y - 25; strcpy(text, demo_text); strcat(text, GetBase14FontName(i)); PdfFont *pFont = document.CreateFont( GetBase14FontName(i) ); pFont->SetFontSize( 12.0 ); painter.SetFont( pFont ); width = pFont->GetFontMetrics()->StringWidth(text); height = pFont->GetFontMetrics()->GetLineSpacing(); std::cout << GetBase14FontName(i) << " Width = " << width << " Height = " << height << std::endl; // draw red box DrawRedFrame( painter, x, y, width, height); // draw text painter.DrawText( x, y , text); } // draw some individual characters: const char *demo_text2 = " @_1jiPlg .;"; int nChars = strlen(demo_text2); // draw individuals for(i = 0; i < nChars; i++) { x = 56; y = y - 25; if ( i==0 ) { strcpy(text, "Helvetica / Arial Comparison:"); } else { text[0] = demo_text2[i]; text[1] = '\0'; } PdfFont *pFont = document.CreateFont("Helvetica"); painter.SetFont( pFont ); height = pFont->GetFontMetrics()->GetLineSpacing(); width = pFont->GetFontMetrics()->StringWidth(text); // draw red box DrawRedFrame( painter, x, y, width, height); // draw text painter.DrawText( x, y , text); if ( i>0 ) { // draw again, with non-Base14 font PdfFont *pFont2 = document.CreateFont("Arial"); painter.SetFont( pFont2 ); height = pFont2->GetFontMetrics()->GetLineSpacing(); width = pFont2->GetFontMetrics()->StringWidth(text); // draw red box DrawRedFrame( painter, x+100, y, width, height); // draw text painter.DrawText( x+100, y , text); } } } podofo-0.9.5/examples/pdfcontentsgraph/0000775000175000017500000000000013044451162020052 5ustar dominikdominikpodofo-0.9.5/examples/pdfcontentsgraph/CMakeLists.txt0000664000175000017500000000045711235544613022624 0ustar dominikdominikADD_EXECUTABLE(pdfcontentsgraph PdfContentsGraph.cpp main.cpp) TARGET_LINK_LIBRARIES(pdfcontentsgraph ${PODOFO_LIB}) SET_TARGET_PROPERTIES(pdfcontentsgraph PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(pdfcontentsgraph ${PODOFO_DEPEND_TARGET}) INCLUDE_DIRECTORIES(${PoDoFo_SOURCE_DIR}) podofo-0.9.5/examples/pdfcontentsgraph/PdfContentsGraph.cpp0000664000175000017500000004435013013650710023771 0ustar dominikdominik#include "PdfContentsGraph.h" #if !defined(PODOFO_HAVE_BOOST) #error This module requires boost::graph #endif #include #include #include #include #include #include #include using namespace std; using namespace boost; using namespace PoDoFo; // Enable some more verbose debugging output #if !defined(DEBUG_CONTENTS_GRAPH) //#define DEBUG_CONTENTS_GRAPH #endif namespace { // // This static structure describes the content stream keywords PoDoFo knows // about. Anything unrecognised will be assumed to be standalone keyword that // doesn't open or close a scope. // // See PDF Reference, table, 4.1, "Operator categories". // static const PdfContentsGraph::KWInfo kwInfo[] = { { PdfContentsGraph::KT_Standalone, KW_m, KW_Undefined, "m", "MoveTo" }, { PdfContentsGraph::KT_Standalone, KW_l, KW_Undefined, "l", "LineTo" }, { PdfContentsGraph::KT_Opening, KW_q, KW_Q, "q", "Save State" }, { PdfContentsGraph::KT_Closing, KW_Q, KW_Undefined, "Q", "Restore State" }, { PdfContentsGraph::KT_Opening, KW_ST, KW_ET, "BT", "Begin Text" }, { PdfContentsGraph::KT_Closing, KW_ET, KW_Undefined, "ET", "End Text" }, { PdfContentsGraph::KT_Opening, KW_BDC, KW_EMC, "BDC", "Begin marked content" }, { PdfContentsGraph::KT_Opening, KW_BMC, KW_EMC, "BMC", "Begin marked content with property list" }, { PdfContentsGraph::KT_Closing, KW_EMC, KW_Undefined, "EMC", "End marked content" }, // Sentinel { PdfContentsGraph::KT_Undefined, KW_Undefined, KW_Undefined, "\0", NULL } }; // // This value is returned when an unknown keyword is encountered. // static const PdfContentsGraph::KWInfo kwInfoUnknown = { PdfContentsGraph::KT_Standalone, KW_Unknown, KW_Undefined, "\0", NULL }; // This function populates kwNameMap at startup, permitting use to look up // KWInfo structures by keyword string value. map generateKWNameMap() { map m; const PdfContentsGraph::KWInfo* ki = &(kwInfo[0]); do { m.insert( pair(ki->kwText,ki) ); ki ++; } while ( ki->kt != PdfContentsGraph::KT_Undefined ); return m; } // This function populates kwIdMap at startup, permitting use to look up KWInfo // structures by keyword enum value. map generateKWIdMap() { map m; const PdfContentsGraph::KWInfo* ki = &(kwInfo[0]); do { m.insert( pair(ki->kw,ki) ); ki ++; } while ( ki->kt != PdfContentsGraph::KT_Undefined ); return m; } // Mapping table from keyword string value to KWInfo static const map kwNameMap = generateKWNameMap(); // Mapping table from keyword enum value to KWInfo static const map kwIdMap = generateKWIdMap(); // Visitor used by KWInstance to convert any stored variant to a string. // kw == KW_Unknown indicates that it should be a no-op, ie return "" struct KWIVariantAsStringVisitor : public static_visitor { string operator()(const std::string& s) const { return s; } string operator()(PdfContentStreamKeyword kw) const { if (kw == KW_Undefined) // Variant has no value return string(); PODOFO_RAISE_LOGIC_IF(kw == KW_Unknown, "Variant in invalid state(may not contain KW_Unknown)"); return PdfContentsGraph::findKwById(kw).kwText; } }; // Visitor used by KWInstance to convert any stored variant to a PdfContentStreamKeyword . // If the variant contains a string that's not a keyword known to podofo, returns KW_Unknown. struct KWIVariantAsIdVisitor : public static_visitor { PdfContentStreamKeyword operator()(PdfContentStreamKeyword kw) const { return kw; } PdfContentStreamKeyword operator()(const std::string& s) const { return PdfContentsGraph::findKwByName(s).kw; } }; // boost graph depth_first_search visitor that prints each node's keyword and // arguments to the provided stream in proper content stream format. // // The `arriving' param is set to true if the // variant visitor this graph visitor invokes is being called on node discovery // (in which case EV must be boost::on_discover_vertex) // and false if it's being called on node exit // (in which case EV must be boost::on_finish_vertex ). template class PrintVertexVisitor { PdfOutputStream * m_os; public: PrintVertexVisitor(PdfOutputStream* os) : m_os(os) { } typedef EV event_filter; void operator()(const PdfContentsGraph::Vertex & v, const PdfContentsGraph::Graph & g) { const PdfContentsGraph::KWInstance& i ( Arriving ? g[v].first : g[v].second ); if (!i.IsRootNode()) i.PrintToStream( *m_os ); } }; // This routine is useful in debugging and error reporting. It formats // the values associated with the passed stack of vertices into a // space-separated string, eg "BT g g g" string formatReversedStack( const PdfContentsGraph::Graph & g, stack s, ostream& os) { vector l; while ( s.size() > 1 ) { l.push_back(s.top()); s.pop(); } while ( l.size() ) { os << g[l.back()].first.GetKwString() << ' '; l.pop_back(); } return string(); } #if defined(DEBUG_CONTENTS_GRAPH) // // This debuging routine prints the current context stack to stderr. // void PrintStack( const PdfContentsGraph::Graph & g, const stack & s, const string & prefix) { PdfOutputDevice outDev( &cerr ); PdfDeviceOutputStream outStream( &outDev ); ostringstream ss; ss << prefix << ' ' << (s.size() - 1) << ' '; formatReversedStack(g,s,ss); ss << '\n'; string out = ss.str(); outStream.Write( out.data(), out.size() ); } #else // Do nothing ; this will inline away nicely and avoids the need for debug // ifdefs or ugly macros. inline void PrintStack( const PdfContentsGraph::Graph &, const stack &, const string &) { } #endif // // Format an error message reporting an open/close operator mismatch error. // std::string formatMismatchError( const PdfContentsGraph::Graph & g, const stack & s, int tokenNumber, PdfContentStreamKeyword gotKW, PdfContentStreamKeyword expectedKW) { // Didn't find matching opening operator at top of stack. ostringstream err; err << "Found mismatching opening/closing operators at token number " << tokenNumber << ". Got: " << PdfContentsGraph::findKwById(gotKW).kwText << ", expected " << PdfContentsGraph::findKwById(expectedKW).kwText << ". Context stack was: "; formatReversedStack(g,s,err); err << '.'; return err.str(); } // Read ahead to try to find an ordering of close operators that satisfies // the requirements of the standard. bool closeFixup( PdfContentsGraph::Graph & g, stack & s, PdfContentsTokenizer & contentsTokenizer, const PdfContentsGraph::KWInfo& badKw ) { // For now we only look ahead one operator, since that's good enough // to let use read the PDF references etc. EPdfContentsType t; const char * kwText; PdfVariant var; bool readToken; // Save a copy of the stack so we can put it back how it was if // our readahead fixup fails. stack s_copy ( s ); // Next item must be a close keyword if ( ( readToken = contentsTokenizer.ReadNext(t, kwText, var) ) ) { if ( t == ePdfContentsType_Keyword ) { const PdfContentsGraph::KWInfo & ki ( PdfContentsGraph::findKwByName(kwText) ); if ( ki.kt == PdfContentsGraph::KT_Closing ) { // We know that the waiting close keyword, badKw, // doesn't match the open keyword on the top of the stack. // If the one we just read does, and badKw matches the // context open outside that, we're OK. PdfContentsGraph::NodeData & n1 ( g[s.top()] ); if ( ki.kw == n1.first.GetKwInfo().kwClose ) { // The keyword we just read was the right one to // close the top context. n1.second.SetKw( ki.kw ); s.pop(); // Leaving us with the newly exposed outer context // node and the old keyword. See if it matches. PdfContentsGraph::NodeData & n2 ( g[s.top()] ); if ( badKw.kw == n2.first.GetKwInfo().kwClose ) { // The old keyword matches the newly exposed // node's close keyword, so everything's OK. n2.second.SetKw( badKw.kw ); s.pop(); // Fixup succeeded return true; } // Whoops, failed. Restore the copied stack // so error reports don't show the effects of the // lookahead. s = s_copy; } } } } // Fixup attempt failed return false; } } // end anon namespace namespace PoDoFo { const PdfContentsGraph::KWInfo& PdfContentsGraph::findKwByName(const string & kwText) { static const map::const_iterator itEnd = kwNameMap.end(); map::const_iterator it = kwNameMap.find(kwText); if (it == itEnd) return kwInfoUnknown; else return *((*it).second); } const PdfContentsGraph::KWInfo& PdfContentsGraph::findKwById(PdfContentStreamKeyword kw) { if ( kw == KW_RootNode ) { PODOFO_RAISE_ERROR_INFO(ePdfError_InvalidEnumValue, "Cannot get KWInfo for root node"); } static const map::const_iterator itEnd = kwIdMap.end(); map::const_iterator it = kwIdMap.find(kw); if ( it == itEnd) { PODOFO_RAISE_ERROR_INFO(ePdfError_InvalidEnumValue, "Bad keyword ID"); } return *((*it).second); } PdfContentsGraph::PdfContentsGraph() : m_graph() { // Init the root node, leaving an otherwise empty graph. Vertex v = add_vertex(m_graph); m_graph[v] = MakeNode(KW_RootNode,KW_RootNode); } PdfContentsGraph::PdfContentsGraph( PdfContentsTokenizer & contentsTokenizer ) : m_graph() { EPdfContentsType t; const char * kwText; PdfVariant var; bool readToken; // Keep a count of the number of tokens read so we can report errors // more usefully. int tokenNumber = 0; // Set up the node stack and initialize the root node stack parentage; parentage.push( add_vertex(m_graph) ); m_graph[parentage.top()] = MakeNode(KW_RootNode,KW_RootNode); // Arguments to be associated with the next keyword found vector args; while ( ( readToken = contentsTokenizer.ReadNext(t, kwText, var) ) ) { ++tokenNumber; if (t == ePdfContentsType_Variant) { // arguments come before operators, but we want to group them up before // their operator. args.push_back(var); } else if (t == ePdfContentsType_Keyword) { const KWInfo & ki ( findKwByName(kwText) ); if (ki.kt != KT_Closing) { // We're going to need a new vertex, so make sure we have one ready. Vertex v = add_vertex( m_graph ); // Switch any waiting arguments into the new node's data. m_graph[v].first.GetArgs().swap( args ); PODOFO_ASSERT( !args.size() ); if (ki.kw == KW_Unknown) { // No idea what this keyword is. We have to assume it's an ordinary // one, possibly with arguments, and just push it in as a node at the // current level. PODOFO_ASSERT( !m_graph[v].first.IsDefined() ); m_graph[v].first.SetKw( string(kwText) ); add_edge( parentage.top(), v, m_graph ); PODOFO_ASSERT( m_graph[v].first.GetKwId() == ki.kw ); PODOFO_ASSERT( m_graph[v].first.GetKwString() == kwText ); } else if (ki.kt == KT_Standalone) { // Plain operator, shove it in the newly reserved vertex (which might already contain // arguments) and add an edge from the top to it. PODOFO_ASSERT( ki.kw != KW_Undefined && ki.kw != KW_Unknown && ki.kw != KW_RootNode ); PODOFO_ASSERT( !m_graph[v].first.IsDefined() ); m_graph[v].first.SetKw( ki.kw ); add_edge( parentage.top(), v, m_graph ); PODOFO_ASSERT( m_graph[v].first.GetKwId() == ki.kw ); PODOFO_ASSERT( m_graph[v].first.GetKwString() == kwText ); } else if (ki.kt == KT_Opening) { PrintStack(m_graph, parentage, "OS: "); PODOFO_ASSERT( ki.kw != KW_Undefined && ki.kw != KW_Unknown && ki.kw != KW_RootNode ); PODOFO_ASSERT( !m_graph[v].first.IsDefined() ); m_graph[v].first.SetKw( ki.kw ); // add an edge from the current top to it add_edge( parentage.top(), v, m_graph ); // and push it to the top of the parentage stack parentage.push( v ); PODOFO_ASSERT( m_graph[v].first.GetKwId() == ki.kw ); PODOFO_ASSERT( m_graph[v].first.GetKwString() == kwText ); PrintStack(m_graph, parentage, "OF: "); } else { PODOFO_ASSERT( false ); } } else if (ki.kt == KT_Closing) { // This keyword closes a context. The top of the parentage tree should // be a node whose KWInstance is the matching opening keyword. We'll check // that, then set the second KWInstance appropriately. PrintStack(m_graph, parentage, "CS: "); PODOFO_ASSERT( ki.kw != KW_Undefined && ki.kw != KW_Unknown && ki.kw != KW_RootNode ); // Get a reference to the node data for the current parent NodeData & n ( m_graph[parentage.top()] ); PODOFO_RAISE_LOGIC_IF( n.second.IsDefined(), "Closing already closed group" ); // Ensure that the opening keyword therein is one that this closing keyword is // a valid match for PdfContentStreamKeyword expectedCloseKw = n.first.GetKwInfo().kwClose; // Ensure there aren't any args to the close kw PODOFO_ASSERT( !args.size() ); // and handle the close matching if ( ki.kw != expectedCloseKw ) { // Some PDFs, even Adobe ones, place close operators // in the wrong order. We'll do some lookahead to see // if we can fix things up before we hit a non-close // operator. if ( !closeFixup( m_graph, parentage, contentsTokenizer, ki ) ) { string err = formatMismatchError(m_graph, parentage, tokenNumber, ki.kw, expectedCloseKw); PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidContentStream, err.c_str() ); } } else { n.second.SetKw( ki.kw ); // Our associated operator is now on the top of the // parentage stack. Since its scope has ended, it should // also be popped. parentage.pop(); } PrintStack(m_graph, parentage, "CF: "); } else { PODOFO_ASSERT( false ); } } else { PODOFO_ASSERT( false ); } } PODOFO_RAISE_LOGIC_IF( args.size(), "Stream ended with unconsumed arguments!" ); PODOFO_RAISE_LOGIC_IF( parentage.size() != 1, "Stream failed to close all levels" ); } void PdfContentsGraph::Write(PdfOutputStream& outStream) { typedef pair,PrintVertexVisitor > EVList; dfs_visitor vis = make_dfs_visitor( EVList( PrintVertexVisitor(&outStream), PrintVertexVisitor(&outStream) ) ); depth_first_search(m_graph, visitor(vis)); } void PdfContentsGraph::WriteToStdErr() { PdfOutputDevice outDev( &cerr ); PdfDeviceOutputStream outStream( &outDev ); Write(outStream); } string PdfContentsGraph::KWInstance::GetKwString() const { return boost::apply_visitor( KWIVariantAsStringVisitor(), m_keyword ); } PdfContentStreamKeyword PdfContentsGraph::KWInstance::GetKwId() const { return boost::apply_visitor( KWIVariantAsIdVisitor(), m_keyword ); } void PdfContentsGraph::KWInstance::PrintToStream(PdfOutputStream& os, const char * szSepStr, long lStrLen) const { string s; if (m_args.size()) { typedef vector::const_iterator Iter; const Iter itEnd = m_args.end(); Iter it = m_args.begin(); while ( it != itEnd ) { (*it).ToString(s); os.Write(s.data(), s.size()); os.Write(szSepStr,lStrLen); ++it; } } s = GetKwString(); os.Write(s.data(), s.size()); os.Write(szSepStr,lStrLen); } }; // namespace PoDoFo podofo-0.9.5/examples/pdfcontentsgraph/README.txt0000664000175000017500000000202611032100623021534 0ustar dominikdominikPdfContentsGraph is a demo that uses the Boost::Graph library to construct a graph of the PDF contents stream(s) that can then be operated on with the usual BGL facilities for graph walking and modification. At present the graph code is incomplete; it makes some assumptions about the structure of PDF content streams that the standard does not require to be true, so it may fail to parse some content streams. The test code in main.cpp parses the stream into a graph. It then walks the graph, using PdfContentsTokenizer to read through the original stream and compare each reached node in the graph to the matching token in the stream. If the graph reflects the content stream and is being walked correctly then the sequence of nodes walked in the graph should match the sequence of tokens read from the stream by PdfContentsTokenizer. This isn't exactly an exciting application. It should be possible to build more useful applications, like a PDF contents stream validator, from the same base. -- Craig Ringer podofo-0.9.5/examples/pdfcontentsgraph/main.cpp0000664000175000017500000000416213013650710021501 0ustar dominikdominik#include "podofo.h" #include "PdfContentsGraph.h" #include #include #include #include #include #include using namespace std; using namespace PoDoFo; void usage() { printf("Usage: pdfcontentgraph [-a] input_filename\n"); printf(" -a Process all pages of input, not just first\n"); } int main( int argc, char* argv[] ) { bool all_pages = false; int firstPageNo = 0; string inputFileName; ++argv; --argc; while (argc) { if( argv[0][0] == '-' ) { // Single character flag switch( argv[0][1] ) { case 'a': // Process all pages, not just first page all_pages = true; break; default: usage(); return 1; } } else { // Input filename if (inputFileName.empty()) { inputFileName = argv[0]; } else { usage(); return 1; } } ++argv; --argc; } if (inputFileName.empty()) { usage(); return 1; } try { PdfMemDocument doc( inputFileName.c_str() ); if( !doc.GetPageCount() ) { std::cerr << "This document contains no page!" << std::endl; return 1; } int toPage = all_pages ? doc.GetPageCount() : firstPageNo + 1 ; for ( int i = firstPageNo; i < toPage; ++i ) { cout << "Processing page " << setw(6) << (i+1) << "..." << std::flush; PdfPage* page = doc.GetPage( i ); PODOFO_RAISE_LOGIC_IF( !page, "Got null page pointer within valid page range" ); PdfContentsTokenizer tokenizer( page ); PdfContentsGraph grapher( tokenizer ); cout << " - page ok" << endl; } } catch( PdfError & e ) { e.PrintErrorMsg(); return e.GetError(); } cout << endl; return 0; } podofo-0.9.5/examples/pdfcontentsgraph/PdfContentsGraph.h0000664000175000017500000002433411541741676023456 0ustar dominikdominik#ifndef _PODOFO_PDFCONTENTSGRAPH_H #define _PODOFO_PDFCONTENTSGRAPH_H #include "podofo/podofo.h" #if defined(PODOFO_HAVE_BOOST) #include #include #include #include #include namespace PoDoFo { class PdfInputStream; class PdfOutputStream; class PdfContentsTokenizer; enum PdfContentStreamKeyword { // Special node for undefined/unset value. Should never get used except when default-constructing // a node variant. KW_Undefined = 0, // Normal PDF operators KW_q, KW_Q, KW_ST, KW_ET, KW_BMC, KW_BDC, KW_EMC, KW_m, KW_l, // Special node with no associated keyword, used to identify the root node that anchors // the graph. KW_RootNode = 0xfe, // Value returned by findKwByName(...) when no enum for the keyword is known. KW_Unknown = 0xff }; /** * PdfContentsGraph provides a concrete representation of a content stream as an * in-memory graph. It can be created as a blank structure to be populated by hand, * or from an existing content stream via PdfContentsTokenizer . It can serialize * its state as a PDF content stream. * * This class does not track the resources used by the content stream. \see PdfCanvas . * * This class is only available when the Boost library, specifically the boost graph * library, has been configured for use. */ class PdfContentsGraph { public: /** * The KWType enumeration is used to identify whether a given keyword * should be expected to open or close a new scope (think q/Q pairs) or * whether it's just a plain unscoped operator. */ enum KWType { KT_Undefined = 0, /**< Only used for sentinel */ KT_Standalone, /**< Keyword doesn't open or close a scope. */ KT_Opening, /**< Keyword opens a new scope. */ KT_Closing /**< Keyword closes an open scope. */ }; /** * KWInfo describes a single PDF keyword's characteristics. See kwInfo[] . */ struct KWInfo { /// Keyword type ( ends scope, begins scope, or scope neutral ) KWType kt; /// Keyword ID (enum) PdfContentStreamKeyword kw; /// ID enum of context closing keyword (only to be set if this /// is a context opening keyword), eg KW_Q if kw = KW_q . PdfContentStreamKeyword kwClose; /// null-terminated keyword text const char kwText[6]; /// Short description text (optional, set to NULL if undesired). const char * kwDesc; }; // KWInstance stores a keyword and any associated arguments. The keyword // may be stored as an enumerated ID (if it's known to PoDoFo) or a string // (if it's not). class KWInstance { typedef boost::variant KWVariant; typedef std::vector KWArgs; KWVariant m_keyword; KWArgs m_args; public: /** Construct a default(KW_Undefined) KWInstance */ KWInstance() : m_keyword(KW_Undefined) { } /** Construct a KWInstance from an enum id. \see SetKw */ KWInstance(PdfContentStreamKeyword kw) : m_keyword(kw) { if (kw == KW_Undefined) PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidEnumValue, "Cannot explicitly init KWInstance to KW_Undefined"); } /** Construct a KWInstance from a string. \see SetKw */ KWInstance(const std::string& kwStr) { SetKw(kwStr); } /** True iff this instance is defined. */ bool IsDefined() const { return GetKwId() != KW_Undefined; } /** True iff this is a root node object. */ bool IsRootNode() const { return GetKwId() == KW_RootNode; } /** Return a string representation of the keyword (as it will appear in a content stream). */ std::string GetKwString() const; /** Returns KW_Unknown if we're a string-based KWInstance for an unknown keyword */ PdfContentStreamKeyword GetKwId() const; /** * Returns a reference to the KWInfo structure for this keyword, or the * special kwInfoUnknown structure (kw=KW_Unknown, * kwType=KT_Standalone) if the keyword is not known. If !IsDefined(), * returns a record with kw=KW_Undefined and kwType=KT_Undefined . * * \see findKwById \see findKwByName */ const KWInfo& GetKwInfo() const { return findKwById(GetKwId()); } /** return a reference to the argument array of this keyword */ KWArgs & GetArgs() { return m_args; } /** Return a reference to the argument array of this keyword. */ const KWArgs & GetArgs() const { return m_args; } /** * Set this keyword to the string `str'. If `str' is recognised by PoDoFo, * it'll be converted to a keyword enum. */ inline void SetKw(const std::string& kwStr); /** Set this keyword to the enum value kw */ void SetKw(PdfContentStreamKeyword kw) { m_keyword = kw; } /** Print this keyword and its arguments to the passed stream in proper content stream format. * If the node is of type KW_Undefined this is a no-op, so it's always safe to call on both sides * of a NodeData pair. * An optional whitespace string `szSepStr' may be provided to override the newline that's * normally written after each argument and keyword. The provided length must NOT include the * trailing NULL (if any); */ void PrintToStream(PdfOutputStream& os, const char * szSepStr = " ", long lSepLen = 1L ) const; }; // Each node actually has two values. Internal nodes have both defined, with the first being the // keyword opening the context and the second being the keyword closing the context. Leaf nodes // have only the first defined (the keyword and its arguments) with the second being undefined. typedef std::pair NodeData; typedef boost::adjacency_list Graph; typedef boost::graph_traits::vertex_descriptor Vertex; /** * Construct a new, blank PdfContentsGraph */ PdfContentsGraph(); /** * Construct a PdfContentsGraph from a PdfContentsTokenizer's output. */ PdfContentsGraph(PdfContentsTokenizer & contentsTokenizer); /** * Destroy the PdfContentsGraph. */ ~PdfContentsGraph() { } /** * Serialize the PdfContentsGraph to the passed output stream. * The output format is valid PDF content stream data. */ void Write(PdfOutputStream& outStream); /** * For quick and easy debugging, serialize the graph to stderr as * a PDF content stream. */ void WriteToStdErr(); /** * Look up a keyword string and return a reference to the associated * keyword info struct If the keyword string is not known, return * a reference to the special kwInfoUnknown structure that sets: * * kwType = PdfContentsGraph::KT_Standalone * kw = KW_Unknown * * (The rest of the members should not be relied upon). */ static const KWInfo& findKwByName(const std::string & kwText); /** * Look up an operator code and return the associated keyword string. All * defined enums MUST exist in kwIdMap . */ static const KWInfo& findKwById(PdfContentStreamKeyword kw); /** * Provide access to the internal graph used by ContentStreamGraph to * represent the content stream. The caller may safely modify this graph * so long as: * * - No cyclic references are created, ie it remains a simple tree * - The root node is not altered/removed/replaced * - All internal nodes (ie nodes with children) have variant type * KWPair, where the first value in the pair is the PdfContentStreamKeyword * for a valid context opening keyword, and the second in the pair is the * corresponding closing keyword. * - Nodes of variant type PdfContentStreamKeyword must not contain a context * opening or closing keyword. * * You can use the findKwById and findKwByName functions to determine the attributes * of a keyword - for example, whether it's a context opening / closing keyword. * * For many complex operations on PDF content streams you will want to modify this * graph directly or use it as input for one of the Boost Graph Library algorithms * in combination with a custom visitor. To see how this works, have a look at the * implementation of this class's Write(...) method. Another example can be found in * test/ContentsParser. * * \see findKwById \see findKwByName */ PODOFO_NOTHROW Graph & GetGraph() { return m_graph; } /** * Provide access to a read only view of the internal graph. * * \see GetGraph() */ PODOFO_NOTHROW const Graph & GetGraph() const { return m_graph; } /** * Return a string-formatted version of the passed KWInstance. */ static std::string formatVariant( const KWInstance& var ); /** * Make a KWNode from a pair of possible keyword values (each of which may * be a type convertable to std::string or a PdfContentStreamKeyword) */ template std::pair MakeNode( const T1 & kw1, const T2 & kw2 ) { return std::pair(kw1,kw2); } /** * Make a KWNode from a possible keyword value ( a type convertable to * std::string or a PdfContentStreamKeyword ), with the second part of * the node being KW_Undefined. */ template std::pair MakeNode( const T1 & kw ) { return std::pair(kw,KWInstance()); } private: // private member variables Graph m_graph; }; /** * Set this keyword to the string `str'. If `str' is recognised by PoDoFo, * it'll be converted to a keyword enum. */ inline void PdfContentsGraph::KWInstance::SetKw(const std::string& kwStr) { const KWInfo& kwInfo = findKwByName(kwStr); if (kwInfo.kw == KW_Unknown) m_keyword = kwStr; else m_keyword = kwInfo.kw; } } // namespace PoDoFo #endif // defined(PODOFO_HAVE_BOOST) #endif podofo-0.9.5/examples/helloworld/0000775000175000017500000000000013044451162016654 5ustar dominikdominikpodofo-0.9.5/examples/helloworld/helloworld.cpp0000664000175000017500000002131613013650710021532 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ /* * Include the standard headers for cout to write * some output to the console. */ #include /* * Now include all podofo header files, to have access * to all functions of podofo and so that you do not have * to care about the order of includes. * * You should always use podofo.h and not try to include * the required headers on your own. */ #include /* * All podofo classes are member of the PoDoFo namespace. */ using namespace PoDoFo; void PrintHelp() { std::cout << "This is a example application for the PoDoFo PDF library." << std::endl << "It creates a small PDF file containing the text >Hello World!<" << std::endl << "Please see http://podofo.sf.net for more information" << std::endl << std::endl; std::cout << "Usage:" << std::endl; std::cout << " examplehelloworld [outputfile.pdf]" << std::endl << std::endl; } void HelloWorld( const char* pszFilename ) { /* * PdfStreamedDocument is the class that can actually write a PDF file. * PdfStreamedDocument is much faster than PdfDocument, but it is only * suitable for creating/drawing PDF files and cannot modify existing * PDF documents. * * The document is written directly to pszFilename while being created. */ PdfStreamedDocument document( pszFilename ); /* * PdfPainter is the class which is able to draw text and graphics * directly on a PdfPage object. */ PdfPainter painter; /* * This pointer will hold the page object later. * PdfSimpleWriter can write several PdfPage's to a PDF file. */ PdfPage* pPage; /* * A PdfFont object is required to draw text on a PdfPage using a PdfPainter. * PoDoFo will find the font using fontconfig on your system and embedd truetype * fonts automatically in the PDF file. */ PdfFont* pFont; try { /* * The PdfDocument object can be used to create new PdfPage objects. * The PdfPage object is owned by the PdfDocument will also be deleted automatically * by the PdfDocument object. * * You have to pass only one argument, i.e. the page size of the page to create. * There are predefined enums for some common page sizes. */ pPage = document.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); /* * If the page cannot be created because of an error (e.g. ePdfError_OutOfMemory ) * a NULL pointer is returned. * We check for a NULL pointer here and throw an exception using the RAISE_ERROR macro. * The raise error macro initializes a PdfError object with a given error code and * the location in the file in which the error ocurred and throws it as an exception. */ if( !pPage ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } /* * Set the page as drawing target for the PdfPainter. * Before the painter can draw, a page has to be set first. */ painter.SetPage( pPage ); /* * Create a PdfFont object using the font "Arial". * The font is found on the system using fontconfig and embedded into the * PDF file. If Arial is not available, a default font will be used. * * The created PdfFont will be deleted by the PdfDocument. */ pFont = document.CreateFont( "Arial" ); /* * If the PdfFont object cannot be allocated return an error. */ if( !pFont ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } /* * Set the font size */ pFont->SetFontSize( 18.0 ); /* * Set the font as default font for drawing. * A font has to be set before you can draw text on * a PdfPainter. */ painter.SetFont( pFont ); /* * You could set a different color than black to draw * the text. * * SAFE_OP( painter.SetColor( 1.0, 0.0, 0.0 ) ); */ /* * Actually draw the line "Hello World!" on to the PdfPage at * the position 2cm,2cm from the top left corner. * Please remember that PDF files have their origin at the * bottom left corner. Therefore we substract the y coordinate * from the page height. * * The position specifies the start of the baseline of the text. * * All coordinates in PoDoFo are in PDF units. * You can also use PdfPainterMM which takes coordinates in 1/1000th mm. * */ painter.DrawText( 56.69, pPage->GetPageSize().GetHeight() - 56.69, "Hello World!" ); /* * Tell PoDoFo that the page has been drawn completely. * This required to optimize drawing operations inside in PoDoFo * and has to be done whenever you are done with drawing a page. */ painter.FinishPage(); /* * Set some additional information on the PDF file. */ document.GetInfo()->SetCreator ( PdfString("examplahelloworld - A PoDoFo test application") ); document.GetInfo()->SetAuthor ( PdfString("Dominik Seichter") ); document.GetInfo()->SetTitle ( PdfString("Hello World") ); document.GetInfo()->SetSubject ( PdfString("Testing the PoDoFo PDF Library") ); document.GetInfo()->SetKeywords( PdfString("Test;PDF;Hello World;") ); /* * The last step is to close the document. */ document.Close(); } catch ( PdfError & e ) { /* * All PoDoFo methods may throw exceptions * make sure that painter.FinishPage() is called * or who will get an assert in its destructor */ try { painter.FinishPage(); } catch( ... ) { /* * Ignore errors this time */ } throw e; } } int main( int argc, char* argv[] ) { /* * Check if a filename was passed as commandline argument. * If more than 1 argument or no argument is passed, * a help message is displayed and the example application * will quit. */ if( argc != 2 ) { PrintHelp(); return -1; } /* * All podofo functions will throw an exception in case of an error. * * You should catch the exception to either fix it or report * back to the user. * * All exceptions podofo throws are objects of the class PdfError. * Thats why we simply catch PdfError objects. */ try { /* * Call the drawing routing which will create a PDF file * with the filename of the output file as argument. */ HelloWorld( argv[1] ); } catch( PdfError & eCode ) { /* * We have to check if an error has occurred. * If yes, we return and print an error message * to the commandline. */ eCode.PrintErrorMsg(); return eCode.GetError(); } try { /** * Free global memory allocated by PoDoFo. * This is normally not necessary as memory * will be free'd when the application terminates. * * If you want to free all memory allocated by * PoDoFo you have to call this method. * * PoDoFo will reallocate the memory if necessary. */ PdfEncodingFactory::FreeGlobalEncodingInstances(); } catch( PdfError & eCode ) { /* * We have to check if an error has occurred. * If yes, we return and print an error message * to the commandline. */ eCode.PrintErrorMsg(); return eCode.GetError(); } /* * The PDF was created sucessfully. */ std::cout << std::endl << "Created a PDF file containing the line \"Hello World!\": " << argv[1] << std::endl << std::endl; return 0; } podofo-0.9.5/examples/helloworld/CMakeLists.txt0000664000175000017500000000126610653303212021414 0ustar dominikdominik# This is not a full standalone CMake configuration for the hello world # example. # # To build it outside the PoDoFo source tree, you must set your build system # make the PoDoFo headers available and must link to the PoDoFo library # and any libraries it depends on (see the README, # "5. Using PoDoFo in Your Application") . # # Note that you don't need the headers for PoDoFo's dependencies in your # header search path. ADD_EXECUTABLE(helloworld helloworld.cpp) TARGET_LINK_LIBRARIES(helloworld ${PODOFO_LIB}) SET_TARGET_PROPERTIES(helloworld PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(helloworld ${PODOFO_DEPEND_TARGET}) INCLUDE_DIRECTORIES(${PoDoFo_SOURCE_DIR}) podofo-0.9.5/cmake/0000775000175000017500000000000013044451156013746 5ustar dominikdominikpodofo-0.9.5/cmake/modules/0000775000175000017500000000000013044451156015416 5ustar dominikdominikpodofo-0.9.5/cmake/modules/FindFONTCONFIG.cmake0000664000175000017500000000265012711716320020655 0ustar dominikdominik# - Try to find the Fontconfig # Once done this will define # # FONTCONFIG_FOUND - system has Fontconfig # FONTCONFIG_LIBRARIES - Link these to use FONTCONFIG # FONTCONFIG_DEFINITIONS - Compiler switches required for using FONTCONFIG # Copyright (c) 2006,2007 Laurent Montel, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. FIND_PACKAGE(PkgConfig) if (FONTCONFIG_LIBRARIES AND FONTCONFIG_INCLUDE_DIR) # in cache already set(FONTCONFIG_FOUND TRUE) else (FONTCONFIG_LIBRARIES AND FONTCONFIG_INCLUDE_DIR) if (PKG_CONFIG_FOUND) # use pkg-config to get the directories and then use these values # in the FIND_PATH() and FIND_LIBRARY() calls pkg_check_modules(FONTCONFIG fontconfig) set(FONTCONFIG_DEFINITIONS ${FONTCONFIG_CFLAGS} CACHE INTERNAL "The compilation flags for fontconfig") endif (PKG_CONFIG_FOUND) find_path(FONTCONFIG_INCLUDE_DIR fontconfig/fontconfig.h PATHS ${FONTCONFIG_INCLUDE_DIRS} /usr/X11/include ) find_library(FONTCONFIG_LIBRARIES NAMES fontconfig PATHS ${FONTCONFIG_LIBRARY_DIRS} ) include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Fontconfig DEFAULT_MSG FONTCONFIG_LIBRARIES FONTCONFIG_INCLUDE_DIR ) mark_as_advanced(FONTCONFIG_LIBRARIES FONTCONFIG_INCLUDE_DIR) endif (FONTCONFIG_LIBRARIES AND FONTCONFIG_INCLUDE_DIR) podofo-0.9.5/cmake/modules/FindOpenSSL.cmake0000664000175000017500000000506611014031047020477 0ustar dominikdominik# - Try to find the OpenSSL encryption library # Once done this will define # # OPENSSL_FOUND - system has the OpenSSL library # OPENSSL_INCLUDE_DIR - the OpenSSL include directory # OPENSSL_LIBRARIES - The libraries needed to use OpenSSL # Copyright (c) 2006, Alexander Neundorf, # Modified by Craig Ringer, 2008: # - Handle !REQUIRED # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. IF(OPENSSL_LIBRARIES) SET(OpenSSL_FIND_QUIETLY TRUE) ENDIF(OPENSSL_LIBRARIES) IF(SSL_EAY_DEBUG AND SSL_EAY_RELEASE) SET(LIB_FOUND 1) ENDIF(SSL_EAY_DEBUG AND SSL_EAY_RELEASE) FIND_PATH(OPENSSL_INCLUDE_DIR openssl/ssl.h ) IF(WIN32 AND MSVC) # /MD and /MDd are the standard values - if somone wants to use # others, the libnames have to change here too # use also ssl and ssleay32 in debug as fallback for openssl < 0.9.8b FIND_LIBRARY(SSL_EAY_DEBUG NAMES ssleay32MDd ssl ssleay32) FIND_LIBRARY(SSL_EAY_RELEASE NAMES ssleay32MD ssl ssleay32) IF(MSVC_IDE) IF(SSL_EAY_DEBUG AND SSL_EAY_RELEASE) SET(OPENSSL_LIBRARIES optimized ${SSL_EAY_RELEASE} debug ${SSL_EAY_DEBUG}) ELSE(SSL_EAY_DEBUG AND SSL_EAY_RELEASE) MESSAGE("OpenSSL: Could not find the debug and release version of openssl") MESSAGE("OpenSSL: Disabling OpenSSL") SET(OPENSSL_LIBRARIES) ENDIF(SSL_EAY_DEBUG AND SSL_EAY_RELEASE) ELSE(MSVC_IDE) STRING(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_TOLOWER) IF(CMAKE_BUILD_TYPE_TOLOWER MATCHES debug) SET(OPENSSL_LIBRARIES ${SSL_EAY_DEBUG}) ELSE(CMAKE_BUILD_TYPE_TOLOWER MATCHES debug) SET(OPENSSL_LIBRARIES ${SSL_EAY_RELEASE}) ENDIF(CMAKE_BUILD_TYPE_TOLOWER MATCHES debug) ENDIF(MSVC_IDE) MARK_AS_ADVANCED(SSL_EAY_DEBUG SSL_EAY_RELEASE) ELSE(WIN32 AND MSVC) FIND_LIBRARY(OPENSSL_LIBRARIES NAMES ssl ssleay32 ssleay32MD ) ENDIF(WIN32 AND MSVC) IF(OPENSSL_INCLUDE_DIR AND OPENSSL_LIBRARIES) SET(OPENSSL_FOUND TRUE) ELSE(OPENSSL_INCLUDE_DIR AND OPENSSL_LIBRARIES) SET(OPENSSL_FOUND FALSE) ENDIF (OPENSSL_INCLUDE_DIR AND OPENSSL_LIBRARIES) IF (OPENSSL_FOUND) IF (NOT OpenSSL_FIND_QUIETLY) MESSAGE(STATUS "Found OpenSSL: ${OPENSSL_LIBRARIES}") ENDIF (NOT OpenSSL_FIND_QUIETLY) ELSE (OPENSSL_FOUND) IF (OpenSSL_FIND_REQUIRED) MESSAGE(FATAL_ERROR "Could NOT find OpenSSL") ENDIF (OpenSSL_FIND_REQUIRED) ENDIF (OPENSSL_FOUND) MARK_AS_ADVANCED(OPENSSL_INCLUDE_DIR OPENSSL_LIBRARIES) podofo-0.9.5/cmake/modules/MacroEnsureVersion.cmake0000664000175000017500000000665610720646026022226 0ustar dominikdominik# This macro compares version numbers of the form "x.y.z" # MACRO_ENSURE_VERSION( FOO_MIN_VERSION FOO_VERSION_FOUND FOO_VERSION_OK) # will set FOO_VERSIN_OK to true if FOO_VERSION_FOUND >= FOO_MIN_VERSION # where both have to be in a 3-part-version format, leading and trailing # text is ok, e.g. # MACRO_ENSURE_VERSION( "2.5.31" "flex 2.5.4a" VERSION_OK) # which means 2.5.31 is required and "flex 2.5.4a" is what was found on the system # Copyright (c) 2006, David Faure, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. MACRO(MACRO_ENSURE_VERSION requested_version found_version var_too_old) # parse the parts of the version string STRING(REGEX REPLACE "([0-9]+)\\.[0-9]+\\.[0-9]+" "\\1" req_major_vers "${requested_version}") STRING(REGEX REPLACE "[0-9]+\\.([0-9]+)\\.[0-9]+" "\\1" req_minor_vers "${requested_version}") STRING(REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" req_patch_vers "${requested_version}") STRING(REGEX REPLACE "[^0-9]*([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" found_major_vers "${found_version}") STRING(REGEX REPLACE "[^0-9]*[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" found_minor_vers "${found_version}") STRING(REGEX REPLACE "[^0-9]*[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" found_patch_vers "${found_version}") # compute an overall version number which can be compared at once MATH(EXPR req_vers_num "${req_major_vers}*10000 + ${req_minor_vers}*100 + ${req_patch_vers}") MATH(EXPR found_vers_num "${found_major_vers}*10000 + ${found_minor_vers}*100 + ${found_patch_vers}") if (found_vers_num LESS req_vers_num) set( ${var_too_old} FALSE ) else (found_vers_num LESS req_vers_num) set( ${var_too_old} TRUE ) endif (found_vers_num LESS req_vers_num) ENDMACRO(MACRO_ENSURE_VERSION) # This macro compares version numbers of the form "x.y" # MACRO_ENSURE_VERSION( FOO_MIN_VERSION FOO_VERSION_FOUND FOO_VERSION_OK) # will set FOO_VERSIN_OK to true if FOO_VERSION_FOUND >= FOO_MIN_VERSION # where both have to be in a 2-part-version format, leading and trailing # text is ok, e.g. # MACRO_ENSURE_VERSION( "0.5" "foo 0.6" VERSION_OK) # which means 0.5 is required and "foo 0.6" is what was found on the system # Copyright (c) 2006, David Faure, # Copyright (c) 2007, Pino Toscano, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. MACRO(MACRO_ENSURE_VERSION2 requested_version found_version var_too_old) # parse the parts of the version string STRING(REGEX REPLACE "([0-9]+)\\.[0-9]+" "\\1" req_major_vers "${requested_version}") STRING(REGEX REPLACE "[0-9]+\\.([0-9]+)" "\\1" req_minor_vers "${requested_version}") STRING(REGEX REPLACE "[^0-9]*([0-9]+)\\.[0-9]+.*" "\\1" found_major_vers "${found_version}") STRING(REGEX REPLACE "[^0-9]*[0-9]+\\.([0-9]+).*" "\\1" found_minor_vers "${found_version}") # compute an overall version number which can be compared at once MATH(EXPR req_vers_num "${req_major_vers}*100 + ${req_minor_vers}") MATH(EXPR found_vers_num "${found_major_vers}*100 + ${found_minor_vers}") if (found_vers_num LESS req_vers_num) set( ${var_too_old} FALSE ) else (found_vers_num LESS req_vers_num) set( ${var_too_old} TRUE ) endif (found_vers_num LESS req_vers_num) ENDMACRO(MACRO_ENSURE_VERSION2) podofo-0.9.5/cmake/modules/FindLIBJPEG.cmake0000664000175000017500000000251012711716320020270 0ustar dominikdominik# - Find LIBJPEG # Find the native LIBJPEG includes and library # This module defines # LIBJPEG_INCLUDE_DIR, where to find jpeglib.h, etc. # LIBJPEG_LIBRARIES, the libraries needed to use LIBJPEG. # LIBJPEG_FOUND, If false, do not try to use LIBJPEG. # also defined, but not for general use are # LIBJPEG_LIBRARY, where to find the LIBJPEG library. FIND_PATH(LIBJPEG_INCLUDE_DIR jpeglib.h) SET(LIBJPEG_LIBRARY_NAMES_RELEASE ${LIBJPEG_LIBRARY_NAMES_RELEASE} ${LIBJPEG_LIBRARY_NAMES} jpeg libjpeg) FIND_LIBRARY(LIBJPEG_LIBRARY_RELEASE NAMES ${LIBJPEG_LIBRARY_NAMES_RELEASE} ) SET(LIBJPEG_LIBRARY_NAMES_DEBUG ${LIBJPEG_LIBRARY_NAMES_DEBUG} jpegd libjpegd jpeg_d libjpeg_d) FIND_LIBRARY(LIBJPEG_LIBRARY_DEBUG NAMES ${LIBJPEG_LIBRARY_NAMES_DEBUG} ) INCLUDE(LibraryDebugAndRelease) SET_LIBRARY_FROM_DEBUG_AND_RELEASE(LIBJPEG) # handle the QUIETLY and REQUIRED arguments and set LIBJPEG_FOUND to TRUE if # all listed variables are TRUE INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBJPEG DEFAULT_MSG LIBJPEG_LIBRARY LIBJPEG_INCLUDE_DIR) IF(LIBJPEG_FOUND) SET(LIBJPEG_LIBRARIES ${LIBJPEG_LIBRARY}) ELSE(LIBJPEG_FOUND) MESSAGE("libjpeg not found: Library ${LIBJPEG_LIBRARY}, headers ${LIBJPEG_INCLUDE_DIR}") ENDIF(LIBJPEG_FOUND) MARK_AS_ADVANCED(LIBJPEG_LIBRARY LIBJPEG_INCLUDE_DIR ) podofo-0.9.5/cmake/modules/FindLua51.cmake0000664000175000017500000000340112711716320020103 0ustar dominikdominik# Locate Lua library # This module defines # LUA_LIBRARIES # LUA_FOUND, if false, do not try to link to Lua # LUA_INCLUDE_DIR, where to find lua.h # # Note that the expected include convention is # #include "lua.h" # and not # #include # This is because, the lua location is not standardized and may exist # in locations other than lua/ FIND_PATH(LUA_INCLUDE_DIR lua.h PATHS $ENV{LUA_DIR} NO_DEFAULT_PATH PATH_SUFFIXES include/lua51 include/lua5.1 include/lua include ) FIND_PATH(LUA_INCLUDE_DIR lua.h PATHS ~/Library/Frameworks /Library/Frameworks /usr/local /usr /sw # Fink /opt/local # DarwinPorts /opt/csw # Blastwave /opt PATH_SUFFIXES include/lua51 include/lua5.1 include/lua include ) FIND_LIBRARY(LUA_LIBRARY NAMES lua51 lua5.1 lua PATHS $ENV{LUA_DIR} NO_DEFAULT_PATH PATH_SUFFIXES lib64 lib ) FIND_LIBRARY(LUA_LIBRARY NAMES lua51 lua5.1 lua PATHS ~/Library/Frameworks /Library/Frameworks /usr/local /usr /sw /opt/local /opt/csw /opt PATH_SUFFIXES lib64 lib ) IF(LUA_LIBRARY) # include the math library for Unix IF(UNIX AND NOT APPLE) FIND_LIBRARY(LUA_MATH_LIBRARY m) SET( LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}" CACHE STRING "Lua Libraries") # For Windows and Mac, don't need to explicitly include the math library ELSE(UNIX AND NOT APPLE) SET( LUA_LIBRARIES "${LUA_LIBRARY}" CACHE STRING "Lua Libraries") ENDIF(UNIX AND NOT APPLE) ENDIF(LUA_LIBRARY) INCLUDE(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if # all listed variables are TRUE FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua50 DEFAULT_MSG LUA_LIBRARIES LUA_INCLUDE_DIR) MARK_AS_ADVANCED(LUA_INCLUDE_DIR LUA_LIBRARIES LUA_LIBRARY LUA_MATH_LIBRARY) podofo-0.9.5/cmake/modules/FindBoost.cmake0000664000175000017500000001417112711716320020310 0ustar dominikdominik# - Find the Boost includes and libraries. # The following variables are set if Boost is found. If Boost is not # found, Boost_FOUND is set to false. # Boost_FOUND - True when the Boost include directory is found. # Boost_INCLUDE_DIRS - the path to where the boost include files are. # Boost_LIBRARY_DIRS - The path to where the boost library files are. # Boost_LIB_DIAGNOSTIC_DEFINITIONS - Only set if using Windows. # ---------------------------------------------------------------------------- # If you have installed Boost in a non-standard location or you have # just staged the boost files using bjam then you have three # options. In the following comments, it is assumed that # points to the root directory of the include directory of Boost. e.g # If you have put boost in C:\development\Boost then is # "C:/development/Boost" and in this directory there will be two # directories, one called either "boost" or "include" and the other called "lib". # 1) After CMake runs, set Boost_INCLUDE_DIR to /include/boost<-version> # 2) Use CMAKE_INCLUDE_PATH to set a path to /include. This will allow FIND_PATH() # to locate Boost_INCLUDE_DIR by utilizing the PATH_SUFFIXES option. e.g. # SET(CMAKE_INCLUDE_PATH ${CMAKE_INCLUDE_PATH} "/include") # 3) Set an environment variable called ${BOOST_ROOT} that points to the root of where you have # installed Boost, e.g. . It is assumed that there is at least a subdirectory called # include in this path. # # Note: # 1) If you are just using the boost headers, then you do not need to use # Boost_LIBRARY_DIRS in your CMakeLists.txt file. # 2) If Boost has not been installed, then when setting Boost_LIBRARY_DIRS # the script will look for /lib first and, if this fails, then for /stage/lib. # # Usage: # In your CMakeLists.txt file do something like this: # ... # # Boost # FIND_PACKAGE(Boost) # ... # INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) # LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) # # In Windows, we make the assumption that, if the Boost files are installed, the default directory # will be C:\boost. # # TODO: # # 1) Automatically find the Boost library files and eliminate the need # to use Link Directories. # IF(WIN32) # In windows, automatic linking is performed, so you do not have to specify the libraries. # If you are linking to a dynamic runtime, then you can choose to link to either a static or a # dynamic Boost library, the default is to do a static link. You can alter this for a specific # library "whatever" by defining BOOST_WHATEVER_DYN_LINK to force Boost library "whatever" to # be linked dynamically. Alternatively you can force all Boost libraries to dynamic link by # defining BOOST_ALL_DYN_LINK. # This feature can be disabled for Boost library "whatever" by defining BOOST_WHATEVER_NO_LIB, # or for all of Boost by defining BOOST_ALL_NO_LIB. # If you want to observe which libraries are being linked against then defining # BOOST_LIB_DIAGNOSTIC will cause the auto-linking code to emit a #pragma message each time # a library is selected for linking. SET(Boost_LIB_DIAGNOSTIC_DEFINITIONS "-DBOOST_LIB_DIAGNOSTIC") ENDIF(WIN32) SET(BOOST_INCLUDE_PATH_DESCRIPTION "directory containing the boost include files, e.g. /usr/local/include/boost-1_33_1 or c:/boost/include/boost-1_33_1") SET(BOOST_DIR_MESSAGE "Set the Boost_INCLUDE_DIR cmake cache entry to the ${BOOST_INCLUDE_PATH_DESCRIPTION} or set the BOOST_ROOT environment variable and re-run cmake.") SET(BOOST_DIR_SEARCH "$ENV{BOOST_ROOT}") IF(BOOST_DIR_SEARCH) FILE(TO_CMAKE_PATH "${BOOST_DIR_SEARCH}" BOOST_DIR_SEARCH) SET(BOOST_DIR_SEARCH "${BOOST_DIR_SEARCH}" "${BOOST_DIR_SEARCH}/include") ENDIF(BOOST_DIR_SEARCH) IF(WIN32) SET(BOOST_DIR_SEARCH "${BOOST_DIR_SEARCH}" C:/boost/include D:/boost/include C:/boost D:/boost ) ELSE(WIN32) SET(BOOST_DIR_SEARCH "${BOOST_DIR_SEARCH}" /usr/include/boost/ ) ENDIF(WIN32) # Add in some path suffixes. These will have to be updated whenever a new Boost version comes out. SET(SUFFIX_FOR_PATH boost-1_34_1 boost-1_34_0 boost-1_33_1 boost-1_33_0 ) # # Look for an installation. # FIND_PATH(Boost_INCLUDE_DIR NAMES boost/config.hpp PATH_SUFFIXES ${SUFFIX_FOR_PATH} PATHS # Look in other places. ${BOOST_DIR_SEARCH} # Help the user find it if we cannot. DOC "The ${BOOST_INCLUDE_PATH_DESCRIPTION}" ) SET(Boost_INCLUDE_DIRS "${Boost_INCLUDE_DIR}") # Now try to get the include and library path. IF(Boost_INCLUDE_DIR) # Look for the boost library path. # Note that the user may not have installed any libraries # so it is quite possible the Boost_LIBRARY_PATH may not exist. SET(Boost_LIBRARY_DIR ${Boost_INCLUDE_DIR}) IF("${Boost_LIBRARY_DIR}" MATCHES "boost-[0-9]+") GET_FILENAME_COMPONENT(Boost_LIBRARY_DIR ${Boost_LIBRARY_DIR} PATH) ENDIF ("${Boost_LIBRARY_DIR}" MATCHES "boost-[0-9]+") IF("${Boost_LIBRARY_DIR}" MATCHES "/include$") # Strip off the trailing "/include" in the path. GET_FILENAME_COMPONENT(Boost_LIBRARY_DIR ${Boost_LIBRARY_DIR} PATH) ENDIF("${Boost_LIBRARY_DIR}" MATCHES "/include$") IF(EXISTS "${Boost_LIBRARY_DIR}/lib") SET (Boost_LIBRARY_DIR ${Boost_LIBRARY_DIR}/lib) ELSE(EXISTS "${Boost_LIBRARY_DIR}/lib") IF(EXISTS "${Boost_LIBRARY_DIR}/stage/lib") SET(Boost_LIBRARY_DIR ${Boost_LIBRARY_DIR}/stage/lib) ELSE(EXISTS "${Boost_LIBRARY_DIR}/stage/lib") SET(Boost_LIBRARY_DIR "") ENDIF(EXISTS "${Boost_LIBRARY_DIR}/stage/lib") ENDIF(EXISTS "${Boost_LIBRARY_DIR}/lib") IF(Boost_LIBRARY_DIR AND EXISTS "${Boost_LIBRARY_DIR}") SET(Boost_LIBRARY_DIRS ${Boost_LIBRARY_DIR}) ENDIF(Boost_LIBRARY_DIR AND EXISTS "${Boost_LIBRARY_DIR}") ENDIF(Boost_INCLUDE_DIR) # We have found boost. It is possible that the user has not # compiled any libraries so we set Boost_FOUND to be true here. # handle the QUIETLY and REQUIRED arguments and set BOOST_FOUND to TRUE if # all listed variables are TRUE INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Boost "Boost was not found. ${BOOST_DIR_MESSAGE}" Boost_INCLUDE_DIR ) SET(Boost_FOUND ${BOOST_FOUND}) MARK_AS_ADVANCED(Boost_INCLUDE_DIR) podofo-0.9.5/cmake/modules/FindLUA.cmake0000664000175000017500000000144412711716320017642 0ustar dominikdominik# LUA_FOUND - system has LUA # LUA_LIBRARIES - Link these to use LUA # LUA_DEFINITIONS - Compiler switches required for using LUA # # Based on FindFONTCONFIG.cmake Copyright (c) 2006,2007 Laurent Montel, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # # TODO: Update this code to handle debug/release builds on win32. if (LUA_LIBRARIES AND LUA_INCLUDE_DIR) # in cache already set(LUA_FOUND TRUE) else (LUA_LIBRARIES AND LUA_INCLUDE_DIR) FIND_PACKAGE(Lua51) include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua DEFAULT_MSG LUA_LIBRARIES LUA_INCLUDE_DIR ) mark_as_advanced(LUA_LIBRARIES LUA_INCLUDE_DIR) endif (LUA_LIBRARIES AND LUA_INCLUDE_DIR) podofo-0.9.5/cmake/modules/FindFREETYPE.cmake0000664000175000017500000000677212711716320020455 0ustar dominikdominik# # Find the native FREETYPE includes and library # # This module defines # FREETYPE_INCLUDE_DIR, where to find ft2build.h, ftheader.h, ... # FREETYPE_LIBRARIES, the libraries to link against to use FREETYPE. # FREETYPE_FOUND, If false, do not try to use FREETYPE. # also defined, but not for general use are # FREETYPE_LIBRARY, where to find the FREETYPE library. SET(FREETYPE_FIND_QUIETLY 1) # first we try to find ft2build.h in the new location as # of freetype 2.5.1 FIND_PATH(FREETYPE_INCLUDE_DIR_FT2BUILD ft2build.h /usr/include/freetype2 /usr/local/include/freetype2 /usr/X11/include/freetype2 NO_CMAKE_SYSTEM_PATH ) # in case we couldn't find it in the new location # we check the old location IF (NOT FREETYPE_INCLUDE_DIR_FT2BUILD) FIND_PATH(FREETYPE_INCLUDE_DIR_FT2BUILD ft2build.h /usr/include /usr/local/include /usr/X11/include NO_CMAKE_SYSTEM_PATH ) ENDIF (NOT FREETYPE_INCLUDE_DIR_FT2BUILD) # now try to find ftheader.h in the new location first FIND_PATH(FREETYPE_INCLUDE_DIR_FTHEADER config/ftheader.h /usr/include/freetype2 /usr/local/include/freetype2 /usr/X11/include/freetype2 ${FREETYPE_INCLUDE_DIR_FT2BUILD} NO_CMAKE_SYSTEM_PATH ) # in case we couldn't find it in the new location # we check the old location IF (NOT FREETYPE_INCLUDE_DIR_FTHEADER) FIND_PATH(FREETYPE_INCLUDE_DIR_FTHEADER freetype/config/ftheader.h /usr/include/freetype2 /usr/local/include/freetype2 /usr/X11/include/freetype2 ${FREETYPE_INCLUDE_DIR_FT2BUILD} ${FREETYPE_INCLUDE_DIR_FT2BUILD}/freetype2 NO_CMAKE_SYSTEM_PATH ) ENDIF (NOT FREETYPE_INCLUDE_DIR_FTHEADER) IF ( FREETYPE_INCLUDE_DIR_FTHEADER AND FREETYPE_INCLUDE_DIR_FT2BUILD ) SET(FREETYPE_INCLUDE_DIR ${FREETYPE_INCLUDE_DIR_FTHEADER} ${FREETYPE_INCLUDE_DIR_FT2BUILD}) ENDIF ( FREETYPE_INCLUDE_DIR_FTHEADER AND FREETYPE_INCLUDE_DIR_FT2BUILD ) LIST(REMOVE_DUPLICATES FREETYPE_INCLUDE_DIR) IF(NOT FREETYPE_FIND_QUIETLY) MESSAGE("FREETYPE_INCLUDE_DIR_FT2BUILD ${FREETYPE_INCLUDE_DIR_FT2BUILD}") MESSAGE("FREETYPE_INCLUDE_DIR_FTHEADER ${FREETYPE_INCLUDE_DIR_FTHEADER}") MESSAGE("FREETYPE_INCLUDE_DIR ${FREETYPE_INCLUDE_DIR}") ENDIF(NOT FREETYPE_FIND_QUIETLY) SET(FREETYPE_LIBRARY_NAMES_DEBUG ${FREETYPE_LIBRARY_NAMES_DEBUG} freetyped libfreetyped) SET(FREETYPE_LIBRARY_NAMES_RELEASE ${FREETYPE_LIBRARY_NAMES_RELEASE} freetype libfreetype) SET(FREETYPE_LIB_PATHS /usr/lib /usr/local/lib /usr/X11/lib) FIND_LIBRARY(FREETYPE_LIBRARY_RELEASE ${FREETYPE_LIBRARY_NAMES_RELEASE} ${FREETYPE_LIBRARY_NAMES} PATHS ${FREETYPE_LIB_PATHS} ) FIND_LIBRARY(FREETYPE_LIBRARY_DEBUG ${FREETYPE_LIBRARY_NAMES_DEBUG} PATHS ${FREETYPE_LIB_PATHS} ) INCLUDE(LibraryDebugAndRelease) SET_LIBRARY_FROM_DEBUG_AND_RELEASE(FREETYPE) SET(FREETYPE_LIBRARIES ${FREETYPE_LIBRARY}) IF(NOT FREETYPE_FIND_QUIETLY) MESSAGE("FREETYPE_LIBRARY_DEBUG ${FREETYPE_LIBRARY_DEBUG}") MESSAGE("FREETYPE_LIBRARY_RELEASE ${FREETYPE_LIBRARY_RELEASE}") MESSAGE("FREETYPE_LIBRARY ${FREETYPE_LIBRARY}") ENDIF(NOT FREETYPE_FIND_QUIETLY) # MESSAGE(STATUS "ft lib ${FREETYPE_LIBRARY}") # MESSAGE(STATUS "ft2 build ${FREETYPE_INCLUDE_DIR_FT2BUILD}") # MESSAGE(STATUS "ft header ${FREETYPE_INCLUDE_DIR_FTHEADER}") INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(FREETYPE DEFAULT_MSG FREETYPE_LIBRARY FREETYPE_INCLUDE_DIR) IF (NOT FREETYPE_FIND_QUIETLY) MESSAGE(STATUS "Found Freetype2: ${FREETYPE_LIBRARY}") ENDIF (NOT FREETYPE_FIND_QUIETLY) podofo-0.9.5/cmake/modules/FindCppUnit.cmake0000664000175000017500000000522310720646026020605 0ustar dominikdominik# - Try to find the libcppunit libraries # Once done this will define # # CppUnit_FOUND - system has libcppunit # CPPUNIT_INCLUDE_DIR - the libcppunit include directory # CPPUNIT_LIBRARIES - libcppunit library include (MacroEnsureVersion) if(NOT CPPUNIT_MIN_VERSION) SET(CPPUNIT_MIN_VERSION 1.12.0) endif(NOT CPPUNIT_MIN_VERSION) FIND_PROGRAM(CPPUNIT_CONFIG_EXECUTABLE cppunit-config ) IF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) # in cache already SET(CppUnit_FOUND TRUE) ELSE(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) SET(CPPUNIT_INCLUDE_DIR) SET(CPPUNIT_LIBRARIES) IF(CPPUNIT_CONFIG_EXECUTABLE) EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --cflags RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_CFLAGS) EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --libs RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_LIBRARIES) EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --version RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_INSTALLED_VERSION) STRING(REGEX REPLACE "-I(.+)" "\\1" CPPUNIT_CFLAGS "${CPPUNIT_CFLAGS}") ELSE(CPPUNIT_CONFIG_EXECUTABLE) # in case win32 needs to find it the old way? FIND_PATH(CPPUNIT_CFLAGS cppunit/TestRunner.h PATHS /usr/include /usr/local/include ) FIND_LIBRARY(CPPUNIT_LIBRARIES NAMES cppunit PATHS /usr/lib /usr/local/lib ) # how can we find cppunit version? MESSAGE (STATUS "Ensure you cppunit installed version is at least ${CPPUNIT_MIN_VERSION}") SET (CPPUNIT_INSTALLED_VERSION ${CPPUNIT_MIN_VERSION}) ENDIF(CPPUNIT_CONFIG_EXECUTABLE) SET(CPPUNIT_INCLUDE_DIR ${CPPUNIT_CFLAGS} "${CPPUNIT_CFLAGS}/cppunit") ENDIF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) IF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) SET(CppUnit_FOUND TRUE) if(NOT CppUnit_FIND_QUIETLY) MESSAGE (STATUS "Found cppunit: ${CPPUNIT_LIBRARIES}") endif(NOT CppUnit_FIND_QUIETLY) IF(CPPUNIT_CONFIG_EXECUTABLE) EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --version RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_INSTALLED_VERSION) ENDIF(CPPUNIT_CONFIG_EXECUTABLE) macro_ensure_version( ${CPPUNIT_MIN_VERSION} ${CPPUNIT_INSTALLED_VERSION} CPPUNIT_INSTALLED_VERSION_OK ) IF(NOT CPPUNIT_INSTALLED_VERSION_OK) MESSAGE ("** CppUnit version is too old: found ${CPPUNIT_INSTALLED_VERSION} installed, ${CPPUNIT_MIN_VERSION} or major is required") SET(CppUnit_FOUND FALSE) ENDIF(NOT CPPUNIT_INSTALLED_VERSION_OK) ELSE(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) SET(CppUnit_FOUND FALSE CACHE BOOL "Not found cppunit library") ENDIF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) MARK_AS_ADVANCED(CPPUNIT_INCLUDE_DIR CPPUNIT_LIBRARIES) podofo-0.9.5/cmake/modules/LibraryDebugAndRelease.cmake0000664000175000017500000000251510714374660022727 0ustar dominikdominik# # This macro is used when we may have a debug and or release build of a library, # and we want to produce a single easy to use library string that'll do the right # thing. If both debug and release versions are available, we'll automatically use the # debug version for debug builds and the release version for release builds. # # If only one build exists, we use that one irrespective of build type. # MACRO(SET_LIBRARY_FROM_DEBUG_AND_RELEASE _NAME) IF(NOT DEFINED "${_NAME}_LIBRARY_RELEASE" OR NOT DEFINED "${_NAME}_LIBRARY_DEBUG") MESSAGE(FATAL_ERROR "${_NAME}_LIBRARY_DEBUG OR ${_NAME}_LIBRARY_RELEASE undefined") ENDIF(NOT DEFINED "${_NAME}_LIBRARY_RELEASE" OR NOT DEFINED "${_NAME}_LIBRARY_DEBUG") IF(${_NAME}_LIBRARY_RELEASE AND ${_NAME}_LIBRARY_DEBUG) SET(${_NAME}_LIBRARY "optimized;${${_NAME}_LIBRARY_RELEASE};debug;${${_NAME}_LIBRARY_DEBUG}") ELSE(${_NAME}_LIBRARY_RELEASE AND ${_NAME}_LIBRARY_DEBUG) IF(${_NAME}_LIBRARY_DEBUG) MESSAGE("WARNING: ${_NAME} debug library will be used even for release builds") SET(${_NAME}_LIBRARY ${${_NAME}_LIBRARY_DEBUG}) ELSE(${_NAME}_LIBRARY_DEBUG) SET(${_NAME}_LIBRARY ${${_NAME}_LIBRARY_RELEASE}) ENDIF(${_NAME}_LIBRARY_DEBUG) ENDIF(${_NAME}_LIBRARY_RELEASE AND ${_NAME}_LIBRARY_DEBUG) ENDMACRO(SET_LIBRARY_FROM_DEBUG_AND_RELEASE) podofo-0.9.5/cmake/modules/FindZLIB.cmake0000664000175000017500000000375312711716320017766 0ustar dominikdominik# - Find zlib # Find the native ZLIB includes and library # # ZLIB_INCLUDE_DIR - where to find zlib.h, etc. # ZLIB_LIBRARIES - List of libraries when using zlib. # ZLIB_FOUND - True if zlib found. IF (ZLIB_INCLUDE_DIR) # Already in cache, be silent SET(ZLIB_FIND_QUIETLY TRUE) ENDIF (ZLIB_INCLUDE_DIR) FIND_PATH(ZLIB_INCLUDE_DIR zlib.h) # On win32, qt statically links to zlib and libpng, and exports their symbols. # We can just link to Qt to get zlib and libpng. We still require the user to # supply their own headers on the search path, but they can and should just # specify ${QTDIR}/src/3rdparty/zlib/include . # To use this, you must use FindQt before FindZlib. IF(QT_QTCORE_LIBRARY AND USE_QT_ZLIB_PNGLIB) MESSAGE("Using zlib from qt") SET(ZLIB_LIBRARY_RELEASE ${QT_QTCORE_LIBRARY_RELEASE}) SET(ZLIB_LIBRARY_DEBUG ${QT_QTCORE_LIBRARY_DEBUG}) SET(ZLIB_LIBRARY ${QT_QTCORE_LIBRARY}) ELSE(QT_QTCORE_LIBRARY AND USE_QT_ZLIB_PNGLIB) SET(ZLIB_LIBRARY_NAMES_RELEASE ${ZLIB_LIBRARY_NAMES_RELEASE} ${ZLIB_LIBRARY_NAMES} zlib1 zlib zdll z) FIND_LIBRARY(ZLIB_LIBRARY_RELEASE NAMES ${ZLIB_LIBRARY_NAMES_RELEASE} ) # Find a debug library if one exists and use that for debug builds. # This really only does anything for win32, but does no harm on other # platforms. SET(ZLIB_LIBRARY_NAMES_DEBUG ${ZLIB_LIBRARY_NAMES_DEBUG} zlib1d zlibd zdlld) FIND_LIBRARY(ZLIB_LIBRARY_DEBUG NAMES ${ZLIB_LIBRARY_NAMES_DEBUG}) INCLUDE(LibraryDebugAndRelease) SET_LIBRARY_FROM_DEBUG_AND_RELEASE(ZLIB) ENDIF(QT_QTCORE_LIBRARY AND USE_QT_ZLIB_PNGLIB) # handle the QUIETLY and REQUIRED arguments and set ZLIB_FOUND to TRUE if # all listed variables are TRUE INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(ZLIB DEFAULT_MSG ZLIB_LIBRARY ZLIB_INCLUDE_DIR) IF(ZLIB_FOUND) SET( ZLIB_LIBRARIES ${ZLIB_LIBRARY} ) ELSE(ZLIB_FOUND) SET( ZLIB_LIBRARIES ) ENDIF(ZLIB_FOUND) MARK_AS_ADVANCED( ZLIB_LIBRARY ZLIB_INCLUDE_DIR ) podofo-0.9.5/cmake/modules/FindLIBIDN.cmake0000664000175000017500000000255212711716320020163 0ustar dominikdominik# - Find libidn # Find the native LIBIDN includes and library # # LIBIDN_INCLUDE_DIR - where to find stringprep.h, etc. # LIBIDN_LIBRARIES - List of libraries when using libidn. # LIBIDN_FOUND - True if libidn found. IF (LIBIDN_INCLUDE_DIR) # Already in cache, be silent SET(LIBIDN_FIND_QUIETLY TRUE) ENDIF (LIBIDN_INCLUDE_DIR) FIND_PATH(LIBIDN_INCLUDE_DIR stringprep.h) SET(LIBIDN_LIBRARY_NAMES_RELEASE ${LIBIDN_LIBRARY_NAMES_RELEASE} ${LIBIDN_LIBRARY_NAMES} idn) FIND_LIBRARY(LIBIDN_LIBRARY_RELEASE NAMES ${LIBIDN_LIBRARY_NAMES_RELEASE} ) # Find a debug library if one exists and use that for debug builds. # This really only does anything for win32, but does no harm on other # platforms. SET(LIBIDN_LIBRARY_NAMES_DEBUG ${LIBIDN_LIBRARY_NAMES_DEBUG} idnd) FIND_LIBRARY(LIBIDN_LIBRARY_DEBUG NAMES ${LIBIDN_LIBRARY_NAMES_DEBUG}) INCLUDE(LibraryDebugAndRelease) SET_LIBRARY_FROM_DEBUG_AND_RELEASE(LIBIDN) # handle the QUIETLY and REQUIRED arguments and set LIBIDN_FOUND to TRUE if # all listed variables are TRUE INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBIDN DEFAULT_MSG LIBIDN_LIBRARY LIBIDN_INCLUDE_DIR) IF(LIBIDN_FOUND) SET( LIBIDN_LIBRARIES ${LIBIDN_LIBRARY} ) ELSE(LIBIDN_FOUND) SET( LIBIDN_LIBRARIES ) ENDIF(LIBIDN_FOUND) MARK_AS_ADVANCED( LIBIDN_LIBRARY LIBIDN_INCLUDE_DIR ) podofo-0.9.5/cmake/modules/FindLIBSTLPORT.cmake0000664000175000017500000000075412626641602020727 0ustar dominikdominikFIND_PATH(LIBSTLPORT_INCLUDE_DIR NAMES stl/_stlport_version.h PATHS /usr/include/stlport ) FIND_LIBRARY(LIBSTLPORT_LIBRARY NAMES stlport libstlport) IF(LIBSTLPORT_INCLUDE_DIR AND LIBSTLPORT_LIBRARY) SET(LIBSTLPORT_FOUND TRUE CACHE BOOLEAN "Was libstlport found?") ELSE(LIBSTLPORT_INCLUDE_DIR AND LIBSTLPORT_LIBRARY) SET(LIBSTLPORT_FOUND FALSE CACHE BOOLEAN "Was libstlport found?") ENDIF(LIBSTLPORT_INCLUDE_DIR AND LIBSTLPORT_LIBRARY) SET(LIBSTLPORT_LIBRARIES ${LIBSTLPORT_LIBRARY}) podofo-0.9.5/cmake/modules/FindTIFF.cmake0000664000175000017500000000210112711716320017740 0ustar dominikdominik# - Find TIFF library # Find the native TIFF includes and library # This module defines # TIFF_INCLUDE_DIR, where to find tiff.h, etc. # TIFF_LIBRARIES, libraries to link against to use TIFF. # TIFF_FOUND, If false, do not try to use TIFF. # also defined, but not for general use are # TIFF_LIBRARY, where to find the TIFF library. FIND_PATH(TIFF_INCLUDE_DIR tiff.h) SET(TIFF_LIBRARY_NAMES_RELEASE ${TIFF_LIBRARY_NAMES_RELEASE} ${TIFF_LIBRARY_NAMES} tiff libtiff) SET(TIFF_LIBRARY_NAMES_DEBUG ${TIFF_LIBRARY_NAMES_DEBUG} tiffd libtiffd) FIND_LIBRARY(TIFF_LIBRARY_RELEASE NAMES ${TIFF_LIBRARY_NAMES_RELEASE} ) FIND_LIBRARY(TIFF_LIBRARY_DEBUG NAMES ${TIFF_LIBRARY_NAMES_DEBUG} ) INCLUDE(LibraryDebugAndRelease) SET_LIBRARY_FROM_DEBUG_AND_RELEASE(TIFF) # handle the QUIETLY and REQUIRED arguments and set TIFF_FOUND to TRUE if # all listed variables are TRUE INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(TIFF DEFAULT_MSG TIFF_LIBRARY TIFF_INCLUDE_DIR) IF(TIFF_FOUND) SET( TIFF_LIBRARIES ${TIFF_LIBRARY} ) ENDIF(TIFF_FOUND) podofo-0.9.5/cmake/modules/FindLIBCRYPTO.cmake0000664000175000017500000000635613013306226020573 0ustar dominikdominik# - Find libCrypto # Find the native OpenSSL LIBCRYPTO includes and library # # LIBCRYPTO_INCLUDE_DIR - where to find sha.h, etc. # LIBCRYPTO_LIBRARIES - List of libraries when using libCrypto. # LIBCRYPTO_FOUND - True if libCrypto found. IF (LIBCRYPTO_INCLUDE_DIR) # Already in cache, be silent SET(LIBCRYPTO_FIND_QUIETLY TRUE) ENDIF (LIBCRYPTO_INCLUDE_DIR) IF (NOT LIBCRYPTO_INCLUDE_DIR OR NOT LIBCRYPTO_LIBRARIES) FIND_PACKAGE(PkgConfig) IF (PKG_CONFIG_FOUND) PKG_CHECK_MODULES (LIBCRYPTO libcrypto) IF (LIBCRYPTO_FOUND) SET (LIBCRYPTO_INCLUDE_DIR ${LIBCRYPTO_INCLUDE_DIRS}) ENDIF (LIBCRYPTO_FOUND) ENDIF (PKG_CONFIG_FOUND) ENDIF (NOT LIBCRYPTO_INCLUDE_DIR OR NOT LIBCRYPTO_LIBRARIES) IF (NOT LIBCRYPTO_INCLUDE_DIR OR NOT LIBCRYPTO_LIBRARIES) # Require a regular OpenSSL even on OSX/iOS # IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") # # MacOSX has deprecated the use of openssl crypto functions # # and replaced it with API-compatible CommonCrypto # FIND_PATH(LIBCRYPTO_INCLUDE_DIR CommonCrypto/CommonDigest.h) # SET(LIBCRYPTO_LIBRARY_NAMES_RELEASE ${LIBCRYPTO_LIBRARY_NAMES_RELEASE} ${LIBCRYPTO_LIBRARY_NAMES} ssl) # SET(LIBCRYPTO_LIBRARY_NAMES_DEBUG ${LIBCRYPTO_LIBRARY_NAMES_DEBUG} ssld) # ELSE(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") FIND_PATH(LIBCRYPTO_INCLUDE_DIR openssl/sha.h) SET(LIBCRYPTO_LIBRARY_NAMES_RELEASE ${LIBCRYPTO_LIBRARY_NAMES_RELEASE} ${LIBCRYPTO_LIBRARY_NAMES} crypto) SET(LIBCRYPTO_LIBRARY_NAMES_DEBUG ${LIBCRYPTO_LIBRARY_NAMES_DEBUG} cryptod) # ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") FIND_LIBRARY(LIBCRYPTO_LIBRARY_RELEASE NAMES ${LIBCRYPTO_LIBRARY_NAMES_RELEASE} ) # Find a debug library if one exists and use that for debug builds. # This really only does anything for win32, but does no harm on other # platforms. FIND_LIBRARY(LIBCRYPTO_LIBRARY_DEBUG NAMES ${LIBCRYPTO_LIBRARY_NAMES_DEBUG}) INCLUDE(LibraryDebugAndRelease) SET_LIBRARY_FROM_DEBUG_AND_RELEASE(LIBCRYPTO) # handle the QUIETLY and REQUIRED arguments and set LIBCRYPTO_FOUND to TRUE if # all listed variables are TRUE INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBCRYPTO DEFAULT_MSG LIBCRYPTO_LIBRARY LIBCRYPTO_INCLUDE_DIR) IF(LIBCRYPTO_FOUND) SET( LIBCRYPTO_LIBRARIES ${LIBCRYPTO_LIBRARY} ) ELSE(LIBCRYPTO_FOUND) SET( LIBCRYPTO_LIBRARIES ) ENDIF(LIBCRYPTO_FOUND) MARK_AS_ADVANCED( LIBCRYPTO_LIBRARY LIBCRYPTO_INCLUDE_DIR ) ENDIF (NOT LIBCRYPTO_INCLUDE_DIR OR NOT LIBCRYPTO_LIBRARIES) # check whether using OpenSSL 1.1 API IF (DEFINED LIBCRYPTO_INCLUDE_DIR AND DEFINED LIBCRYPTO_LIBRARIES) INCLUDE(CheckCSourceCompiles) SET(CMAKE_REQUIRED_INCLUDES ${LIBCRYPTO_INCLUDE_DIR}) SET(CMAKE_REQUIRED_LIBRARIES ${LIBCRYPTO_LIBRARIES}) CHECK_C_SOURCE_COMPILES("#include #ifndef OPENSSL_VERSION_NUMBER #error No OPENSSL_VERSION_NUMBER defined #endif #if OPENSSL_VERSION_NUMBER < 0x10100000L #error This is not OpenSSL 1.1 or higher #endif int main(void) { return 0; }" PODOFO_HAVE_OPENSSL_1_1) UNSET(CMAKE_REQUIRED_INCLUDES) UNSET(CMAKE_REQUIRED_LIBRARIES) ENDIF (DEFINED LIBCRYPTO_INCLUDE_DIR AND DEFINED LIBCRYPTO_LIBRARIES) podofo-0.9.5/COPYING0000664000175000017500000004313110432364310013714 0ustar dominikdominik GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. podofo-0.9.5/CODINGSTYLE.txt0000664000175000017500000003041712715346234015224 0ustar dominikdominikThis document tries to give an overview of the codingstyle used in PoDoFo. To keep the code consistent every commit should apply to this codingstyle. The codingstyle of PoDoFo is in no way perfect and is in parts not even the preferred codingstyle of the maintainers. But consistency is more important than personal preferences and most parts of the style can be applied through simple editor settings. 2006 Dominik Seichter 0. Overall Rule =============== Documentation is an important part of PoDoFo. Every class and method should include appropriate documentation in Doxygen format so that automatic API documentation can be generated and the code can be easily understand by everyone. The comments are most important in the header files, though additional information may also be included in the source itself if necessary. 1. Code formatting ================== 1.1 Indentation The code is indented by 4 spaces. No tabs and no discussion ;) EMACS users might apply those settings: (setq tab-width 4) ;; the the preferred tab-width (setq indent-tabs-mode nil) ;; indent using spaces instead of tabs (setq c-basic-offset tab-width) 1.2 Brackets Brackets always start in a new line of their own. The only exception are class and struct declarations and try and catch blocks. Example: if( true ) { // do something } but class MyClass { }; If only one line follows after an if or while statement, no brackets are needed, however they may be used if the author feels that there is a possibility for future expansion in that area. 1.3 Inline functions Inline functions are declared in the class definition in the header file. They are implemented in the header file after the class definition. The author may choose to either implement them directly at the same location as the declaration or may place them at the end of the header file (preferred). 2. Naming ========= 2.1 Variables Someone started to use hungarian notation in PoDoFo. Well, the maintainer thinks this was one of the worst ideas he ever had... . Nontheless, the point is consistency and not personall preference. PoDoFo uses hungarian notation for the following types: enum typenames should start with an E enum variables should start with an e struture typesnames should start with a T struture variables should start with a t pointer should start with a p strings should start with a s c-strings should start with psz (pointer zero terminated) numbers should start with a n long's should start with a l bool's should start with a b references often start with a r Example: bool bDecision; long lValue; char* pszString; int nNumber; 2.2 Member variables Member variables in classes are additionally prefixed with "m_". Examples: class MyClass { private: bool m_bMemberVar; }; 2.3 Methods All methods start with an uppercase letter and every new word is capitalized again. MyClass::FunctionWithLongName( long lParameter ); Properties are set using a function with the prefix "Set", and retrieved with a "Get". Also, unless there is a good reason not to - all "Getters" should be marked as const. MyClass::SetProperty( long lValue ); long MyClass::GetProperty() const; Additionally, please use the prefixes "Has" and "Is" when appropriate. E.g. PdfDictionary::HasKey(); PdfDocument::IsLinearized(); Avoid the throw() qualifier (see 3.5). 2.4 NULL-Pointers NULL Pointers are initialized in the code with the constant NULL. Please do not use 0 or 0L but use NULL. 3. General Guidelines =================== 3.1 Casting C++ style casting is strongly preferred, and the use of C-style casts will generate warnings on gcc builds. Use, as appropriate, static_cast<> const_cast<> reinterpret_cast<> Dynamic casting and typeid are not presently used in PoDoFo. const_cast<> should be avoided unless it is absolutely required, especially for `const char *' variables that might ever take a string literal value. 3.2 Local variable declaration Local variables should always be declared closest to their point of use, and should be declared `const' wherever possible. For example: Thing f() { Thing ret; // blah blah blah ret = DoSomething(); // blah blah blah return ret; } would be better written as: Thing f() { // blah blah blah Thing ret ( DoSomething() ); // blah blah blah return ret; } Remember your const pointers: char * x; Pointer to char const char * x; Pointer to const char char * const x; Const pointer to char const char * const x; Const pointer to const char 3.3 Static arrays Static data should be declared as an array of const char rather than a pointer to const char whereever possible. This will help the compiler put it in the static read only data section of the compiled object, resulting in a smaller memory footprint, faster load times, and hardware protection against accidental writes to the data. const char myStaticData[] = "This is the right way". const char * myStaticData = "Avoid this way". Two dimensional arrays may be specified in a similar way - see s_szPdfVersions in PdfDefines.{cpp,h} . It's usually better to waste a few bytes by padding the array to the length of the longest member and get it into the readonly data section of the executable than it is to use an array of pointers to char and save a few bytes. Which is best is, however, dependent on what "a few bytes" is in a given situation. 3.4 Use of temporary objects Where possible, it can be better to use a temporary rather than storing a named object, eg: DoSomething( PdfName("blah") ); rather than PdfName n("blah"); DoSomething( n ); as this makes it easier for the compiler to optimise the call, may reduce the stack size of the function, etc. Don't forget to consider the lifetime of the temporary, however. 3.5 The `throw' qualifier Under no circumstances use exception specifiers, even the empty exception specifier `throw()'. C++ checked exceptions - when implemented according to the standard - are essentially useless and may actually be costly. If you want to tell the compiler a method will not throw (as an optimisation) use a macro for __declspec(nothrow) instead. podofoapi provides appropriate macros for use in podofo. (Note that VC++ treats throw() as __declspec(nothrow) in violation of the standard, but that's all the more reason to just use __declspec(nothrow)). see: http://msdn2.microsoft.com/en-us/library/49147z04.aspx http://gcc.gnu.org/onlinedocs/gcc-3.3.1/gcc/Function-Attributes.html 3.6 Exported API PoDoFo draws a distinction between exported and private API on some platforms (currently Windows DLL builds and gcc 4 with PODOFO_USE_VISIBILITY). To do this it uses some macros defined in podofoapi.h to tell the compiler what's public API that should appear in the DLL/shared library's symbol table. The rest is not exported. This may have several positive effects depending on the particular platform and compiler. It can result in a smaller binary, better link times, help the compiler optimise better, and ensure that API intended to be private to PoDoFo _cannot_ be called from outside it. If you add new classes to PoDoFo, annotate them with PODOFO_API as shown in podofoapi.h if they're intended as public API. If an outside user will ever need to reference those symbols directly (by constructing the class, calling its methods, etc) they're public. Note that classes that only inherit and implement an abstract interface (adding no other public methods intended for use outside PoDoFo) that're only constructed through a factory or through other PoDoFo classes need not be exported. If you have a class that needs to be exported as public API, but it has quite a few methods that do not need to be externally visible (private helper methods etc), you can annotate those with the PODOFO_LOCAL macro as shown in podofoapi.h . This omits just those methods from the symbol table. Note that if the methods are accessed via public or protected inline functions it is not safe to make them private. If in doubt, ask for help on podofo-users. It also helps to build PoDoFo as a DLL (Windows) or, on UNIX platforms, use gcc4 and enable visibility support. This will help catch cases where you forgot to export required API. 3.7 Memory allocations in inlined methods It's not safe to (directly) allocate or free heap memory in an inlined function, because it only works if the same runtime library is used in the shared library and the executable linking to the library. Using malloc and/or new in inlined methods will lead to crashes on MS Windows systems. It might be undetected on Linux systems (even though it is bad style on Linux, too), because most processes and libraries use the same runtime library on a Linux system. There's also no point inlining functions that call new / delete / malloc / free, because the memory allocation is dramatically more expensive than a mere function call is. Using STL classes that may perform allocations internally is fine since they tend to carry their own std::allocator instance (or reference, anyway) around with them. 3.8 Visibility of 3rd party headers If at all possible, it's desirable not to expose the use of 3rd party headers in the PoDoFo headers. Rather than including headers for required libraries, try to forward-declare required types and then include the header in the implementation (.cpp) files. If the header is widely used, you might want to put it in PdfDefinesPrivate.h . Widely used forward declarations can go in Pdf3rdPtyForwardDecl.h . Avoiding exposing used 3rd party headers means that users' build systems don't need to know how to find those headers, and means that users' programs don't get their namespaces polluted by unrelated symbols from libjpeg, zlib, libtiff, freetype, etc etc etc. As some headers (*cough*freetype*cough*) aren't trivial to reliably locate, this can really simplify the build of tools that use PoDoFo. This applies to some system headers too. for example is a difficult and quirky header. Its behaviour is strongly affected by a variety of preprocessor definitions and it scatters macros everywhere. We shouldn't be exposing it to library users, because it's quite likely they'll need to include it with different macro parameters, and theirs may conflict with ours or vice versa. If you need to include a 3rd party header to make something a direct member, consider making it a member by pointer instead, initializing it in the object's ctor and destroying it it the dtor. That way you don't need to include the 3rd party's header to get access to their type sizes in the PoDoFo headers, only in the .cpp files. See, for example, PdfMutex.h . 4. Structure ============ 4.1 Project structure The PoDoFo project is structure as follows. There are two libraries: podofo-base and podofo-doc. Podofo-base contains everythign needed to work with reading, writing and modifying PDF files and there objects. It should have a minimal set of dependencies. Podofo-doc provides a rich interface, which also allows to easily create PDF files using the PdfPainter and PdfFont infrastructure. Additionally, there are two more projects. The test/ subdirectory contains tests for both libraries. All new tests shall go to the test/unit/ sub-projects to provide unit-tests for PoDoFo. Utility programs that come with PoDoFo go into the tools/ subdirectory. These tools provide a direct benefit for end users who want to work with PDF files on the commandline and are also a nice way to showcase the features of the PoDoFo libraries to new developers. podofo-0.9.5/README.html0000664000175000017500000010472111725624277014530 0ustar dominikdominik PoDoFo Readme

PoDoFo

  1. What is PoDoFo?
  2. Where can I can get it?
  3. Requirements
  4. Installation
    1. STLPort support
    2. Boost support
    3. Installation with CMake
      1. CMake builds on Linux/UNIX
      2. CMake builds on Mac OS X
      3. Homebrew builds on Mac OS X
      4. CMake builds on Windows
  5. Using PoDoFo in Your Application
  6. Preprocessor defines used in PoDoFo
  7. Structure of the library
  8. Contact
  9. Licensing

What is PoDoFo?

PoDoFo is a library to work with the PDF file format and includes also a few tools. The name comes from the first two letters of PDF (Portable Document Format).

The PoDoFo library is a free portable C++ library which includes classes to parse a PDF file and modify its contents into memory. The changes can be written back to disk easily. PoDoFo is designed to avoid loading large PDF objects into memory until they are required and can write large streams immediately to disk, so it is possible to manipulate quite large files with it. PoDoFo uses and relies on exceptions, so it must be built with them enabled.

Besides PDF parsing and writing PoDoFo includes also very simple classes to create your own PDF files. All classes are documented so it is easy to start writing your own application using PoDoFo.

PoDoFo is primarily useful for applications that wish to do lower level manipulation of PDF, such as extracting content or merging files. It's also useful if your application has specific requirements for it's PDF output that more general output-oriented libraries like Cairo cannot satisfy. Canvas/drawing support is currently very limited in PoDoFo, so for pure output tasks a library like Cairo will be more suitable. PoDoFo cannot render PDF, so you should look at a library like Poppler for that.

See:

The PoDoFo tools are simple tools build around the PoDoFo library. These tools are first of all examples on how to use the PoDoFo library in your own projects. But secondly they offer also features for working with PDF files. More tools will come with future release and the existing tools will gain more features. The following tools are currently available:

  • podofoencrypt - Encrypts any PDF and allows to set PDF permissions..
  • podofoimgextract - Extracts all images from a given PDF file.
  • podofoimpose - A powerful PDF imposition tool. It places pages from one or more source PDFs onto pages of a new PDF, applying scaling and positioning. If you have lua5.1 development libraries installed, it will be built with support for Lua plan files, which allow for mighty PDF transformations.
  • podofomerge - Merges two PDF files into onw.
  • podofopdfinfo - Provides some basic info about a PDF - metadata, page details, etc.
  • podofotxt2pdf - Converts a text file to a PDF
  • podofotxtextract - A tool that extracts all text from a PDF file. Works only for simple PDFs at the moment.
  • podofouncompress - Removes all compression filters from a PDF file. This is useful for debugging existing PDF files. You might also find PoDoFoBrowser, distributed separately, to be useful if you're using this tool a lot.

Additionally there is the external tool PoDoFoBrowser which is not included in this package, but can be downloaded from the PoDoFo webpage. PoDoFoBrowser is a Qt application for browsing and modifying the objects in a PDF file, examining the structure of PDF files, and manipulating PDF streams. It is very useful if you want to look on the internal structure of PDF files.

As of version 0.7 PoDoFo is available for Unix, Mac OS X and Windows platforms.

Where can I can get it?

PoDoFo is available on the internet: podofo.sf.net

Requirements

To build PoDoFo lib you need a working toolchain and a c++ compiler as well as the following libraries:

  • zlib
  • freetype2
  • fontconfig (Unix & Mac OS X only)
  • libjpeg (optional)
  • libtiff (optional)
  • libidn (optional)
  • libCrypto++ (optional)

See Installation with CMake for a list of tested platforms and compilers. In general, any reasonably well behaved C++ compiler should work.

A list of known -dev / -devel packages required for various Linux distros is maintained in the required Linux packages appendix.

See also Using PoDoFo.

Installation

Rather than using binary packages, you should usually build PoDoFo yourself. This ensures that it will be built with the same compiler and settings as your program. Because most platforms have no consistent C++ ABI or runtime libraries, this is important to ensure that you get a compatible STL, correct memory management between podofo and your app, etc.

PoDoFo is built and installed using CMake. The autotools build, Visual Studio project and XCode project were dropped as maintaining three unrelated and incompatible build systems that are exclusive to three different platforms consumes a lot of resources which can be spend better on improving PoDoFo itself. Even if you've never used CMake before, you'll find it pretty easy.

Unix users should generate Unix Makefiles with CMake, though it's also possible to produce a KDevelop project. See CMake builds on Linux/UNIX

If your application or library uses Visual Studio, CMake can be used to build a Visual Studio project you can use. Alternately, if you are using MinGW for your existing code, CMake can make you a MinGW makefile to build a mingw compatible version of PoDoFo. You must build PoDoFo with the same compiler as your application. See CMake builds on Windows

Mac OS X users will need to use CMake to generate a conventional UNIX build with Makefiles, or may generate an XCode project with CMake. See the Mac OS X section below, and the generic instructions for cmake builds

STLPort support

Don't know what STLPort is? Ignore it and skip this section. Packagers should not enable STLPort.

If your project uses STLPort rather than your platform/toolset's native STL, you must configure PoDoFo to use STLPort as well. Use the -DUSE_STLPORT=1 argument to configure. Do not enable STLPort for podofo unless you use it in your project; you will get an incompatible C++ STL leading to link errors, runtime crashes, or other problems.

It is unnecessary and unwise to build PoDoFo against STLPort on any current major platform unless you have a specific reason to do so.

Boost support

PoDoFo can make limited use of the Boost libraries if they are available. There is no need to use them, but some things may work more smoothly, and more use is expected in the future. If PoDoFo is built to use Boost, your application must also have Boost's headers (boost graph libraries) on its search path. Set -DWANT_BOOST:BOOL=1 to enable Boost support.

Packagers should not currently build PoDoFo with boost support.

Installation with CMake

PoDoFo has support for builds using CMake on all supported platforms. The CMake build has been tested on:

  • Visual C++ 9 Express Edition [Win32] ("Visual Studio 9 2008" target)
  • Visual C++ 8 Express Edition [Win32] ("Visual Studio 8 2005" target) (needs additional setup)
  • Visual C++ 8 Express +NMake [Win32] ("NMake Makefiles" target) (needs additional setup)
  • MinGW with GCC 3.4.2 [Win32] ("MinGW Makefiles" target)
  • gcc 3.3.5 [Linux: Debian 3.1] ("Unix Makefiles" target)
  • gcc 4.0, 4.1, 4.2 [Linux: Debian 4.0] ("Unix Makefiles" target)
  • gcc 4.0 [Mac OS X 10.4.10] ("Unix Makefiles" target)

PoDoFo is also known to build with Visual C++ 6 using CMake, though it is not regularly tested by the team so you might need to do some work to use a recent svn build.

You can use the CMake variable CMAKE_BUILD_TYPE to control the type of build. The main values supported are DEBUG and RELEASE. The default is DEBUG. Set the build type with the CMake argument:
  -DCMAKE_BUILD_TYPE=DEBUG
   or
  -DCMAKE_BUILD_TYPE=RELEASE
as appropriate.

You can control where the files are installed with `make install' with -DCMAKE_INSTALL_PREFIX=/path/to/install/dir

All instructons below use out-of-tree builds (recommended). To clean up an out-of-tree build, just delete the build directory, as no files are touched within the source directory.

On all Makefile-style builds, set the VERBOSE flag to 1 on the make command line to see all compiler commands etc, eg: make VERBOSE=1

CMake builds on Linux/UNIX

Linux and UNIX users should be able to build PoDoFo by cd'ing into the PoDoFo checkout or unpacked tarball directory (here assumed to be named "podofo-src") then running the build commands shown below. The CMake command below will install into $HOME/podofo to avoid needing root priveleges for installation, but you can change the destination to wherever you want or remove the install prefix setting to use the default.

To build and install:

mkdir ../podofo-build
cd ../podofo-build
cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="$HOME/podofo" ../podofo-src
make
make install

To see detailed compiler output, use:

make VERBOSE=1

If you're working on a 64 bit linux that has a /usr/lib64 directory, add -DWANT_LIB64:BOOL=TRUE to the CMake command line.

If you need to specify additional paths to search for libraries, set the CMAKE_INCLUDE_PATH and CMAKE_LIBRARY_PATH environment variables or set them on the command line:

cmake -G "Unix Makefiles" ../podofo-src \
	-DCMAKE_INCLUDE_PATH=/usr/sfw/include \
	-DCMAKE_LIBRARY_PATH=/usr/sfw/lib

If you wish to generate only a static library or only a shared library, set the PODOFO_BUILD_SHARED and/or PODOFO_BUILD_STATIC flags:

cmake -G "Unix Makefiles" ../podofo-src \
	-DCMAKE_INCLUDE_PATH=/usr/sfw/include \
	-DCMAKE_LIBRARY_PATH=/usr/sfw/lib \
	-DPODOFO_BUILD_SHARED:BOOL=TRUE \
	-DPODOFO_BUILD_STATIC:BOOL=FALSE

By default, with CMake 2.6.x all supported library types will be built where possible. Only the shared library will be built by default using 2.4.x because of a CMake limitation; you can build a static library instead with -DPODOFO_BUILD_STATIC:BOOL=TRUE, or upgrade to CMake 2.6.x .

Note that the instructions above run an out-of-tree build. CMake does support in-tree builds, but the use of out-of-tree builds is very strongly recommended.

If your system has gcc 4, PoDoFo will tell gcc to make symbols hidden by default using the -fvisibility=hidden flag to gcc. Only symbols explicitly exported by PoDoFo will be exported. You can explicitly enable or disable this behaviour with the boolean flag: -DPODOFO_USE_VISIBILITY=1 (or 0 for off). Enabling default hidden visibility reduces the PoDoFo binary size dramatically and improves link times. It also helps prevent accidental use of symbols that are not part of PoDoFo's public API. PoDoFo developers will also find this useful, as it will cause some mistakes to be reported as link errors that would otherwise go undetected and break the win32 builds.

CMake builds on Mac OS X

Mac OS X users can build PoDoFo using CMake either by generating conventional UNIX Makefiles (the "Unix Makefiles" CMake target) or generating an XCode project (the "Xcode" target). In either case the following applies.

You will need freetype and fontconfig. It's possible to omit the use of libjpeg (see the platform-independent documentation) but by default libjpeg will also be required. If you have these libraries already (say, from fink or DarwinPorts) you can skip the following section and update the CMAKE_INCLUDE_PATH and CMAKE_LIBRARY_PATH arguments appropriately.

Dependencies

I'll assume you're installing podofo and any required libraries into $HOME/libs . Adjust to taste, but keep it consistent.

The easiest way to get any required libraries is to use MacPorts to install the libjpeg, fontconfig, and freetype libraries. Once you've installed MacPorts, just run:

/opt/local/bin/port install fontconfig freetype jpeg tiff lua

MacPorts will automatically build the libraries and their dependencies, installing them in /opt/local.

If you want to distribute the libraries with your application, all you'll need to do is use install_name_tool to set appropriate relative paths for their linkage and include them in your application bundle - just like you do with any other libraries.

PoDoFo its self

You should be able to configure and install podofo on Mac OS X using:

	cmake -G "Unix Makefiles" \
		-DWANT_FONTCONFIG:BOOL=TRUE \
		-DCMAKE_INSTALL_PREFIX=/opt/podofo \
		-DCMAKE_INCLUDE_PATH=/opt/local/include \
		-DCMAKE_LIBRARY_PATH=/opt/local/lib \
		../podofo
	make
	sudo mkdir /opt/podofo
	sudo chown $USER /opt/podofo
	make install

change "Unix Makefiles" to "Xcode" if you want to build an XCode project instead, then instead of running `make' and `make install' just open the project file and work as normal

Homebrew builds on Mac OS X

For Homebrew (package manager for Mac OS X) it is quite simple to install podofo. Freetype2 and zlib should be installed on Mac OS X by default.

brew install fontconfig
brew install libjpeg
brew install libtiff
cd ((directory of podofo))
cmake -G "Unix Makefiles"
make
make install

CMake builds on Windows

Windows Dependencies

PoDoFo requires a couple of other open source libraries to work. At minimum it needs zlib and libjpeg. Additional functionality is enabled if libtiff and/or openssl are available.

zlib

Both MinGW and Visual Studio users should use the standard precompiled zlib dll from zlib.org. There is no need to compile your own.

Remember that you must ship zlib1.dll with your application. During testing it must be in the same directory as the PoDoFo-using executable or the directory containing it must be on your system PATH.

libjpeg

MinGW users can download the latest libjpeg installer from GnuWin32

.

For Visual Studio you will need to build libjpeg with your version of Visual Studio. Download the libjpeg sources from http://www.ijg.org/ and unpack them into a working directory. I'll assume you've used C:\Developer\jpeg. Once the sources are unpacked, start a visual studio command prompt and cd into c:\developer\jpeg then run copy jconfig.vc jconfig.h then nmake /f makefile.vc /a

.

If you use a DLL build of libjpeg remember that you must ship the DLL with your application. During testing the libjpeg dll must be in the same directory as the PoDoFo-using executable or the directory containing it must be on your system PATH. These requirements do not apply to the (recommended) static library libjpeg.

Building PoDoFo on Windows

Building PoDoFo on Windows can be done using MinGW (a minimalist gcc-based compliler environment for Windows) or Visual Studio. Other methods may work but have not been tested.

CMake 2.6.x is required for Windows. You can download it from cmake.org

.

Because the C++ ABIs of most of the win32 compilers are incompatible, you must build PoDoFo with the same compiler and version that you will use to build the programs linked to PoDoFo. Failure to follow this restriction will result in link errors at best, and bizarre runtime failures at worst.

On Windows, if you are linking against a shared (DLL) build of PoDoFo you MUST define the preprocessor macro USING_SHARED_PODOFO when including any podofo headers. Failure to do so will result in link time and/or runtime errors. Similarly, defining it when linking with a static PoDoFo can cause problems.

On Windows, PoDoFo may be built as either a shared or static library. Building both is not supported. By default only the shared library will be built. If you want a static library, just disable generation of the shared library with the extra argument to cmake:

	-DPODOFO_BUILD_SHARED=FALSE

PoDoFo will generally work correctly if you download pre-built libraries, such as those published by the GnuWin32 project, even if they were built with a different compiler. The primary exception is freetype, which should if at all possible be built using your compiler. Freetype provides a VC++ project file and is very easy to build. Make sure to build both the debug multi-threaded and release multi-threaded versions.

For release you should generally build your own copy of these libraries unless there is a well known and high quality pre-built version, like there is for zlib. If you have built your own libjpeg you can improve PoDoFo's use of it a bit by passing -DJPEG_COMPATIBLE_RUNTIME to CMake to tell PoDoFo it's safe not to use its' workarounds for incompatible runtimes.

Handling library naming on win32

Especially on Windows it is also common for custom built libraries to have different names to those you might download as pre-built copies. CMake won't be able to find them if they're called something else unless you tell it. Use these variables to tell CMake what names to look for a library under:

  • FREETYPE_LIBRARY_NAMES_DEBUG, FREETYPE_LIBRARY_NAMES_RELEASE and FREETYPE_LIBRARY_NAMES
  • TIFF_LIBRARY_NAMES_DEBUG, TIFF_LIBRARY_NAMES_RELEASE and TIFF_LIBRARY_NAMES
  • LIBJPEG_LIBRARY_NAMES_DEBUG, LIBJPEG_LIBRARY_NAMES_RELEASE and LIBJPEG_LIBRARY_NAMES
  • ZLIB_LIBRARY_NAMES_DEBUG, ZLIB_LIBRARY_NAMES_RELEASE, ZLIB_LIBRARY_NAMES

For example, a cmake command line might include -DFREETYPE_LIBRARY_NAMES_DEBUG=freetype239MT_D -DFREETYPE_LIBRARY_NAMES_RELEASE=freetype239MT . If you only have the release library, just use -DFREETYPE_LIBRARY_NAMES . Telling CMake which are debug and release libraries helps it ensure you link to the right libraries depending on build type, but that does no good if you don't have a debug library.

CMake builds on Windows with MinGW

To build PoDoFo with MinGW, you'll naturally need MinGW. The author recommends installing Qt 4 from Trolltech, which has a well packaged version of MinGW and is also useful for some PoDoFo tools like PoDoFoBrowser.

Once MinGW is set up, make sure that the MinGW "bin" directory is on your PATH, and be sure to set CMAKE_INCLUDE_PATH and CMAKE_LIBRARY_PATH such that CMake can find the headers and .lib files for the libraries PoDoFo requires. The GnuWin32 library packages from http://gnuwin32.sf.net/ are known to work with PoDoFo, so installing zlib, freetype, and libjpeg from there should do the trick.

To configure and build PoDoFo with a default GnuWin32 install and with MinGW already on your PATH:

md ..\podofo-debug
cd ..\podofo-debug
cmake -G "MinGW Makefiles" ..\podofo-src -DCMAKE_INCLUDE_PATH=c:\progra~1\gnuwin32\include -DCMAKE_LIBRARY_PATH=c:\progra~1\gnuwin32\lib -DPODOFO_BUILD_SHARED:BOOL=FALSE
mingw32-make

It is extremely strongly recommended that you build PoDoFo only as a static library if you are using MinGW by setting the -DPODOFO_BUILD_SHARED:BOOL=FALSE flag to cmake. libstdc++ on MinGW at the time of writing was not a shared library, causing serious issues with memory allocation and deallocation when C++ objects like std::string are passed by value across DLL boundaries or are otherwise deleted in a different DLL to where they were allocated. Of course, this will cause you problems if you intend to use PoDoFo across DLL boundaries, but until libstd++ is made shared on MinGW there's not much to be done. VC++ does not suffer from this issue.

CMake builds on Windows with Visual Studio

A Visual Studio build requires that Microsoft Visual Studio be installed. Visual Studio 9 2008 Express Edition is known to work, and is a free download from Microsoft. You should get zlib from zlib.org. If you want JPEG support, build your own libjpeg from sources or use the version from GnuWin32 (which will work OK, if a bit slower, despite being built with gcc). It is preferable to build your own copies of freetype, libjpeg and libtiff with your own compiler and bundle those copies.

You'll also need CMake 2.6.

If you're using Visual Studio you really should build your own freetype. With recent VC++ versions the GnuWin32 version of freetype is unlikely to work reliably. Download the sources from http://download.savannah.gnu.org/releases/freetype/ - you want something like ft245.zip . Unpack them and open builds\win32\visualc\freetype.sln in VC++, upgrading it if required. Build it in both debug multithreaded and release multithreaded modes. You should now see some .lib files in a subdirectory of the objs\win32\ directory. The following instructions will assume they're named freetype239MT.lib and freetype239MT_D.lib and are found in objs\win32\vc2008, so adjust if yours are different.

If you built a debug freetype, you will also need to copy vc90.pdb (assuming you're using VC++ 9, otherwise the name will vary) from objs\debug_mt\vc90.pdb to objs\win32\vc2008\ so that VC++ can find Freetype's debug info.

The visual studio build of PoDoFo has two stages - first, CMake is used to generate a Visual Studio solution, then the solution is built in VC++. I prefer to create a short build.cmd file for the CMake command since on Windows it tends to get rather long. Here's an example that assumes the build.cmd file is in an empty directory with ..\podofo-src being the relative path to the PoDoFo sources.

del cmakecache.txt
set FTDIR=C:\developer\freetype-2.3.5
set FTLIBDIR=C:\developer\freetype-2.3.5\objs\win32\vc2008
set JPEGDIR=C:\Developer\jpeg
set ZLIBDIR=C:\developer\zlib123-dll
cmake -G "Visual Studio 9 2008" ..\podofo-src -DCMAKE_INCLUDE_PATH="%FTDIR%\include;%JPEGDIR%\include;%JPEGDIR%;%ZLIBDIR%\include" -DCMAKE_LIBRARY_PATH="%FTLIBDIR%;%FTDIR%\lib;%JPEGDIR%\lib;%JPEGDIR%;%ZLIBDIR%\lib" -DPODOFO_BUILD_SHARED:BOOL=FALSE -DFREETYPE_LIBRARY_NAMES_DEBUG=freetype239MT_D -DFREETYPE_LIBRARY_NAMES_RELEASE=freetype239MT

Run the saved build.cmd from a cmd.exe window. If all goes well, you can open and build the generated podofo.sln in Visual Studio and build it.

Note that CMake should automatically find your Visual Studio install, so you shouldn't need any special settings unless you have an unusual setup or more than copy of the same version of Visual Studio installed.

You can download the free Visual C++ Express Edition 9 from Microsoft.

PROBLEMS?

If you have problems, try deleting your build directory then re-running the commands above after running:

set PATH=%SystemRoot%;%SystemRoot%\SYSTEM32

in the cmd.exe window you are using. If you do this you'll have to copy jpeg62.dll, freetype6.dll, and zlib.dll (names may vary; make sure they're the ones that match the LIB files you linked to) to the same folder as the .exe you are trying to run. This should resolve any issues caused by incompatible DLLs with the same names being present earlier on your PATH - a rather common issue if you have lots of open source software installed. Do this if you get unexplained crashes or errors about missing/mismatched ordinals.

CMake builds on Windows with NMake

PoDoFo can also be built with NMake. The build procedure is essentially the same as described for MinGW or Visual Studio, but you must use the target name "NMake Makefiles" and run "nmake" after CMake completes. Remember to run everything from within a Visual Studio environment shell or to run vcvarsall.bat before running CMake.

With Visual C++ Express Edition 8, you must also separately run setenv.cmd from the Win32 SDK. This is not required for Express Edition 9.

Using PoDoFo in Your Application

A simple example that uses PoDoFo can be found in examples/helloworld . You will also find the tests and tools shipped with PoDoFo informative when learning to use the library. Reading the documentation on PdfMemDocument, PdfStreamedDocument, PdfObject and PdfVariant may also be useful.

UNSTABLE API (IMPORTANT)

It is very important to understand that PoDoFo's 0.x's API is not stable from release to release. As such, rather than relying on a particular version of PoDoFo being shipped by the OS/distro that you are targeting, consider building and linking to your own private copy of PoDoFo. (Win32 developers will do this anyway). For example, between PoDoFo 0.5.0 and early PoDoFo 0.6.0svn, PdfDocument changed from being a concrete class to an abstract parent of PdfMemDocument and PdfStreamedDocument, thus breaking code that instantiates PdfDocument .

A good way to handle maintaining your own private copy if you use Subversion for your project is to use the svn:externals mechanism to automatically reference a specific revision of PoDoFo from podofo svn, or a particular tag . This permits you to control when you update to a new version and lets you make sure your code is updated for any API changes, without forcing users to go and find a specific version of PoDoFo. Alternately, you can just check the tree into your own revision control system and do periodic code drops. Have a look at PoDoFoBrowser for an example of the svn:externals approach.

If you statically link to podofo, that'll prevent any unexpected problems with linker paths. Another option on most platforms is to use rpath linking to ensure that a specific copy of the podofo library is preferred by the linker. CMake takes care of this automatically if you're using it for your project.

When PoDoFo reaches 1.x versions it is expected that API changes will be less frequent. At this point, though, they're an unavoidable part of improving and completing the library.

If you are using CMake in your project and you choose to bundle a copy of the PoDoFo sources, with svn:externals or otherwise, you can quite easily build a private copy of PoDoFo as part of your app's normal build process. Have a look at FindLIBPODOFO.cmake from PoDoFoBrowser to see how to do that, or just copy that file.

Compiling and Linking Against PoDoFo

PoDoFo's headers are designed to avoid exposing its library dependencies, so you do not need the headers for Freetype etc on the include path. However, you MUST link your application to podofo's required libraries on most platforms, eg on UNIX:

    -lpodofo -lfreetype -lfontconfig -ljpeg -lz

is generally appropriate. Win32 users must also ensure that they link to gdi32 and ws_win32.

Handling Exceptions

When working with PoDoFo it is important to remember that the library makes use of exceptions. Your code must be built with exception support and must be exception safe in areas that call PoDoFo. gcc users may not build with -fno-exceptions. If you have non-exception-safe code or code (such as pure C code) that cannot propagate exceptions your podofo-using code must catch all exceptions before they propagate to such unsafe sections. PoDoFo will throw a PdfError& for PoDoFo-specific exceptions. It may also propagate STL/runtime generated exceptions like std::bad_alloc, though it'll never throw them directly. PoDoFo cannot be built without exceptions.

More general information about exception handling is in the FAQ.

Preprocessor defines used in PoDoFo

Several preprocessor defines are used inside PoDoFo. This section tries to document all of them. These defines are set automatically by the CMake build system, so usually you do not have to worry about them.

Define Meaning
DEBUG Indicates a debug build of PoDoFo.
PODOFO_EXTRA_CHECKS Should we do lots of extra (expensive) sanity checking? You should not define this on production builds because of the runtime cost and because it might cause the library to abort() if it notices something nasty. It may also change the size of some objects, and is thus not binary compatible.
PODOFO_IS_LITTLE_ENDIAN This define is set on all little endian system and required on these systems for PoDoFo to work properly.
PODOFO_IS_BIG_ENDIAN This define is set on all big endian system and required on these systems for PoDoFo to work properly.
PODOFO_MULTI_THREAD Will compile PoDoFo with threading support, e.g. mutex that lock global variables.
PODOFO_VERBOSE_DEBUG This will cause PoDoFo to write even more debug output to the commandline.
HAVE_BOOST If defined PoDoFo is compiled with Boost support.
PODOFO_HAVE_JPEG_LIB If defined PoDoFo will use libJpeg to read and decode JPEG images.
PODOFO_HAVE_TIFF_LIB If defined PoDoFo will use libTiff to read and decode TIFF images.
PODOFO_HAVE_LUA If defined PoDoFoImpose will be built with Lua support for plan files.

Structure of the library

PoDoFo is structured into two libraries podofo-base and podofo-doc, where most users want to use podofo-doc which includes all the PoDoFo features and dependends on the podofo-base library.

If you only need basic PDF editing features and are not afraid of working with the object in a PDF file directly (see PdfObject), podofo-base is the right choice for you. It has only a few dependencies (zlib and libjpeg for compression). Contrary, podofo-doc provides you with a much richer and easier to use interface, but has some more dependencies to handle fonts and images. The image below shows the dependencies of each of the two libraries.

Architecture

Contact

If you have questions on PoDoFo or bug reports, feature requests you can email our mailinglist <podofo-users@lists.sf.net>. Sign up details are available on the podofo support page.

Licensing

The library is licensed under the LGPL (i.e. you may even use the shared library in closed sourced applications). The tests and tools which are included in PoDoFo are licensed under the GPL. See the files COPYING and COPYING.LIB for details. More detailed explanations are in the FAQ on the website, but the licenses have the final say.

Appendices

Required Linux Packages

Linux distros love to name their packages in various weird ways. Here are commands to install the required -dev or -devel packages for PoDoFo for various distros. Please send additions for reasonably recent distros to the PoDoFo mailing list.

  • Ubuntu (also generally applies to recent Debian)
    • 8.10 and most others: sudo aptitude install build-essential g++ cmake libz-dev libtiff-dev libjpeg-dev libfreetype6-dev libfontconfig-dev
podofo-0.9.5/cmake_uninstall.cmake.in0000664000175000017500000000144410653272660017455 0ustar dominikdominikIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) STRING(REGEX REPLACE "\n" ";" files "${files}") FOREACH(file ${files}) MESSAGE(STATUS "Uninstalling \"${file}\"") IF(NOT EXISTS "${file}") MESSAGE(FATAL_ERROR "File \"${file}\" does not exists.") ENDIF(NOT EXISTS "${file}") EXEC_PROGRAM("@CMAKE_COMMAND@" ARGS "-E remove \"${file}\"" OUTPUT_VARIABLE rm_out RETURN_VARIABLE rm_retval) IF("${rm_retval}" GREATER 0) MESSAGE(FATAL_ERROR "Problem when removing \"${file}\"") ENDIF("${rm_retval}" GREATER 0) ENDFOREACH(file)podofo-0.9.5/podofo_config.h.in0000664000175000017500000000346213013306226016255 0ustar dominikdominik/* Template filled out by CMake */ /* * *** THIS HEADER IS INCLUDED BY PdfCompilerCompat.h *** * *** DO NOT INCLUDE DIRECTLY *** */ #ifndef _PDF_COMPILERCOMPAT_H #error Please include PdfDefines.h instead #endif #define PODOFO_VERSION_MAJOR @PODOFO_VERSION_MAJOR@ #define PODOFO_VERSION_MINOR @PODOFO_VERSION_MINOR@ #define PODOFO_VERSION_PATCH @PODOFO_VERSION_PATCH@ /* PoDoFo configuration options */ #cmakedefine PODOFO_MULTI_THREAD /* somewhat platform-specific headers */ #cmakedefine PODOFO_HAVE_STRINGS_H 1 #cmakedefine PODOFO_HAVE_ARPA_INET_H 1 #cmakedefine PODOFO_HAVE_WINSOCK2_H 1 #cmakedefine PODOFO_HAVE_MEM_H 1 #cmakedefine PODOFO_HAVE_CTYPE_H 1 /* Integer types - headers */ #cmakedefine PODOFO_HAVE_STDINT_H 1 #cmakedefine PODOFO_HAVE_BASETSD_H 1 #cmakedefine PODOFO_HAVE_SYS_TYPES_H 1 /* Integer types - type names */ #cmakedefine PDF_INT8_TYPENAME @PDF_INT8_TYPENAME@ #cmakedefine PDF_INT16_TYPENAME @PDF_INT16_TYPENAME@ #cmakedefine PDF_INT32_TYPENAME @PDF_INT32_TYPENAME@ #cmakedefine PDF_INT64_TYPENAME @PDF_INT64_TYPENAME@ #cmakedefine PDF_UINT8_TYPENAME @PDF_UINT8_TYPENAME@ #cmakedefine PDF_UINT16_TYPENAME @PDF_UINT16_TYPENAME@ #cmakedefine PDF_UINT32_TYPENAME @PDF_UINT32_TYPENAME@ #cmakedefine PDF_UINT64_TYPENAME @PDF_UINT64_TYPENAME@ /* Sizes of int64 and long, to pick proper printf format */ #cmakedefine SZ_INT64 @SZ_INT64@ #cmakedefine SZ_LONG @SZ_LONG@ /* Endianness */ #cmakedefine TEST_BIG /* Features */ #cmakedefine PODOFO_NO_FONTMANAGER /* Libraries */ #cmakedefine PODOFO_HAVE_JPEG_LIB #cmakedefine PODOFO_HAVE_PNG_LIB #cmakedefine PODOFO_HAVE_TIFF_LIB #cmakedefine PODOFO_HAVE_FONTCONFIG #cmakedefine PODOFO_HAVE_LUA #cmakedefine PODOFO_HAVE_BOOST #cmakedefine PODOFO_HAVE_CPPUNIT #cmakedefine PODOFO_HAVE_OPENSSL #cmakedefine PODOFO_HAVE_OPENSSL_1_1 #cmakedefine PODOFO_HAVE_LIBIDN podofo-0.9.5/src/0000775000175000017500000000000013044451161013451 5ustar dominikdominikpodofo-0.9.5/src/CMakeLists.txt0000664000175000017500000002315313013116642016213 0ustar dominikdominikCMAKE_MINIMUM_REQUIRED(VERSION 2.6) IF(NOT PODOFO_MAIN_CMAKELISTS_READ) MESSAGE(FATAL_ERROR "Run cmake on the CMakeLists.txt in the project root, not the one in the 'src' directory. You will need to delete CMakeCache.txt from the current directory.") ENDIF(NOT PODOFO_MAIN_CMAKELISTS_READ) SET(PODOFO_BASE_DEPEND_TARGET CACHE INTERNAL "Which PoDoFo library target to depend on when building tools and tests") SET(PODOFO_DEPEND_TARGET CACHE INTERNAL "Which PoDoFo library target to depend on when building tools and tests") SET(PODOFO_BASE_SOURCES base/PdfArray.cpp base/PdfCanvas.cpp base/PdfColor.cpp base/PdfContentsTokenizer.cpp base/PdfData.cpp base/PdfDataType.cpp base/PdfDate.cpp base/PdfDictionary.cpp base/PdfEncoding.cpp base/PdfEncodingFactory.cpp base/PdfEncrypt.cpp base/PdfError.cpp base/PdfFileStream.cpp base/PdfFilter.cpp base/PdfFiltersPrivate.cpp base/PdfImmediateWriter.cpp base/PdfInputDevice.cpp base/PdfInputStream.cpp base/PdfLocale.cpp base/PdfMemStream.cpp base/PdfMemoryManagement.cpp base/PdfName.cpp base/PdfObject.cpp base/PdfObjectStreamParserObject.cpp base/PdfOutputDevice.cpp base/PdfOutputStream.cpp base/PdfParser.cpp base/PdfParserObject.cpp base/PdfRect.cpp base/PdfRefCountedBuffer.cpp base/PdfRefCountedInputDevice.cpp base/PdfReference.cpp base/PdfStream.cpp base/PdfString.cpp base/PdfTokenizer.cpp base/PdfVariant.cpp base/PdfVecObjects.cpp base/PdfWriter.cpp base/PdfXRef.cpp base/PdfXRefStream.cpp base/PdfXRefStreamParserObject.cpp ) SET(PODOFO_DOC_SOURCES doc/PdfAcroForm.cpp doc/PdfAction.cpp doc/PdfAnnotation.cpp doc/PdfCMapEncoding.cpp doc/PdfContents.cpp doc/PdfDestination.cpp doc/PdfDifferenceEncoding.cpp doc/PdfDocument.cpp doc/PdfElement.cpp doc/PdfEncodingObjectFactory.cpp doc/PdfExtGState.cpp doc/PdfField.cpp doc/PdfFileSpec.cpp doc/PdfFont.cpp doc/PdfFontCID.cpp doc/PdfFontCache.cpp doc/PdfFontConfigWrapper.cpp doc/PdfFontFactory.cpp doc/PdfFontMetrics.cpp doc/PdfFontMetricsBase14.cpp doc/PdfFontMetricsFreetype.cpp doc/PdfFontMetricsObject.cpp doc/PdfFontSimple.cpp doc/PdfFontTTFSubset.cpp doc/PdfFontTrueType.cpp doc/PdfFontType1.cpp doc/PdfFontType3.cpp doc/PdfFontType1Base14.cpp doc/PdfFunction.cpp doc/PdfHintStream.cpp doc/PdfIdentityEncoding.cpp doc/PdfImage.cpp doc/PdfInfo.cpp doc/PdfMemDocument.cpp doc/PdfNamesTree.cpp doc/PdfOutlines.cpp doc/PdfPage.cpp doc/PdfPagesTree.cpp doc/PdfPagesTreeCache.cpp doc/PdfPainter.cpp doc/PdfPainterMM.cpp doc/PdfShadingPattern.cpp doc/PdfSignOutputDevice.cpp doc/PdfSignatureField.cpp doc/PdfStreamedDocument.cpp doc/PdfTable.cpp doc/PdfTilingPattern.cpp doc/PdfXObject.cpp ) IF(WIN32) # If we build for windows systems, we also include the resource file SET(PODOFO_DOC_SOURCES ${PODOFO_DOC_SOURCES} doc/podofo-doc.rc) ENDIF(WIN32) SET(PODOFO_HEADERS podofo-base.h podofo.h) SET(PODOFO_BASE_HEADERS ${PoDoFo_BINARY_DIR}/podofo_config.h base/Pdf3rdPtyForwardDecl.h base/PdfArray.h base/PdfCanvas.h base/PdfColor.h base/PdfCompilerCompat.h base/PdfCompilerCompatPrivate.h base/PdfContentsTokenizer.h base/PdfData.h base/PdfDataType.h base/PdfDate.h base/PdfDefines.h base/PdfDefinesPrivate.h base/PdfDictionary.h base/PdfEncoding.h base/PdfEncodingFactory.h base/PdfEncrypt.h base/PdfExtension.h base/PdfError.h base/PdfFileStream.h base/PdfFilter.h base/PdfFiltersPrivate.h base/PdfImmediateWriter.h base/PdfInputDevice.h base/PdfInputStream.h base/PdfLocale.h base/PdfMemStream.h base/PdfMemoryManagement.h base/PdfName.h base/PdfObject.h base/PdfObjectStreamParserObject.h base/PdfOutputDevice.h base/PdfOutputStream.h base/PdfParser.h base/PdfParserObject.h base/PdfRect.h base/PdfRefCountedBuffer.h base/PdfRefCountedInputDevice.h base/PdfReference.h base/PdfStream.h base/PdfString.h base/PdfTokenizer.h base/PdfVariant.h base/PdfVecObjects.h base/PdfVersion.h base/PdfWriter.h base/PdfXRef.h base/PdfXRefStream.h base/PdfXRefStreamParserObject.h base/podofoapi.h ) SET(PODOFO_BASE_HEADERS2 base/util/PdfMutex.h base/util/PdfMutexImpl_noop.h base/util/PdfMutexImpl_win32.h base/util/PdfMutexImpl_pthread.h base/util/PdfMutexWrapper.h ) SET(PODOFO_DOC_HEADERS doc/PdfAcroForm.h doc/PdfAction.h doc/PdfAnnotation.h doc/PdfCMapEncoding.h doc/PdfContents.h doc/PdfDestination.h doc/PdfDifferenceEncoding.h doc/PdfDocument.h doc/PdfElement.h doc/PdfEncodingObjectFactory.h doc/PdfExtGState.h doc/PdfField.h doc/PdfFileSpec.h doc/PdfFont.h doc/PdfFontCID.h doc/PdfFontCache.h doc/PdfFontConfigWrapper.h doc/PdfFontFactory.h doc/PdfFontFactoryBase14Data.h doc/PdfFontMetrics.h doc/PdfFontMetricsBase14.h doc/PdfFontMetricsFreetype.h doc/PdfFontMetricsObject.h doc/PdfFontSimple.h doc/PdfFontTTFSubset.h doc/PdfFontTrueType.h doc/PdfFontType1.h doc/PdfFontType3.h doc/PdfFontType1Base14.h doc/PdfFunction.h doc/PdfHintStream.h doc/PdfIdentityEncoding.h doc/PdfImage.h doc/PdfInfo.h doc/PdfMemDocument.h doc/PdfNamesTree.h doc/PdfOutlines.h doc/PdfPage.h doc/PdfPagesTree.h doc/PdfPagesTreeCache.h doc/PdfPainter.h doc/PdfPainterMM.h doc/PdfShadingPattern.h doc/PdfSignOutputDevice.h doc/PdfSignatureField.h doc/PdfStreamedDocument.h doc/PdfTable.h doc/PdfTilingPattern.h doc/PdfXObject.h ) # Create a Source Group for Visual Studio # so that headers are listed in the folder view # and are easier accessible SOURCE_GROUP(Headers FILES ${PODOFO_HEADERS} ${PODOFO_BASE_HEADERS} ${PODOFO_BASE_HEADERS2} ${PODOFO_DOC_HEADERS}) INSTALL(FILES ${PODOFO_HEADERS} DESTINATION "include/podofo" ) INSTALL(FILES ${PODOFO_BASE_HEADERS} DESTINATION "include/podofo/base" ) INSTALL(FILES ${PODOFO_BASE_HEADERS2} DESTINATION "include/podofo/base/util" ) INSTALL(FILES ${PODOFO_DOC_HEADERS} DESTINATION "include/podofo/doc" ) IF(NOT PODOFO_BUILD_SHARED AND NOT PODOFO_BUILD_STATIC) MESSAGE(FATAL_ERROR "At least one of PODOFO_BUILD_SHARED and PODOF_BUILD_STATIC must be set") ENDIF(NOT PODOFO_BUILD_SHARED AND NOT PODOFO_BUILD_STATIC) IF(PODOFO_BUILD_STATIC) MESSAGE("Building static PoDoFo library") ADD_LIBRARY(podofo_static STATIC ${PODOFO_BASE_SOURCES} ${PODOFO_DOC_SOURCES}) TARGET_LINK_LIBRARIES(podofo_static ${PODOFO_LIB_DEPENDS}) SET_TARGET_PROPERTIES(podofo_static PROPERTIES VERSION "${PODOFO_LIBVERSION}" SOVERSION "${PODOFO_SOVERSION}" CLEAN_DIRECT_OUTPUT 1 OUTPUT_NAME "podofo" COMPILE_FLAGS "-DBUILDING_PODOFO" ) SET(PODOFO_DEPEND_TARGET podofo_static CACHE INTERNAL "Which PoDoFo library variant to depend on") SET(USING_SHARED_PODOFO FALSE) INSTALL(TARGETS podofo_static RUNTIME DESTINATION "bin" LIBRARY DESTINATION "${LIBDIRNAME}" ARCHIVE DESTINATION "${LIBDIRNAME}" ) ENDIF(PODOFO_BUILD_STATIC) IF(PODOFO_BUILD_SHARED) MESSAGE("Building shared PoDoFo library") ADD_LIBRARY(podofo_shared SHARED ${PODOFO_BASE_SOURCES} ${PODOFO_DOC_SOURCES}) TARGET_LINK_LIBRARIES(podofo_shared ${PODOFO_LIB_DEPENDS}) # TODO: set /wd4251 flag if we're doing a debug build with # Visual Studio, since it produces invalid warnings about STL # use. SET_TARGET_PROPERTIES(podofo_shared PROPERTIES VERSION "${PODOFO_LIBVERSION}" SOVERSION "${PODOFO_SOVERSION}" CLEAN_DIRECT_OUTPUT 1 OUTPUT_NAME "podofo" COMPILE_FLAGS "-DBUILDING_PODOFO" ) # Since we're building a shared podofo, prefer to depend on this one for # tests and tools over the static library (if built). SET(PODOFO_DEPEND_TARGET podofo_shared CACHE INTERNAL "Which PoDoFo library variant to depend on") SET(USING_SHARED_PODOFO TRUE) INSTALL(TARGETS podofo_shared RUNTIME DESTINATION "bin" LIBRARY DESTINATION "${LIBDIRNAME}" ARCHIVE DESTINATION "${LIBDIRNAME}" ) # Create a pkg-config file for linking against shared library # if pkg-config is available on the system. # Add a version to the file name corresponding to the API compatibility. FIND_PROGRAM(PKG_CONFIG_FOUND pkg-config) IF(PKG_CONFIG_FOUND) MESSAGE("Pkg-config found, creating a pkg-config file for linking against shared library.") CONFIGURE_FILE( "libpodofo.pc.in" "${PoDoFo_BINARY_DIR}/libpodofo-${PODOFO_VERSION_MAJOR}.pc" @ONLY) INSTALL( FILES "${PoDoFo_BINARY_DIR}/libpodofo-${PODOFO_VERSION_MAJOR}.pc" DESTINATION "${LIBDIRNAME}/pkgconfig") ELSE(PKG_CONFIG_FOUND) MESSAGE("Pkg-config not found. No pkg-config file will be created.") ENDIF(PKG_CONFIG_FOUND) ENDIF(PODOFO_BUILD_SHARED) # Use these flags when compiling code that includes PoDoFo headers. # Failure to do so will result in compilation or link-time errors # on some platforms, and can even cause undefined results at runtime. IF(WIN32 AND USING_SHARED_PODOFO) SET(PODOFO_CFLAGS "-DUSING_SHARED_PODOFO" CACHE INTERNAL "Extra flags required when linking to PoDoFo") ELSE(WIN32 AND USING_SHARED_PODOFO) SET(PODOFO_CFLAGS "" CACHE INTERNAL "Extra flags required when linking to PoDoFo") ENDIF(WIN32 AND USING_SHARED_PODOFO) # Write the cflags and depend target to the config file FILE(APPEND "${PoDoFo_BINARY_DIR}/PoDoFoConfig.cmake" "SET(PODOFO_CFLAGS ${PODOFO_CFLAGS})\n" ) FILE(APPEND "${PoDoFo_BINARY_DIR}/PoDoFoConfig.cmake" "SET(PODOFO_DEPEND_TARGET ${PODOFO_DEPEND_TARGET})\n" ) podofo-0.9.5/src/base/0000775000175000017500000000000013044451161014363 5ustar dominikdominikpodofo-0.9.5/src/base/PdfXRefStreamParserObject.cpp0000664000175000017500000002277712466711113022067 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2009 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfXRefStreamParserObject.h" #include "PdfArray.h" #include "PdfDictionary.h" #include "PdfStream.h" #include "PdfVariant.h" #include namespace PoDoFo { PdfXRefStreamParserObject::PdfXRefStreamParserObject(PdfVecObjects* pCreator, const PdfRefCountedInputDevice & rDevice, const PdfRefCountedBuffer & rBuffer, PdfParser::TVecOffsets* pOffsets ) : PdfParserObject( pCreator, rDevice, rBuffer ), m_lNextOffset(-1L), m_pOffsets( pOffsets ) { } PdfXRefStreamParserObject::~PdfXRefStreamParserObject() { } void PdfXRefStreamParserObject::Parse() { // Ignore the encryption in the XREF as the XREF stream must no be encrypted (see PDF Reference 3.4.7) this->ParseFile( NULL ); // Do some very basic error checking if( !this->GetDictionary().HasKey( PdfName::KeyType ) ) { PODOFO_RAISE_ERROR( ePdfError_NoXRef ); } PdfObject* pObj = this->GetDictionary().GetKey( PdfName::KeyType ); if( !pObj->IsName() || ( pObj->GetName() != "XRef" ) ) { PODOFO_RAISE_ERROR( ePdfError_NoXRef ); } if( !this->GetDictionary().HasKey( PdfName::KeySize ) || !this->GetDictionary().HasKey( "W" ) ) { PODOFO_RAISE_ERROR( ePdfError_NoXRef ); } if( !this->HasStreamToParse() ) { PODOFO_RAISE_ERROR( ePdfError_NoXRef ); } if( this->GetDictionary().HasKey("Prev") ) { m_lNextOffset = static_cast(this->GetDictionary().GetKeyAsLong( "Prev", 0 )); } } void PdfXRefStreamParserObject::ReadXRefTable() { pdf_int64 lSize = this->GetDictionary().GetKeyAsLong( PdfName::KeySize, 0 ); PdfVariant vWArray = *(this->GetDictionary().GetKey( "W" )); // The pdf reference states that W is always an array with 3 entries // all of them have to be integers if( !vWArray.IsArray() || vWArray.GetArray().size() != 3 ) { PODOFO_RAISE_ERROR( ePdfError_NoXRef ); } pdf_int64 nW[W_ARRAY_SIZE] = { 0, 0, 0 }; for( int i=0;i(vWArray.GetArray()[i].GetNumber()); } std::vector vecIndeces; GetIndeces( vecIndeces, static_cast(lSize) ); ParseStream( nW, vecIndeces ); } void PdfXRefStreamParserObject::ParseStream( const pdf_int64 nW[W_ARRAY_SIZE], const std::vector & rvecIndeces ) { char* pBuffer; pdf_long lBufferLen; const size_t entryLen = static_cast(nW[0] + nW[1] + nW[2]); this->GetStream()->GetFilteredCopy( &pBuffer, &lBufferLen ); std::vector::const_iterator it = rvecIndeces.begin(); char* const pStart = pBuffer; while( it != rvecIndeces.end() ) { pdf_int64 nFirstObj = *it; ++it; pdf_int64 nCount = *it; ++it; //pdf_int64 nFirstObjOrg = nFirstObj; //pdf_int64 nCountOrg = nCount; //printf("\n"); //printf("nFirstObj=%i\n", static_cast(nFirstObj)); //printf("nCount=%i\n", static_cast(nCount)); while( nCount > 0 ) { if( (pBuffer - pStart) >= lBufferLen ) { PODOFO_RAISE_ERROR_INFO( ePdfError_NoXRef, "Invalid count in XRef stream" ); } //printf("nCount=%i ", static_cast(nCount)); //printf("pBuffer=%li ", (long)(pBuffer - pStart)); //printf("pEnd=%li ", lBufferLen); if ( nFirstObj >= 0 && nFirstObj < static_cast(m_pOffsets->size()) && ! (*m_pOffsets)[static_cast(nFirstObj)].bParsed) { ReadXRefStreamEntry( pBuffer, lBufferLen, nW, static_cast(nFirstObj) ); } nFirstObj++ ; pBuffer += entryLen; --nCount; } //printf("Exp: nFirstObj=%i nFirstObjOrg + nCount=%i\n", nFirstObj - 1, nFirstObjOrg + nCountOrg - 1 ); //printf("===\n"); } podofo_free( pStart ); } void PdfXRefStreamParserObject::GetIndeces( std::vector & rvecIndeces, pdf_int64 size ) { // get the first object number in this crossref stream. // it is not required to have an index key though. if( this->GetDictionary().HasKey( "Index" ) ) { PdfVariant array = *(this->GetDictionary().GetKey( "Index" )); if( !array.IsArray() ) { PODOFO_RAISE_ERROR( ePdfError_NoXRef ); } TCIVariantList it = array.GetArray().begin(); while ( it != array.GetArray().end() ) { rvecIndeces.push_back( (*it).GetNumber() ); ++it; } } else { // Default rvecIndeces.push_back( static_cast(0) ); rvecIndeces.push_back( size ); } // vecIndeces must be a multiple of 2 if( rvecIndeces.size() % 2 != 0) { PODOFO_RAISE_ERROR( ePdfError_NoXRef ); } } void PdfXRefStreamParserObject::ReadXRefStreamEntry( char* pBuffer, pdf_long, const pdf_int64 lW[W_ARRAY_SIZE], int nObjNo ) { int i; pdf_int64 z; unsigned long nData[W_ARRAY_SIZE]; for( i=0;i W_MAX_BYTES ) { PdfError::LogMessage( eLogSeverity_Error, "The XRef stream dictionary has an entry in /W of size %i.\nThe maximum supported value is %i.\n", lW[i], W_MAX_BYTES ); PODOFO_RAISE_ERROR( ePdfError_InvalidXRefStream ); } nData[i] = 0; for( z=W_MAX_BYTES-lW[i];z(*pBuffer); ++pBuffer; } } //printf("OBJ=%i nData = [ %i %i %i ]\n", nObjNo, static_cast(nData[0]), static_cast(nData[1]), static_cast(nData[2]) ); (*m_pOffsets)[nObjNo].bParsed = true; switch( lW[0] == 0 ? 1 : nData[0] ) // nData[0] contains the type information of this entry { case 0: // a free object (*m_pOffsets)[nObjNo].lOffset = nData[1]; (*m_pOffsets)[nObjNo].lGeneration = nData[2]; (*m_pOffsets)[nObjNo].cUsed = 'f'; break; case 1: // normal uncompressed object (*m_pOffsets)[nObjNo].lOffset = nData[1]; (*m_pOffsets)[nObjNo].lGeneration = nData[2]; (*m_pOffsets)[nObjNo].cUsed = 'n'; break; case 2: // object that is part of an object stream (*m_pOffsets)[nObjNo].lOffset = nData[2]; // index in the object stream (*m_pOffsets)[nObjNo].lGeneration = nData[1]; // object number of the stream (*m_pOffsets)[nObjNo].cUsed = 's'; // mark as stream break; default: { PODOFO_RAISE_ERROR( ePdfError_InvalidXRefType ); } } //printf("m_offsets = [ %i %i %c ]\n", (*m_pOffsets)[nObjNo].lOffset, (*m_pOffsets)[nObjNo].lGeneration, (*m_pOffsets)[nObjNo].cUsed ); } }; podofo-0.9.5/src/base/PdfXRef.cpp0000664000175000017500000002615613013650710016374 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfXRef.h" #include "PdfOutputDevice.h" #include "PdfDefinesPrivate.h" #include namespace PoDoFo { bool PdfXRef::PdfXRefBlock::InsertItem( const TXRefItem & rItem, bool bUsed ) { if( rItem.reference.ObjectNumber() == m_nFirst + m_nCount ) { // Insert at back m_nCount++; if( bUsed ) items.push_back( rItem ); else freeItems.push_back( rItem.reference ); return true; // no sorting required } else if( rItem.reference.ObjectNumber() == m_nFirst - 1 ) { // Insert at front m_nFirst--; m_nCount++; // This is known to be slow, but should not occur actually if( bUsed ) items.insert( items.begin(), rItem ); else freeItems.insert( freeItems.begin(), rItem.reference ); return true; // no sorting required } else if( rItem.reference.ObjectNumber() > m_nFirst - 1 && rItem.reference.ObjectNumber() < m_nFirst + m_nCount ) { // Insert at back m_nCount++; if( bUsed ) { items.push_back( rItem ); std::sort( items.begin(), items.end() ); } else { freeItems.push_back( rItem.reference ); std::sort( freeItems.begin(), freeItems.end() ); } return true; } return false; } PdfXRef::PdfXRef() : m_offset( 0 ) { } PdfXRef::~PdfXRef() { } void PdfXRef::AddObject( const PdfReference & rRef, pdf_uint64 offset, bool bUsed ) { TIVecXRefBlock it = m_vecBlocks.begin(); PdfXRef::TXRefItem item( rRef, offset ); bool bInsertDone = false; while( it != m_vecBlocks.end() ) { if( (*it).InsertItem( item, bUsed ) ) { bInsertDone = true; break; } ++it; } if( !bInsertDone ) { PdfXRefBlock block; block.m_nFirst = rRef.ObjectNumber(); block.m_nCount = 1; if( bUsed ) block.items.push_back( item ); else block.freeItems.push_back( rRef ); m_vecBlocks.push_back( block ); std::sort( m_vecBlocks.begin(), m_vecBlocks.end() ); } } void PdfXRef::Write( PdfOutputDevice* pDevice ) { PdfXRef::TCIVecXRefBlock it = m_vecBlocks.begin(); PdfXRef::TCIVecXRefItems itItems; PdfXRef::TCIVecReferences itFree; const PdfReference* pNextFree = NULL; pdf_objnum nFirst = 0; pdf_uint32 nCount = 0; MergeBlocks(); m_offset = pDevice->Tell(); this->BeginWrite( pDevice ); while( it != m_vecBlocks.end() ) { nCount = (*it).m_nCount; nFirst = (*it).m_nFirst; itFree = (*it).freeItems.begin(); itItems = (*it).items.begin(); if( nFirst == 1 ) { --nFirst; ++nCount; } // when there is only one, then we need to start with 0 and the bogus object... this->WriteSubSection( pDevice, nFirst, nCount ); if( !nFirst ) { const PdfReference* pFirstFree = this->GetFirstFreeObject( it, itFree ); this->WriteXRefEntry( pDevice, pFirstFree ? pFirstFree->ObjectNumber() : 0, EMPTY_OBJECT_OFFSET, 'f' ); } while( itItems != (*it).items.end() ) { // check if there is a free object at the current position while( itFree != (*it).freeItems.end() && *itFree < (*itItems).reference ) { pdf_gennum nGen = (*itFree).GenerationNumber(); // get a pointer to the next free object pNextFree = this->GetNextFreeObject( it, itFree ); // write free object this->WriteXRefEntry( pDevice, pNextFree ? pNextFree->ObjectNumber() : 0, nGen, 'f' ); ++itFree; } this->WriteXRefEntry( pDevice, (*itItems).offset, (*itItems).reference.GenerationNumber(), 'n', (*itItems).reference.ObjectNumber() ); ++itItems; } // Check if there are any free objects left! while( itFree != (*it).freeItems.end() ) { pdf_gennum nGen = (*itFree).GenerationNumber(); // get a pointer to the next free object pNextFree = this->GetNextFreeObject( it, itFree ); // write free object this->WriteXRefEntry( pDevice, pNextFree ? pNextFree->ObjectNumber() : 0, nGen, 'f' ); ++itFree; } ++it; } this->EndWrite( pDevice ); } const PdfReference* PdfXRef::GetFirstFreeObject( PdfXRef::TCIVecXRefBlock itBlock, PdfXRef::TCIVecReferences itFree ) const { const PdfReference* pRef = NULL; // find the next free object while( itBlock != m_vecBlocks.end() ) { if( itFree != (*itBlock).freeItems.end() ) break; // got a free object ++itBlock; if(itBlock != m_vecBlocks.end()) itFree = (*itBlock).freeItems.begin(); } // if there is another free object, return it if( itBlock != m_vecBlocks.end() && itFree != (*itBlock).freeItems.end() ) { pRef = &(*itFree); return pRef; } return pRef; } const PdfReference* PdfXRef::GetNextFreeObject( PdfXRef::TCIVecXRefBlock itBlock, PdfXRef::TCIVecReferences itFree ) const { const PdfReference* pRef = NULL; // check if itFree points to a valid free object at the moment if( itFree != (*itBlock).freeItems.end() ) ++itFree; // we currently have a free object, so go to the next one // find the next free object while( itBlock != m_vecBlocks.end() ) { if( itFree != (*itBlock).freeItems.end() ) break; // got a free object ++itBlock; if( itBlock != m_vecBlocks.end() ) itFree = (*itBlock).freeItems.begin(); } // if there is another free object, return it if( itBlock != m_vecBlocks.end() && itFree != (*itBlock).freeItems.end() ) { pRef = &(*itFree); return pRef; } return pRef; } pdf_uint32 PdfXRef::GetSize() const { pdf_uint32 nCount = 0; PdfXRef::TCIVecXRefBlock it = m_vecBlocks.begin(); while( it != m_vecBlocks.end() ) { nCount += (*it).m_nCount; ++it; } //return nCount; if( !m_vecBlocks.size() ) return 0; const PdfXRefBlock& lastBlock = m_vecBlocks.back(); pdf_objnum highObj = lastBlock.items.size() ? lastBlock.items.back().reference.ObjectNumber() : 0; pdf_objnum highFree = lastBlock.freeItems.size() ? lastBlock.freeItems.back().ObjectNumber() : 0; pdf_uint32 max = PDF_MAX( highObj, highFree ); // From the PdfReference: /Size's value is 1 greater than the highes object number used in the file. return max+1; } void PdfXRef::MergeBlocks() { PdfXRef::TIVecXRefBlock it = m_vecBlocks.begin(); PdfXRef::TIVecXRefBlock itNext = it+1; // Do not crash in case we have no blocks at all if( it == m_vecBlocks.end() ) { PODOFO_RAISE_ERROR( ePdfError_NoXRef ); } while( itNext != m_vecBlocks.end() ) { if( (*itNext).m_nFirst == (*it).m_nFirst + (*it).m_nCount ) { // merge the two (*it).m_nCount += (*itNext).m_nCount; (*it).items.reserve( (*it).items.size() + (*itNext).items.size() ); (*it).items.insert( (*it).items.end(), (*itNext).items.begin(), (*itNext).items.end() ); (*it).freeItems.reserve( (*it).freeItems.size() + (*itNext).freeItems.size() ); (*it).freeItems.insert( (*it).freeItems.end(), (*itNext).freeItems.begin(), (*itNext).freeItems.end() ); itNext = m_vecBlocks.erase( itNext ); it = itNext - 1; } else it = itNext++; } } void PdfXRef::BeginWrite( PdfOutputDevice* pDevice ) { pDevice->Print( "xref\n" ); } void PdfXRef::WriteSubSection( PdfOutputDevice* pDevice, pdf_objnum nFirst, pdf_uint32 nCount ) { #ifdef DEBUG PdfError::DebugMessage("Writing XRef section: %u %u\n", nFirst, nCount ); #endif // DEBUG pDevice->Print( "%u %u\n", nFirst, nCount ); } void PdfXRef::WriteXRefEntry( PdfOutputDevice* pDevice, pdf_uint64 offset, pdf_gennum generation, char cMode, pdf_objnum ) { pDevice->Print( "%0.10" PDF_FORMAT_UINT64 " %0.5hu %c \n", offset, generation, cMode ); } void PdfXRef::EndWrite( PdfOutputDevice* ) { } void PdfXRef::SetFirstEmptyBlock() { PdfXRefBlock block; block.m_nFirst = 0; block.m_nCount = 1; m_vecBlocks.insert(m_vecBlocks.begin(), block ); } }; podofo-0.9.5/src/base/PdfArray.cpp0000664000175000017500000001252312344436402016605 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfArray.h" #include "PdfOutputDevice.h" #include "PdfDefinesPrivate.h" #include namespace PoDoFo { PdfArray::PdfArray() : PdfArrayBaseClass(), PdfDataType(), m_bDirty( false ) { } PdfArray::~PdfArray() { } PdfArray::PdfArray( const PdfObject & var ) : PdfArrayBaseClass(), PdfDataType(), m_bDirty( false ) { this->push_back( var ); } PdfArray::PdfArray( const PdfArray & rhs ) : PdfArrayBaseClass(rhs), PdfDataType(rhs), m_bDirty(rhs.m_bDirty) { this->operator=( rhs ); } PdfArray& PdfArray::operator=(const PdfArray& rhs) { if (this != &rhs) { m_bDirty = rhs.m_bDirty; PdfArrayBaseClass::operator=( rhs ); } else { //do nothing } return *this; } void PdfArray::Write( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, const PdfEncrypt* pEncrypt ) const { PdfArray::const_iterator it = this->begin(); int count = 1; if( (eWriteMode & ePdfWriteMode_Clean) == ePdfWriteMode_Clean ) { pDevice->Print( "[ " ); } else { pDevice->Print( "[" ); } while( it != this->end() ) { (*it).Write( pDevice, eWriteMode, pEncrypt ); if( (eWriteMode & ePdfWriteMode_Clean) == ePdfWriteMode_Clean ) { pDevice->Print( (count % 10 == 0) ? "\n" : " " ); } ++it; ++count; } pDevice->Print( "]" ); } bool PdfArray::ContainsString( const std::string& cmpString ) const { bool foundIt = false; TCIVariantList it(this->begin()); while( it != this->end() ) { if( (*it).GetDataType() == ePdfDataType_String ) { if ( (*it).GetString().GetString() == cmpString ) { foundIt = true; break; } } ++it; } return foundIt; } size_t PdfArray::GetStringIndex( const std::string& cmpString ) const { size_t foundIdx = std::numeric_limits::max(); for ( size_t i=0; isize(); i++ ) { if( (*this)[i].GetDataType() == ePdfDataType_String ) { if ( (*this)[i].GetString().GetString() == cmpString ) { foundIdx = i; break; } } } return foundIdx; } bool PdfArray::IsDirty() const { // If the array itself is dirty // return immediately // otherwise check all children. if( m_bDirty ) return m_bDirty; PdfArray::const_iterator it(this->begin()); while( it != this->end() ) { if( (*it).IsDirty() ) return true; ++it; } return false; } void PdfArray::SetDirty( bool bDirty ) { m_bDirty = bDirty; if( !m_bDirty ) { // Propagate state to all subclasses PdfArray::iterator it(this->begin()); while( it != this->end() ) { (*it).SetDirty( m_bDirty ); ++it; } } } }; podofo-0.9.5/src/base/PdfColor.h0000664000175000017500000006774212344436402016267 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_COLOR_H_ #define _PDF_COLOR_H_ #include "PdfDefines.h" #include "PdfName.h" namespace PoDoFo { class PdfArray; class PdfObject; class PdfVecObjects; /** A color object can represent either a grayscale * value, a RGB color, a CMYK color, a separation color or * a CieLab color. * * All drawing functions in PoDoFo accept a PdfColor object * to specify a drawing color in one of these colorspaces. * * Derived classes PdfColorGray, PdfColorRGB, PdfColorCMYK, PdfColorSeparation * and PdfColorCieLab are available for easy construction */ class PODOFO_API PdfColor { public: /** Create a PdfColor object that is RGB black. */ PdfColor(); /** Create a new PdfColor object with * a grayscale value. * * \param dGray a grayscalue value between 0.0 and 1.0 */ explicit PdfColor( double dGray ); /** Create a new PdfColor object with * a RGB color * * \param dRed the value of the red component, must be between 0.0 and 1.0 * \param dGreen the value of the green component, must be between 0.0 and 1.0 * \param dBlue the value of the blue component, must be between 0.0 and 1.0 */ PdfColor( double dRed, double dGreen, double dBlue ); /** Create a new PdfColor object with * a CMYK color * * \param dCyan the value of the cyan component, must be between 0.0 and 1.0 * \param dMagenta the value of the magenta component, must be between 0.0 and 1.0 * \param dYellow the value of the yellow component, must be between 0.0 and 1.0 * \param dBlack the value of the black component, must be between 0.0 and 1.0 */ PdfColor( double dCyan, double dMagenta, double dYellow, double dBlack ); /** Copy constructor * * \param rhs copy rhs into this object */ PdfColor( const PdfColor & rhs ); /** Destructor */ virtual ~PdfColor(); /** Assignment operator * * \param rhs copy rhs into this object * * \returns a reference to this color object */ const PdfColor & operator=( const PdfColor & rhs ); /** Test for equality of colors. * * \param rhs color to compare ro * * \returns true if object color is equal to rhs */ inline bool operator==( const PdfColor & rhs ) const; /** Test for inequality of colors. * * \param rhs color to compare ro * * \returns true if object color is not equal to rhs */ inline bool operator!=( const PdfColor & rhs ) const; /** Test if this is a grayscale color. * * \returns true if this is a grayscale PdfColor object */ inline bool IsGrayScale() const; /** Test if this is a RGB color. * * \returns true if this is a RGB PdfColor object */ inline bool IsRGB() const; /** Test if this is a CMYK color. * * \returns true if this is a CMYK PdfColor object */ inline bool IsCMYK() const; /** Test if this is a separation color. * * \returns true if this is a separation PdfColor object */ inline bool IsSeparation() const; /** Test if this is a CIE-Lab color. * * \returns true if this is a lab Color object */ inline bool IsCieLab() const; /** Get the colorspace of this PdfColor object * * \returns the colorspace of this PdfColor object */ inline EPdfColorSpace GetColorSpace() const; /** Get the alternate colorspace of this PdfColor object * * \returns the colorspace of this PdfColor object (must be separation) */ inline EPdfColorSpace GetAlternateColorSpace() const; /** Get the grayscale color value * of this object. * * Throws an exception if this is no grayscale color object. * * \returns the grayscale color value of this object (between 0.0 and 1.0) * * \see IsGrayScale */ inline double GetGrayScale() const; /** Get the red color value * of this object. * * Throws an exception if this is no RGB color object. * * \returns the red color value of this object (between 0.0 and 1.0) * * \see IsRGB */ inline double GetRed() const; /** Get the green color value * of this object. * * Throws an exception if this is no RGB color object. * * \returns the green color value of this object (between 0.0 and 1.0) * * \see IsRGB */ inline double GetGreen() const; /** Get the blue color value * of this object. * * Throws an exception if this is no RGB color object. * * \returns the blue color value of this object (between 0.0 and 1.0) * * \see IsRGB */ inline double GetBlue() const; /** Get the cyan color value * of this object. * * Throws an exception if this is no CMYK or separation color object. * * \returns the cyan color value of this object (between 0.0 and 1.0) * * \see IsCMYK */ inline double GetCyan() const; /** Get the magenta color value * of this object. * * Throws an exception if this is no CMYK or separation color object. * * \returns the magenta color value of this object (between 0.0 and 1.0) * * \see IsCMYK */ inline double GetMagenta() const; /** Get the yellow color value * of this object. * * Throws an exception if this is no CMYK or separation color object. * * \returns the yellow color value of this object (between 0.0 and 1.0) * * \see IsCMYK */ inline double GetYellow() const; /** Get the black color value * of this object. * * Throws an exception if this is no CMYK or separation color object. * * \returns the black color value of this object (between 0.0 and 1.0) * * \see IsCMYK */ inline double GetBlack() const; /** Get the separation name of this object. * * Throws an exception if this is no separation color object. * * \returns the name of this object * * \see IsSeparation */ inline const std::string GetName() const; /** Get the density color value * of this object. * * Throws an exception if this is no separation color object. * * \returns the density value of this object (between 0.0 and 1.0) * * \see IsSeparation */ inline double GetDensity() const; /** Get the L color value * of this object. * * Throws an exception if this is no CIE-Lab color object. * * \returns the L color value of this object (between 0.0 and 100.0) * * \see IsCieLab */ inline double GetCieL() const; /** Get the A color value * of this object. * * Throws an exception if this is no CIE-Lab color object. * * \returns the A color value of this object (between -128.0 and 127.0) * * \see IsCieLab */ inline double GetCieA() const; /** Get the B color value * of this object. * * Throws an exception if this is no CIE-Lab color object. * * \returns the B color value of this object (between -128.0 and 127.0) * * \see IsCieLab */ inline double GetCieB() const; /** Converts the color object into a grayscale * color object. * * This is only a convinience function. It might be useful * for on screen display but is in NO WAY suitable to * professional printing! * * \returns a grayscale color object * \see IsGrayScale() */ PdfColor ConvertToGrayScale() const; /** Converts the color object into a RGB * color object. * * This is only a convinience function. It might be useful * for on screen display but is in NO WAY suitable to * professional printing! * * \returns a RGB color object * \see IsRGB() */ PdfColor ConvertToRGB() const; /** Converts the color object into a CMYK * color object. * * This is only a convinience function. It might be useful * for on screen display but is in NO WAY suitable to * professional printing! * * \returns a CMYK color object * \see IsCMYK() */ PdfColor ConvertToCMYK() const; /** Creates a PdfArray which represents a color from a color. * \returns a PdfArray object */ PdfArray ToArray() const; /** Creates a color object from a string. * * \param pszName a string describing a color. * * Supported values are: * - single gray values as string (e.g. '0.5') * - a named color (e.g. 'auquamarine' or 'magenta') * - hex values (e.g. #FF002A (RGB) or #FF12AB3D (CMYK)) * - PdfArray's * * \returns a PdfColor object */ static PdfColor FromString( const char* pszName ); /** Creates a color object from a PdfArray which represents a color. * * Raises an exception if this is no PdfColor! * * \param rArray an array that must be a color PdfArray * \returns a PdfColor object */ static PdfColor FromArray( const PdfArray & rArray ); /** * Convert a name into a colorspace enum. * @param rName name representing a colorspace such as DeviceGray * @returns colorspace enum or ePdfColorSpace_Unknown if name is unknown * @see GetNameForColorSpace */ static EPdfColorSpace GetColorSpaceForName( const PdfName & rName ); /** * Convert a colorspace enum value into a name such as DeviceRGB * @param eColorSpace a colorspace * @returns a name * @see GetColorSpaceForName */ static PdfName GetNameForColorSpace( EPdfColorSpace eColorSpace ); /** Creates a colorspace object from a color to insert into resources. * * \param pOwner a pointer to the owner of the generated object * \returns a PdfObject pointer, which can be insert into resources, NULL if not needed */ PdfObject* BuildColorSpace( PdfVecObjects* pOwner ) const; protected: union { double cmyk[4]; double rgb[3]; double lab[3]; double gray; } m_uColor; std::string m_separationName; double m_separationDensity; EPdfColorSpace m_eColorSpace; EPdfColorSpace m_eAlternateColorSpace; private: static const unsigned int* const m_hexDigitMap; ///< Mapping of hex sequences to int value }; class PODOFO_API PdfColorGray : public PdfColor { public: /** Create a new PdfColor object with * a grayscale value. * * \param dGray a grayscalue value between 0.0 and 1.0 */ explicit PdfColorGray( double dGray ); /** Class destructor. */ virtual ~PdfColorGray(); private: /** Default constructor, not implemented */ PdfColorGray(); /** Copy constructor, not implemented */ PdfColorGray(const PdfColorGray& ); /** Copy assignment operator, not implemented */ PdfColorGray& operator=(const PdfColorGray&); }; class PODOFO_API PdfColorRGB : public PdfColor { public: /** Create a new PdfColor object with * a RGB color * * \param dRed the value of the red component, must be between 0.0 and 1.0 * \param dGreen the value of the green component, must be between 0.0 and 1.0 * \param dBlue the value of the blue component, must be between 0.0 and 1.0 */ PdfColorRGB( double dRed, double dGreen, double dBlue ); /** Class destructor. */ virtual ~PdfColorRGB(); private: /** Default constructor, not implemented */ PdfColorRGB(); /** Copy constructor, not implemented */ PdfColorRGB(const PdfColorRGB& ); /** Copy assignment operator, not implemented */ PdfColorRGB& operator=(const PdfColorRGB&); }; class PODOFO_API PdfColorCMYK : public PdfColor { public: /** Create a new PdfColor object with * a CMYK color * * \param dCyan the value of the cyan component, must be between 0.0 and 1.0 * \param dMagenta the value of the magenta component, must be between 0.0 and 1.0 * \param dYellow the value of the yellow component, must be between 0.0 and 1.0 * \param dBlack the value of the black component, must be between 0.0 and 1.0 */ PdfColorCMYK( double dCyan, double dMagenta, double dYellow, double dBlack ); /** Class destructor. */ virtual ~PdfColorCMYK(); private: /** Default constructor, not implemented */ PdfColorCMYK(); /** Copy constructor, not implemented */ PdfColorCMYK(const PdfColorCMYK& ); /** Copy assignment operator, not implemented */ PdfColorCMYK& operator=(const PdfColorCMYK&); }; class PODOFO_API PdfColorSeparationAll : public PdfColor { public: /** Create a new PdfColor object with * Separation color All. * */ PdfColorSeparationAll(); /** Class destructor. */ virtual ~PdfColorSeparationAll(); private: /** Copy constructor, not implemented */ PdfColorSeparationAll(const PdfColorSeparationAll& ); /** Copy assignment operator, not implemented */ PdfColorSeparationAll& operator=(const PdfColorSeparationAll&); }; class PODOFO_API PdfColorSeparationNone : public PdfColor { public: /** Create a new PdfColor object with * Separation color None. * */ PdfColorSeparationNone(); /** Class destructor. */ virtual ~PdfColorSeparationNone(); private: /** Copy constructor, not implemented */ PdfColorSeparationNone(const PdfColorSeparationNone& ); /** Copy assignment operator, not implemented */ PdfColorSeparationNone& operator=(const PdfColorSeparationNone&); }; class PODOFO_API PdfColorSeparation : public PdfColor { public: /** Create a new PdfColor object with * a separation-name and an equivalent color * * \param sName Name of the separation color * \param sDensity the density value of the separation color * \param alternateColor the alternate color, must be of typ gray, rgb, cmyk or cie */ PdfColorSeparation( const std::string & sName, double dDensity, const PdfColor & alternateColor ); /** Class destructor. */ virtual ~PdfColorSeparation(); private: /** Default constructor, not implemented */ PdfColorSeparation(); /** Copy constructor, not implemented */ PdfColorSeparation(const PdfColorSeparation& ); /** Copy assignment operator, not implemented */ PdfColorSeparation& operator=(const PdfColorSeparation&); }; class PODOFO_API PdfColorCieLab : public PdfColor { public: /** Create a new PdfColor object with * a CIE-LAB-values * * \param dCieL the value of the L component, must be between 0.0 and 100.0 * \param dCieA the value of the A component, must be between -128.0 and 127.0 * \param dCieB the value of the B component, must be between -128.0 and 127.0 */ PdfColorCieLab( double dCieL, double dCieA, double dCieB ); /** Class destructor. */ virtual ~PdfColorCieLab(); private: /** Default constructor, not implemented */ PdfColorCieLab(); /** Copy constructor, not implemented */ PdfColorCieLab(const PdfColorCieLab& ); /** Copy assignment operator, not implemented */ PdfColorCieLab& operator=(const PdfColorCieLab&); }; // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfColor::operator==( const PdfColor & rhs ) const { if ( m_eColorSpace == rhs.m_eColorSpace ) { if ( (m_eColorSpace == ePdfColorSpace_DeviceGray) && (m_uColor.gray == rhs.m_uColor.gray) ) return true; if ( (m_eColorSpace == ePdfColorSpace_DeviceRGB) && (m_uColor.rgb[0] == rhs.m_uColor.rgb[0]) && (m_uColor.rgb[1] == rhs.m_uColor.rgb[1]) && (m_uColor.rgb[2] == rhs.m_uColor.rgb[2]) ) return true; if ( (m_eColorSpace == ePdfColorSpace_DeviceCMYK) && (m_uColor.cmyk[0] == rhs.m_uColor.cmyk[0]) && (m_uColor.cmyk[1] == rhs.m_uColor.cmyk[1]) && (m_uColor.cmyk[2] == rhs.m_uColor.cmyk[2]) && (m_uColor.cmyk[3] == rhs.m_uColor.cmyk[3]) ) return true; if ( (m_eColorSpace == ePdfColorSpace_CieLab) && (m_uColor.lab[0] == rhs.m_uColor.lab[0]) && (m_uColor.lab[1] == rhs.m_uColor.lab[1]) && (m_uColor.lab[2] == rhs.m_uColor.lab[2]) ) return true; if ( (m_eColorSpace == ePdfColorSpace_Separation) && (m_separationDensity == rhs.m_separationDensity) && (m_separationName == rhs.m_separationName) && (m_eAlternateColorSpace == rhs.m_eAlternateColorSpace) && ( ( (m_eAlternateColorSpace == ePdfColorSpace_DeviceGray) && (m_uColor.gray == rhs.m_uColor.gray) ) || ( (m_eAlternateColorSpace == ePdfColorSpace_DeviceRGB) && (m_uColor.rgb[0] == rhs.m_uColor.rgb[0]) && (m_uColor.rgb[1] == rhs.m_uColor.rgb[1]) && (m_uColor.rgb[2] == rhs.m_uColor.rgb[2]) ) || ( (m_eAlternateColorSpace == ePdfColorSpace_DeviceCMYK) && (m_uColor.cmyk[0] == rhs.m_uColor.cmyk[0]) && (m_uColor.cmyk[1] == rhs.m_uColor.cmyk[1]) && (m_uColor.cmyk[2] == rhs.m_uColor.cmyk[2]) && (m_uColor.cmyk[3] == rhs.m_uColor.cmyk[3]) ) || ( (m_eAlternateColorSpace == ePdfColorSpace_CieLab) && (m_uColor.lab[0] == rhs.m_uColor.lab[0]) && (m_uColor.lab[1] == rhs.m_uColor.lab[1]) && (m_uColor.lab[2] == rhs.m_uColor.lab[2]) ) ) ) return true; if (m_eColorSpace == ePdfColorSpace_Unknown) return true; } return false; } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfColor::operator!=( const PdfColor & rhs ) const { return ! (*this == rhs); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfColor::IsGrayScale() const { return (m_eColorSpace == ePdfColorSpace_DeviceGray); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfColor::IsRGB() const { return (m_eColorSpace == ePdfColorSpace_DeviceRGB); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfColor::IsCMYK() const { return (m_eColorSpace == ePdfColorSpace_DeviceCMYK); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfColor::IsSeparation() const { return (m_eColorSpace == ePdfColorSpace_Separation); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfColor::IsCieLab() const { return (m_eColorSpace == ePdfColorSpace_CieLab); } // ----------------------------------------------------- // // ----------------------------------------------------- EPdfColorSpace PdfColor::GetColorSpace() const { return m_eColorSpace; } // ----------------------------------------------------- // // ----------------------------------------------------- EPdfColorSpace PdfColor::GetAlternateColorSpace() const { PODOFO_RAISE_LOGIC_IF( !this->IsSeparation(), "PdfColor::GetAlternateColorSpace cannot be called on non separation color objects!"); return m_eAlternateColorSpace; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfColor::GetGrayScale() const { PODOFO_RAISE_LOGIC_IF( !this->IsGrayScale() && !(this->IsSeparation() && (this->m_eAlternateColorSpace == ePdfColorSpace_DeviceGray)), "PdfColor::GetGrayScale cannot be called on non grayscale color objects!"); return m_uColor.gray; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfColor::GetRed() const { PODOFO_RAISE_LOGIC_IF( !this->IsRGB() && !(this->IsSeparation() && (this->m_eAlternateColorSpace == ePdfColorSpace_DeviceRGB)), "PdfColor::GetRed cannot be called on non RGB color objects!"); return m_uColor.rgb[0]; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfColor::GetGreen() const { PODOFO_RAISE_LOGIC_IF( !this->IsRGB() && !(this->IsSeparation() && (this->m_eAlternateColorSpace == ePdfColorSpace_DeviceRGB)), "PdfColor::GetGreen cannot be called on non RGB color objects!"); return m_uColor.rgb[1]; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfColor::GetBlue() const { PODOFO_RAISE_LOGIC_IF( !this->IsRGB() && !(this->IsSeparation() && (this->m_eAlternateColorSpace == ePdfColorSpace_DeviceRGB)), "PdfColor::GetBlue cannot be called on non RGB color objects!"); return m_uColor.rgb[2]; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfColor::GetCyan() const { PODOFO_RAISE_LOGIC_IF( !this->IsCMYK() && !(this->IsSeparation() && (this->m_eAlternateColorSpace == ePdfColorSpace_DeviceCMYK)), "PdfColor::GetCyan cannot be called on non CMYK color objects!"); return m_uColor.cmyk[0]; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfColor::GetMagenta() const { PODOFO_RAISE_LOGIC_IF( !this->IsCMYK() && !(this->IsSeparation() && (this->m_eAlternateColorSpace == ePdfColorSpace_DeviceCMYK)), "PdfColor::GetMagenta cannot be called on non CMYK color objects!"); return m_uColor.cmyk[1]; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfColor::GetYellow() const { PODOFO_RAISE_LOGIC_IF( !this->IsCMYK() && !(this->IsSeparation() && (this->m_eAlternateColorSpace == ePdfColorSpace_DeviceCMYK)), "PdfColor::GetYellow cannot be called on non CMYK color objects!"); return m_uColor.cmyk[2]; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfColor::GetBlack() const { PODOFO_RAISE_LOGIC_IF( !this->IsCMYK() && !(this->IsSeparation() && (this->m_eAlternateColorSpace == ePdfColorSpace_DeviceCMYK)), "PdfColor::GetBlack cannot be called on non CMYK color objects!"); return m_uColor.cmyk[3]; } // ----------------------------------------------------- // // ----------------------------------------------------- const std::string PdfColor::GetName() const { PODOFO_RAISE_LOGIC_IF( !this->IsSeparation(), "PdfColor::GetName cannot be called on non separation color objects!"); return m_separationName; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfColor::GetDensity() const { PODOFO_RAISE_LOGIC_IF( !this->IsSeparation(), "PdfColor::GetDensity cannot be called on non separation color objects!"); return m_separationDensity; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfColor::GetCieL() const { PODOFO_RAISE_LOGIC_IF( !this->IsCieLab() && !(this->IsSeparation() && (this->m_eAlternateColorSpace == ePdfColorSpace_CieLab)), "PdfColor::GetCieL cannot be called on non CIE-Lab color objects!"); return m_uColor.lab[0]; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfColor::GetCieA() const { PODOFO_RAISE_LOGIC_IF( !this->IsCieLab() && !(this->IsSeparation() && (this->m_eAlternateColorSpace == ePdfColorSpace_CieLab)), "PdfColor::GetCieA cannot be called on non CIE-Lab color objects!"); return m_uColor.lab[1]; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfColor::GetCieB() const { PODOFO_RAISE_LOGIC_IF( !this->IsCieLab() && !(this->IsSeparation() && (this->m_eAlternateColorSpace == ePdfColorSpace_CieLab)), "PdfColor::GetCieB cannot be called on non CIE-Lab color objects!"); return m_uColor.lab[2]; } }; #endif // _PDF_COLOR_H_ podofo-0.9.5/src/base/PdfCanvas.cpp0000664000175000017500000001327412347347566016765 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfCanvas.h" #include "PdfDictionary.h" #include "PdfName.h" #include "PdfColor.h" #include "PdfStream.h" #include "PdfDefinesPrivate.h" namespace PoDoFo { PdfArray PdfCanvas::s_procset; const PdfArray & PdfCanvas::GetProcSet() { if( s_procset.empty() ) { s_procset.push_back( PdfName( "PDF" ) ); s_procset.push_back( PdfName( "Text" ) ); s_procset.push_back( PdfName( "ImageB" ) ); s_procset.push_back( PdfName( "ImageC" ) ); s_procset.push_back( PdfName( "ImageI" ) ); } return s_procset; } void PdfCanvas::AddColorResource( const PdfColor & rColor ) { PdfObject* pResource = GetResources(); if( !pResource ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } switch( rColor.GetColorSpace() ) { case ePdfColorSpace_Separation: { std::string csPrefix( "ColorSpace" ); std::string csName = rColor.GetName(); std::string temp( csPrefix + csName ); if ( ! pResource->GetDictionary().HasKey( "ColorSpace" ) || ! pResource->GetDictionary().GetKey( "ColorSpace" )->GetDictionary().HasKey( csPrefix + csName ) ) { // Build color-spaces for separation PdfObject* csp = rColor.BuildColorSpace( GetContents()->GetOwner() ); AddResource( csPrefix + csName, csp->Reference(), PdfName("ColorSpace") ); } } break; case ePdfColorSpace_CieLab: { if ( ! pResource->GetDictionary().HasKey( "ColorSpace" ) || ! pResource->GetDictionary().GetKey( "ColorSpace" )->GetDictionary().HasKey( "ColorSpaceLab" ) ) { // Build color-spaces for CIE-lab PdfObject* csp = rColor.BuildColorSpace( GetContents()->GetOwner() ); AddResource( "ColorSpaceCieLab", csp->Reference(), PdfName("ColorSpace") ); } } break; case ePdfColorSpace_DeviceGray: case ePdfColorSpace_DeviceRGB: case ePdfColorSpace_DeviceCMYK: case ePdfColorSpace_Indexed: // No colorspace needed case ePdfColorSpace_Unknown: default: break; } } void PdfCanvas::AddResource( const PdfName & rIdentifier, const PdfReference & rRef, const PdfName & rName ) { if( !rName.GetLength() || !rIdentifier.GetLength() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } PdfObject* pResource = this->GetResources(); if( !pResource ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if( !pResource->GetDictionary().HasKey( rName ) ) { pResource->GetDictionary().AddKey( rName, PdfDictionary() ); } // Peter Petrov: 18 December 2008. Bug fix if (ePdfDataType_Reference == pResource->GetDictionary().GetKey( rName )->GetDataType()) { PdfObject *directObject = pResource->GetOwner()->GetObject(pResource->GetDictionary().GetKey( rName )->GetReference()); if (0 == directObject) { PODOFO_RAISE_ERROR( ePdfError_NoObject ); } if( !directObject->GetDictionary().HasKey( rIdentifier ) ) directObject->GetDictionary().AddKey( rIdentifier, rRef ); }else { if( !pResource->GetDictionary().GetKey( rName )->GetDictionary().HasKey( rIdentifier ) ) pResource->GetDictionary().GetKey( rName )->GetDictionary().AddKey( rIdentifier, rRef ); } } }; podofo-0.9.5/src/base/PdfEncodingFactory.cpp0000664000175000017500000002206012704763166020614 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfEncodingFactory.h" #include "PdfEncoding.h" #include "util/PdfMutexWrapper.h" #include "PdfName.h" #include "PdfObject.h" #include "PdfDefinesPrivate.h" #include "doc/PdfIdentityEncoding.h" namespace PoDoFo { const PdfDocEncoding* PdfEncodingFactory::s_pDocEncoding = NULL; const PdfWinAnsiEncoding* PdfEncodingFactory::s_pWinAnsiEncoding = NULL; const PdfMacRomanEncoding* PdfEncodingFactory::s_pMacRomanEncoding = NULL; const PdfStandardEncoding* PdfEncodingFactory::s_pStandardEncoding = NULL; // OC 13.08.2010 New. const PdfMacExpertEncoding* PdfEncodingFactory::s_pMacExpertEncoding = NULL; // OC 13.08.2010 New. const PdfSymbolEncoding* PdfEncodingFactory::s_pSymbolEncoding = NULL; // OC 13.08.2010 New. const PdfZapfDingbatsEncoding* PdfEncodingFactory::s_pZapfDingbatsEncoding = NULL; // OC 13.08.2010 New. const PdfIdentityEncoding * PdfEncodingFactory::s_pIdentityEncoding = NULL; const PdfWin1250Encoding * PdfEncodingFactory::s_pWin1250Encoding = NULL; const PdfIso88592Encoding * PdfEncodingFactory::s_pIso88592Encoding = NULL; Util::PdfMutex PdfEncodingFactory::s_mutex; PdfEncodingFactory::PdfEncodingFactory() { } const PdfEncoding* PdfEncodingFactory::GlobalPdfDocEncodingInstance() { if(!s_pDocEncoding) // First check { Util::PdfMutexWrapper wrapper( PdfEncodingFactory::s_mutex ); if(!s_pDocEncoding) // Double check s_pDocEncoding = new PdfDocEncoding(); } return s_pDocEncoding; } const PdfEncoding* PdfEncodingFactory::GlobalWinAnsiEncodingInstance() { if(!s_pWinAnsiEncoding) // First check { Util::PdfMutexWrapper wrapper( PdfEncodingFactory::s_mutex ); if(!s_pWinAnsiEncoding) // Double check s_pWinAnsiEncoding = new PdfWinAnsiEncoding(); } return s_pWinAnsiEncoding; } const PdfEncoding* PdfEncodingFactory::GlobalMacRomanEncodingInstance() { if(!s_pMacRomanEncoding) // First check { Util::PdfMutexWrapper wrapper( PdfEncodingFactory::s_mutex ); if(!s_pMacRomanEncoding) // Double check s_pMacRomanEncoding = new PdfMacRomanEncoding(); } return s_pMacRomanEncoding; } // OC 13.08.2010: const PdfEncoding* PdfEncodingFactory::GlobalStandardEncodingInstance() { if(!s_pStandardEncoding) // First check { Util::PdfMutexWrapper wrapper( PdfEncodingFactory::s_mutex ); if(!s_pStandardEncoding) // Double check s_pStandardEncoding = new PdfStandardEncoding(); } return s_pStandardEncoding; } // OC 13.08.2010: const PdfEncoding* PdfEncodingFactory::GlobalMacExpertEncodingInstance() { if(!s_pMacExpertEncoding) // First check { Util::PdfMutexWrapper wrapper( PdfEncodingFactory::s_mutex ); if(!s_pMacExpertEncoding) // Double check s_pMacExpertEncoding = new PdfMacExpertEncoding(); } return s_pMacExpertEncoding; } // OC 13.08.2010: const PdfEncoding* PdfEncodingFactory::GlobalSymbolEncodingInstance() { if(!s_pSymbolEncoding) // First check { Util::PdfMutexWrapper wrapper( PdfEncodingFactory::s_mutex ); if(!s_pSymbolEncoding) // Double check s_pSymbolEncoding = new PdfSymbolEncoding(); } return s_pSymbolEncoding; } // OC 13.08.2010: const PdfEncoding* PdfEncodingFactory::GlobalZapfDingbatsEncodingInstance() { if(!s_pZapfDingbatsEncoding) // First check { Util::PdfMutexWrapper wrapper( PdfEncodingFactory::s_mutex ); if(!s_pZapfDingbatsEncoding) // Double check s_pZapfDingbatsEncoding = new PdfZapfDingbatsEncoding(); } return s_pZapfDingbatsEncoding; } const PdfEncoding* PdfEncodingFactory::GlobalIdentityEncodingInstance() { if(!s_pIdentityEncoding) // First check { Util::PdfMutexWrapper wrapper( PdfEncodingFactory::s_mutex ); if(!s_pIdentityEncoding) // Double check s_pIdentityEncoding = new PdfIdentityEncoding( 0, 0xffff, false ); } return s_pIdentityEncoding; } const PdfEncoding* PdfEncodingFactory::GlobalWin1250EncodingInstance() { if(!s_pWin1250Encoding) // First check { Util::PdfMutexWrapper wrapper( PdfEncodingFactory::s_mutex ); if(!s_pWin1250Encoding) // Double check s_pWin1250Encoding = new PdfWin1250Encoding(); } return s_pWin1250Encoding; } const PdfEncoding* PdfEncodingFactory::GlobalIso88592EncodingInstance() { if(!s_pIso88592Encoding) // First check { Util::PdfMutexWrapper wrapper( PdfEncodingFactory::s_mutex ); if(!s_pIso88592Encoding) // Double check s_pIso88592Encoding = new PdfIso88592Encoding(); } return s_pIso88592Encoding; } int podofo_number_of_clients = 0; void PdfEncodingFactory::FreeGlobalEncodingInstances() { Util::PdfMutexWrapper wrapper( PdfEncodingFactory::s_mutex ); podofo_number_of_clients--; if (podofo_number_of_clients <= 0) { Util::PdfMutexWrapper wrapper( PdfEncodingFactory::s_mutex ); if (NULL != s_pMacRomanEncoding) { delete s_pMacRomanEncoding; } if (NULL != s_pWinAnsiEncoding) { delete s_pWinAnsiEncoding; } if (NULL != s_pDocEncoding) { delete s_pDocEncoding; } if (NULL != s_pStandardEncoding) // OC 13.08.2010 { delete s_pStandardEncoding; } if (NULL != s_pMacExpertEncoding) // OC 13.08.2010 { delete s_pMacExpertEncoding; } if (NULL != s_pSymbolEncoding) // OC 13.08.2010 { delete s_pSymbolEncoding; } if (NULL != s_pZapfDingbatsEncoding) // OC 13.08.2010 { delete s_pZapfDingbatsEncoding; } if (NULL != s_pIdentityEncoding) { delete s_pIdentityEncoding; } if (NULL != s_pWin1250Encoding) { delete s_pWin1250Encoding; } if (NULL != s_pIso88592Encoding) { delete s_pIso88592Encoding; } s_pMacRomanEncoding = NULL; s_pWinAnsiEncoding = NULL; s_pDocEncoding = NULL; s_pStandardEncoding = NULL; // OC 13.08.2010 s_pMacExpertEncoding = NULL; // OC 13.08.2010 s_pSymbolEncoding = NULL; // OC 13.08.2010 s_pZapfDingbatsEncoding = NULL; // OC 13.08.2010 s_pIdentityEncoding = NULL; s_pWin1250Encoding = NULL; s_pIso88592Encoding = NULL; } } void PdfEncodingFactory::PoDoFoClientAttached() { podofo_number_of_clients++; } }; podofo-0.9.5/src/base/PdfEncoding.h0000664000175000017500000005765312711716603016741 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_ENCODING_H_ #define _PDF_ENCODING_H_ #include "PdfDefines.h" #include "PdfName.h" #include "PdfString.h" #include "util/PdfMutex.h" #include namespace PoDoFo { class PdfDictionary; class PdfFont; class PdfObject; /** * A PdfEncoding is in PdfFont to transform a text string * into a representation so that it can be displayed in a * PDF file. * * PdfEncoding can also be used to convert strings from a * PDF file back into a PdfString. */ class PODOFO_API PdfEncoding { protected: /** * Create a new PdfEncoding. * * \param nFirstChar the first supported character code * (either a byte value in the current encoding or a unicode value) * \param nLastChar the last supported character code, must be larger than nFirstChar * (either a byte value in the current encoding or a unicode value) * */ PdfEncoding( int nFirstChar, int nLastChar, PdfObject* = NULL ); /** Get a unique ID for this encoding * which can used for comparisons! * * \returns a unique id for this encoding! */ virtual const PdfName & GetID() const = 0; public: #if defined(_MSC_VER) && _MSC_VER <= 1200 // ab Visualstudio 6 class PODOFO_API const_iterator : public std::iterator< std::forward_iterator_tag, int, ptrdiff_t> { #else class PODOFO_API const_iterator : public std::iterator< std::forward_iterator_tag, int, std::ptrdiff_t, const int *, const int &> { #endif public: const_iterator( const PdfEncoding* pEncoding, int nCur ) : m_pEncoding( pEncoding ), m_nCur( nCur ) { } const_iterator( const const_iterator & rhs ) { this->operator=(rhs); } const const_iterator & operator=( const const_iterator & rhs ) { m_nCur = rhs.m_nCur; m_pEncoding = rhs.m_pEncoding; return *this; } inline bool operator==( const const_iterator & rhs ) const { return (m_nCur == rhs.m_nCur); } inline bool operator!=( const const_iterator & rhs ) const { return (m_nCur != rhs.m_nCur); } inline pdf_utf16be operator*() const { return m_pEncoding->GetCharCode( m_nCur ); } inline const_iterator & operator++() { m_nCur++; return *this; } private: const PdfEncoding* m_pEncoding; int m_nCur; }; virtual ~PdfEncoding(); /** Comparison operator. * * \param rhs the PdfEncoding to which this encoding should be compared * * \returns true if both encodings are the same. */ inline bool operator==( const PdfEncoding & rhs ) const; /** Comparison operator. * * \param rhs the PdfEncoding to which this encoding should be compared * * \returns true if this encoding is less than the specified. */ inline bool operator<( const PdfEncoding & rhs ) const; /** Add this encoding object to a dictionary * usually be adding an /Encoding key in font dictionaries. * * \param rDictionary add the encoding to this dictionary */ virtual void AddToDictionary( PdfDictionary & rDictionary ) const = 0; /** Convert a string that is encoded with this encoding * to an unicode PdfString. * * \param rEncodedString a string encoded by this encoding. * Usually this string was read from a content stream. * \param pFont the font for which this string is converted * * \returns an unicode PdfString. */ virtual PdfString ConvertToUnicode( const PdfString & rEncodedString, const PdfFont* pFont ) const; /** Convert a unicode PdfString to a string encoded with this encoding. * * \param rString an unicode PdfString. * \param pFont the font for which this string is converted * * \returns an encoded PdfRefCountedBuffer. The PdfRefCountedBuffer is treated as a series of bytes * and is allowed to have 0 bytes. The returned buffer must not be a unicode string. */ virtual PdfRefCountedBuffer ConvertToEncoding( const PdfString & rString, const PdfFont* pFont ) const; virtual bool IsAutoDelete() const = 0; virtual bool IsSingleByteEncoding() const = 0; /** * \returns the first character code that is defined for this encoding */ inline int GetFirstChar() const; /** * \returns the last character code that is defined for this encoding */ inline int GetLastChar() const; /** Iterate over all unicode character points in this * encoding, beginning with the first. * * \returns iterator pointing to the first defined unicode character */ inline const_iterator begin() const; /** Iterate over all unicode character points in this * encoding, beginning with the first. * * \returns iterator pointing at the end */ inline const_iterator end() const; /** Get the unicode character code for this encoding * at the position nIndex. nIndex is a position between * GetFirstChar() and GetLastChar() * * \param nIndex character code at position index * \returns unicode character code * * \see GetFirstChar * \see GetLastChar * * Will throw an exception if nIndex is out of range. */ virtual pdf_utf16be GetCharCode( int nIndex ) const = 0; protected: bool m_bToUnicodeIsLoaded; ///< If true, ToUnicode has been parse private: int m_nFirstChar; ///< The first defined character code int m_nLastChar; ///< The last defined character code PdfObject* m_pToUnicode; ///< Pointer to /ToUnicode object, if any protected: std::map m_toUnicode; private: /** Parse the /ToUnicode object */ void ParseToUnicode(); pdf_utf16be GetUnicodeValue( pdf_utf16be ) const; pdf_utf16be GetCIDValue( pdf_utf16be ) const; }; // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfEncoding::operator<( const PdfEncoding & rhs ) const { return (this->GetID() < rhs.GetID()); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfEncoding::operator==( const PdfEncoding & rhs ) const { return (this->GetID() == rhs.GetID()); } // ----------------------------------------------------- // // ----------------------------------------------------- inline int PdfEncoding::GetFirstChar() const { return m_nFirstChar; } // ----------------------------------------------------- // // ----------------------------------------------------- inline int PdfEncoding::GetLastChar() const { return m_nLastChar; } // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfEncoding::const_iterator PdfEncoding::begin() const { return PdfEncoding::const_iterator( this, this->GetFirstChar() ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfEncoding::const_iterator PdfEncoding::end() const { return PdfEncoding::const_iterator( this, this->GetLastChar() + 1 ); } /** * A common base class for standard PdfEncoding which are * known by name. * * - PdfDocEncoding (only use this for strings which are not printed * in the document. This is for meta data in the PDF). * - MacRomanEncoding * - WinAnsiEncoding * - MacExpertEncoding * - StandardEncoding * - SymbolEncoding * - ZapfDingbatsEncoding * * \see PdfWinAnsiEncoding * \see PdfMacRomanEncoding * \see PdfMacExportEncoding *..\see PdfStandardEncoding * \see PdfSymbolEncoding * \see PdfZapfDingbatsEncoding * */ class PODOFO_API PdfSimpleEncoding : public PdfEncoding { public: /* * Create a new simple PdfEncoding which uses 1 byte. * * \param rName the name of a standard PdfEncoding * * As of now possible values for rName are: * - MacRomanEncoding * - WinAnsiEncoding * - MacExpertEncoding * - StandardEncoding * - SymbolEncoding * - ZapfDingbatsEncoding * * \see PdfWinAnsiEncoding * \see PdfMacRomanEncoding * \see PdfMacExportEncoding * \see PdfStandardEncoding * \see PdfSymbolEncoding * \see PdfZapfDingbatsEncoding * * This will allocate a table of 65535 short values * to make conversion from unicode to encoded strings * faster. As this requires a lot of memory, make sure that * only one object of a certain encoding exists at one * time, which is no problem as all methods are const anyways! * */ PdfSimpleEncoding( const PdfName & rName ); ~PdfSimpleEncoding(); /** Add this encoding object to a dictionary * usually be adding an /Encoding key in font dictionaries. * * \param rDictionary add the encoding to this dictionary */ virtual void AddToDictionary( PdfDictionary & rDictionary ) const; /** Convert a string that is encoded with this encoding * to an unicode PdfString. * * \param rEncodedString a string encoded by this encoding. * Usually this string was read from a content stream. * \param pFont the font for which this string is converted * * \returns an unicode PdfString. */ virtual PdfString ConvertToUnicode( const PdfString & rEncodedString, const PdfFont* pFont ) const; /** Convert a unicode PdfString to a string encoded with this encoding. * * \param rString an unicode PdfString. * \param pFont the font for which this string is converted * * \returns an encoded PdfRefCountedBuffer. The PdfRefCountedBuffer is treated as a series of bytes * and is allowed to have 0 bytes. The returned buffer must not be a unicode string. */ virtual PdfRefCountedBuffer ConvertToEncoding( const PdfString & rString, const PdfFont* pFont ) const; /** * PdfSimpleEncoding subclasses are usuylla not auto-deleted, as * they are allocated statically only once. * * \returns true if this encoding should be deleted automatically with the * font. * * \see PdfFont::WinAnsiEncoding * \see PdfFont::MacRomanEncoding */ virtual bool IsAutoDelete() const; /** * \returns true if this is a single byte encoding with a maximum of 256 values. */ inline virtual bool IsSingleByteEncoding() const; /** Get the name of this encoding. * * \returns the name of this encoding. */ inline const PdfName & GetName() const; /** Get the unicode character code for this encoding * at the position nIndex. nIndex is a position between * GetFirstChar() and GetLastChar() * * \param nIndex character code at position index * \returns unicode character code * * \see GetFirstChar * \see GetLastChar * * Will throw an exception if nIndex is out of range. */ virtual pdf_utf16be GetCharCode( int nIndex ) const; char GetUnicodeCharCode(pdf_utf16be unicodeValue) const; private: /** Initialize the internal table of mappings from unicode code points * to encoded byte values. */ void InitEncodingTable(); protected: /** Get a unique ID for this encoding * which can used for comparisons! * * \returns a unique id for this encoding! */ inline virtual const PdfName & GetID() const; /** Gets a table of 256 short values which are the * big endian unicode code points that are assigned * to the 256 values of this encoding. * * This table is used internally to convert an encoded * string of this encoding to and from unicode. * * \returns an array of 256 big endian unicode code points */ virtual const pdf_utf16be* GetToUnicodeTable() const = 0; protected: Util::PdfMutex * m_mutex; ///< Mutex for the creation of the encoding table private: PdfName m_name; ///< The name of the encoding char* m_pEncodingTable; ///< The helper table for conversions into this encoding }; // ----------------------------------------------------- // // ----------------------------------------------------- inline const PdfName & PdfSimpleEncoding::GetID() const { return m_name; } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfSimpleEncoding::IsAutoDelete() const { return false; } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfSimpleEncoding::IsSingleByteEncoding() const { return true; } // ----------------------------------------------------- // // ----------------------------------------------------- inline const PdfName & PdfSimpleEncoding::GetName() const { return m_name; } /** * The PdfDocEncoding is the default encoding for * all strings in PoDoFo which are data in the PDF * file. * * Do not allocate this class yourself, as allocations * might be expensive. Try using PdfFont::DocEncoding. * * \see PdfFont::DocEncoding */ class PODOFO_API PdfDocEncoding : public PdfSimpleEncoding { public: /** Create a new PdfDocEncoding */ PdfDocEncoding() : PdfSimpleEncoding( PdfName("PdfDocEncoding") ) { } protected: /** Gets a table of 256 short values which are the * big endian unicode code points that are assigned * to the 256 values of this encoding. * * This table is used internally to convert an encoded * string of this encoding to and from unicode. * * \returns an array of 256 big endian unicode code points */ virtual const pdf_utf16be* GetToUnicodeTable() const; private: static const pdf_utf16be s_cEncoding[256]; ///< conversion table from DocEncoding to UTF16 }; /** * The WinAnsi Encoding is the default encoding in PoDoFo for * contents on PDF pages. * * It is also called CP-1252 encoding. * This class may be used as base for derived encodings. * * \see PdfWin1250Encoding * * Do not allocate this class yourself, as allocations * might be expensive. Try using PdfFont::WinAnsiEncoding. * * \see PdfFont::WinAnsiEncoding */ class PODOFO_API PdfWinAnsiEncoding : public PdfSimpleEncoding { public: /** Create a new PdfWinAnsiEncoding */ PdfWinAnsiEncoding() : PdfSimpleEncoding( PdfName("WinAnsiEncoding") ) { } protected: /** Gets a table of 256 short values which are the * big endian unicode code points that are assigned * to the 256 values of this encoding. * * This table is used internally to convert an encoded * string of this encoding to and from unicode. * * \returns an array of 256 big endian unicode code points */ virtual const pdf_utf16be* GetToUnicodeTable() const; /** Add this encoding object to a dictionary * usually be adding an /Encoding key in font dictionaries. * * This method generates array of differences into /Encoding * dictionary if called from derived class with * different unicode table. * * \param rDictionary add the encoding to this dictionary */ virtual void AddToDictionary( PdfDictionary & rDictionary ) const; private: static const pdf_utf16be s_cEncoding[256]; ///< conversion table from WinAnsiEncoding to UTF16 }; /** * Do not allocate this class yourself, as allocations * might be expensive. Try using PdfFont::MacRomanEncoding. * * \see PdfFont::MacRomanEncoding */ class PODOFO_API PdfMacRomanEncoding : public PdfSimpleEncoding { public: /** Create a new PdfMacRomanEncoding */ PdfMacRomanEncoding() : PdfSimpleEncoding( PdfName("MacRomanEncoding") ) { } protected: /** Gets a table of 256 short values which are the * big endian unicode code points that are assigned * to the 256 values of this encoding. * * This table is used internally to convert an encoded * string of this encoding to and from unicode. * * \returns an array of 256 big endian unicode code points */ virtual const pdf_utf16be* GetToUnicodeTable() const; private: static const pdf_utf16be s_cEncoding[256]; ///< conversion table from MacRomanEncoding to UTF16 }; /** */ class PODOFO_API PdfMacExpertEncoding : public PdfSimpleEncoding { public: /** Create a new PdfMacExpertEncoding */ inline PdfMacExpertEncoding() : PdfSimpleEncoding( PdfName("MacExpertEncoding") ) { } protected: /** Gets a table of 256 short values which are the * big endian unicode code points that are assigned * to the 256 values of this encoding. * * This table is used internally to convert an encoded * string of this encoding to and from unicode. * * \returns an array of 256 big endian unicode code points */ virtual const pdf_utf16be* GetToUnicodeTable() const; private: static const pdf_utf16be s_cEncoding[256]; ///< conversion table from MacExpertEncoding to UTF16 }; // OC 13.08.2010 Neu: StandardEncoding /** * Do not allocate this class yourself, as allocations * might be expensive. Try using PdfFont::StandardEncoding. * * \see PdfFont::StandardEncoding */ class PODOFO_API PdfStandardEncoding : public PdfSimpleEncoding { public: /** Create a new PdfStandardEncoding */ PdfStandardEncoding() : PdfSimpleEncoding( PdfName("StandardEncoding") ) { } protected: /** Gets a table of 256 short values which are the * big endian unicode code points that are assigned * to the 256 values of this encoding. * * This table is used internally to convert an encoded * string of this encoding to and from unicode. * * \returns an array of 256 big endian unicode code points */ virtual const pdf_utf16be* GetToUnicodeTable() const; private: static const pdf_utf16be s_cEncoding[256]; ///< conversion table from StandardEncoding to UTF16 }; // OC 13.08.2010 Neu: SymbolEncoding /** * Do not allocate this class yourself, as allocations * might be expensive. Try using PdfFont::SymbolEncoding. * * \see PdfFont::SymbolEncoding */ class PODOFO_API PdfSymbolEncoding : public PdfSimpleEncoding { public: /** Create a new PdfSymbolEncoding */ PdfSymbolEncoding() : PdfSimpleEncoding( PdfName("SymbolEncoding") ) { } protected: /** Gets a table of 256 short values which are the * big endian unicode code points that are assigned * to the 256 values of this encoding. * * This table is used internally to convert an encoded * string of this encoding to and from unicode. * * \returns an array of 256 big endian unicode code points */ virtual const pdf_utf16be* GetToUnicodeTable() const; private: static const pdf_utf16be s_cEncoding[256]; ///< conversion table from SymbolEncoding to UTF16 }; // OC 13.08.2010 Neu: ZapfDingbatsEncoding /** * Do not allocate this class yourself, as allocations * might be expensive. Try using PdfFont::ZapfDingbats. * * \see PdfFont::ZapfDingbatsEncoding */ class PODOFO_API PdfZapfDingbatsEncoding : public PdfSimpleEncoding { public: /** Create a new PdfZapfDingbatsEncoding */ PdfZapfDingbatsEncoding() : PdfSimpleEncoding( PdfName("ZapfDingbatsEncoding") ) { } protected: /** Gets a table of 256 short values which are the * big endian unicode code points that are assigned * to the 256 values of this encoding. * * This table is used internally to convert an encoded * string of this encoding to and from unicode. * * \returns an array of 256 big endian unicode code points */ virtual const pdf_utf16be* GetToUnicodeTable() const; private: static const pdf_utf16be s_cEncoding[256]; ///< conversion table from ZapfDingbatsEncoding to UTF16 }; /** * WINDOWS-1250 encoding */ class PODOFO_API PdfWin1250Encoding : public PdfWinAnsiEncoding { public: /** Create a new PdfWin1250Encoding */ PdfWin1250Encoding() { } protected: /** Gets a table of 256 short values which are the * big endian unicode code points that are assigned * to the 256 values of this encoding. * * This table is used internally to convert an encoded * string of this encoding to and from unicode. * * \returns an array of 256 big endian unicode code points */ virtual const pdf_utf16be* GetToUnicodeTable() const; private: static const pdf_utf16be s_cEncoding[256]; ///< conversion table from Win1250Encoding to UTF16 }; /** * ISO-8859-2 encoding */ class PODOFO_API PdfIso88592Encoding : public PdfWinAnsiEncoding { public: /** Create a new PdfIso88592Encoding */ PdfIso88592Encoding() { } protected: /** Gets a table of 256 short values which are the * big endian unicode code points that are assigned * to the 256 values of this encoding. * * This table is used internally to convert an encoded * string of this encoding to and from unicode. * * \returns an array of 256 big endian unicode code points */ virtual const pdf_utf16be* GetToUnicodeTable() const; private: static const pdf_utf16be s_cEncoding[256]; ///< conversion table from Iso88592Encoding to UTF16 }; }; /* namespace PoDoFo */ #endif // _PDF_ENCODING_H_ podofo-0.9.5/src/base/PdfFileStream.h0000664000175000017500000001555712715357362017252 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FILE_STREAM_H_ #define _PDF_FILE_STREAM_H_ #include "PdfDefines.h" #include "PdfStream.h" namespace PoDoFo { class PdfOutputStream; /** A PDF stream can be appended to any PdfObject * and can contain arbitrary data. * * Most of the time it will contain either drawing commands * to draw onto a page or binary data like a font or an image. * * A PdfFileStream writes all data directly to an output device * without keeping it in memory. * PdfFileStream is used automatically when creating PDF files * using PdfImmediateWriter. * * \see PdfVecObjects * \see PdfStream * \see PdfMemoryStream * \see PdfFileStream */ class PODOFO_API PdfFileStream : public PdfStream { public: /** Create a new PdfFileStream object which has a parent PdfObject. * The stream will be deleted along with the parent. * This constructor will be called by PdfObject::Stream() for you. * * \param pParent parent object * \param pDevice output device */ PdfFileStream( PdfObject* pParent, PdfOutputDevice* pDevice ); virtual ~PdfFileStream(); /** Set an encryption object which is used to encrypt * all data written to this stream. * * \param pEncrypt an encryption object or NULL if no encryption should be done */ void SetEncrypted( PdfEncrypt* pEncrypt ); /** Write the stream to an output device * \param pDevice write to this outputdevice. * \param pEncrypt encrypt stream data using this object */ virtual void Write( PdfOutputDevice* pDevice, PdfEncrypt* pEncrypt = NULL ); /** Get a malloced buffer of the current stream. * No filters will be applied to the buffer, so * if the stream is Flate compressed the compressed copy * will be returned. * * The caller has to podofo_free() the buffer. * * This is currently not implemented for PdfFileStreams * and will raise an ePdfError_InternalLogic exception * * \param pBuffer pointer to the buffer address (output parameter) * \param lLen pointer to the buffer length (output parameter) */ virtual void GetCopy( char** pBuffer, pdf_long* lLen ) const; /** Get a copy of a the stream and write it to a PdfOutputStream * * \param pStream data is written to this stream. */ virtual void GetCopy( PdfOutputStream* pStream ) const; /** Get the streams length with all filters applied (eg the compressed * length of a Flate compressed stream). * * \returns the length of the stream with all filters applied */ inline virtual pdf_long GetLength() const; protected: /** Required for the GetFilteredCopy implementation * \returns a handle to the internal buffer */ inline virtual const char* GetInternalBuffer() const; /** Required for the GetFilteredCopy implementation * \returns the size of the internal buffer */ inline virtual pdf_long GetInternalBufferSize() const; /** Begin appending data to this stream. * Clears the current stream contents. * * \param vecFilters use this filters to encode any data written to the stream. */ virtual void BeginAppendImpl( const TVecFilters & vecFilters ); /** Append a binary buffer to the current stream contents. * * \param pszString a buffer * \param lLen length of the buffer * * \see BeginAppend * \see Append * \see EndAppend */ virtual void AppendImpl( const char* pszString, size_t lLen ); /** Finish appending data to the stream */ virtual void EndAppendImpl(); private: PdfOutputDevice* m_pDevice; PdfOutputStream* m_pStream; PdfOutputStream* m_pDeviceStream; PdfOutputStream* m_pEncryptStream; pdf_long m_lLenInitial; pdf_long m_lLength; PdfObject* m_pLength; PdfEncrypt* m_pCurEncrypt; }; // ----------------------------------------------------- // // ----------------------------------------------------- pdf_long PdfFileStream::GetLength() const { return m_lLength; } // ----------------------------------------------------- // // ----------------------------------------------------- const char* PdfFileStream::GetInternalBuffer() const { return NULL; } // ----------------------------------------------------- // // ----------------------------------------------------- pdf_long PdfFileStream::GetInternalBufferSize() const { return 0; } }; #endif // _PDF_FILE_STREAM_H_ podofo-0.9.5/src/base/PdfColor.cpp0000664000175000017500000013001212347347566016616 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfColor.h" #include "PdfArray.h" #include "PdfDictionary.h" #include "PdfLocale.h" #include "PdfStream.h" #include "PdfTokenizer.h" #include "PdfVariant.h" #include "PdfDefinesPrivate.h" #include #include namespace PoDoFo { /** A PdfNamedColor holds * a PdfColor object and a name. */ class PdfNamedColor { public: /** Create a PdfNamedColor object. * * \param pszName the name. The string must be allocated as static memory somewhere * The string data will not be copied! * \param rColor a PdfColor object */ PdfNamedColor( const char* pszName, const PdfColor & rColor ) : m_pszName( pszName ), m_color( rColor ) { } /** Create a PdfNamedColor object. * * \param pszName the name. The string must be allocated as static memory somewhere * The string data will not be copied! * \param rColorName RGB hex value (e.g. #FFABCD) */ PdfNamedColor( const char* pszName, const char* rColorName ) : m_pszName( pszName ), m_color( FromRGBString(rColorName) ) { } /** Copy constructor */ PdfNamedColor(const PdfNamedColor& rhs) : m_pszName( rhs.m_pszName ), m_color( rhs.m_color ) { } /** Class destructor. */ ~PdfNamedColor() { } /** Compare this color object to a name * The comparison is case insensitive! * \returns true if the passed string is smaller than the name * of this color object. */ inline bool operator<( const char* pszName ) const { return pszName ? PoDoFo::compat::strcasecmp( m_pszName, pszName ) < 0 : true; } /** Compare this color object to a PdfNamedColor comparing only the name. * The comparison is case insensitive! * \returns true if the passed string is smaller than the name * of this color object. */ inline bool operator<( const PdfNamedColor & rhs ) const { return rhs.GetName() ? PoDoFo::compat::strcasecmp( m_pszName, rhs.GetName() ) < 0 : true; } /** Compare this color object to a name * The comparison is case insensitive! * \returns true if the passed string is the name * of this color object. */ inline bool operator==( const char* pszName ) const { return pszName ? PoDoFo::compat::strcasecmp( m_pszName, pszName ) == 0 : false; } /** * \returns a reference to the internal color object */ inline const PdfColor & GetColor() const { return m_color; } /** * \returns a pointer to the name of the color */ inline const char* GetName() const { return m_pszName; } private: /** default constructor, not implemented */ PdfNamedColor(); /** copy assignment operator, not implemented */ PdfNamedColor& operator=(const PdfNamedColor&); /** Creates a color object from a RGB string. * * \param pszName a string describing a color. * * Supported values are: * - hex values (e.g. #FF002A (RGB)) * * \returns a PdfColor object */ static PdfColor FromRGBString( const char* pszName ) { //This method cannot use PdfTokenizer::GetHexValue() as static values used there have //not been initialised yet. This function should used only during program startup //and the only purpose is use at s_NamedColors table. size_t lLen = strlen( pszName ); if ( (lLen == 7) && (pszName[0] == '#') && isxdigit(pszName[1]) ) { const unsigned long NAME_CONVERTED_TO_LONG_HEX = static_cast(strtol(&pszName[1], 0, 16)); const unsigned long R = (NAME_CONVERTED_TO_LONG_HEX & 0x00FF0000) >> 16; const unsigned long G = (NAME_CONVERTED_TO_LONG_HEX & 0x0000FF00) >> 8; const unsigned long B = (NAME_CONVERTED_TO_LONG_HEX & 0x000000FF); return PdfColor( static_cast(R)/255.0, static_cast(G)/255.0, static_cast(B)/255.0 ); } else { PODOFO_RAISE_ERROR( ePdfError_CannotConvertColor ); } } const char* m_pszName; PdfColor m_color; }; /** * Predicate to allow binary search in the list * of PdfNamedColor's using for example std::equal_range. */ class NamedColorComparatorPredicate { public: NamedColorComparatorPredicate() { } inline bool operator()( const PdfNamedColor & rNamedColor1, const PdfNamedColor & rNamedColor2 ) const { return rNamedColor1 < rNamedColor2; } }; // Table based on http://cvsweb.xfree86.org/cvsweb/xc/programs/rgb/rgb.txt?rev=1.2 // Hex values have been copied from http://en.wikipedia.org/wiki/X11_color_names (21/11/2010) static const size_t s_nNumNamedColors = 148; static const PdfNamedColor s_NamedColors[s_nNumNamedColors] = { PdfNamedColor( "aliceblue", "#F0F8FF" ) , PdfNamedColor( "antiquewhite", "#FAEBD7" ) , PdfNamedColor( "aqua", "#00FFFF" ) , PdfNamedColor( "aquamarine", "#7FFFD4" ) , PdfNamedColor( "azure", "#F0FFFF" ) , PdfNamedColor( "beige", "#F5F5DC" ) , PdfNamedColor( "bisque", "#FFE4C4" ) , PdfNamedColor( "black", "#000000" ) , PdfNamedColor( "blanchedalmond","#FFEBCD" ) , PdfNamedColor( "blue", "#0000FF" ) , PdfNamedColor( "blueviolet", "#8A2BE2" ) , PdfNamedColor( "brown", "#A52A2A" ) , PdfNamedColor( "burlywood", "#DEB887" ) , PdfNamedColor( "cadetblue", "#5F9EA0" ) , PdfNamedColor( "chartreuse", "#7FFF00" ) , PdfNamedColor( "chocolate", "#D2691E" ) , PdfNamedColor( "coral", "#FF7F50" ) , PdfNamedColor( "cornflowerblue","#6495ED" ) , PdfNamedColor( "cornsilk", "#FFF8DC" ) , PdfNamedColor( "crimson", "#DC143C" ) , PdfNamedColor( "cyan", "#00FFFF" ) , PdfNamedColor( "darkblue", "#00008B" ) , PdfNamedColor( "darkcyan", "#008B8B" ) , PdfNamedColor( "darkgoldenrod", "#B8860B" ) , PdfNamedColor( "darkgray", "#A9A9A9" ) , PdfNamedColor( "darkgreen", "#006400" ) , PdfNamedColor( "darkgrey", "#A9A9A9" ) , PdfNamedColor( "darkkhaki", "#BDB76B" ) , PdfNamedColor( "darkmagenta", "#8B008B" ) , PdfNamedColor( "darkolivegreen","#556B2F" ) , PdfNamedColor( "darkorange", "#FF8C00" ) , PdfNamedColor( "darkorchid", "#9932CC" ) , PdfNamedColor( "darkred", "#8B0000" ) , PdfNamedColor( "darksalmon", "#E9967A" ) , PdfNamedColor( "darkseagreen", "#8FBC8F" ) , PdfNamedColor( "darkslateblue", "#483D8B" ) , PdfNamedColor( "darkslategray", "#2F4F4F" ) , PdfNamedColor( "darkslategrey", "#2F4F4F" ) , PdfNamedColor( "darkturquoise", "#00CED1" ) , PdfNamedColor( "darkviolet", "#9400D3" ) , PdfNamedColor( "deeppink", "#FF1493" ) , PdfNamedColor( "deepskyblue", "#00BFFF" ) , PdfNamedColor( "dimgray", "#696969" ) , PdfNamedColor( "dimgrey", "#696969" ) , PdfNamedColor( "dodgerblue", "#1E90FF" ) , PdfNamedColor( "firebrick", "#B22222" ) , PdfNamedColor( "floralwhite", "#FFFAF0" ) , PdfNamedColor( "forestgreen", "#228B22" ) , PdfNamedColor( "fuchsia", "#FF00FF" ) , PdfNamedColor( "gainsboro", "#DCDCDC" ) , PdfNamedColor( "ghostwhite", "#F8F8FF" ) , PdfNamedColor( "gold", "#FFD700" ) , PdfNamedColor( "goldenrod", "#DAA520" ) , PdfNamedColor( "gray", "#BEBEBE" ) , //RG changed from W3C to X11 value PdfNamedColor( "green", "#00FF00" ) , PdfNamedColor( "greenyellow", "#ADFF2F" ) , PdfNamedColor( "grey", "#BEBEBE" ) , //RG changed from W3C to X11 value PdfNamedColor( "honeydew", "#F0FFF0" ) , PdfNamedColor( "hotpink", "#FF69B4" ) , PdfNamedColor( "indianred", "#CD5C5C" ) , PdfNamedColor( "indigo", "#4B0082" ) , PdfNamedColor( "ivory", "#FFFFF0" ) , PdfNamedColor( "khaki", "#F0E68C" ) , PdfNamedColor( "lavender", "#E6E6FA" ) , PdfNamedColor( "lavenderblush", "#FFF0F5" ) , PdfNamedColor( "lawngreen", "#7CFC00" ) , PdfNamedColor( "lemonchiffon", "#FFFACD" ) , PdfNamedColor( "lightblue", "#ADD8E6" ) , PdfNamedColor( "lightcoral", "#F08080" ) , PdfNamedColor( "lightcyan", "#E0FFFF" ) , PdfNamedColor( "lightgoldenrod", "#EEDD82" ) , PdfNamedColor( "lightgoldenrodyellow", "#FAFAD2" ) , PdfNamedColor( "lightgray", "#D3D3D3" ) , PdfNamedColor( "lightgreen", "#90EE90" ) , PdfNamedColor( "lightgrey", "#D3D3D3" ) , PdfNamedColor( "lightpink", "#FFB6C1" ) , PdfNamedColor( "lightsalmon", "#FFA07A" ) , PdfNamedColor( "lightseagreen", "#20B2AA" ) , PdfNamedColor( "lightskyblue", "#87CEFA" ) , PdfNamedColor( "lightslategray","#778899" ) , PdfNamedColor( "lightslategrey","#778899" ) , PdfNamedColor( "lightsteelblue","#B0C4DE" ) , PdfNamedColor( "lightyellow", "#FFFFE0" ) , PdfNamedColor( "lime", "#00FF00" ) , PdfNamedColor( "limegreen", "#32CD32" ) , PdfNamedColor( "linen", "#FAF0E6" ) , PdfNamedColor( "magenta", "#FF00FF" ) , PdfNamedColor( "maroon", "#B03060" ) , //RG changed from W3C to X11 value PdfNamedColor( "mediumaquamarine", "#66CDAA" ) , PdfNamedColor( "mediumblue", "#0000CD" ) , PdfNamedColor( "mediumorchid", "#BA55D3" ) , PdfNamedColor( "mediumpurple", "#9370DB" ) , PdfNamedColor( "mediumseagreen","#3CB371" ) , PdfNamedColor( "mediumslateblue", "#7B68EE" ) , PdfNamedColor( "mediumspringgreen", "#00FA9A" ) , PdfNamedColor( "mediumturquoise", "#48D1CC" ) , PdfNamedColor( "mediumvioletred", "#C71585" ) , PdfNamedColor( "midnightblue", "#191970" ) , PdfNamedColor( "mintcream", "#F5FFFA" ) , PdfNamedColor( "mistyrose", "#FFE4E1" ) , PdfNamedColor( "moccasin", "#FFE4B5" ) , PdfNamedColor( "navajowhite", "#FFDEAD" ) , PdfNamedColor( "navy", "#000080" ) , PdfNamedColor( "oldlace", "#FDF5E6" ) , PdfNamedColor( "olive", "#808000" ) , PdfNamedColor( "olivedrab", "#6B8E23" ) , PdfNamedColor( "orange", "#FFA500" ) , PdfNamedColor( "orangered", "#FF4500" ) , PdfNamedColor( "orchid", "#DA70D6" ) , PdfNamedColor( "palegoldenrod", "#EEE8AA" ) , PdfNamedColor( "palegreen", "#98FB98" ) , PdfNamedColor( "paleturquoise", "#AFEEEE" ) , PdfNamedColor( "palevioletred", "#DB7093" ) , PdfNamedColor( "papayawhip", "#FFEFD5" ) , PdfNamedColor( "peachpuff", "#FFDAB9" ) , PdfNamedColor( "peru", "#CD853F" ) , PdfNamedColor( "pink", "#FFC0CB" ) , PdfNamedColor( "plum", "#DDA0DD" ) , PdfNamedColor( "powderblue", "#B0E0E6" ) , PdfNamedColor( "purple", "#A020F0" ) , //RG changed from W3C to X11 value PdfNamedColor( "red", "#FF0000" ) , PdfNamedColor( "rosybrown", "#BC8F8F" ) , PdfNamedColor( "royalblue", "#4169E1" ) , PdfNamedColor( "saddlebrown", "#8B4513" ) , PdfNamedColor( "salmon", "#FA8072" ) , PdfNamedColor( "sandybrown", "#F4A460" ) , PdfNamedColor( "seagreen", "#2E8B57" ) , PdfNamedColor( "seashell", "#FFF5EE" ) , PdfNamedColor( "sienna", "#A0522D" ) , PdfNamedColor( "silver", "#C0C0C0" ) , PdfNamedColor( "skyblue", "#87CEEB" ) , PdfNamedColor( "slateblue", "#6A5ACD" ) , PdfNamedColor( "slategray", "#708090" ) , PdfNamedColor( "slategrey", "#708090" ) , PdfNamedColor( "snow", "#FFFAFA" ) , PdfNamedColor( "springgreen", "#00FF7F" ) , PdfNamedColor( "steelblue", "#4682B4" ) , PdfNamedColor( "tan", "#D2B48C" ) , PdfNamedColor( "teal", "#008080" ) , PdfNamedColor( "thistle", "#D8BFD8" ) , PdfNamedColor( "tomato", "#FF6347" ) , PdfNamedColor( "turquoise", "#40E0D0" ) , PdfNamedColor( "violet", "#EE82EE" ) , PdfNamedColor( "wheat", "#F5DEB3" ) , PdfNamedColor( "white", "#FFFFFF" ) , PdfNamedColor( "whitesmoke", "#F5F5F5" ) , PdfNamedColor( "yellow", "#FFFF00" ) , PdfNamedColor( "yellowgreen", "#9ACD32" ) }; inline void CheckDoubleRange( double val, double min, double max ) { if( (val < min) || (val > max) ) { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } } PdfColor::PdfColor() : m_uColor(), m_separationName(), m_separationDensity(0.0), m_eColorSpace(ePdfColorSpace_Unknown), m_eAlternateColorSpace(ePdfColorSpace_Unknown) { m_uColor.rgb[0] = 0.0; m_uColor.rgb[1] = 0.0; m_uColor.rgb[2] = 0.0; } PdfColor::PdfColor( double dGray ) : m_uColor(), m_separationName(), m_separationDensity(0.0), m_eColorSpace(ePdfColorSpace_DeviceGray), m_eAlternateColorSpace(ePdfColorSpace_Unknown) { CheckDoubleRange( dGray, 0.0, 1.0 ); m_uColor.gray = dGray; } PdfColor::PdfColor( double dRed, double dGreen, double dBlue ) : m_uColor(), m_separationName(), m_separationDensity(0.0), m_eColorSpace(ePdfColorSpace_DeviceRGB), m_eAlternateColorSpace(ePdfColorSpace_Unknown) { CheckDoubleRange( dRed, 0.0, 1.0 ); CheckDoubleRange( dGreen, 0.0, 1.0 ); CheckDoubleRange( dBlue, 0.0, 1.0 ); m_uColor.rgb[0] = dRed; m_uColor.rgb[1] = dGreen; m_uColor.rgb[2] = dBlue; } PdfColor::PdfColor( double dCyan, double dMagenta, double dYellow, double dBlack ) : m_uColor(), m_separationName(), m_separationDensity(0.0), m_eColorSpace( ePdfColorSpace_DeviceCMYK ), m_eAlternateColorSpace(ePdfColorSpace_Unknown) { CheckDoubleRange( dCyan, 0.0, 1.0 ); CheckDoubleRange( dMagenta, 0.0, 1.0 ); CheckDoubleRange( dYellow, 0.0, 1.0 ); CheckDoubleRange( dBlack, 0.0, 1.0 ); m_uColor.cmyk[0] = dCyan; m_uColor.cmyk[1] = dMagenta; m_uColor.cmyk[2] = dYellow; m_uColor.cmyk[3] = dBlack; } PdfColor::PdfColor( const PdfColor & rhs ) : m_uColor(), m_separationName(rhs.m_separationName), m_separationDensity(rhs.m_separationDensity), m_eColorSpace(rhs.m_eColorSpace), m_eAlternateColorSpace(rhs.m_eAlternateColorSpace) { memcpy( &m_uColor, &rhs.m_uColor, sizeof(m_uColor) ); } PdfColor::~PdfColor() { } PdfColorGray::PdfColorGray( double dGray ) : PdfColor( dGray ) { } PdfColorGray::~PdfColorGray() { } PdfColorRGB::PdfColorRGB( double dRed, double dGreen, double dBlue ) : PdfColor( dRed, dGreen, dBlue ) { } PdfColorRGB::~PdfColorRGB() { } PdfColorCMYK::PdfColorCMYK( double dCyan, double dMagenta, double dYellow, double dBlack ) : PdfColor( dCyan, dMagenta, dYellow, dBlack ) { } PdfColorCMYK::~PdfColorCMYK() { } PdfColorCieLab::PdfColorCieLab( double dCieL, double dCieA, double dCieB ) : PdfColor() { CheckDoubleRange( dCieL, 0.0, 100.0 ); CheckDoubleRange( dCieA, -128.0, 127.0 ); CheckDoubleRange( dCieB, -128.0, 127.0 ); m_eColorSpace = ePdfColorSpace_CieLab; m_uColor.lab[0] = dCieL; m_uColor.lab[1] = dCieA; m_uColor.lab[2] = dCieB; } PdfColorCieLab::~PdfColorCieLab() { } PdfColorSeparationAll::PdfColorSeparationAll() : PdfColor() { m_eColorSpace = ePdfColorSpace_Separation; m_separationName = "All"; m_separationDensity = 1.0; m_eAlternateColorSpace = ePdfColorSpace_DeviceCMYK; m_uColor.cmyk[0] = 1.0; m_uColor.cmyk[1] = 1.0; m_uColor.cmyk[2] = 1.0; m_uColor.cmyk[3] = 1.0; } PdfColorSeparationAll::~PdfColorSeparationAll() { } PdfColorSeparationNone::PdfColorSeparationNone() : PdfColor() { m_eColorSpace = ePdfColorSpace_Separation; m_separationName = "None"; m_separationDensity = 0.0; m_eAlternateColorSpace = ePdfColorSpace_DeviceCMYK; m_uColor.cmyk[0] = 0.0; m_uColor.cmyk[1] = 0.0; m_uColor.cmyk[2] = 0.0; m_uColor.cmyk[3] = 0.0; } PdfColorSeparationNone::~PdfColorSeparationNone() { } PdfColorSeparation::PdfColorSeparation( const std::string & sName, double dDensity, const PdfColor & alternateColor ) : PdfColor() { m_eAlternateColorSpace = alternateColor.GetColorSpace(); switch( m_eAlternateColorSpace ) { case ePdfColorSpace_DeviceGray: { m_uColor.gray = alternateColor.GetGrayScale(); break; } case ePdfColorSpace_DeviceRGB: { m_uColor.rgb[0] = alternateColor.GetRed(); m_uColor.rgb[1] = alternateColor.GetGreen(); m_uColor.rgb[2] = alternateColor.GetBlue(); break; } case ePdfColorSpace_DeviceCMYK: { m_uColor.cmyk[0] = alternateColor.GetCyan(); m_uColor.cmyk[1] = alternateColor.GetMagenta(); m_uColor.cmyk[2] = alternateColor.GetYellow(); m_uColor.cmyk[3] = alternateColor.GetBlack(); break; } case ePdfColorSpace_CieLab: { m_uColor.lab[0] = alternateColor.GetCieL(); m_uColor.lab[1] = alternateColor.GetCieA(); m_uColor.lab[2] = alternateColor.GetCieB(); break; } case ePdfColorSpace_Separation: { PODOFO_RAISE_LOGIC_IF( true, "PdfColor::PdfColorSeparation alternateColor must be Gray, RGB, CMYK or CieLab!"); break; } case ePdfColorSpace_Unknown: case ePdfColorSpace_Indexed: default: { PODOFO_RAISE_ERROR( ePdfError_InvalidEnumValue ); break; } } m_eColorSpace = ePdfColorSpace_Separation; m_separationName = sName; m_separationDensity = dDensity; } PdfColorSeparation::~PdfColorSeparation() { } const PdfColor & PdfColor::operator=( const PdfColor & rhs ) { if (this != &rhs) { memcpy( &m_uColor, &rhs.m_uColor, sizeof(m_uColor) ); m_separationName = rhs.m_separationName; m_separationDensity = rhs.m_separationDensity; m_eColorSpace = rhs.m_eColorSpace; m_eAlternateColorSpace = rhs.m_eAlternateColorSpace; } else { //do nothing } return *this; } PdfColor PdfColor::ConvertToGrayScale() const { switch(m_eColorSpace) { case ePdfColorSpace_DeviceGray: { return *this; } case ePdfColorSpace_DeviceRGB: { return PdfColor( 0.299*m_uColor.rgb[0] + 0.587*m_uColor.rgb[1] + 0.114*m_uColor.rgb[2] ); } case ePdfColorSpace_DeviceCMYK: { return ConvertToRGB().ConvertToGrayScale(); } case ePdfColorSpace_Separation: { if ( m_eAlternateColorSpace == ePdfColorSpace_DeviceCMYK ) { double dCyan = m_uColor.cmyk[0]; double dMagenta = m_uColor.cmyk[1]; double dYellow = m_uColor.cmyk[2]; double dBlack = m_uColor.cmyk[3]; double dRed = dCyan * (1.0 - dBlack) + dBlack; double dGreen = dMagenta * (1.0 - dBlack) + dBlack; double dBlue = dYellow * (1.0 - dBlack) + dBlack; return PdfColor( 1.0 - dRed, 1.0 - dGreen, 1.0 - dBlue ); } else { PODOFO_RAISE_ERROR( ePdfError_NotImplemented ); } break; } case ePdfColorSpace_CieLab: case ePdfColorSpace_Indexed: case ePdfColorSpace_Unknown: { PODOFO_RAISE_ERROR( ePdfError_CannotConvertColor ); break; } default: { PODOFO_RAISE_ERROR( ePdfError_InvalidEnumValue ); break; } }; return PdfColor(); } PdfColor PdfColor::ConvertToRGB() const { switch(m_eColorSpace) { case ePdfColorSpace_DeviceGray: { return PdfColor( m_uColor.gray, m_uColor.gray, m_uColor.gray ); } case ePdfColorSpace_DeviceRGB: { return *this; } case ePdfColorSpace_DeviceCMYK: { double dCyan = m_uColor.cmyk[0]; double dMagenta = m_uColor.cmyk[1]; double dYellow = m_uColor.cmyk[2]; double dBlack = m_uColor.cmyk[3]; double dRed = dCyan * (1.0 - dBlack) + dBlack; double dGreen = dMagenta * (1.0 - dBlack) + dBlack; double dBlue = dYellow * (1.0 - dBlack) + dBlack; return PdfColor( 1.0 - dRed, 1.0 - dGreen, 1.0 - dBlue ); } case ePdfColorSpace_Separation: { if ( m_eAlternateColorSpace == ePdfColorSpace_DeviceCMYK ) { double dCyan = m_uColor.cmyk[0]; double dMagenta = m_uColor.cmyk[1]; double dYellow = m_uColor.cmyk[2]; double dBlack = m_uColor.cmyk[3]; double dRed = dCyan * (1.0 - dBlack) + dBlack; double dGreen = dMagenta * (1.0 - dBlack) + dBlack; double dBlue = dYellow * (1.0 - dBlack) + dBlack; return PdfColor( 1.0 - dRed, 1.0 - dGreen, 1.0 - dBlue ); } else { PODOFO_RAISE_ERROR( ePdfError_NotImplemented ); } break; } case ePdfColorSpace_CieLab: case ePdfColorSpace_Indexed: case ePdfColorSpace_Unknown: { PODOFO_RAISE_ERROR( ePdfError_CannotConvertColor ); break; } default: { PODOFO_RAISE_ERROR( ePdfError_InvalidEnumValue ); break; } }; return PdfColor(); } PdfColor PdfColor::ConvertToCMYK() const { switch(m_eColorSpace) { case ePdfColorSpace_DeviceGray: { return ConvertToRGB().ConvertToCMYK(); } case ePdfColorSpace_DeviceRGB: { double dRed = m_uColor.rgb[0]; double dGreen = m_uColor.rgb[1]; double dBlue = m_uColor.rgb[2]; double dBlack = PDF_MIN( 1.0-dRed, PDF_MIN( 1.0-dGreen, 1.0-dBlue ) ); double dCyan = 0.0; double dMagenta = 0.0; double dYellow = 0.0; if (dBlack < 1.0) { dCyan = (1.0 - dRed - dBlack) / (1.0 - dBlack); dMagenta = (1.0 - dGreen - dBlack) / (1.0 - dBlack); dYellow = (1.0 - dBlue - dBlack) / (1.0 - dBlack); } //else do nothing return PdfColor( dCyan, dMagenta, dYellow, dBlack ); } case ePdfColorSpace_DeviceCMYK: { return *this; } case ePdfColorSpace_Separation: case ePdfColorSpace_CieLab: case ePdfColorSpace_Indexed: case ePdfColorSpace_Unknown: { PODOFO_RAISE_ERROR( ePdfError_CannotConvertColor ); break; } default: { PODOFO_RAISE_ERROR( ePdfError_InvalidEnumValue ); break; } }; } PdfArray PdfColor::ToArray() const { PdfArray array; switch(m_eColorSpace) { case ePdfColorSpace_DeviceGray: { array.push_back( m_uColor.gray ); break; } case ePdfColorSpace_DeviceRGB: { array.push_back( m_uColor.rgb[0] ); array.push_back( m_uColor.rgb[1] ); array.push_back( m_uColor.rgb[2] ); break; } case ePdfColorSpace_DeviceCMYK: { array.push_back( m_uColor.cmyk[0] ); array.push_back( m_uColor.cmyk[1] ); array.push_back( m_uColor.cmyk[2] ); array.push_back( m_uColor.cmyk[3] ); break; } case ePdfColorSpace_CieLab: { array.push_back( m_uColor.lab[0] ); array.push_back( m_uColor.lab[1] ); array.push_back( m_uColor.lab[2] ); break; } case ePdfColorSpace_Separation: { array.push_back( m_separationDensity ); break; } case ePdfColorSpace_Indexed: case ePdfColorSpace_Unknown: { PODOFO_RAISE_ERROR( ePdfError_CannotConvertColor ); break; } default: { PODOFO_RAISE_ERROR( ePdfError_InvalidEnumValue ); break; } }; return array; } PdfColor PdfColor::FromString( const char* pszName ) { if( pszName ) { size_t lLen = strlen( pszName ); // first see if it's a single number - if so, that's a single gray value if( isdigit( pszName[0] ) || (pszName[0] == '.') ) { double dGrayVal = 0.0; std::istringstream stream( pszName ); PdfLocaleImbue(stream); if( !(stream >> dGrayVal) ) { PODOFO_RAISE_ERROR( ePdfError_CannotConvertColor ); } else { return PdfColor( dGrayVal ); } } // now check for a hex value (#xxxxxx or #xxxxxxxx) else if( pszName[0] == '#' ) { ++pszName; if( lLen == 7 ) // RGB { const unsigned int R_HI = static_cast(PdfTokenizer::GetHexValue( *pszName++ )); const unsigned int R_LO = static_cast(PdfTokenizer::GetHexValue( *pszName++ )); const unsigned int R = (R_HI << 4) | R_LO; const unsigned int G_HI = static_cast(PdfTokenizer::GetHexValue( *pszName++ )); const unsigned int G_LO = static_cast(PdfTokenizer::GetHexValue( *pszName++ )); const unsigned int G = (G_HI << 4) | G_LO; const unsigned int B_HI = static_cast(PdfTokenizer::GetHexValue( *pszName++ )); const unsigned int B_LO = static_cast(PdfTokenizer::GetHexValue( *pszName++ )); const unsigned int B = (B_HI << 4) | B_LO; if ( (R_HI != PdfTokenizer::HEX_NOT_FOUND) && (R_LO != PdfTokenizer::HEX_NOT_FOUND) && (G_HI != PdfTokenizer::HEX_NOT_FOUND) && (G_LO != PdfTokenizer::HEX_NOT_FOUND) && (B_HI != PdfTokenizer::HEX_NOT_FOUND) && (B_LO != PdfTokenizer::HEX_NOT_FOUND) ) { return PdfColor( static_cast(R)/255.0, static_cast(G)/255.0, static_cast(B)/255.0 ); } else { PODOFO_RAISE_ERROR( ePdfError_CannotConvertColor ); } } else if( lLen == 9 ) // CMYK { const unsigned int C_HI = static_cast(PdfTokenizer::GetHexValue( *pszName++ )); const unsigned int C_LO = static_cast(PdfTokenizer::GetHexValue( *pszName++ )); const unsigned int C = (C_HI << 4) | C_LO; const unsigned int M_HI = static_cast(PdfTokenizer::GetHexValue( *pszName++ )); const unsigned int M_LO = static_cast(PdfTokenizer::GetHexValue( *pszName++ )); const unsigned int M = (M_HI << 4) | M_LO; const unsigned int Y_HI = static_cast(PdfTokenizer::GetHexValue( *pszName++ )); const unsigned int Y_LO = static_cast(PdfTokenizer::GetHexValue( *pszName++ )); const unsigned int Y = (Y_HI << 4) | Y_LO; const unsigned int K_HI = static_cast(PdfTokenizer::GetHexValue( *pszName++ )); const unsigned int K_LO = static_cast(PdfTokenizer::GetHexValue( *pszName++ )); const unsigned int K = (K_HI << 4) | K_LO; if ( (C_HI != PdfTokenizer::HEX_NOT_FOUND) && (C_LO != PdfTokenizer::HEX_NOT_FOUND) && (M_HI != PdfTokenizer::HEX_NOT_FOUND) && (M_LO != PdfTokenizer::HEX_NOT_FOUND) && (Y_HI != PdfTokenizer::HEX_NOT_FOUND) && (Y_LO != PdfTokenizer::HEX_NOT_FOUND) && (K_HI != PdfTokenizer::HEX_NOT_FOUND) && (K_LO != PdfTokenizer::HEX_NOT_FOUND) ) { return PdfColor( static_cast(C)/255.0, static_cast(M)/255.0, static_cast(Y)/255.0, static_cast(K)/255.0 ); } else { PODOFO_RAISE_ERROR( ePdfError_CannotConvertColor ); } } } // PdfArray else if( pszName[0] == '[' ) { PdfTokenizer tokenizer( pszName, lLen ); PdfVariant var; tokenizer.GetNextVariant( var, NULL ); // No encryption... if( var.IsArray() ) return PdfColor::FromArray( var.GetArray() ); } // it must be a named RGB color else { std::pair iterators = std::equal_range( &(s_NamedColors[0]), s_NamedColors + s_nNumNamedColors, PdfNamedColor( pszName, PdfColor() ), NamedColorComparatorPredicate() ); if( iterators.first != iterators.second ) { return (*(iterators.first)).GetColor(); } } } return PdfColor(); } PdfColor PdfColor::FromArray( const PdfArray & rArray ) { if( rArray.GetSize() == 1 ) // grayscale return PdfColor( rArray[0].GetReal() ); else if( rArray.GetSize() == 3 ) // RGB or spot return PdfColor( rArray[0].GetReal(), rArray[1].GetReal(), rArray[2].GetReal() ); else if( rArray.GetSize() == 4 ) // CMYK return PdfColor( rArray[0].GetReal(), rArray[1].GetReal(), rArray[2].GetReal(), rArray[3].GetReal() ); PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "PdfColor::FromArray supports only GrayScale, RGB and CMYK colors." ); } PdfObject* PdfColor::BuildColorSpace( PdfVecObjects* pOwner ) const { switch( m_eColorSpace ) { case ePdfColorSpace_Separation: { // Build color-spaces for separation PdfObject* csTintFunc = pOwner->CreateObject(); csTintFunc->GetDictionary().AddKey( "BitsPerSample", static_cast(8) ); PdfArray decode; decode.push_back( static_cast(0) ); decode.push_back( static_cast(1) ); decode.push_back( static_cast(0) ); decode.push_back( static_cast(1) ); decode.push_back( static_cast(0) ); decode.push_back( static_cast(1) ); decode.push_back( static_cast(0) ); decode.push_back( static_cast(1) ); csTintFunc->GetDictionary().AddKey( "Decode", decode ); PdfArray domain; domain.push_back( static_cast(0) ); domain.push_back( static_cast(1) ); csTintFunc->GetDictionary().AddKey( "Domain", domain ); PdfArray encode; encode.push_back( static_cast(0) ); encode.push_back( static_cast(1) ); csTintFunc->GetDictionary().AddKey( "Encode", encode ); csTintFunc->GetDictionary().AddKey( "Filter", PdfName( "FlateDecode" ) ); csTintFunc->GetDictionary().AddKey( "FunctionType", PdfVariant( static_cast(0L) ) ); //csTintFunc->GetDictionary().AddKey( "FunctionType", // PdfVariant( static_cast(ePdfFunctionType_Sampled) ) ); switch ( m_eAlternateColorSpace ) { case ePdfColorSpace_DeviceGray: { char data[1*2]; data[0] = 0; data[1] = static_cast (m_uColor.gray); PdfArray range; range.push_back( static_cast(0) ); range.push_back( static_cast(1) ); csTintFunc->GetDictionary().AddKey( "Range", range ); PdfArray size; size.push_back( static_cast(2) ); csTintFunc->GetDictionary().AddKey( "Size", size ); PdfMemoryInputStream stream( data, 1*2 ); csTintFunc->GetStream()->Set( &stream ); PdfArray csArr; csArr.push_back( PdfName("Separation") ); csArr.push_back( PdfName( m_separationName ) ); csArr.push_back( PdfName("DeviceGray") ); csArr.push_back( csTintFunc->Reference() ); PdfObject* csp = pOwner->CreateObject( csArr ); return csp; } break; case ePdfColorSpace_DeviceRGB: { char data[3*2]; data[0] = data[1] = data[2] = 0; data[3] = static_cast (m_uColor.rgb[0] * 255); data[4] = static_cast (m_uColor.rgb[1] * 255); data[5] = static_cast (m_uColor.rgb[2] * 255); PdfArray range; range.push_back( static_cast(0) ); range.push_back( static_cast(1) ); range.push_back( static_cast(0) ); range.push_back( static_cast(1) ); range.push_back( static_cast(0) ); range.push_back( static_cast(1) ); csTintFunc->GetDictionary().AddKey( "Range", range ); PdfArray size; size.push_back( static_cast(2) ); csTintFunc->GetDictionary().AddKey( "Size", size ); PdfMemoryInputStream stream( data, 3*2 ); csTintFunc->GetStream()->Set( &stream ); PdfArray csArr; csArr.push_back( PdfName("Separation") ); csArr.push_back( PdfName( m_separationName ) ); csArr.push_back( PdfName("DeviceRGB") ); csArr.push_back( csTintFunc->Reference() ); PdfObject* csp = pOwner->CreateObject( csArr ); return csp; } break; case ePdfColorSpace_DeviceCMYK: { char data[4*2]; data[0] = data[1] = data[2] = data[3] = 0; data[4] = static_cast (m_uColor.cmyk[0] * 255); data[5] = static_cast (m_uColor.cmyk[1] * 255); data[6] = static_cast (m_uColor.cmyk[2] * 255); data[7] = static_cast (m_uColor.cmyk[3] * 255); PdfArray range; range.push_back( static_cast(0) ); range.push_back( static_cast(1) ); range.push_back( static_cast(0) ); range.push_back( static_cast(1) ); range.push_back( static_cast(0) ); range.push_back( static_cast(1) ); range.push_back( static_cast(0) ); range.push_back( static_cast(1) ); csTintFunc->GetDictionary().AddKey( "Range", range ); PdfArray size; size.push_back( static_cast(2) ); csTintFunc->GetDictionary().AddKey( "Size", size ); PdfArray csArr; csArr.push_back( PdfName("Separation") ); csArr.push_back( PdfName( m_separationName ) ); csArr.push_back( PdfName("DeviceCMYK") ); csArr.push_back( csTintFunc->Reference() ); PdfMemoryInputStream stream( data, 4*2 ); csTintFunc->GetStream()->Set( &stream ); // set stream as last, so that it will work with PdfStreamedDocument PdfObject* csp = pOwner->CreateObject( csArr ); return csp; } break; case ePdfColorSpace_CieLab: { char data[3*2]; data[0] = data[1] = data[2] = 0; data[3] = static_cast (m_uColor.lab[0] * 255); data[4] = static_cast (m_uColor.lab[1] * 255); data[5] = static_cast (m_uColor.lab[2] * 255); PdfArray range; range.push_back( static_cast(0) ); range.push_back( static_cast(1) ); range.push_back( static_cast(0) ); range.push_back( static_cast(1) ); range.push_back( static_cast(0) ); range.push_back( static_cast(1) ); csTintFunc->GetDictionary().AddKey( "Range", range ); PdfArray size; size.push_back( static_cast(2) ); csTintFunc->GetDictionary().AddKey( "Size", size ); PdfMemoryInputStream stream( data, 3*2 ); csTintFunc->GetStream()->Set( &stream ); PdfArray csArr; csArr.push_back( PdfName("Separation") ); csArr.push_back( PdfName( m_separationName ) ); csArr.push_back( PdfName("Lab") ); csArr.push_back( csTintFunc->Reference() ); PdfObject* csp = pOwner->CreateObject( csArr ); return csp; } break; case ePdfColorSpace_Separation: case ePdfColorSpace_Indexed: { break; } case ePdfColorSpace_Unknown: default: { PODOFO_RAISE_ERROR( ePdfError_InvalidEnumValue ); break; } } } break; case ePdfColorSpace_CieLab: { // Build color-spaces for CIE-lab PdfDictionary labDict; // D65-whitepoint PdfArray wpArr; wpArr.push_back( 0.9505 ); wpArr.push_back( 1.0000 ); wpArr.push_back( 1.0890 ); labDict.AddKey( PdfName("WhitePoint" ), wpArr ); // Range for A,B, L is implicit 0..100 PdfArray rangeArr; rangeArr.push_back( static_cast(-128) ); rangeArr.push_back( static_cast(127) ); rangeArr.push_back( static_cast(-128) ); rangeArr.push_back( static_cast(127) ); labDict.AddKey( PdfName("Range" ), rangeArr ); PdfArray labArr; labArr.push_back( PdfName("Lab") ); labArr.push_back( labDict ); PdfObject* labp = pOwner->CreateObject( labArr ); return labp; } break; case ePdfColorSpace_DeviceGray: case ePdfColorSpace_DeviceRGB: case ePdfColorSpace_DeviceCMYK: case ePdfColorSpace_Indexed: { break; } case ePdfColorSpace_Unknown: default: { PODOFO_RAISE_ERROR( ePdfError_InvalidEnumValue ); break; } } return NULL; } EPdfColorSpace PdfColor::GetColorSpaceForName( const PdfName & rName ) { EPdfColorSpace ePdfColorSpace = ePdfColorSpace_Unknown; if( PdfName("DeviceGray") == rName ) { ePdfColorSpace = ePdfColorSpace_DeviceGray; } else if( PdfName("DeviceRGB") == rName ) { ePdfColorSpace = ePdfColorSpace_DeviceRGB; } else if( PdfName("DeviceCMYK") == rName ) { ePdfColorSpace = ePdfColorSpace_DeviceCMYK; } else if( PdfName("Indexed") == rName ) { ePdfColorSpace = ePdfColorSpace_Indexed; } else { // TODO: other are not supported at the moment PdfError::LogMessage( eLogSeverity_Information, "Unsupported colorspace name: %s", rName.GetName().c_str() ); } return ePdfColorSpace; } PdfName PdfColor::GetNameForColorSpace( EPdfColorSpace eColorSpace ) { switch( eColorSpace ) { case ePdfColorSpace_DeviceGray: return PdfName("DeviceGray"); case ePdfColorSpace_DeviceRGB: return PdfName("DeviceRGB"); case ePdfColorSpace_DeviceCMYK: return PdfName("DeviceCMYK"); case ePdfColorSpace_Separation: return PdfName("Separation"); case ePdfColorSpace_CieLab: return PdfName("Lab"); case ePdfColorSpace_Indexed: return PdfName("Indexed"); case ePdfColorSpace_Unknown: default: PdfError::LogMessage( eLogSeverity_Information, "Unsupported colorspace enum: %i", eColorSpace ); return PdfName(); } } }; podofo-0.9.5/src/base/PdfLocale.h0000664000175000017500000000225712312006110016356 0ustar dominikdominik#ifndef PODOFO_PDFLOCALE_H #define PODOFO_PDFLOCALE_H #include namespace PoDoFo { /** * The locale to use for PDF I/O . See PoDoFo::PdfLocaleImbue() . */ static const char PdfIOLocale[] = "C"; /** * Imbue the passed stream with a locale that will be safe to do * I/O of the low level PDF format with. * * PDF document structure I/O is done with the C++ standard library * IOStreams code. By default, this will adapt to the current locale. * That's not good at all when doing I/O of PDF data structures, which * follow POSIX/english locale conventions irrespective of runtime locale. * Make sure to to call this function on any stream you intend to use for * PDF I/O. Avoid using this stream for anything that should be done in the * regional locale. * * \warning This method may throw ePdfError_InvalidDeviceOperation * if your STL does not support the locale string in PdfIOLocale . * * If you fail to call this on a stream you use for PDF I/O you will encounter * problems like German and other European users getting numbers in the format * "10110,4" or even "10.110,4" instead of "10110.4" . */ void PODOFO_API PdfLocaleImbue(std::ios_base&); }; #endif podofo-0.9.5/src/base/PdfDataType.h0000664000175000017500000001313613013650710016702 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_DATATYPE_H_ #define _PDF_DATATYPE_H_ #include "PdfDefines.h" namespace PoDoFo { class PdfEncrypt; class PdfOutputDevice; /** An interface for all PDF datatype classes. * * * \see PdfName \see PdfArray \see PdfReference * \see PdfVariant \see PdfDictionary \see PdfString */ class PODOFO_API PdfDataType { protected: /** Create a new PdfDataType. * Can only be called by subclasses */ PdfDataType(); public: virtual ~PdfDataType(); /** Write the complete datatype to a file. * \param pDevice write the object to this device * \param eWriteMode additional options for writing this object * \param pEncrypt an encryption object which is used to encrypt this object * or NULL to not encrypt this object */ virtual void Write( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, const PdfEncrypt* pEncrypt = NULL ) const = 0; /** The dirty flag is set if this variant * has been modified after construction. * * Usually the dirty flag is also set * if you call any non-const member function * as we cannot determine if you actually changed * something or not. * * \returns true if the value is dirty and has been * modified since construction */ virtual bool IsDirty() const; /** Sets the dirty flag of this PdfVariant * * \param bDirty true if this PdfVariant has been * modified from the outside * * \see IsDirty */ virtual void SetDirty( bool bDirty ); /** * Sets this object to immutable, * so that no keys can be edited or changed. * * @param bImmutable if true set the object to be immutable * * This is used by PdfImmediateWriter and PdfStreamedDocument so * that no keys can be added to an object after setting stream data on it. * */ inline void SetImmutable(bool bImmutable); /** * Retrieve if an object is immutable. * * This is used by PdfImmediateWriter and PdfStreamedDocument so * that no keys can be added to an object after setting stream data on it. * * @returns true if the object is immutable */ inline bool GetImmutable() const; protected: /** * Will throw an exception if called on an immutable object, * so this should be called before actually changing a value! * */ inline void AssertMutable() const; private: bool m_bImmutable; }; // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfDataType::SetImmutable(bool bImmutable) { m_bImmutable = bImmutable; } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfDataType::GetImmutable() const { return m_bImmutable; } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfDataType::AssertMutable() const { if(m_bImmutable) { PODOFO_RAISE_ERROR( ePdfError_ChangeOnImmutable ); } } }; // namespace PoDoFo #endif /* _PDF_DATATYPE_H_ */ podofo-0.9.5/src/base/PdfXRef.h0000664000175000017500000002034512262234754016046 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_XREF_H_ #define _PDF_XREF_H_ #include "PdfDefines.h" #include "PdfReference.h" namespace PoDoFo { #define EMPTY_OBJECT_OFFSET 65535 class PdfOutputDevice; /** * Creates an XRef table. * * This is an internal class of PoDoFo used by PdfWriter. */ class PdfXRef { protected: struct TXRefItem{ TXRefItem( const PdfReference & rRef, const pdf_uint64 & off ) : reference( rRef ), offset( off ) { } PdfReference reference; pdf_uint64 offset; bool operator<( const TXRefItem & rhs ) const { return this->reference < rhs.reference; } }; typedef std::vector TVecXRefItems; typedef TVecXRefItems::iterator TIVecXRefItems; typedef TVecXRefItems::const_iterator TCIVecXRefItems; typedef std::vector TVecReferences; typedef TVecReferences::iterator TIVecReferences; typedef TVecReferences::const_iterator TCIVecReferences; class PdfXRefBlock { public: PdfXRefBlock() : m_nFirst( 0 ), m_nCount( 0 ) { } PdfXRefBlock( const PdfXRefBlock & rhs ) : m_nFirst( 0 ), m_nCount( 0 ) { this->operator=( rhs ); } bool InsertItem( const TXRefItem & rItem, bool bUsed ); bool operator<( const PdfXRefBlock & rhs ) const { return m_nFirst < rhs.m_nFirst; } const PdfXRefBlock & operator=( const PdfXRefBlock & rhs ) { m_nFirst = rhs.m_nFirst; m_nCount = rhs.m_nCount; items = rhs.items; freeItems = rhs.freeItems; return *this; } pdf_objnum m_nFirst; pdf_uint32 m_nCount; TVecXRefItems items; TVecReferences freeItems; }; typedef std::vector TVecXRefBlock; typedef TVecXRefBlock::iterator TIVecXRefBlock; typedef TVecXRefBlock::const_iterator TCIVecXRefBlock; public: /** Create a new XRef table */ PdfXRef(); /** Destruct the XRef table */ virtual ~PdfXRef(); /** Add an object to the XRef table. * The object should have been written to an output device already. * * \param rRef reference of this object * \param offset the offset where on the device the object was written * \param bUsed specifies wether this is an used or free object. * Set this value to true for all normal objects and to false * for free object references. */ void AddObject( const PdfReference & rRef, pdf_uint64 offset, bool bUsed ); /** Write the XRef table to an output device. * * \param pDevice an output device (usually a PDF file) * */ void Write( PdfOutputDevice* pDevice ); /** Get the size of the XRef table. * I.e. the highest object number + 1. * * \returns the size of the xref table */ pdf_uint32 GetSize() const; /** * \returns the offset in the file at which the XRef table * starts after it was written */ inline virtual pdf_uint64 GetOffset() const; /** * Mark as empty block. */ void SetFirstEmptyBlock(); protected: /** Called at the start of writing the XRef table. * This method can be overwritten in subclasses * to write a general header for the XRef table. * * @param pDevice the output device to which the XRef table * should be written. */ virtual void BeginWrite( PdfOutputDevice* pDevice ); /** Begin an XRef subsection. * All following calls of WriteXRefEntry belong to this XRef subsection. * * @param pDevice the output device to which the XRef table * should be written. * @param nFirst the object number of the first object in this subsection * @param nCount the number of entries in this subsection */ virtual void WriteSubSection( PdfOutputDevice* pDevice, pdf_objnum nFirst, pdf_uint32 nCount ); /** Write a single entry to the XRef table * * @param pDevice the output device to which the XRef table * should be written. * @param offset the offset of the object * @param generation the generation number * @param cMode the mode 'n' for object and 'f' for free objects * @param objectNumber the object number of the currently written object if cMode = 'n' * otherwise undefined */ virtual void WriteXRefEntry( PdfOutputDevice* pDevice, pdf_uint64 offset, pdf_gennum generation, char cMode, pdf_objnum objectNumber = 0 ); /** Called at the end of writing the XRef table. * Sub classes can overload this method to finish a XRef table. * * @param pDevice the output device to which the XRef table * should be written. */ virtual void EndWrite( PdfOutputDevice* pDevice ); private: const PdfReference* GetFirstFreeObject( PdfXRef::TCIVecXRefBlock itBlock, PdfXRef::TCIVecReferences itFree ) const; const PdfReference* GetNextFreeObject( PdfXRef::TCIVecXRefBlock itBlock, PdfXRef::TCIVecReferences itFree ) const; /** Merge all xref blocks that follow immediately after each other * into a single block. * * This results in slitely smaller PDF files which are easier to parse * for other applications. */ void MergeBlocks(); private: pdf_uint64 m_offset; protected: TVecXRefBlock m_vecBlocks; }; // ----------------------------------------------------- // // ----------------------------------------------------- inline pdf_uint64 PdfXRef::GetOffset() const { return m_offset; } }; #endif /* _PDF_XREF_H_ */ podofo-0.9.5/src/base/PdfDate.cpp0000664000175000017500000001647013013650710016403 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfDate.h" #include "PdfDefinesPrivate.h" #include #include namespace PoDoFo { PdfDate::PdfDate() : m_bValid( false ) { m_time = time( &m_time ); CreateStringRepresentation(); } PdfDate::PdfDate( const time_t & t ) : m_bValid( false ) { m_time = t; CreateStringRepresentation(); } PdfDate::PdfDate( const PdfString & sDate ) : m_bValid( false ) { m_time = -1; if ( !sDate.IsValid() ) { m_szDate[0] = 0; return; } strncpy(m_szDate,sDate.GetString(),PDF_DATE_BUFFER_SIZE); struct tm _tm; memset( &_tm, 0, sizeof(_tm) ); int nZoneShift = 0; int nZoneHour = 0; int nZoneMin = 0; const char * pszDate = sDate.GetString(); if ( pszDate == NULL ) return; if ( *pszDate == 'D' ) { pszDate++; if ( *pszDate++ != ':' ) return; } if ( ParseFixLenNumber(pszDate,4,0,9999,_tm.tm_year) == false ) return; _tm.tm_year -= 1900; if ( *pszDate != '\0' ) { if ( ParseFixLenNumber(pszDate,2,1,12,_tm.tm_mon) == false ) return; _tm.tm_mon--; if ( *pszDate != '\0' ) { if ( ParseFixLenNumber(pszDate,2,1,31,_tm.tm_mday) == false ) return; if ( *pszDate != '\0' ) { if ( ParseFixLenNumber(pszDate,2,0,23,_tm.tm_hour) == false ) return; if ( *pszDate != '\0' ) { if ( ParseFixLenNumber(pszDate,2,0,59,_tm.tm_min) == false ) return; if ( *pszDate != '\0' ) { if ( ParseFixLenNumber(pszDate,2,0,59,_tm.tm_sec) == false ) return; if ( *pszDate != '\0' ) { switch(*pszDate++) { case '+': nZoneShift = -1; break; case '-': nZoneShift = 1; break; case 'Z': nZoneShift = 0; break; default: return; } if ( ParseFixLenNumber(pszDate,2,0,59,nZoneHour) == false ) return; if ( *pszDate == '\'' ) { pszDate++; if ( ParseFixLenNumber(pszDate,2,0,59,nZoneMin) == false ) return; if ( *pszDate != '\'' ) return; pszDate++; } } } } } } } if ( *pszDate != '\0' ) { return; } // convert to m_time = mktime(&_tm); if ( m_time == -1 ) { return; } m_time += nZoneShift*(nZoneHour*3600 + nZoneMin*60); m_bValid = true; } PdfDate::~PdfDate() { } void PdfDate::CreateStringRepresentation() { const int ZONE_STRING_SIZE = 6; const char* INVALIDDATE = "INVALIDDATE"; char szZone[ZONE_STRING_SIZE]; char szDate[PDF_DATE_BUFFER_SIZE]; struct tm* stm = localtime( &m_time ); #ifdef _WIN32 // On win32, strftime with %z returns a verbose time zone name // like "W. Australia Standard time". We use time/gmtime/mktime // instead. time_t cur_time = time( NULL ); struct tm* cur_gmt = gmtime( &cur_time ); // assumes _timezone cannot include DST (mabri: documentation unclear IMHO) time_t time_off = cur_time - mktime( cur_gmt ); // interpreted as local snprintf( szZone, ZONE_STRING_SIZE, "%+03d", static_cast( time_off/3600 ) ); #else if( strftime( szZone, ZONE_STRING_SIZE, "%z", stm ) == 0 ) { std::ostringstream ss; ss << "Generated invalid date from time_t value " << m_time << " (couldn't determine time zone)\n"; PdfError::DebugMessage( ss.str().c_str() ); strcpy( m_szDate, INVALIDDATE ); return; } #endif // only the first 3 characters are important for the pdf date representation // e.g. +01 instead off +0100 szZone[3] = '\0'; if( strftime( szDate, PDF_DATE_BUFFER_SIZE, "D:%Y%m%d%H%M%S", stm ) == 0 ) { std::ostringstream ss; ss << "Generated invalid date from time_t value " << m_time << "\n"; PdfError::DebugMessage( ss.str().c_str() ); strcpy( m_szDate, INVALIDDATE ); return; } snprintf( m_szDate, PDF_DATE_BUFFER_SIZE, "%s%s'00'", szDate, szZone ); m_bValid = true; } bool PdfDate::ParseFixLenNumber(const char *&in, unsigned int length, int min, int max, int &ret) { ret = 0; for(unsigned int i=0;i max ) return false; return true; } }; podofo-0.9.5/src/base/PdfData.h0000664000175000017500000001213212344436402016041 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_DATA_H_ #define _PDF_DATA_H_ #include "PdfDefines.h" #include "PdfDataType.h" namespace PoDoFo { class PdfOutputDevice; /** A datatype that allows to write abitrary data * to a PDF file. * The user of this class has to ensure that the data * written to the PDF file using this class is valid data * for a PDF file! * * This class is used in PoDoFo to pad PdfVariants. * */ class PODOFO_API PdfData : public PdfDataType { public: /** * Create a new PdfData object with valid PdfData * * The contained data has to be a valid value in a PDF file. * It will be written directly to the PDF file. * * \param pszData a null-terminated string to be copied. */ PdfData( const char* pszData ) : PdfDataType(), m_sData( pszData ) { } /** * Create a new PdfData object with valid PdfData. * * \param pszData a char * buffer to be copied. * \param dataSize size of buffer */ PdfData( const char* pszData, size_t dataSize ) : PdfDataType(), m_sData( pszData, dataSize ) { } /** Copy an existing PdfData * \param rhs another PdfData to copy */ PdfData( const PdfData & rhs ) : PdfDataType() { this->operator=( rhs ); } /** Write the complete datatype to a file. * \param pDevice write the object to this device * \param eWriteMode additional options for writing this object * \param pEncrypt an encryption object which is used to encrypt this object * or NULL to not encrypt this object * * PdfData cannot do any encryption for you. So the encryption object will * be ignored as it is also the case for the write mode! */ void Write( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, const PdfEncrypt* pEncrypt = NULL ) const; /** Copy an existing PdfData * \param rhs another PdfData to copy * \returns this object */ inline const PdfData & operator=( const PdfData & rhs ); /** * Access the data as a std::string * \returns a const reference to the contained data */ inline const std::string & data() const; private: std::string m_sData; }; // ----------------------------------------------------- // // ----------------------------------------------------- const PdfData & PdfData::operator=( const PdfData & rhs ) { m_sData = rhs.m_sData; return (*this); } // ----------------------------------------------------- // // ----------------------------------------------------- const std::string & PdfData::data() const { return m_sData; } }; // namespace PoDoFo #endif /* _PDF_DATATYPE_H_ */ podofo-0.9.5/src/base/PdfMemoryManagement.cpp0000664000175000017500000001757513043357617021017 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2009 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfMemoryManagement.h" #include "PdfDefines.h" #include "PdfDefinesPrivate.h" #ifndef SIZE_MAX #include #define SIZE_MAX std::numeric_limits::max() #endif #if defined(_MSC_VER) && ( _MSC_VER <= 1200 ) // errno.h isn't available in Visual C++ 6 (definitions are in stdlib.h which is already included) #else #include #endif namespace PoDoFo { bool podofo_is_little_endian() { int _p = 1; return ((reinterpret_cast(&_p))[0] == 1); } void* podofo_malloc( size_t size ) { /* malloc behaviour with size==0 is platform specific Windows Visual C++ MSDN: If size is 0, malloc allocates a zero-length item in the heap and returns a valid pointer to that item. Code: malloc_base.c code in VS 2015 shows it shows it allocates a 1-byte block when size==0 OpenBSD Man: If size is equal to 0, a unique pointer to an access protected, zero sized object is returned. Access via this pointer will generate a SIGSEGV exception. Linux Man: If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free(). OS X Man: Behaviour unspecified Code: Apple malloc.c source code shows it allocates a 1-byte block when size==0 Behaviour on Linux is interesting: http://www.unix.com/man-page/redhat/3/malloc/ Linux follows an optimistic memory allocation strategy. This means that when malloc() returns non-NULL there is no guarantee that the memory really is available. In case it turns out that the system is out of memory, one or more processes will be killed by the infamous OOM killer. */ if (size == 0) size = 1; return malloc( size ); } void* podofo_calloc(size_t nmemb, size_t size) { /* calloc behaviour with size==0 or nmemb==0 is platform specific Windows Visual C++ Behaviour unspecified in MSDN (allocates 1 byte in VC 2015 calloc_base.c) OpenBSD If size or nmemb is equal to 0, a unique pointer to an access protected, zero sized object is returned. Access via this pointer will generate a SIGSEGV exception. Linux If size or nmemb is equal to 0 then calloc() returns either NULL, or a unique pointer value that can later be successfully passed to free(). OS X Behaviour unspecified */ if (size == 0) size = 1; if (nmemb == 0) nmemb = 1; /* This overflow check is from OpenBSD reallocarray.c, and is also used in GifLib 5.1.2 onwards. Very old versions of calloc() in NetBSD and OS X 10.4 just multiplied size*nmemb which can overflow size_t and allocate much less memory than expected e.g. 2*(SIZE_MAX/2+1) = 2 bytes. The calloc() overflow is also present in GCC 3.1.1, GNU Libc 2.2.5 and Visual C++ 6. http://cert.uni-stuttgart.de/ticker/advisories/calloc.html MUL_NO_OVERFLOW is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW */ #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && nmemb > 0 && SIZE_MAX / nmemb < size) { errno = ENOMEM; return NULL; } return calloc(nmemb, size); } void* podofo_realloc( void* buffer, size_t size ) { /* realloc behaviour with size==0 is platform specific (and dangerous in Visual C++) Windows Visual C++ If size is zero, then the block pointed to by memblock is freed; the return value is NULL, and buffer is left pointing at a freed block. NOTE: this is very dangerous, since NULL is also returned when there's not enough memory, but the block ISN'T freed OpenBSD If size is equal to 0, a unique pointer to an access protected, zero sized object is returned. Access via this pointer will generate a SIGSEGV exception. Linux If size was equal to 0, either NULL or a pointer suitable to be passed to free() is returned. OS X If size is zero and buffer is not NULL, a new, minimum sized object is allocated and the original object is freed. */ if (size == 0) size = 1; return realloc( buffer, size ); } void podofo_free( void* buffer ) { free( buffer ); } }; // OC 17.08.2010: Activate showing the correct source for Memory Leak Detection in Visual Studio: // See: looking for _AFX_NO_DEBUG_CRT // // Annotation: // defining the new and delete operators and initializeDebugHeap // have to be done inside the dll if podofo is compiled as dll. // // If podofo is compiled as static library // the main program is responsible for theese definitions and initialisations. // Specially the new operator may be implemented completely different // and may not be redefined here. #ifdef _MSC_VER #ifdef DEBUG_NEW // #if defined(_DEBUG) && defined(DEFINE_NEW_DEBUG_NEW) #if defined(COMPILING_SHARED_PODOFO) || defined(podofo_shared_EXPORTS) #undef new void* operator new(size_t ai_NewSize, const char* ac_File_, int ai_Line) { return ::operator new(ai_NewSize, _NORMAL_BLOCK, ac_File_, ai_Line); } void operator delete(void* av_Ptr_, const char* ac_File_, int ai_Line) { ::operator delete(av_Ptr_); } #define new DEBUG_NEW static int initializeDebugHeap() { _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); // _CRTDBG_CHECK_ALWAYS_DF|_CRTDBG_DELAY_FREE_MEM_DF // test if the memory leak detection works: static const char leakdata[] = "*** test memory leak ***"; char* memleak = new char[sizeof(leakdata)]; memcpy(memleak, leakdata, sizeof(leakdata)); return 1; } int isDebugHeapInitialized = initializeDebugHeap(); #endif // podofo_shared_EXPORTS #endif // DEBUG_NEW #endif // _MSC_VER podofo-0.9.5/src/base/PdfObject.h0000664000175000017500000004076513035512444016412 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_OBJECT_H_ #define _PDF_OBJECT_H_ #include "PdfDefines.h" #include "PdfName.h" #include "PdfParser.h" #include "PdfReference.h" #include "PdfString.h" #include "PdfVariant.h" namespace PoDoFo { class PdfEncrypt; class PdfObject; class PdfOutputDevice; class PdfStream; class PdfVecObjects; /** * This class represents a PDF indirect Object in memory * * It is possible to manipulate the stream which can be appended to the object * (if the object is of underlying type dictionary). A PdfObject is uniquely * identified by an object number and a generation number which has to be * passed to the constructor. * * The object can be written to a file easily using the WriteObject() function. * * \see WriteObject() */ class PODOFO_API PdfObject : public PdfVariant { friend class PdfVecObjects; public: /** Create a PDF object with object and generation number -1 * and the value of being an empty PdfDictionary. */ PdfObject(); /** Construct a new PDF object of type PdfDictionary. * * \param rRef reference of this object * \param pszType if type is not null a key "/Type" will be added to the dictionary with * the value of type. */ PdfObject( const PdfReference & rRef, const char* pszType); /** Construct a new PDF object. * \param rRef reference of this object * \param rVariant the value of the PdfObject (which is copied) */ PdfObject( const PdfReference & rRef, const PdfVariant & rVariant ); /** Create a PDF object with object and generation number -1 * and the value of the passed variant. * * \param var the value of the object */ PdfObject( const PdfVariant & var ); /** Construct a PdfObject with object and generation number -1 * and a bool as value. * * \param b the boolean value of this PdfObject */ PdfObject( bool b ); /** Construct a PdfObject with object and generation number -1 * and a pdf_int64 as value. * * \param l the pdf_int64 value of this PdfObject */ PdfObject( pdf_int64 l ); /** Construct a PdfObject with object and generation number -1 * and a double as value. * * \param d the double value of this PdfObject */ PdfObject( double d ); /** Construct a PdfObject with object and generation number -1 * and a PdfString as value. * * \param rsString the string value of this PdfObject */ PdfObject( const PdfString & rsString ); /** Construct a PdfObject with object and generation number -1 * and a PdfName as value. * * \param rName the value of this PdfObject */ PdfObject( const PdfName & rName ); /** Construct a PdfObject with object and generation number -1 * and a PdfReference as value. * * \param rRef the value of the this PdfObject */ PdfObject( const PdfReference & rRef ); /** Construct a PdfObject with object and generation number -1 * and a PdfArray as value. * * \param tList the value of the this PdfObject */ PdfObject( const PdfArray & tList ); /** Construct a PdfObject with object and generation number -1 * and a PdfDictionary as value. * * \param rDict the value of the this PdfObject */ PdfObject( const PdfDictionary & rDict ); /** Creates a copy of an existing PdfObject * All assosiated objects and streams will be copied along with the PdfObject * \param rhs PdfObject to clone */ PdfObject( const PdfObject & rhs ); virtual ~PdfObject(); /** Get the keys value out of the dictionary. If the key is a reference, * the reference is resolved and the object pointed to by the reference is returned. * * \param key look for the key named key in the dictionary * * \returns the found value or NULL if the value is not in the * dictionary or if this object is no dictionary */ PdfObject* GetIndirectKey( const PdfName & key ) const; /** * MustGetIndirectKey() wraps GetIndirectKey to throw on null return. * This makes it MUCH more readable to look up deep chains of linked keys * with the cost that it's not easy to tell at which point a missing key/object * was encountered. * * \returns the found value, which is never null * \throws PdfError(ePdfError_NoObject) . */ inline PdfObject* MustGetIndirectKey( const PdfName & key ) const; /** Write the complete object to a file. * \param pDevice write the object to this device * \param pEncrypt an encryption object which is used to encrypt this object * or NULL to not encrypt this object * \param eWriteMode additional options for writing the object * \param keyStop if not KeyNull and a key == keyStop is found * writing will stop right before this key! */ void WriteObject( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, PdfEncrypt* pEncrypt, const PdfName & keyStop = PdfName::KeyNull ) const; /** Get the length of the object in bytes if it was written to disk now. * \param eWriteMode additional options for writing the object * \returns the length of the object */ pdf_long GetObjectLength( EPdfWriteMode eWriteMode ); /** Get a indirect reference to this object * \returns a PdfReference pointing to this object. */ inline const PdfReference & Reference() const; /** Get a handle to a PDF stream object * If the PDF object does not have a stream, * one will be created. * \returns a PdfStream object * * This will set the dirty flag of this object. * \see IsDirty */ PdfStream* GetStream(); /** Get a handle to a const PDF stream object * If the PDF object does not have a stream, * null is returned * \returns a PdfStream object or null */ const PdfStream* GetStream() const; /** Check if this object has a PdfStream object * appended. * * \returns true if the object has a stream */ inline bool HasStream() const; /** This operator is required for sorting a list of * PdfObjects. It compares the objectnumber. If objectnumbers * are equal, the generation number is compared. */ PODOFO_NOTHROW inline bool operator<( const PdfObject & rhs ) const; /** Comperasion operator. * Compares two PDF object only based on their object and generation number */ PODOFO_NOTHROW inline bool operator==( const PdfObject & rhs ) const; /** Set the owner of this object, i.e. the PdfVecObjects to which * this object belongs. * * \param pVecObjects a vector of pdf objects */ inline void SetOwner( PdfVecObjects* pVecObjects ); /** Get the owner of this object. * \return the creator of this object */ inline PdfVecObjects* GetOwner() const; /** Creates a copy of an existing PdfObject * All assosiated objects and streams will be copied along with the PdfObject * \param rhs PdfObject to clone * \returns a reference to this object */ const PdfObject & operator=( const PdfObject & rhs ); /** This function compresses any currently set stream * using the FlateDecode algorithm. JPEG compressed streams * will not be compressed again using this function. * Entries to the filter dictionary will be added if necessary. */ void FlateCompressStream(); /** Calculate the byte offset of the key pszKey from the start of the object * if the object was written to disk at the moment of calling this function. * * This function is very calculation intensive! * * \param pszKey key to calculate the byte offset * \param eWriteMode additional options for writing the PDF * \returns the offset of the key */ pdf_long GetByteOffset( const char* pszKey, EPdfWriteMode eWriteMode ); /** * Dynamically load this object and any associated stream from a PDF file * by calling the virtual method DelayedStreamLoadImpl if the stream is not * already loaded. Will call DelayedLoad() first if it is required. * * Call graph: * * DelayedStreamLoad ---> DelayedLoad() --> DelayedLoadImpl() * | * --> DelayedStreamLoadImpl() * * For objects complete created in memory this function does nothing. */ inline void DelayedStreamLoad() const; protected: /** Flag any stream associated with the object as incompletely loaded, * so that DelayedStreamLoad() will be called when needed. * * All constructors initialize a PdfObject with delayed loading of streams * disabled . If you want delayed loading of streams you must ask for it. * If you do so, call this method early in your ctor and be sure to * override DelayedStreamLoadImpl() * * Note that it is quite possible to have a PdfObject that requires a * delayed-load of its stream but does an immediate load of the PdfVariant * base. If you want to delay loading of that too, make sure to call * EnableDelayedLoading(). */ inline void EnableDelayedStreamLoading(); /** Load the stream of the object if it has one and if delayed loading is enabled. * * You should override this to control deferred stream loading in your subclass. * * Never call this method directly; use DelayedStreamLoad() instead. */ inline virtual void DelayedStreamLoadImpl(); /** Same as GetStream() but won't trigger a delayed load, so it's safe * for use while a delayed load is in progress. * * This will set the dirty flag of this object. * \see IsDirty */ PdfStream* GetStream_NoDL(); private: /* See PdfVariant.h for a detailed explanation of this member, which is * here to prevent accidental construction of a PdfObject of integer type * when passing a pointer. */ template PdfObject(T*); // Shared initialization between all the ctors void InitPdfObject(); // No touchy. Only for manipulation by PdfObject private routines. // Tracks whether deferred loading is still pending (in which case it'll be // false). If true, deferred loading is not requried or has been completed. mutable bool m_bDelayedStreamLoadDone; #if defined(PODOFO_EXTRA_CHECKS) protected: PODOFO_NOTHROW bool DelayedStreamLoadInProgress() const { return m_bDelayedStreamLoadInProgress; } private: mutable bool m_bDelayedStreamLoadInProgress; #endif // order of member variables has significant effect on sizeof(PdfObject) which // is important in PDFs with many objects (PDF32000_2008.pdf has 750,000 PdfObjects) // be very careful to test class sizes on 32-bit and 64-bit platforms when adding // or re-ordering objects protected: PdfReference m_reference; PdfStream* m_pStream; PdfVecObjects* m_pOwner; PODOFO_NOTHROW inline bool DelayedStreamLoadDone() const; }; // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfObject::DelayedStreamLoadDone() const { return m_bDelayedStreamLoadDone; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfObject::EnableDelayedStreamLoading() { m_bDelayedStreamLoadDone = false; } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfReference & PdfObject::Reference() const { return m_reference; } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfObject::SetOwner( PdfVecObjects* pVecObjects ) { m_pOwner = pVecObjects; } // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfVecObjects* PdfObject::GetOwner() const { return m_pOwner; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfObject::operator<( const PdfObject & rhs ) const { return m_reference < rhs.m_reference; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfObject::operator==( const PdfObject & rhs ) const { return (m_reference == rhs.m_reference); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfObject::HasStream() const { DelayedStreamLoad(); return ( m_pStream != NULL ); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfObject* PdfObject::MustGetIndirectKey( const PdfName & key ) const { PdfObject* obj = GetIndirectKey(key); if (!obj) PODOFO_RAISE_ERROR( ePdfError_NoObject ); return obj; } // ----------------------------------------------------- // // ----------------------------------------------------- // Default implementation of virtual void DelayedStreamLoadImpl() // throws, since delayed loading of steams should not be enabled // except by types that support it. inline void PdfObject::DelayedStreamLoadImpl() { PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } inline void PdfObject::DelayedStreamLoad() const { DelayedLoad(); #if defined(PODOFO_EXTRA_CHECKS) if( m_bDelayedStreamLoadInProgress ) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Recursive DelayedStreamLoad() detected" ); #endif if( !m_bDelayedStreamLoadDone ) { #if defined(PODOFO_EXTRA_CHECKS) m_bDelayedStreamLoadInProgress = true; #endif const_cast(this)->DelayedStreamLoadImpl(); // Nothing was thrown, so if the implementer of DelayedstreamLoadImpl() is // following the rules we're done. m_bDelayedStreamLoadDone = true; #if defined(PODOFO_EXTRA_CHECKS) m_bDelayedStreamLoadInProgress = false; #endif } } }; #endif // _PDF_OBJECT_H_ podofo-0.9.5/src/base/PdfCompilerCompat.h0000664000175000017500000001443113035513162020107 0ustar dominikdominik#ifndef _PDF_COMPILERCOMPAT_H #define _PDF_COMPILERCOMPAT_H // // *** THIS HEADER IS INCLUDED BY PdfDefines.h *** // *** DO NOT INCLUDE DIRECTLY *** #ifndef _PDF_DEFINES_H_ #error Please include PdfDefines.h instead #endif #include "podofo_config.h" #ifndef PODOFO_COMPILE_RC // Silence some annoying warnings from Visual Studio #ifdef _MSC_VER #if _MSC_VER <= 1200 // Visual Studio 6 #pragma warning(disable: 4786) #pragma warning(disable: 4251) #elif _MSC_VER <= 1400 // Visual Studio 2005 #pragma warning(disable: 4251) #pragma warning(disable: 4275) #endif // _MSC_VER #endif // _MSC_VER // Make sure that DEBUG is defined // for debug builds on Windows // as Visual Studio defines only _DEBUG #ifdef _DEBUG #ifndef DEBUG #define DEBUG 1 #endif // DEBUG #endif // _DEBUG #if defined(__BORLANDC__) || defined( __TURBOC__) # include #else # include #endif #if defined(TEST_BIG) # define PODOFO_IS_BIG_ENDIAN #else # define PODOFO_IS_LITTLE_ENDIAN #endif #if PODOFO_HAVE_STDINT_H #include #endif #if PODOFO_HAVE_BASETSD_H #include #endif #if PODOFO_HAVE_SYS_TYPES_H #include #endif #if PODOFO_HAVE_MEM_H #include #endif #if PODOFO_HAVE_CTYPE_H #include #endif #if PODOFO_HAVE_STRINGS_H #include #endif // alloca() is defined only in on Mac OS X, // only in on win32, and in both on Linux. #if defined(_WIN32) #include #endif // Disable usage of min() and max() macros #if defined(_WIN32) && !defined(__MINGW32__) #define NOMINMAX #endif // Integer types - fixed size types guaranteed to work anywhere // because we detect the right underlying type name to use with // CMake. Use typedefs rather than macros for saner error messages // etc. namespace PoDoFo { typedef PDF_INT8_TYPENAME pdf_int8; typedef PDF_INT16_TYPENAME pdf_int16; typedef PDF_INT32_TYPENAME pdf_int32; typedef PDF_INT64_TYPENAME pdf_int64; typedef PDF_UINT8_TYPENAME pdf_uint8; typedef PDF_UINT16_TYPENAME pdf_uint16; typedef PDF_UINT32_TYPENAME pdf_uint32; typedef PDF_UINT64_TYPENAME pdf_uint64; }; #undef PDF_INT8_TYPENAME #undef PDF_INT16_TYPENAME #undef PDF_INT32_TYPENAME #undef PDF_INT64_TYPENAME #undef PDF_UINT8_TYPENAME #undef PDF_UINT16_TYPENAME #undef PDF_UINT32_TYPENAME #undef PDF_UINT64_TYPENAME /* * Some elderly compilers, notably VC6, don't support LL literals. * In those cases we can use the oversized literal without any suffix. */ #if defined(_MSC_VER) && _MSC_VER <= 1200 // Visual Studio 6 # define PODOFO_LL_LITERAL(x) x # define PODOFO_ULL_LITERAL(x) x #else #if defined(PODOFO_COMPILER_LACKS_LL_LITERALS) # define PODOFO_LL_LITERAL(x) x # define PODOFO_ULL_LITERAL(x) x #else # define PODOFO_LL_LITERAL(x) x##LL # define PODOFO_ULL_LITERAL(x) x##ULL #endif #endif #if defined(_MSC_VER) && _MSC_VER <= 1200 // Visual Studio 6 # define PODOFO_MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b)) #else # define PODOFO_MIN(_a, _b) (std::min((_a), (_b))) #endif // pdf_long is defined as ptrdiff_t . It's a pointer-sized signed quantity // used throughout the code for a variety of purposes. // // pdf_long is DEPRECATED. Please use one of the explicitly sized types // instead, or define a typedef that meaningfully describes what it's for. // Good choices in many cases include size_t (string and buffer sizes) and // ptrdiff_t (offsets and pointer arithmetic). // // pdf_long should not be used in new code. // namespace PoDoFo { typedef ptrdiff_t pdf_long; }; // Different compilers use different format specifiers for 64-bit integers // (yay!). Use these macros with C's automatic string concatenation to handle // that ghastly quirk. // // for example: printf("Value of signed 64-bit integer: %"PDF_FORMAT_INT64" (more blah)", 128LL) // #if defined(_MSC_VER) # define PDF_FORMAT_INT64 "I64d" # define PDF_FORMAT_UINT64 "I64u" #elif defined(SZ_INT64) && defined(SZ_LONG) && SZ_INT64 == SZ_LONG # define PDF_FORMAT_INT64 "ld" # define PDF_FORMAT_UINT64 "lu" #else # define PDF_FORMAT_INT64 "lld" # define PDF_FORMAT_UINT64 "llu" #endif // Different compilers express __FUNC__ in different ways and with different // capabilities. Try to find the best option. // // Note that __LINE__ and __FILE__ are *NOT* included. // Further note that you can't use compile-time string concatenation on __FUNC__ and friends // on many compilers as they're defined to behave as if they were a: // static const char* __func__ = 'nameoffunction'; // just after the opening brace of each function. // #if (defined(_MSC_VER) && _MSC_VER <= 1200) # define PODOFO__FUNCTION__ __FUNCTION__ #elif defined(__BORLANDC__) || defined(__TURBOC__) # define PODOFO__FUNCTION__ __FUNC__ #elif defined(__GNUC__) # define PODOFO__FUNCTION__ __PRETTY_FUNCTION__ #else # define PODOFO__FUNCTION__ __FUNCTION__ #endif #if defined(_WIN32) // Undefined stuff which windows does define that breaks the build // e.g. GetObject is defined to either GetObjectA or GetObjectW #ifdef GetObject #undef GetObject #endif // GetObject #ifdef CreateFont #undef CreateFont #endif // CreateFont #ifdef DrawText #undef DrawText #endif // DrawText #endif // defined(_WIN32) // Visual C++ 2015 (_MSC_VER 1900) still uses __cplusplus = 199711 so, we need both tests // this shrinks enum types from sizeof(int) to sizeof(char) which creates significant // space savings on PdfObject / PdfVariant #if (defined(_MSC_VER) && _MSC_VER < 1900) || (!defined(_MSC_VER) && __cplusplus < 201103) #define PODOFO_ENUM_UINT8 #else #define PODOFO_ENUM_UINT8 : uint8_t #endif /** * \page PoDoFo PdfCompilerCompat Header * * PdfCompilerCompat.h gathers up nastyness required for various * compiler compatibility into a central place. All compiler-specific defines, * wrappers, and the like should be included here and (if necessary) in * PdfCompilerCompat.cpp if they must be visible to public users of the library. * * If the nasty platform and compiler specific hacks can be kept to PoDoFo's * build and need not be visible to users of the library, put them in * PdfCompilerCompatPrivate.{cpp,h} instead. * * Please NEVER use symbols from this header or the PoDoFo::compat namespace in * a "using" directive. Always explicitly reference names so it's clear that * you're pulling them from the compat cruft. */ #endif // !PODOFO_COMPILE_RC #endif podofo-0.9.5/src/base/PdfParserObject.cpp0000664000175000017500000003631113013650710020105 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfParserObject.h" #include "PdfArray.h" #include "PdfDictionary.h" #include "PdfEncrypt.h" #include "PdfInputDevice.h" #include "PdfInputStream.h" #include "PdfParser.h" #include "PdfStream.h" #include "PdfVariant.h" #include "PdfDefinesPrivate.h" #include #include namespace PoDoFo { using namespace std; static const int s_nLenEndObj = 6; // strlen("endobj"); static const int s_nLenStream = 6; // strlen("stream"); //static const int s_nLenEndStream = 9; // strlen("endstream"); PdfParserObject::PdfParserObject( PdfVecObjects* pCreator, const PdfRefCountedInputDevice & rDevice, const PdfRefCountedBuffer & rBuffer, pdf_long lOffset ) : PdfObject( PdfVariant::NullValue ), PdfTokenizer( rDevice, rBuffer ), m_pEncrypt( NULL ) { m_pOwner = pCreator; InitPdfParserObject(); m_lOffset = lOffset == -1 ? m_device.Device()->Tell() : lOffset; } PdfParserObject::PdfParserObject( const PdfRefCountedBuffer & rBuffer ) : PdfObject( PdfVariant::NullValue ), PdfTokenizer( PdfRefCountedInputDevice(), rBuffer ), m_pEncrypt( NULL ) { InitPdfParserObject(); } PdfParserObject::~PdfParserObject() { } void PdfParserObject::InitPdfParserObject() { m_bIsTrailer = false; // Whether or not demand loading is disabled we still don't load // anything in the ctor. This just controls whether ::ParseFile(...) // forces an immediate demand load, or lets it genuinely happen // on demand. m_bLoadOnDemand = false; // We rely heavily on the demand loading infrastructure whether or not // we *actually* delay loading. EnableDelayedLoading(); EnableDelayedStreamLoading(); m_lOffset = -1; m_bStream = false; m_lStreamOffset = 0; } void PdfParserObject::ReadObjectNumber() { try { pdf_long obj = this->GetNextNumber(); pdf_long gen = this->GetNextNumber(); m_reference = PdfReference( static_cast(obj), static_cast(gen) ); } catch( PdfError & e ) { e.AddToCallstack( __FILE__, __LINE__, "Object and generation number cannot be read." ); throw e; } if( !this->IsNextToken( "obj" )) { std::ostringstream oss; oss << "Error while reading object " << m_reference.ObjectNumber() << " " << m_reference.GenerationNumber() << ": Next token is not 'obj'." << std::endl; PODOFO_RAISE_ERROR_INFO( ePdfError_NoObject, oss.str().c_str() ); } } void PdfParserObject::ParseFile( PdfEncrypt* pEncrypt, bool bIsTrailer ) { if( !m_device.Device() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if( m_lOffset > -1 ) m_device.Device()->Seek( m_lOffset ); if( !bIsTrailer ) ReadObjectNumber(); #if defined(PODOFO_VERBOSE_DEBUG) std::cerr << "Parsing object number: " << m_reference.ObjectNumber() << " " << m_reference.GenerationNumber() << " obj" << " " << m_lOffset << " offset" << " (DL: " << ( m_bLoadOnDemand ? "on" : "off" ) << ")" << endl; #endif // PODOFO_VERBOSE_DEBUG m_lOffset = m_device.Device()->Tell(); m_pEncrypt = pEncrypt; m_bIsTrailer = bIsTrailer; if( !m_bLoadOnDemand ) { // Force immediate loading of the object. We need to do this through // the deferred loading machinery to avoid getting the object into an // inconsistent state. // We can't do a full DelayedStreamLoad() because the stream might use // an indirect /Length or /Length1 key that hasn't been read yet. DelayedLoad(); // TODO: support immediate loading of the stream here too. For that, we need // to be able to trigger the reading of not-yet-parsed indirect objects // such as might appear in a /Length key with an indirect reference. #if defined(PODOFO_EXTRA_CHECKS) // Sanity check - the variant base must be fully loaded now if (!DelayedLoadDone() ) { // We don't know what went wrong, but the internal state is // broken or the API rules aren't being followed and we // can't carry on. PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } #endif // PODOF_EXTRA_CHECKS } } // Only called via the demand loading mechanism // Be very careful to avoid recursive demand loads via PdfVariant // or PdfObject method calls here. void PdfParserObject::ParseFileComplete( bool bIsTrailer ) { #if defined(PODOFO_EXTRA_CHECKS) PODOFO_ASSERT( DelayedLoadInProgress() ); PODOFO_ASSERT( !DelayedLoadDone() ); #endif const char* pszToken; m_device.Device()->Seek( m_lOffset ); if( m_pEncrypt ) m_pEncrypt->SetCurrentReference( m_reference ); // Do not call GetNextVariant directly, // but GetNextToken, to handle empty objects like: // 13 0 obj // endobj EPdfTokenType eTokenType; bool gotToken = this->GetNextToken( pszToken, &eTokenType ); if (!gotToken) { PODOFO_RAISE_ERROR_INFO( ePdfError_UnexpectedEOF, "Expected variant." ); } // Check if we have an empty object or data if( strncmp( pszToken, "endobj", s_nLenEndObj ) != 0 ) { this->GetNextVariant( pszToken, eTokenType, *this, m_pEncrypt ); this->SetDirty( false ); if( !bIsTrailer ) { bool gotToken = this->GetNextToken( pszToken ); if (!gotToken) { PODOFO_RAISE_ERROR_INFO( ePdfError_UnexpectedEOF, "Expected 'endobj' or (if dict) 'stream', got EOF." ); } if( strncmp( pszToken, "endobj", s_nLenEndObj ) == 0 ) ; // nothing to do, just validate that the PDF is correct // If it's a dictionary, it might have a stream, so check for that else if( this->IsDictionary() && strncmp( pszToken, "stream", s_nLenStream ) == 0 ) { m_bStream = true; m_lStreamOffset = m_device.Device()->Tell(); // NOTE: whitespace after "stream" handle in stream parser! // Most of the code relies on PdfObjects that are dictionaries // to have the datatype ePdfDataType_Dictionary and not Stream. // Please use PdfObject::HasStream to check wether it has a stream. // // Commenting this out is right now easier than fixing all code to check // either for ePdfDataType_Stream or ePdfDataType_Dictionary // //eDataType = ePdfDataType_Stream; // reset the object type to stream! } else { PODOFO_RAISE_ERROR_INFO( ePdfError_NoObject, pszToken ); } } } } // Only called during delayed loading. Must be careful to avoid // triggering recursive delay loading due to use of accessors of // PdfVariant or PdfObject. void PdfParserObject::ParseStream() { #if defined(PODOFO_EXTRA_CHECKS) PODOFO_ASSERT( DelayedLoadDone() ); PODOFO_ASSERT( DelayedStreamLoadInProgress() ); PODOFO_ASSERT( !DelayedStreamLoadDone() ); #endif pdf_int64 lLen = -1; int c; if( !m_device.Device() || !m_pOwner ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } m_device.Device()->Seek( m_lStreamOffset ); // From the PDF Reference manual // The keyword stream that follows // the stream dictionary should be followed by an end-of-line marker consisting of // either a carriage return and a line feed or just a line feed, and not by a carriage re- // turn alone. c = m_device.Device()->Look(); if( PdfTokenizer::IsWhitespace( c ) ) { c = m_device.Device()->GetChar(); if( c == '\r' ) { c = m_device.Device()->Look(); if( c == '\n' ) { c = m_device.Device()->GetChar(); } } } pdf_long fLoc = m_device.Device()->Tell(); // we need to save this, since loading the Length key could disturb it! PdfObject* pObj = this->GetDictionary_NoDL().GetKey( PdfName::KeyLength ); if( pObj && pObj->IsNumber() ) { lLen = pObj->GetNumber(); } else if( pObj && pObj->IsReference() ) { pObj = m_pOwner->GetObject( pObj->GetReference() ); if( !pObj ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "/Length key referenced indirect object that could not be loaded" ); } /*PdfError::LogMessage(eLogSeverity_Information, "Reading object %i 0 R with type: %s\n", pObj->Reference().ObjectNumber(), pObj->GetDataTypeString());*/ if( !pObj->IsNumber() ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidStreamLength, "/Length key for stream referenced non-number" ); } lLen = pObj->GetNumber(); // DS: This code makes no sense, // as empty streams with length 0 are valid, too. //if( !lLen ) //{ // PODOFO_RAISE_ERROR( ePdfError_InvalidStreamLength ); //} // we do not use indirect references for the length of the document // DS: Even though do not remove the length key, // as 2 or more object might use the same object for key lengths. // Deleting the length object of the first object will make // all other objects non readable. // If you want those length object to be removed, // run the garbage collection of PdfVecObjects over your PDF. //delete m_pOwner->RemoveObject( pObj->Reference() ); } else { PODOFO_RAISE_ERROR( ePdfError_InvalidStreamLength ); } m_device.Device()->Seek( fLoc ); // reset it before reading! PdfDeviceInputStream reader( m_device.Device() ); if( m_pEncrypt && !m_pEncrypt->IsMetadataEncrypted() ) { // If metadata is not encrypted the Filter is set to "Crypt" PdfObject* pFilterObj = this->GetDictionary_NoDL().GetKey( PdfName::KeyFilter ); if( pFilterObj && pFilterObj->IsArray() ) { PdfArray filters = pFilterObj->GetArray(); for(PdfArray::iterator it = filters.begin(); it != filters.end(); it++) { if( (*it).IsName() ) if( (*it).GetName() == "Crypt" ) m_pEncrypt = 0; } } } if( m_pEncrypt ) { m_pEncrypt->SetCurrentReference( m_reference ); PdfInputStream* pInput = m_pEncrypt->CreateEncryptionInputStream( &reader ); this->GetStream_NoDL()->SetRawData( pInput, static_cast(lLen) ); delete pInput; } else this->GetStream_NoDL()->SetRawData( &reader, static_cast(lLen) ); this->SetDirty( false ); /* SAFE_OP( GetNextStringFromFile( ) ); if( strncmp( m_buffer.Buffer(), "endstream", s_nLenEndStream ) != 0 ) return ERROR_PDF_MISSING_ENDSTREAM; */ } void PdfParserObject::DelayedLoadImpl() { #if defined(PODOFO_EXTRA_CHECKS) // DelayedLoadImpl() should only ever be called via DelayedLoad(), // which ensures that it is never called repeatedly. PODOFO_ASSERT( !DelayedLoadDone() ); PODOFO_ASSERT( DelayedLoadInProgress() ); #endif ParseFileComplete( m_bIsTrailer ); // If we complete without throwing DelayedLoadDone will be set // for us. } void PdfParserObject::DelayedStreamLoadImpl() { #if defined(PODOFO_EXTRA_CHECKS) // DelayedLoad() must've been called, either directly earlier // or via DelayedStreamLoad. DelayedLoad() will throw if the load // failed, so if we're being called this condition must be true. PODOFO_ASSERT( DelayedLoadDone() ); // Similarly, we should not be being called unless the stream isn't // already loaded. PODOFO_ASSERT( !DelayedStreamLoadDone() ); PODOFO_ASSERT( DelayedStreamLoadInProgress() ); #endif // Note: we can't use HasStream() here because it'll call DelayedStreamLoad() // causing a nasty loop. test m_pStream directly instead. if( this->HasStreamToParse() && !m_pStream ) { try { this->ParseStream(); } catch( PdfError & e ) { // TODO: track object ptr in error info so we don't have to do this memory-intensive // formatting here. std::ostringstream s; s << "Unable to parse the stream for object " << Reference().ObjectNumber() << ' ' << Reference().GenerationNumber() << " obj ."; e.AddToCallstack( __FILE__, __LINE__, s.str().c_str()); throw e; } } // If we complete without throwing the stream will be flagged as loaded. } void PdfParserObject::FreeObjectMemory( bool bForce ) { if( this->IsLoadOnDemand() && (bForce || !this->IsDirty()) ) { PdfVariant::Clear(); delete m_pStream; m_pStream = NULL; EnableDelayedLoading(); EnableDelayedStreamLoading(); } } }; podofo-0.9.5/src/base/PdfData.cpp0000664000175000017500000000524212344436402016400 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfData.h" #include "PdfOutputDevice.h" #include "PdfDefinesPrivate.h" namespace PoDoFo { void PdfData::Write( PdfOutputDevice* pDevice, EPdfWriteMode, const PdfEncrypt* ) const { pDevice->Write( m_sData.c_str(), m_sData.length() ); } }; podofo-0.9.5/src/base/PdfReference.cpp0000664000175000017500000000612312344436402017424 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfReference.h" #include "PdfOutputDevice.h" #include "PdfDefinesPrivate.h" #include namespace PoDoFo { void PdfReference::Write( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, const PdfEncrypt* ) const { if( (eWriteMode & ePdfWriteMode_Compact) == ePdfWriteMode_Compact ) { // Write space before the reference pDevice->Print( " %i %hi R", m_nObjectNo, m_nGenerationNo ); } else { pDevice->Print( "%i %hi R", m_nObjectNo, m_nGenerationNo ); } } const std::string PdfReference::ToString() const { std::ostringstream out; out << m_nObjectNo << " " << m_nGenerationNo << " R"; return out.str(); } }; podofo-0.9.5/src/base/PdfMemStream.cpp0000664000175000017500000002221513013650710017412 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfMemStream.h" #include "PdfArray.h" #include "PdfEncrypt.h" #include "PdfFilter.h" #include "PdfObject.h" #include "PdfOutputDevice.h" #include "PdfOutputStream.h" #include "PdfVariant.h" #include "PdfDefinesPrivate.h" #include namespace PoDoFo { PdfMemStream::PdfMemStream( PdfObject* pParent ) : PdfStream( pParent ), m_pStream( NULL ), m_pBufferStream( NULL ), m_lLength( 0 ) { } PdfMemStream::PdfMemStream( const PdfMemStream & rhs ) : PdfStream( NULL ), m_pStream( NULL ), m_pBufferStream( NULL ), m_lLength( 0 ) { operator=(rhs); } PdfMemStream::~PdfMemStream() { } void PdfMemStream::BeginAppendImpl( const TVecFilters & vecFilters ) { m_buffer = PdfRefCountedBuffer(); m_lLength = 0; if( vecFilters.size() ) { m_pBufferStream = new PdfBufferOutputStream( &m_buffer ); m_pStream = PdfFilterFactory::CreateEncodeStream( vecFilters, m_pBufferStream ); } else m_pStream = new PdfBufferOutputStream( &m_buffer ); } void PdfMemStream::AppendImpl( const char* pszString, size_t lLen ) { m_pStream->Write( pszString, lLen ); } void PdfMemStream::EndAppendImpl() { if( m_pStream ) { m_pStream->Close(); if( !m_pBufferStream ) { PdfBufferOutputStream* pBufferOutputStream = dynamic_cast(m_pStream); if( pBufferOutputStream ) m_lLength = pBufferOutputStream->GetLength(); } delete m_pStream; m_pStream = NULL; } if( m_pBufferStream ) { m_pBufferStream->Close(); m_lLength = m_pBufferStream->GetLength(); delete m_pBufferStream; m_pBufferStream = NULL; } if( m_pParent ) m_pParent->GetDictionary().AddKey( PdfName::KeyLength, PdfVariant(static_cast(m_lLength) ) ); } void PdfMemStream::GetCopy( char** pBuffer, pdf_long* lLen ) const { if( !pBuffer || !lLen ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } *pBuffer = static_cast(podofo_calloc( m_lLength, sizeof(char) )); *lLen = m_lLength; if( !*pBuffer ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } memcpy( *pBuffer, m_buffer.GetBuffer(), m_lLength ); } void PdfMemStream::GetCopy(PdfOutputStream * pStream) const { if( !pStream) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } pStream->Write(m_buffer.GetBuffer(), m_lLength); } void PdfMemStream::FlateCompress() { PdfObject* pObj; PdfVariant vFilter( PdfName("FlateDecode" ) ); PdfVariant vFilterList; PdfArray tFilters; PdfArray::const_iterator tciFilters; if( !m_lLength ) return; // ePdfError_ErrOk // TODO: Handle DecodeParms if( m_pParent->GetDictionary().HasKey( "Filter" ) ) { pObj = m_pParent->GetIndirectKey( "Filter" ); if( pObj->IsName() ) { if( pObj->GetName() != "DCTDecode" && pObj->GetName() != "FlateDecode" ) { tFilters.push_back( vFilter ); tFilters.push_back( *pObj ); } } else if( pObj->IsArray() ) { tciFilters = pObj->GetArray().begin(); while( tciFilters != pObj->GetArray().end() ) { if( (*tciFilters).IsName() ) { // do not compress DCTDecoded are already FlateDecoded streams again if( (*tciFilters).GetName() == "DCTDecode" || (*tciFilters).GetName() == "FlateDecode" ) { return; } } ++tciFilters; } tFilters.push_back( vFilter ); tciFilters = pObj->GetArray().begin(); while( tciFilters != pObj->GetArray().end() ) { tFilters.push_back( (*tciFilters) ); ++tciFilters; } } else return; vFilterList = PdfVariant( tFilters ); m_pParent->GetDictionary().AddKey( "Filter", vFilterList ); FlateCompressStreamData(); // throws an exception on error } else { m_pParent->GetDictionary().AddKey( "Filter", PdfName( "FlateDecode" ) ); FlateCompressStreamData(); } } void PdfMemStream::Uncompress() { pdf_long lLen; char* pBuffer = NULL; TVecFilters vecEmpty; if( m_pParent && m_pParent->IsDictionary() && m_pParent->GetDictionary().HasKey( "Filter" ) && m_lLength ) { try { this->GetFilteredCopy( &pBuffer, &lLen ); } catch( PdfError & e ) { if( pBuffer ) podofo_free( pBuffer ); throw e; } this->Set( pBuffer, lLen, vecEmpty ); // free the memory allocated by GetFilteredCopy again. podofo_free( pBuffer ); m_pParent->GetDictionary().RemoveKey( "Filter" ); if( m_pParent->GetDictionary().HasKey( "DecodeParms" ) ) { m_pParent->GetDictionary().RemoveKey( "DecodeParms" ); } } } void PdfMemStream::FlateCompressStreamData() { char* pBuffer; pdf_long lLen; if( !m_lLength ) return; std::auto_ptr pFilter = PdfFilterFactory::Create( ePdfFilter_FlateDecode ); if( pFilter.get() ) { pFilter->Encode( m_buffer.GetBuffer(), m_buffer.GetSize(), &pBuffer, &lLen ); this->Set( pBuffer, lLen ); } else { PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter ); } } const PdfStream & PdfMemStream::operator=( const PdfStream & rhs ) { const PdfMemStream* pStream = dynamic_cast(&rhs); if( pStream ) m_buffer = pStream->m_buffer; else return PdfStream::operator=( rhs ); m_lLength = rhs.GetLength(); if( m_pParent ) m_pParent->GetDictionary().AddKey( PdfName::KeyLength, PdfVariant( static_cast(m_lLength) ) ); return *this; } void PdfMemStream::Write( PdfOutputDevice* pDevice, PdfEncrypt* pEncrypt ) { pDevice->Print( "stream\n" ); if( pEncrypt ) { pdf_long lLen = this->GetLength(); pdf_long nOutputLen = pEncrypt->CalculateStreamLength(lLen); char *pOutputBuffer = new char[nOutputLen]; pEncrypt->Encrypt( reinterpret_cast(this->Get()), lLen, reinterpret_cast(pOutputBuffer), nOutputLen); pDevice->Write( pOutputBuffer, nOutputLen ); delete[] pOutputBuffer; } else { pDevice->Write( this->Get(), this->GetLength() ); } pDevice->Print( "\nendstream\n" ); } pdf_long PdfMemStream::GetLength() const { return m_lLength; } }; podofo-0.9.5/src/base/PdfTokenizer.h0000664000175000017500000003025712730052013017141 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_TOKENIZER_H_ #define _PDF_TOKENIZER_H_ #include "PdfDefines.h" #include "PdfRefCountedBuffer.h" #include "PdfRefCountedInputDevice.h" #include #include namespace PoDoFo { class PdfEncrypt; class PdfVariant; enum EPdfTokenType { ePdfTokenType_Delimiter, ePdfTokenType_Token, ePdfTokenType_Unknown = 0xFF }; typedef std::pair TTokenizerPair; typedef std::deque TTokenizerQueque; typedef TTokenizerQueque::iterator TITokenizerQueque; typedef TTokenizerQueque::const_iterator TCITokenizerQueque; /** * A simple tokenizer for PDF files and PDF content streams */ class PODOFO_API PdfTokenizer { public: PdfTokenizer(); PdfTokenizer( const char* pBuffer, size_t lLen ); PdfTokenizer( const PdfRefCountedInputDevice & rDevice, const PdfRefCountedBuffer & rBuffer ); virtual ~PdfTokenizer(); /** Reads the next token from the current file position * ignoring all comments. * * \param[out] pszToken On true return, set to a pointer to the read * token (a NULL-terminated C string). The pointer is * to memory owned by PdfTokenizer and must NOT be * freed. The contents are invalidated on the next * call to GetNextToken(..) and by the destruction of * the PdfTokenizer. Undefined on false return. * * \param[out] peType On true return, if not NULL the type of the read token * will be stored into this parameter. Undefined on false * return. * * \returns True if a token was read, false if there are no * more tokens to read. * * \see GetBuffer */ virtual bool GetNextToken( const char *& pszToken, EPdfTokenType* peType = NULL); /** Reads the next token from the current file position * ignoring all comments and compare the passed token * to the read token. * * If there is no next token available, throws UnexpectedEOF. * * \param pszToken a token that is compared to the * read token * * \returns true if the read token equals the passed token. */ bool IsNextToken( const char* pszToken ); /** Read the next number from the current file position * ignoring all comments. * * Raises NoNumber exception if the next token is no number, and * UnexpectedEOF if no token could be read. No token is consumed if * NoNumber is thrown. * * \returns a number read from the input device. */ pdf_long GetNextNumber(); /** Read the next variant from the current file position * ignoring all comments. * * Raises an UnexpectedEOF exception if there is no variant left in the * file. * * \param rVariant write the read variant to this value * \param pEncrypt an encryption object which is used to decrypt strings during parsing */ void GetNextVariant( PdfVariant& rVariant, PdfEncrypt* pEncrypt ); /** Returns true if the given character is a whitespace * according to the pdf reference * * \returns true if it is a whitespace character otherwise false */ PODOFO_NOTHROW inline static bool IsWhitespace(const unsigned char ch); /** Returns true if the given character is a delimiter * according to the pdf reference * * \returns true if it is a delimiter character otherwise false */ PODOFO_NOTHROW inline static bool IsDelimiter(const unsigned char ch); /** * True if the passed character is a regular character according to the PDF * reference (Section 3.1.1, Character Set); ie it is neither a white-space * nor a delimeter character. */ PODOFO_NOTHROW inline static bool IsRegular(const unsigned char ch); /** * True if the passed character is within the generally accepted "printable" * ASCII range. */ PODOFO_NOTHROW inline static bool IsPrintable(const unsigned char ch); /** * Get the hex value from a static map of a given hex character (0-9, A-F, a-f). * * \param ch hex character * * \returns hex value or HEX_NOT_FOUND if invalid * * \see HEX_NOT_FOUND */ PODOFO_NOTHROW inline static int GetHexValue(const unsigned char ch); /** * Constant which is returned for invalid hex values. */ static const unsigned int HEX_NOT_FOUND; protected: /** Read the next variant from the current file position * ignoring all comments. * * Raises an exception if there is no variant left in the file. * * \param pszToken a token that has already been read * \param eType type of the passed token * \param rVariant write the read variant to this value * \param pEncrypt an encryption object which is used to decrypt strings during parsing */ void GetNextVariant( const char* pszToken, EPdfTokenType eType, PdfVariant& rVariant, PdfEncrypt* pEncrypt ); /** Determine the possible datatype of a token. * Numbers, reals, bools or NULL values are parsed directly by this function * and saved to a variant. * * \returns the expected datatype */ EPdfDataType DetermineDataType( const char* pszToken, EPdfTokenType eType, PdfVariant& rVariant ); void ReadDataType( EPdfDataType eDataType, PdfVariant& rVariant, PdfEncrypt* pEncrypt ); /** Read a dictionary from the input device * and store it into a variant. * * \param rVariant store the dictionary into this variable * \param pEncrypt an encryption object which is used to decrypt strings during parsing */ void ReadDictionary( PdfVariant& rVariant, PdfEncrypt* pEncrypt ); /** Read an array from the input device * and store it into a variant. * * \param rVariant store the array into this variable * \param pEncrypt an encryption object which is used to decrypt strings during parsing */ void ReadArray( PdfVariant& rVariant, PdfEncrypt* pEncrypt ); /** Read a string from the input device * and store it into a variant. * * \param rVariant store the string into this variable * \param pEncrypt an encryption object which is used to decrypt strings during parsing */ void ReadString( PdfVariant& rVariant, PdfEncrypt* pEncrypt ); /** Read a hex string from the input device * and store it into a variant. * * \param rVariant store the hex string into this variable * \param pEncrypt an encryption object which is used to decrypt strings during parsing */ void ReadHexString( PdfVariant& rVariant, PdfEncrypt* pEncrypt ); /** Read a name from the input device * and store it into a variant. * * Throws UnexpectedEOF if there is nothing to read. * * \param rVariant store the name into this variable */ void ReadName( PdfVariant& rVariant ); /** Add a token to the queue of tokens. * GetNextToken() will return all enqueued tokens first before * reading new tokens from the input device. * * \param pszToken string of the token * \param eType type of the token * * \see GetNextToken */ void QuequeToken( const char* pszToken, EPdfTokenType eType ); protected: PdfRefCountedInputDevice m_device; PdfRefCountedBuffer m_buffer; private: // 256-byte array mapping character ordinal values to a truth value // indicating whether or not they are whitespace according to the PDF // standard. static const char * const s_delimiterMap; static const char * const s_whitespaceMap; static const char s_octMap[]; ///< Map of bool values, if a certain char ///< is a valid octal digit static const char * const s_escMap; ///< Mapping of escape sequences to their value static const char * const s_hexMap; ///< Mapping of hex characters to their value TTokenizerQueque m_deqQueque; // A vector which is used as a buffer to read strings. // It is a member of the class to avoid reallocations while parsing. std::vector m_vecBuffer; // we use a vector instead of a string // because we might read a unicode // string which is allowed to contain 0 bytes. /// An istringstream which is used /// to read double values instead of strtod /// which is locale depend. std::istringstream m_doubleParser; }; // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfTokenizer::IsWhitespace(const unsigned char ch) { return ( PdfTokenizer::s_whitespaceMap[static_cast(ch)] != 0 ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfTokenizer::IsDelimiter(const unsigned char ch) { return ( PdfTokenizer::s_delimiterMap[ch] != 0 ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfTokenizer::IsRegular(const unsigned char ch) { return !IsWhitespace(ch) && !IsDelimiter(static_cast(ch)); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfTokenizer::IsPrintable(const unsigned char ch) { return ((ch > 32U) && (ch < 125U)); } // ----------------------------------------------------- // // ----------------------------------------------------- inline int PdfTokenizer::GetHexValue(const unsigned char ch) { return PdfTokenizer::s_hexMap[static_cast(ch)]; } }; #endif // _PDF_TOKENIZER_H_ podofo-0.9.5/src/base/PdfObject.cpp0000664000175000017500000002344113013650710016730 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfObject.h" #include "PdfArray.h" #include "PdfDictionary.h" #include "PdfEncrypt.h" #include "PdfFileStream.h" #include "PdfOutputDevice.h" #include "PdfStream.h" #include "PdfVariant.h" #include "PdfDefinesPrivate.h" #include #include #include using namespace std; namespace PoDoFo { PdfObject::PdfObject() : PdfVariant( PdfDictionary() ) { InitPdfObject(); } PdfObject::PdfObject( const PdfReference & rRef, const char* pszType ) : PdfVariant( PdfDictionary() ), m_reference( rRef ) { InitPdfObject(); if( pszType ) this->GetDictionary().AddKey( PdfName::KeyType, PdfName( pszType ) ); } PdfObject::PdfObject( const PdfReference & rRef, const PdfVariant & rVariant ) : PdfVariant( rVariant ), m_reference( rRef ) { InitPdfObject(); } PdfObject::PdfObject( const PdfVariant & var ) : PdfVariant( var ) { InitPdfObject(); } PdfObject::PdfObject( bool b ) : PdfVariant( b ) { InitPdfObject(); } PdfObject::PdfObject( pdf_int64 l ) : PdfVariant( l ) { InitPdfObject(); } PdfObject::PdfObject( double d ) : PdfVariant( d ) { InitPdfObject(); } PdfObject::PdfObject( const PdfString & rsString ) : PdfVariant( rsString ) { InitPdfObject(); } PdfObject::PdfObject( const PdfName & rName ) : PdfVariant( rName ) { InitPdfObject(); } PdfObject::PdfObject( const PdfReference & rRef ) : PdfVariant( rRef ) { InitPdfObject(); } PdfObject::PdfObject( const PdfArray & tList ) : PdfVariant( tList ) { InitPdfObject(); } PdfObject::PdfObject( const PdfDictionary & rDict ) : PdfVariant( rDict ) { InitPdfObject(); } PdfObject::PdfObject( const PdfObject & rhs ) : PdfVariant( rhs ), m_reference( rhs.m_reference ) { InitPdfObject(); // DS: If you change this code, also change the assignment operator. // As the copy constructor is called very often, // it contains a copy of parts of the assignment code to be faster. const_cast(&rhs)->DelayedStreamLoad(); m_bDelayedStreamLoadDone = rhs.DelayedStreamLoadDone(); if( rhs.m_pStream && m_pOwner ) m_pStream = m_pOwner->CreateStream( *(rhs.m_pStream) ); #if defined(PODOFO_EXTRA_CHECKS) // Must've been demand loaded or already done PODOFO_ASSERT( DelayedLoadDone() ); PODOFO_ASSERT( DelayedStreamLoadDone() ); #endif } PdfObject::~PdfObject() { delete m_pStream; m_pStream = NULL; } void PdfObject::InitPdfObject() { m_pStream = NULL; m_pOwner = NULL; m_bDelayedStreamLoadDone = true; #if defined(PODOFO_EXTRA_CHECKS) m_bDelayedStreamLoadInProgress = false; #endif } void PdfObject::WriteObject( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, PdfEncrypt* pEncrypt, const PdfName & keyStop ) const { DelayedStreamLoad(); if( !pDevice ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if( m_reference.IsIndirect() ) { if( (eWriteMode & ePdfWriteMode_Clean) == ePdfWriteMode_Clean ) { pDevice->Print( "%i %i obj\n", m_reference.ObjectNumber(), m_reference.GenerationNumber() ); } else { pDevice->Print( "%i %i obj", m_reference.ObjectNumber(), m_reference.GenerationNumber() ); } } if( pEncrypt ) { pEncrypt->SetCurrentReference( m_reference ); } if( pEncrypt && m_pStream ) { // Set length if it is a key PdfFileStream* pFileStream = dynamic_cast(m_pStream); if( !pFileStream ) { // PdfFileStream handles encryption internally pdf_long lLength = pEncrypt->CalculateStreamLength(m_pStream->GetLength()); PdfVariant varLength = static_cast(lLength); *(const_cast(this)->GetIndirectKey( PdfName::KeyLength )) = varLength; } } this->Write( pDevice, eWriteMode, pEncrypt, keyStop ); pDevice->Print( "\n" ); if( m_pStream ) { m_pStream->Write( pDevice, pEncrypt ); } if( m_reference.IsIndirect() ) { pDevice->Print( "endobj\n" ); } } PdfObject* PdfObject::GetIndirectKey( const PdfName & key ) const { const PdfObject* pObj = NULL; if( this->IsDictionary() && this->GetDictionary().HasKey( key ) ) { pObj = this->GetDictionary().GetKey( key ); if( pObj->IsReference() ) { if( !m_pOwner ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "Object is a reference but does not have an owner!" ); } pObj = m_pOwner->GetObject( pObj->GetReference() ); } else const_cast(pObj)->SetOwner( GetOwner() );// even directs might want an owner... } // DominikS: TODO Remove const on GetIndirectKey return const_cast(pObj); } pdf_long PdfObject::GetObjectLength( EPdfWriteMode eWriteMode ) { PdfOutputDevice device; this->WriteObject( &device, eWriteMode, NULL ); return device.GetLength(); } PdfStream* PdfObject::GetStream() { DelayedStreamLoad(); return GetStream_NoDL(); } PdfStream* PdfObject::GetStream_NoDL() { if( !m_pStream ) { if ( GetDataType() != ePdfDataType_Dictionary ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Tried to get stream of non-dictionary object"); } if ( !m_reference.IsIndirect() ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Tried to get stream of non-indirect PdfObject"); } if( !m_pOwner ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "Tried to create stream on PdfObject lacking owning document/PdfVecObjects" ); } m_pStream = m_pOwner->CreateStream( this ); } SetDirty( true ); return m_pStream; } const PdfStream* PdfObject::GetStream() const { DelayedStreamLoad(); return m_pStream; } void PdfObject::FlateCompressStream() { // TODO: If the stream isn't already in memory, defer loading and compression until first read of the stream to save some memory. DelayedStreamLoad(); /* if( m_pStream ) m_pStream->FlateCompress(); */ } const PdfObject & PdfObject::operator=( const PdfObject & rhs ) { // DS: If you change this code, also change the copy constructor. // As the copy constructor is called very often, // it contains a copy of parts of this code to be faster. delete m_pStream; const_cast(&rhs)->DelayedStreamLoad(); m_reference = rhs.m_reference; m_pOwner = rhs.m_pOwner; PdfVariant::operator=( rhs ); m_bDelayedStreamLoadDone = rhs.DelayedStreamLoadDone(); if( rhs.m_pStream ) m_pStream = m_pOwner->CreateStream( *(rhs.m_pStream) ); #if defined(PODOFO_EXTRA_CHECKS) // Must've been demand loaded or already done PODOFO_ASSERT( DelayedLoadDone() ); PODOFO_ASSERT( DelayedStreamLoadDone() ); #endif return *this; } pdf_long PdfObject::GetByteOffset( const char* pszKey, EPdfWriteMode eWriteMode ) { PdfOutputDevice device; if( !pszKey ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if( !this->GetDictionary().HasKey( pszKey ) ) { PODOFO_RAISE_ERROR( ePdfError_InvalidKey ); } this->Write( &device, eWriteMode, NULL, pszKey ); return device.GetLength(); } }; podofo-0.9.5/src/base/PdfName.cpp0000664000175000017500000001772713013650710016414 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfName.h" #include "PdfOutputDevice.h" #include "PdfTokenizer.h" #include "PdfDefinesPrivate.h" #include using PoDoFo::ePdfError_InvalidName; namespace { /** * This function writes a hex encoded representation of the character * `ch' to `buf', advancing the iterator by two steps. * * \warning no buffer length checking is performed, so MAKE SURE * you have enough room for the two characters that * will be written to the buffer. * * \param ch The character to write a hex representation of * \param buf An iterator (eg a char* or std::string::iterator) to write the * characters to. Must support the postfix ++, operator=(char) and * dereference operators. */ template inline void hexchr(const unsigned char ch, T & it) { *(it++) = "0123456789ABCDEF"[ch / 16]; *(it++) = "0123456789ABCDEF"[ch % 16]; } /** Escape the input string according to the PDF name * escaping rules and return the result. * * \param it Iterator referring to the start of the input string * ( eg a `const char *' or a `std::string::iterator' ) * \param length Length of input string * \returns Escaped string */ template static std::string EscapeName(T it, size_t length) { // Scan the input string once to find out how much memory we need // to reserve for the encoded result string. We could do this in one // pass using a std::ostringstream instead, but it's a LOT slower. T it2(it); unsigned int outchars = 0; for (size_t i = 0; i < length; ++i) { // Null chars are illegal in names, even escaped if (*it2 == '\0') { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidName, "Null byte in PDF name is illegal"); } else { // Leave room for either just the char, or a #xx escape of it. outchars += (::PoDoFo::PdfTokenizer::IsRegular(*it2) && ::PoDoFo::PdfTokenizer::IsPrintable(*it2) && (*it2 != '#')) ? 1 : 3; } ++it2; } // Reserve it. We can't use reserve() because the GNU STL doesn't seem to // do it correctly; the memory never seems to get allocated. std::string buf; buf.resize(outchars); // and generate the encoded string std::string::iterator bufIt(buf.begin()); for (size_t z = 0; z < length; ++z) { if (::PoDoFo::PdfTokenizer::IsRegular(*it) && ::PoDoFo::PdfTokenizer::IsPrintable(*it) && (*it != '#') ) *(bufIt++) = *it; else { *(bufIt++) = '#'; hexchr(static_cast(*it), bufIt); } ++it; } return buf; } /** Interpret the passed string as an escaped PDF name * and return the unescaped form. * * \param it Iterator referring to the start of the input string * ( eg a `const char *' or a `std::string::iterator' ) * \param length Length of input string * \returns Unescaped string */ template static std::string UnescapeName(T it, size_t length) { // We know the decoded string can be AT MOST // the same length as the encoded one, so: std::string buf; buf.resize(length); unsigned int incount = 0, outcount = 0; while (incount++ < length) { if (*it == '#') { unsigned char hi = static_cast(*(++it)); ++incount; unsigned char low = static_cast(*(++it)); ++incount; hi -= ( hi < 'A' ? '0' : 'A'-10 ); low -= ( low < 'A' ? '0' : 'A'-10 ); buf[outcount++] = (hi << 4) | (low & 0x0F); } else buf[outcount++] = *it; ++it; } // Chop buffer off at number of decoded bytes buf.resize(outcount); return buf; } }; // End anonymous namespace namespace PoDoFo { const PdfName PdfName::KeyContents = PdfName( "Contents" ); const PdfName PdfName::KeyFlags = PdfName( "Flags" ); const PdfName PdfName::KeyLength = PdfName( "Length" ); const PdfName PdfName::KeyNull = PdfName(); const PdfName PdfName::KeyRect = PdfName( "Rect" ); const PdfName PdfName::KeySize = PdfName( "Size" ); const PdfName PdfName::KeySubtype = PdfName( "Subtype" ); const PdfName PdfName::KeyType = PdfName( "Type" ); const PdfName PdfName::KeyFilter = PdfName( "Filter" ); PdfName::~PdfName() { } PdfName PdfName::FromEscaped( const std::string & sName ) { return PdfName(UnescapeName(sName.begin(), sName.length())); } PdfName PdfName::FromEscaped( const char * pszName, pdf_long ilen ) { if( !pszName ) return PdfName(); if( !ilen ) ilen = strlen( pszName ); return PdfName(UnescapeName(pszName, ilen)); } void PdfName::Write( PdfOutputDevice* pDevice, EPdfWriteMode, const PdfEncrypt* ) const { // Allow empty names, which are legal according to the PDF specification pDevice->Print( "/" ); if( m_Data.length() ) { std::string escaped( EscapeName(m_Data.begin(), m_Data.length()) ); pDevice->Write( escaped.c_str(), escaped.length() ); } } std::string PdfName::GetEscapedName() const { return EscapeName(m_Data.begin(), m_Data.length()); } bool PdfName::operator==( const char* rhs ) const { /* If the string is empty and you pass NULL - that's equivalent If the string is NOT empty and you pass NULL - that's not equal Otherwise, compare them */ if( m_Data.empty() && !rhs ) return true; else if( !m_Data.empty() && !rhs ) return false; else return ( m_Data == std::string( rhs ) ); } }; podofo-0.9.5/src/base/PdfCanvas.h0000664000175000017500000001146112344436402016407 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_CANVAS_H_ #define _PDF_CANVAS_H_ #include "PdfDefines.h" #include "PdfArray.h" namespace PoDoFo { class PdfDictionary; class PdfObject; class PdfRect; class PdfColor; /** A interface that provides the necessary features * for a painter to draw onto a PdfObject. */ class PODOFO_API PdfCanvas { public: /** Virtual destructor * to avoid compiler warnings */ virtual ~PdfCanvas() {}; /** Get access to the contents object of this page. * If you want to draw onto the page, you have to add * drawing commands to the stream of the Contents object. * \returns a contents object */ virtual PdfObject* GetContents() const = 0; /** Get access an object that you can use to ADD drawing to. * If you want to draw onto the page, you have to add * drawing commands to the stream of the Contents object. * \returns a contents object */ virtual PdfObject* GetContentsForAppending() const = 0; /** Get access to the resources object of this page. * This is most likely an internal object. * \returns a resources object */ virtual PdfObject* GetResources() const = 0; /** Get the current page size in PDF Units * \returns a PdfRect containing the page size available for drawing */ virtual const PdfRect GetPageSize() const = 0; /** Get a reference to a static procset PdfArray. * \returns a reference to a static procset PdfArray */ static const PdfArray & GetProcSet(); /** Register a colourspace for a (separation) colour in the resource dictionary * of this page or XObbject so that it can be used for any following drawing * operations. * * \param rColor reference to the PdfColor */ void AddColorResource( const PdfColor & rColor ); /** Register an object in the resource dictionary of this page or XObbject * so that it can be used for any following drawing operations. * * \param rIdentifier identifier of this object, e.g. /Ft0 * \param rRef reference to the object you want to register * \param rName register under this key in the resource dictionary */ void AddResource( const PdfName & rIdentifier, const PdfReference & rRef, const PdfName & rName ); private: /** The procset is the same for all * PdfContents objects */ static PdfArray s_procset; }; }; #endif /* _PDF_CANVAS_H_ */ podofo-0.9.5/src/base/PdfRefCountedBuffer.h0000664000175000017500000002653412344436402020373 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_REF_COUNTED_BUFFER_H_ #define _PDF_REF_COUNTED_BUFFER_H_ #include "PdfDefines.h" namespace PoDoFo { /** * A reference counted buffer object * which is deleted as soon as the last * object having access to it is delteted. * * The attached memory object can be resized. */ class PODOFO_API PdfRefCountedBuffer { public: /** Created an empty reference counted buffer * The buffer will be initialize to NULL */ inline PdfRefCountedBuffer(); /** Created an reference counted buffer and use an exiting buffer * The buffer will be owned by this object. * * \param pBuffer a pointer to an allocated buffer * \param lSize size of the allocated buffer * * \see SetTakePossesion */ PdfRefCountedBuffer( char* pBuffer, size_t lSize ); /** Create a new PdfRefCountedBuffer. * \param lSize buffer size */ inline PdfRefCountedBuffer( size_t lSize ); /** Copy an existing PdfRefCountedBuffer and increase * the reference count * \param rhs the PdfRefCountedBuffer to copy */ inline PdfRefCountedBuffer( const PdfRefCountedBuffer & rhs ); /** Decrease the reference count and delete the buffer * if this is the last owner */ inline ~PdfRefCountedBuffer(); /* !Non-Doxygen comment because constructor is disabled! * Append to the current buffers contents. * If the buffer is referenced by another PdfRefCountedBuffer * this object detaches from this buffer and allocates an own * buffer. Otherwise the internal buffer is used and resized if * necessary. * * \param pszString a buffer * \param lLen length of the buffer */ //void Append( const char* pszString, long lLen ); /** Get access to the buffer * \returns the buffer */ inline char* GetBuffer() const; /** Return the buffer size. * * \returns the buffer size */ inline size_t GetSize() const; /** Resize the buffer to hold at least * lSize bytes. * * \param lSize the size of bytes the buffer can at least hold * * If the buffer is larger no operation is performed. */ inline void Resize( size_t lSize ); /** Copy an existing PdfRefCountedBuffer and increase * the reference count * \param rhs the PdfRefCountedBuffer to copy * \returns the copied object */ const PdfRefCountedBuffer & operator=( const PdfRefCountedBuffer & rhs ); /** If the PdfRefCountedBuffer has no possesion on its buffer, * it won't delete the buffer. By default the buffer is owned * and deleted by the PdfRefCountedBuffer object. * * \param bTakePossession if false the buffer will not be deleted. */ inline void SetTakePossesion( bool bTakePossession ); /** * \returns true if the buffer is owned by the PdfRefCountedBuffer * and is deleted along with it. */ inline bool TakePossesion() const; /** Compare to buffers. * \param rhs compare to this buffer * \returns true if both buffers contain the same contents */ bool operator==( const PdfRefCountedBuffer & rhs ) const; /** Compare to buffers. * \param rhs compare to this buffer * \returns true if this buffer is lexically littler than rhs */ bool operator<( const PdfRefCountedBuffer & rhs ) const; /** Compare to buffers. * \param rhs compare to this buffer * \returns true if this buffer is lexically greater than rhs */ bool operator>( const PdfRefCountedBuffer & rhs ) const; private: /** * Indicate that the buffer is no longer being used, freeing it if there * are no further users. The buffer becomes inaccessible to this * PdfRefCountedBuffer in either case. */ inline void DerefBuffer(); /** * Free a buffer if the refcount is zero. Internal method used by DerefBuffer. */ void FreeBuffer(); /** Detach from a shared buffer or do nothing if we are the only * one referencing the buffer. * * Call this function before any operation modifiying the buffer! * * \param lLen an additional parameter specifiying extra bytes * to be allocated to optimize allocations of a new buffer. */ inline void Detach( size_t lExtraLen = 0 ); /** * Called by Detach() to do the work if action is actually required. * \see Detach */ void ReallyDetach( size_t lExtraLen ); /** * Do the hard work of resizing the buffer if it turns out not to already be big enough. * \see Resize */ void ReallyResize( size_t lSize ); private: struct TRefCountedBuffer { enum { INTERNAL_BUFSIZE = 32 }; // Convenience inline for buffer switching PODOFO_NOTHROW inline char * GetRealBuffer() { return m_bOnHeap? m_pHeapBuffer : &(m_sInternalBuffer[0]); } // size in bytes of the buffer. If and only if this is strictly >INTERNAL_BUFSIZE, // this buffer is on the heap in memory pointed to by m_pHeapBuffer . If it is <=INTERNAL_BUFSIZE, // the buffer is in the in-object buffer m_sInternalBuffer. size_t m_lBufferSize; // Size in bytes of m_pBuffer that should be reported to clients. We // over-allocate on the heap for efficiency and have a minimum 32 byte // size, but this extra should NEVER be visible to a client. size_t m_lVisibleSize; long m_lRefCount; char* m_pHeapBuffer; char m_sInternalBuffer[INTERNAL_BUFSIZE]; bool m_bPossesion; // Are we using the heap-allocated buffer in place of our small internal one? bool m_bOnHeap; }; TRefCountedBuffer* m_pBuffer; }; // ----------------------------------------------------- // // ----------------------------------------------------- PdfRefCountedBuffer::PdfRefCountedBuffer() : m_pBuffer( NULL ) { } // ----------------------------------------------------- // // ----------------------------------------------------- PdfRefCountedBuffer::PdfRefCountedBuffer( size_t lSize ) : m_pBuffer( NULL ) { this->Resize( lSize ); } // ----------------------------------------------------- // // ----------------------------------------------------- // We define the copy ctor separately to the assignment // operator since it's a *LOT* faster this way. PdfRefCountedBuffer::PdfRefCountedBuffer( const PdfRefCountedBuffer & rhs ) : m_pBuffer( rhs.m_pBuffer ) { if (m_pBuffer) ++(m_pBuffer->m_lRefCount); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfRefCountedBuffer::~PdfRefCountedBuffer() { DerefBuffer(); } // ----------------------------------------------------- // // ----------------------------------------------------- inline char* PdfRefCountedBuffer::GetBuffer() const { if (!m_pBuffer) return NULL; return m_pBuffer->GetRealBuffer(); } // ----------------------------------------------------- // // ----------------------------------------------------- inline size_t PdfRefCountedBuffer::GetSize() const { return m_pBuffer ? m_pBuffer->m_lVisibleSize : 0; } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfRefCountedBuffer::SetTakePossesion( bool bTakePossession ) { if( m_pBuffer ) m_pBuffer->m_bPossesion = bTakePossession; } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfRefCountedBuffer::TakePossesion() const { return m_pBuffer ? m_pBuffer->m_bPossesion : false; } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfRefCountedBuffer::Detach( size_t lExtraLen ) { if (m_pBuffer && m_pBuffer->m_lRefCount > 1L) ReallyDetach(lExtraLen); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfRefCountedBuffer::Resize( size_t lSize ) { if (m_pBuffer && m_pBuffer->m_lRefCount == 1L && static_cast(m_pBuffer->m_lBufferSize) >= lSize) { // We have a solely owned buffer the right size already; no need to // waste any time detaching or resizing it. Just let the client see // more of it (or less if they're shrinking their view). m_pBuffer->m_lVisibleSize = lSize; } else { ReallyResize( lSize ); } } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfRefCountedBuffer::DerefBuffer() { if ( m_pBuffer && !(--m_pBuffer->m_lRefCount) ) FreeBuffer(); // Whether or not it still exists, we no longer have anything to do with // the buffer we just released our claim on. m_pBuffer = NULL; } }; #endif // _PDF_REF_COUNTED_BUFFER_H_ podofo-0.9.5/src/base/PdfParserObject.h0000664000175000017500000002264613012362162017560 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_PARSER_OBJECT_H_ #define _PDF_PARSER_OBJECT_H_ #include "PdfDefines.h" #include "PdfObject.h" #include "PdfTokenizer.h" namespace PoDoFo { class PdfEncrypt; class PdfParser; /** * A PdfParserObject constructs a PdfObject from a PDF file. * Parsing starts always at the current file position. */ class PODOFO_API PdfParserObject : public PdfObject, public PdfTokenizer { public: /** Parse the object data from the given file handle starting at * the current position. * \param pCreator pointer to a PdfVecObjects to resolve object references * \param rDevice an open reference counted input device which is positioned in * front of the object which is going to be parsed. * \param rBuffer buffer to use for parsing to avoid reallocations * \param lOffset the position in the device from which the object shall be read * if lOffset = -1, the object will be read from the current * position in the file. */ PdfParserObject( PdfVecObjects* pCreator, const PdfRefCountedInputDevice & rDevice, const PdfRefCountedBuffer & rBuffer, pdf_long lOffset = -1 ); /** Parse the object data for an internal object. * You have to call ParseDictionaryKeys as next function call. * * The following two parameters are used to avoid allocation of a new * buffer in PdfSimpleParser. * * \warning This constructor is for internal usage only! * * \param rBuffer buffer to use for parsing to avoid reallocations */ explicit PdfParserObject( const PdfRefCountedBuffer & rBuffer ); virtual ~PdfParserObject(); /** Parse the object data from the given file handle * If delayed loading is enabled, only the object and generation number * is read now and everything else is read later. * * \param pEncrypt an encryption dictionary which is used to decrypt * strings and streams during parsing or NULL if the PDF * file was not encrypted * \param bIsTrailer wether this is a trailer dictionary or not. * trailer dictionaries do not have a object number etc. */ void ParseFile( PdfEncrypt* pEncrypt, bool bIsTrailer = false ); /** Returns if this object has a stream object appended. * which has to be parsed. * \returns true if there is a stream */ inline bool HasStreamToParse() const; /** \returns true if this PdfParser loads all objects at * the time they are accessed for the first time. * The default is to load all object immediately. * In this case false is returned. */ inline bool IsLoadOnDemand() const; /** Sets wether this object shall be loaded on demand * when it's data is accessed for the first time. * \param bDelayed if true the object is loaded delayed. */ inline void SetLoadOnDemand( bool bDelayed ); /** Set the object number of this object. * It is almost never necessary to use this call. * It is only included for usage in the PdfParser. * * \param nObjNo the new object number of this object */ inline void SetObjectNumber( unsigned int nObjNo ); /** Tries to free all memory allocated by this * PdfObject (variables and streams) and reads * it from disk again if it is requested another time. * * This will only work if load on demand is used. * If the object is dirty if will not be free'd. * * \param bForce if true the object will be free'd * even if IsDirty() returns true. * So you will loose any changes made * to this object. * * \see IsLoadOnDemand * \see IsDirty */ void FreeObjectMemory( bool bForce = false ); /** Gets an offset in which the object beginning is stored in the file. * Note the offset points just after the object identificator ("0 0 obj"). * * \returns an offset in which the object is stored in the source device, * or -1, if the object was created on demand. */ inline pdf_int64 GetOffset( void ) const; protected: /** Load all data of the object if load object on demand is enabled. * Reimplemented from PdfVariant. Do not call this directly, use * DelayedLoad(). */ virtual void DelayedLoadImpl(); /** Load the stream of the object if it has one and if loading on demand is enabled. * Reimplemented from PdfObject. Do not call this directly, use * DelayedStreamLoad(). */ virtual void DelayedStreamLoadImpl(); /** Starts reading at the file position m_lStreamOffset and interprets all bytes * as contents of the objects stream. * It is assumed that the dictionary has a valid /Length key already. * * Called from DelayedStreamLoadImpl(). Do not call directly. */ void ParseStream(); private: /** Initialize private members in this object with their default values */ void InitPdfParserObject(); /** Parse the object data from the given file handle * \param bIsTrailer wether this is a trailer dictionary or not. * trailer dictionaries do not have a object number etc. */ void ParseFileComplete( bool bIsTrailer ); void ReadObjectNumber(); private: PdfEncrypt* m_pEncrypt; bool m_bIsTrailer; // Should the object try to defer loading of its contents until needed? // If false, object contents will be loaded during ParseFile(...). Note that // this still uses the delayed loading infrastructure. // If true, loading will be triggered the first time the information is needed by // an external caller. // Outside callers should not be able to tell the difference between the two modes // of operation. bool m_bLoadOnDemand; pdf_long m_lOffset; bool m_bStream; pdf_long m_lStreamOffset; }; // ----------------------------------------------------- // // ----------------------------------------------------- void PdfParserObject::SetObjectNumber( unsigned int nObjNo ) { m_reference.SetObjectNumber( nObjNo ); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfParserObject::IsLoadOnDemand() const { return m_bLoadOnDemand; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfParserObject::SetLoadOnDemand( bool bDelayed ) { m_bLoadOnDemand = bDelayed; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfParserObject::HasStreamToParse() const { return m_bStream; } // ----------------------------------------------------- // // ----------------------------------------------------- pdf_int64 PdfParserObject::GetOffset( void ) const { return static_cast(m_lOffset); } }; #endif // _PDF_PARSER_OBJECT_H_ podofo-0.9.5/src/base/PdfXRefStream.h0000664000175000017500000001332112344436402017211 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_XREF_STREAM_H_ #define _PDF_XREF_STREAM_H_ #include "PdfDefines.h" #include "PdfArray.h" #include "PdfXRef.h" namespace PoDoFo { class PdfOutputDevice; class PdfVecObjects; class PdfWriter; /** * Creates an XRef table that is a stream object. * Requires at least PDF 1.5. XRef streams are more * compact than normal XRef tables. * * This is an internal class of PoDoFo used by PdfWriter. */ class PdfXRefStream : public PdfXRef { public: /** Create a new XRef table * * \param pParent a vector of PdfObject is required * to create a PdfObject for the XRef * \param pWriter is needed to fill the trailer directory * correctly which is included into the XRef */ PdfXRefStream( PdfVecObjects* pParent, PdfWriter* pWriter ); /** Destruct the XRef table */ virtual ~PdfXRefStream(); /** * \returns the offset in the file at which the XRef table * starts after it was written */ inline virtual pdf_uint64 GetOffset() const; protected: /** Called at the start of writing the XRef table. * This method can be overwritten in subclasses * to write a general header for the XRef table. * * @param pDevice the output device to which the XRef table * should be written. */ virtual void BeginWrite( PdfOutputDevice* pDevice ); /** Begin an XRef subsection. * All following calls of WriteXRefEntry belong to this XRef subsection. * * @param pDevice the output device to which the XRef table * should be written. * @param nFirst the object number of the first object in this subsection * @param nCount the number of entries in this subsection */ virtual void WriteSubSection( PdfOutputDevice* pDevice, pdf_objnum nFirst, pdf_uint32 nCount ); /** Write a single entry to the XRef table * * @param pDevice the output device to which the XRef table * should be written. * @param offset the offset of the object * @param generation the generation number * @param cMode the mode 'n' for object and 'f' for free objects * @param objectNumber the object number of the currently written object if cMode = 'n' * otherwise undefined */ virtual void WriteXRefEntry( PdfOutputDevice* pDevice, pdf_uint64 offset, pdf_gennum generation, char cMode, pdf_objnum objectNumber = 0 ); /** Called at the end of writing the XRef table. * Sub classes can overload this method to finish a XRef table. * * @param pDevice the output device to which the XRef table * should be written. */ virtual void EndWrite( PdfOutputDevice* pDevice ); private: PdfVecObjects* m_pParent; PdfWriter* m_pWriter; PdfObject* m_pObject; PdfArray m_indeces; size_t m_bufferLen; ///< The length of the internal buffer for one XRef entry pdf_uint64 m_offset; ///< Offset of the XRefStream object }; // ----------------------------------------------------- // // ----------------------------------------------------- inline pdf_uint64 PdfXRefStream::GetOffset() const { return m_offset; } }; #endif /* _PDF_XREF_H_ */ podofo-0.9.5/src/base/PdfVecObjects.h0000664000175000017500000005177613012362162017232 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_VEC_OBJECTS_H_ #define _PDF_VEC_OBJECTS_H_ #include "PdfDefines.h" #include "PdfReference.h" #include namespace PoDoFo { class PdfDocument; class PdfObject; class PdfStream; class PdfVariant; // Use deque as many insertions are here way faster than with using std::list // This is especially useful for PDFs like PDFReference17.pdf with // lot's of free objects. typedef std::deque TPdfReferenceList; typedef TPdfReferenceList::iterator TIPdfReferenceList; typedef TPdfReferenceList::const_iterator TCIPdfReferenceList; typedef std::set TPdfReferenceSet; typedef TPdfReferenceSet::iterator TIPdfReferenceSet; typedef TPdfReferenceSet::const_iterator TCIPdfReferenceSet; typedef std::list TReferencePointerList; typedef TReferencePointerList::iterator TIReferencePointerList; typedef TReferencePointerList::const_iterator TCIReferencePointerList; typedef std::vector TVecReferencePointerList; typedef TVecReferencePointerList::iterator TIVecReferencePointerList; typedef TVecReferencePointerList::const_iterator TCIVecReferencePointerList; /* typedef std::vector TVecObjects; typedef TVecObjects::iterator TIVecObjects; typedef TVecObjects::const_iterator TCIVecObjects; */ typedef std::vector TVecObjects; typedef TVecObjects::iterator TIVecObjects; typedef TVecObjects::const_iterator TCIVecObjects; /** A STL vector of PdfObjects. I.e. a list of PdfObject classes. * The PdfParser will read the PdfFile into memory and create * a PdfVecObjects of all dictionaries found in the PDF file. * * The PdfWriter class contrary creates a PdfVecObjects internally * and writes it to a PDF file later with an appropriate table of * contents. * * These class contains also advanced funtions for searching of PdfObject's * in a PdfVecObject. */ class PODOFO_API PdfVecObjects { friend class PdfWriter; public: // An incomplete set of container typedefs, just enough to handle // the begin() and end() methods we wrap from the internal vector. // TODO: proper wrapper iterator class. typedef TVecObjects::iterator iterator; typedef TVecObjects::const_iterator const_iterator; /** Every observer of PdfVecObjects has to implement this interface. */ class PODOFO_API Observer { friend class PdfVecObjects; public: virtual ~Observer() { } virtual void WriteObject( const PdfObject* pObject ) = 0; /** * This method is called when the observed PdfVecObjects is delted. * * No more method may be called on the observable * after this method was called on the observer. */ virtual void ParentDestructed() = 0; /** Called whenever appending to a stream is started. * \param pStream the stream object the user currently writes to. */ virtual void BeginAppendStream( const PdfStream* pStream ) = 0; /** Called whenever appending to a stream has ended. * \param pStream the stream object the user currently writes to. */ virtual void EndAppendStream( const PdfStream* pStream ) = 0; virtual void Finish() = 0; }; /** This class is used to implement stream factories in PoDoFo. */ class PODOFO_API StreamFactory { public: virtual ~StreamFactory() { } /** Creates a stream object * * \param pParent parent object * * \returns a new stream object */ virtual PdfStream* CreateStream( PdfObject* pParent ) = 0; }; private: typedef std::vector TVecObservers; typedef TVecObservers::iterator TIVecObservers; typedef TVecObservers::const_iterator TCIVecObservers; public: /** Default constuctor */ PdfVecObjects(); virtual ~PdfVecObjects(); /** \returns a pointer to a PdfDocument that is the * parent of this vector. * Might be NULL if the vector has no parent. */ inline PdfDocument* GetParentDocument() const; /** Sets a parent document of this vector * \param pDocument the parent of this vector */ inline void SetParentDocument( PdfDocument* pDocument ); /** Enable/disable auto deletion. * By default auto deletion is disabled. * * \param bAutoDelete if true all objects will be deleted when the PdfVecObjects is * deleted. */ inline void SetAutoDelete( bool bAutoDelete ); /** * \returns if autodeletion is enabled and all objects will be deleted when the PdfVecObjects is * deleted. */ inline bool AutoDelete() const; /** Enable/disable object numbers re-use. * By default object numbers re-use is enabled. * * \param bCanReuseObjectNumbers if true, free object numbers can be re-used when creating new objects. * * If set to false, the list of free object numbers is automatically cleared. */ void SetCanReuseObjectNumbers( bool bCanReuseObjectNumbers ); /** * \returns whether can re-use free object numbers when creating new objects. */ inline bool GetCanReuseObjectNumbers() const; /** Removes all objects from the vector * and resets it to the default state. * * If SetAutoDelete is true all objects are deleted. * All observers are removed from the vector. * * \see SetAutoDelete * \see AutoDelete */ void Clear(); /** * \returns the size of the internal vector */ inline size_t GetSize() const; /** * \returns the highest object number in the vector */ size_t GetObjectCount() const { return m_nObjectCount; } /** Finds the object with the given reference in m_vecOffsets * and returns a pointer to it if it is found. * \param ref the object to be found * \returns the found object or NULL if no object was found. */ PdfObject* GetObject( const PdfReference & ref ) const; /** Finds the object with the given reference in m_vecOffsets * and returns the index to it. * \param ref the object to be found * \returns the found object or NULL if no object was found. */ size_t GetIndex( const PdfReference & ref ) const; /** Remove the object with the given object and generation number from the list * of objects. * The object is returned if it was found. Otherwise NULL is returned. * The caller has to delete the object by hisself. * * \param ref the object to be found * \param bMarkAsFree if true the removed object reference is marked as free object * you will always want to have this true * as invalid PDF files can be generated otherwise * \returns The removed object. */ PdfObject* RemoveObject( const PdfReference & ref, bool bMarkAsFree = true ); /** Remove the object with the iterator it from the vector and return it * \param it the object to remove * \returns the removed object */ PdfObject* RemoveObject( const TIVecObjects & it ); /** Creates a new object and inserts it into the vector. * This function assigns the next free object number to the PdfObject. * * \param pszType optionall value of the /Type key of the object * \returns PdfObject pointer to the new PdfObject */ PdfObject* CreateObject( const char* pszType = NULL ); /** Creates a new object (of type rVariants) and inserts it into the vector. * This function assigns the next free object number to the PdfObject. * * \param rVariant value of the PdfObject * \returns PdfObject pointer to the new PdfObject */ PdfObject* CreateObject( const PdfVariant & rVariant ); /** Mark a reference as unused so that it can be reused for new objects. * \param rReference the reference to reuse * * \see GetCanReuseObjectNumbers */ void AddFreeObject( const PdfReference & rReference ); /** \returns a list of free references in this vector */ inline const TPdfReferenceList & GetFreeObjects() const; /** * Renumbers all objects according to there current position in the vector. * All references remain intact. * Warning! This function is _very_ calculation intensive. * * \param pTrailer the trailer object * \param pNotDelete a list of object which must not be deleted * \param bDoGarbageCollection enable garbage collection, which deletes * all objects that are not reachable from the trailer. This might be slow! * * \see CollectGarbage */ void RenumberObjects( PdfObject* pTrailer, TPdfReferenceSet* pNotDelete = NULL, bool bDoGarbageCollection = false ); /** * \see insert_sorted * * Simple forward to insert sorted, as PdfVecObjects is always sorted. */ void push_back( PdfObject* pObj ); /** Insert an object into this vector so that * the vector remains sorted w.r.t. * the ordering based on object and generation numbers * m_bObjectCount will be increased for the object. * * \param pObj pointer to the object you want to insert */ void insert_sorted( PdfObject *pObj ); /** * Sort the objects in the vector based on their object and generation numbers */ void Sort(); /** * Causes the internal vector to reserve space for size elements. * \param size reserve space for that much elements in the internal vector */ inline void Reserve( size_t size ); /** Get a set with all references of objects that the passed object * depends on. * \param pObj the object to calculate all dependencies for * \param pList write the list of dependencies to this list * */ void GetObjectDependencies( const PdfObject* pObj, TPdfReferenceList* pList ) const; /** Attach a new observer * \param pObserver to attach */ inline void Attach( Observer* pObserver ); /** Detach an observer. * * \param pObserver observer to detach */ void Detach( Observer* pObserver ); /** Sets a StreamFactory which is used whenever CreateStream is called. * * \param pFactory a stream factory or NULL to reset to the default factory */ inline void SetStreamFactory( StreamFactory* pFactory ); /** Creates a stream object * This method is a factory for PdfStream objects. * * \param pParent parent object * * \returns a new stream object */ PdfStream* CreateStream( PdfObject* pParent ); /** Creates a stream object by copying an existing stream * * \param rhs copy this stream * * \returns a new stream object */ PdfStream* CreateStream( const PdfStream & rhs ); /** Can be called to force objects to be written to disk. * * \param pObject a PdfObject that should be written to disk. */ void WriteObject( PdfObject* pObject ); /** Call whenever a document is finished */ void Finish(); /** Every stream implementation has to call this in BeginAppend * \param pStream the stream object that is calling */ void BeginAppendStream( const PdfStream* pStream ); /** Every stream implementation has to call this in EndAppend * \param pStream the stream object that is calling */ void EndAppendStream( const PdfStream* pStream ); /** Iterator pointing at the begining of the vector * \returns beginning iterator */ inline TIVecObjects begin(); /** Iterator pointing at the begining of the vector * \returns beginning iterator */ inline TCIVecObjects begin() const; /** Iterator pointing at the end of the vector * \returns ending iterator */ inline TIVecObjects end(); /** Iterator pointing at the end of the vector * \returns ending iterator */ inline TCIVecObjects end() const; inline PdfObject*& operator[](size_t index); /** Get the last object in the vector * \returns the last object in the vector or NULL * if the vector is emtpy. */ inline PdfObject* GetBack(); /** * Deletes all objects that are not references by other objects * besides the trailer (which references the root dictionary, which in * turn should reference all other objects). * * \param pTrailer trailer object of the PDF * * Warning this might be slow! */ void CollectGarbage( PdfObject* pTrailer ); /** Get next unique subset-prefix * * \returns a string to use as subset-prefix. */ std::string GetNextSubsetPrefix(); /** * Set the object count so that the object described this reference * is contained in the object count. * * \param rRef reference of newly added object */ void SetObjectCount( const PdfReference & rRef ); private: /** * \returns the next free object reference */ PdfReference GetNextFreeObject(); /** * Create a list of all references that point to the object * for each object in this vector. * \param pList write all references to this list */ void BuildReferenceCountVector( TVecReferencePointerList* pList ); void InsertReferencesIntoVector( const PdfObject* pObj, TVecReferencePointerList* pList ); /** Assumes that the PdfVecObjects is sorted */ void InsertOneReferenceIntoVector( const PdfObject* pObj, TVecReferencePointerList* pList ); /** Delete all objects from the vector which do not have references to them selves * \param pList must be a list created by BuildReferenceCountVector * \param pTrailer must be the trailer object so that it is not deleted * \param pNotDelete a list of object which must not be deleted * \see BuildReferenceCountVector */ void GarbageCollection( TVecReferencePointerList* pList, PdfObject* pTrailer, TPdfReferenceSet* pNotDelete = NULL ); private: bool m_bAutoDelete; bool m_bCanReuseObjectNumbers; size_t m_nObjectCount; bool m_bSorted; TVecObjects m_vector; TVecObservers m_vecObservers; TPdfReferenceList m_lstFreeObjects; PdfDocument* m_pDocument; StreamFactory* m_pStreamFactory; std::string m_sSubsetPrefix; ///< Prefix for BaseFont and FontName of subsetted font }; // ----------------------------------------------------- // // ----------------------------------------------------- inline size_t PdfVecObjects::GetSize() const { return m_vector.size(); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfVecObjects::Reserve( size_t size ) { m_vector.reserve( size ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfDocument* PdfVecObjects::GetParentDocument() const { return m_pDocument; } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfVecObjects::SetParentDocument( PdfDocument* pDocument ) { m_pDocument = pDocument; } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfVecObjects::SetAutoDelete( bool bAutoDelete ) { m_bAutoDelete = bAutoDelete; } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfVecObjects::AutoDelete() const { return m_bAutoDelete; } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfVecObjects::GetCanReuseObjectNumbers() const { return m_bCanReuseObjectNumbers; } // ----------------------------------------------------- // // ----------------------------------------------------- inline const TPdfReferenceList & PdfVecObjects::GetFreeObjects() const { return m_lstFreeObjects; } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfVecObjects::Attach( Observer* pObserver ) { m_vecObservers.push_back( pObserver ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfVecObjects::SetStreamFactory( StreamFactory* pFactory ) { m_pStreamFactory = pFactory; } // ----------------------------------------------------- // // ----------------------------------------------------- inline TIVecObjects PdfVecObjects::begin() { return m_vector.begin(); } // ----------------------------------------------------- // // ----------------------------------------------------- inline TCIVecObjects PdfVecObjects::begin() const { return m_vector.begin(); } // ----------------------------------------------------- // // ----------------------------------------------------- inline TIVecObjects PdfVecObjects::end() { return m_vector.end(); } // ----------------------------------------------------- // // ----------------------------------------------------- inline TCIVecObjects PdfVecObjects::end() const { return m_vector.end(); } // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfObject* PdfVecObjects::GetBack() { return m_vector.back(); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfVecObjects::SetObjectCount( const PdfReference & rRef ) { if( rRef.ObjectNumber() >= m_nObjectCount ) // Peter Petrov 18 September 2008 { // This was a bug. //++m_nObjectCount; // In fact "m_bObjectCount" is used for the next free object number. // We need to use the greatest object number + 1 for the next free object number. // Otherwise, object number overlap would have occurred. m_nObjectCount = rRef.ObjectNumber() + 1; } } // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfObject*& PdfVecObjects::operator[](size_t index) { return m_vector[index]; } //inline PdfObject const * & PdfVecObjects::operator[](int index) const { return m_vector[index]; } }; #endif // _PDF_VEC_OBJECTS_H_ podofo-0.9.5/src/base/PdfEncodingFactory.h0000664000175000017500000002055512704763166020270 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_ENCODING_FACTORY_H_ #define _PDF_ENCODING_FACTORY_H_ #include "PdfDefines.h" #include "util/PdfMutex.h" #include "string.h" namespace PoDoFo { class PdfEncoding; class PdfDocEncoding; class PdfMacRomanEncoding; class PdfObject; class PdfWinAnsiEncoding; class PdfStandardEncoding; // OC 13.08.2010 class PdfMacExpertEncoding; // OC 13.08.2010 class PdfSymbolEncoding; // OC 13.08.2010 class PdfZapfDingbatsEncoding; // OC 13.08.2010 class PdfIdentityEncoding; class PdfWin1250Encoding; class PdfIso88592Encoding; /** This factory creates a PdfEncoding * from an existing object in the PDF. */ class PODOFO_API PdfEncodingFactory { public: /** Singleton method which returns a global instance * of PdfDocEncoding. * * \returns global instance of PdfDocEncoding */ static const PdfEncoding* GlobalPdfDocEncodingInstance(); /** Singleton method which returns a global instance * of WinAnsiEncoding. * * \returns global instance of WinAnsiEncoding * * \see GlobalWin1250EncodingInstance, GlobalIso88592EncodingInstance */ static const PdfEncoding* GlobalWinAnsiEncodingInstance(); /** Singleton method which returns a global instance * of MacRomanEncoding. * * \returns global instance of MacRomanEncoding */ static const PdfEncoding* GlobalMacRomanEncodingInstance(); // OC 13.08.2010: /** Singleton method which returns a global instance * of StandardEncoding. * * \returns global instance of StandardEncoding */ static const PdfEncoding* GlobalStandardEncodingInstance(); // OC 13.08.2010: /** Singleton method which returns a global instance * of MacExpertEncoding. * * \returns global instance of MacExpertEncoding */ static const PdfEncoding* GlobalMacExpertEncodingInstance(); // OC 13.08.2010: /** Singleton method which returns a global instance * of SymbolEncoding. * * \returns global instance of SymbolEncoding */ static const PdfEncoding* GlobalSymbolEncodingInstance(); // OC 13.08.2010: /** Singleton method which returns a global instance * of ZapfDingbatsEncoding. * * \returns global instance of ZapfDingbatsEncoding */ static const PdfEncoding* GlobalZapfDingbatsEncodingInstance(); /** Singleton method which returns a global instance * of IndentityEncoding useful for writing direct UTF8 strings. * * \returns global instance of IdentityEncoding */ static const PdfEncoding* GlobalIdentityEncodingInstance(); /** Singleton method which returns a global instance * of Win1250Encoding. * * \returns global instance of Win1250Encoding * * \see GlobalWinAnsiEncodingInstance, GlobalIso88592EncodingInstance */ static const PdfEncoding* GlobalWin1250EncodingInstance(); /** Singleton method which returns a global instance * of Iso88592Encoding. * * \returns global instance of Iso88592Encoding * * \see GlobalWinAnsiEncodingInstance, GlobalWin1250EncodingInstance */ static const PdfEncoding* GlobalIso88592EncodingInstance(); /** Free's the memory allocated by * the global encoding instancess in this singleton. * * PoDoFo will reallocated these encodings as soon * as they are needed again. * * Only call this method if no other class * of PoDoFo exists anymore, as PdfString etc * contain pointers to the global instances. * */ static void FreeGlobalEncodingInstances(); static void PoDoFoClientAttached(); private: // prohibit instantiating all-methods-static factory from outside PdfEncodingFactory(); /** Always use this static declaration, * if you need an instance of PdfDocEncoding * as heap allocation is expensive for PdfDocEncoding. */ static const PdfDocEncoding* s_pDocEncoding; /** Always use this static declaration, * if you need an instance of PdfWinAnsiEncoding * as heap allocation is expensive for PdfWinAnsiEncoding. */ static const PdfWinAnsiEncoding* s_pWinAnsiEncoding; /** Always use this static declaration, * if you need an instance of PdfWinAnsiEncoding * as heap allocation is expensive for PdfWinAnsiEncoding. */ static const PdfMacRomanEncoding* s_pMacRomanEncoding; // OC 13.08.2010: /** Always use this static declaration, * if you need an instance of StandardEncoding * as heap allocation is expensive for PdfStandardEncoding. */ static const PdfStandardEncoding* s_pStandardEncoding; // OC 13.08.2010: /** Always use this static declaration, * if you need an instance of MacExpertEncoding * as heap allocation is expensive for PdfMacExpertEncoding. */ static const PdfMacExpertEncoding* s_pMacExpertEncoding; // OC 13.08.2010: /** Always use this static declaration, * if you need an instance of SymbolEncoding * as heap allocation is expensive for PdfSymbolEncoding. */ static const PdfSymbolEncoding* s_pSymbolEncoding; // OC 13.08.2010: /** Always use this static declaration, * if you need an instance of ZapfDingbatsEncoding * as heap allocation is expensive for PdfZapfDingbatsEncoding. */ static const PdfZapfDingbatsEncoding* s_pZapfDingbatsEncoding; static const PdfIdentityEncoding *s_pIdentityEncoding; /** Always use this static declaration, * if you need an instance of PdfWin1250Encoding * as heap allocation is expensive for PdfWin1250Encoding. */ static const PdfWin1250Encoding* s_pWin1250Encoding; /** Always use this static declaration, * if you need an instance of PdfIso88592Encoding * as heap allocation is expensive for PdfIso88592Encoding. */ static const PdfIso88592Encoding* s_pIso88592Encoding; static Util::PdfMutex s_mutex; }; }; /* namespace PoDoFo */ #endif // _PDF_ENCODING_FACTORY_H__ podofo-0.9.5/src/base/PdfExtension.h0000664000175000017500000000630512340213643017145 0ustar dominikdominik/************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_EXTENSION_H_ #define _PDF_EXTENSION_H_ #include "podofo/base/PdfDefines.h" namespace PoDoFo { /** PdfExtension is a simple class that describes a vendor-specific extension to * the official specifications. */ class PODOFO_DOC_API PdfExtension { public: PdfExtension(const char* ns, EPdfVersion baseVersion, pdf_int64 level): _ns(ns), _baseVersion(baseVersion), _level(level) {} const std::string& getNamespace() const { return _ns; } EPdfVersion getBaseVersion() const { return _baseVersion; } pdf_int64 getLevel() const { return _level; } private: std::string _ns; EPdfVersion _baseVersion; pdf_int64 _level; }; } #endif // _PDF_EXTENSION_H_ podofo-0.9.5/src/base/PdfWriter.cpp0000664000175000017500000006364613017566505017025 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfWriter.h" #include "PdfData.h" #include "PdfDate.h" #include "PdfDictionary.h" //#include "PdfHintStream.h" #include "PdfObject.h" #include "PdfParser.h" #include "PdfParserObject.h" #include "PdfStream.h" #include "PdfVariant.h" #include "PdfXRef.h" #include "PdfXRefStream.h" #include "PdfDefinesPrivate.h" #define PDF_MAGIC "\xe2\xe3\xcf\xd3\n" // 10 spaces #define LINEARIZATION_PADDING " " #include #include namespace PoDoFo { PdfWriter::PdfWriter( PdfParser* pParser ) : m_bXRefStream( false ), m_pEncrypt( NULL ), m_pEncryptObj( NULL ), m_eWriteMode( ePdfWriteMode_Compact ), m_lPrevXRefOffset( 0 ), m_bIncrementalUpdate( false ), m_bLinearized( false ), m_lFirstInXRef( 0 ), m_lLinearizedOffset(0), m_lLinearizedLastOffset(0), m_lTrailerOffset(0) { if( !(pParser && pParser->GetTrailer()) ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } m_eVersion = pParser->GetPdfVersion(); m_pTrailer = new PdfObject( *(pParser->GetTrailer()) ); m_vecObjects = pParser->m_vecObjects; } PdfWriter::PdfWriter( PdfVecObjects* pVecObjects, const PdfObject* pTrailer ) : m_bXRefStream( false ), m_pEncrypt( NULL ), m_pEncryptObj( NULL ), m_eWriteMode( ePdfWriteMode_Compact ), m_lPrevXRefOffset( 0 ), m_bIncrementalUpdate( false ), m_bLinearized( false ), m_lFirstInXRef( 0 ), m_lLinearizedOffset(0), m_lLinearizedLastOffset(0), m_lTrailerOffset(0) { if( !pVecObjects || !pTrailer ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } m_eVersion = ePdfVersion_Default; m_pTrailer = new PdfObject( *pTrailer ); m_vecObjects = pVecObjects; } PdfWriter::PdfWriter( PdfVecObjects* pVecObjects ) : m_bXRefStream( false ), m_pEncrypt( NULL ), m_pEncryptObj( NULL ), m_eWriteMode( ePdfWriteMode_Compact ), m_lPrevXRefOffset( 0 ), m_bIncrementalUpdate( false ), m_bLinearized( false ), m_lFirstInXRef( 0 ), m_lLinearizedOffset(0), m_lLinearizedLastOffset(0), m_lTrailerOffset(0) { m_eVersion = ePdfVersion_Default; m_pTrailer = new PdfObject(); m_vecObjects = pVecObjects; } PdfWriter::~PdfWriter() { delete m_pTrailer; delete m_pEncrypt; m_pTrailer = NULL; m_vecObjects = NULL; } void PdfWriter::Write( const char* pszFilename ) { PdfOutputDevice device( pszFilename ); this->Write( &device ); } #ifdef _WIN32 void PdfWriter::Write( const wchar_t* pszFilename ) { PdfOutputDevice device( pszFilename ); this->Write( &device ); } #endif // _WIN32 void PdfWriter::Write( PdfOutputDevice* pDevice ) { this->Write( pDevice, false ); } void PdfWriter::Write( PdfOutputDevice* pDevice, bool bRewriteXRefTable ) { CreateFileIdentifier( m_identifier, m_pTrailer, &m_originalIdentifier ); if( !pDevice ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } // setup encrypt dictionary if( m_pEncrypt ) { m_pEncrypt->GenerateEncryptionKey( m_identifier ); // Add our own Encryption dictionary m_pEncryptObj = m_vecObjects->CreateObject(); m_pEncrypt->CreateEncryptionDictionary( m_pEncryptObj->GetDictionary() ); } if( m_bLinearized ) { if( m_bIncrementalUpdate ) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Cannot write an incremental update as a linearized document." ); this->WriteLinearized( pDevice ); } else { PdfXRef* pXRef = m_bXRefStream ? new PdfXRefStream( m_vecObjects, this ) : new PdfXRef(); try { if( !m_bIncrementalUpdate ) WritePdfHeader( pDevice ); WritePdfObjects( pDevice, *m_vecObjects, pXRef, bRewriteXRefTable ); if( m_bIncrementalUpdate ) pXRef->SetFirstEmptyBlock(); pXRef->Write( pDevice ); // XRef streams contain the trailer in the XRef if( !m_bXRefStream ) { PdfObject trailer; // if we have a dummy offset we write also a prev entry to the trailer FillTrailerObject( &trailer, pXRef->GetSize(), false ); pDevice->Print("trailer\n"); trailer.WriteObject( pDevice, m_eWriteMode, NULL ); // Do not encrypt the trailer dictionary!!! } pDevice->Print( "startxref\n%li\n%%%%EOF\n", pXRef->GetOffset() ); delete pXRef; } catch( PdfError & e ) { // Make sure pXRef is always deleted delete pXRef; // P.Zent: Delete Encryption dictionary (cannot be reused) if(m_pEncryptObj) { m_vecObjects->RemoveObject(m_pEncryptObj->Reference()); delete m_pEncryptObj; } e.AddToCallstack( __FILE__, __LINE__ ); throw e; } } // P.Zent: Delete Encryption dictionary (cannot be reused) if(m_pEncryptObj) { m_vecObjects->RemoveObject(m_pEncryptObj->Reference()); delete m_pEncryptObj; } } void PdfWriter::WriteUpdate( PdfOutputDevice* pDevice, PdfInputDevice* pSourceInputDevice, bool bRewriteXRefTable ) { if( !pDevice ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } // make sure it's set that this is an incremental update m_bIncrementalUpdate = true; // the source device can be NULL, then the output device // is positioned at the end of the original file by the caller if( pSourceInputDevice ) { // copy the original file content first unsigned int uBufferLen = 65535; char *pBuffer; while( pBuffer = reinterpret_cast( podofo_malloc( sizeof( char ) * uBufferLen) ), !pBuffer ) { uBufferLen = uBufferLen / 2; if( !uBufferLen ) break; } if( !pBuffer ) PODOFO_RAISE_ERROR (ePdfError_OutOfMemory); try { pSourceInputDevice->Seek(0); while( !pSourceInputDevice->Eof() ) { std::streamoff didRead; didRead = pSourceInputDevice->Read( pBuffer, uBufferLen ); if( didRead > 0) pDevice->Write( pBuffer, didRead ); } podofo_free( pBuffer ); } catch( PdfError & e ) { podofo_free( pBuffer ); throw e; } } // then write the changes this->Write (pDevice, bRewriteXRefTable ); } void PdfWriter::WriteLinearized( PdfOutputDevice* /* pDevice */ ) { PODOFO_RAISE_ERROR( ePdfError_NotImplemented ); /* PdfObject* pLinearize = NULL; PdfPage* pPage; PdfObject* pLast; NonPublic::PdfHintStream* pHint; PdfOutputDevice length; TVecXRefTable vecXRef; TVecXRefOffset vecXRefOffset; TIVecOffsets it; // prepare the document for linearization this->FetchPagesTree(); pPage = m_pPagesTree->GetPage( 0 ); pLinearize = CreateLinearizationDictionary(); pHint = new NonPublic::PdfHintStream( m_vecObjects, m_pPagesTree ); this->ReorderObjectsLinearized( pLinearize, pHint, pPage, &pLast ); // The file is prepared for linearization, // so write it now. WritePdfHeader( pDevice ); m_lLinearizedOffset = pDevice->GetLength(); pLinearize->WriteObject( pDevice ); // fill the XRef table with the objects { // Use nested scope and stack local for PdfOutputDevice // rather than using a temporary to stop gcc's whining. PdfOutputDevice o; WritePdfObjects(&o, m_vecLinearized, &vecXRef ); } // prepend the linearization dictionary to the XRef table TXRefEntry entry; entry.lOffset = m_lLinearizedOffset; entry.lGeneration = pLinearize->Reference().GenerationNumber(); entry.cUsed = 'n'; vecXRef[0].nCount++; vecXRef[0].nFirst--; vecXRef[0].vecOffsets.insert( vecXRef[0].vecOffsets.begin(), entry ); // Calculate the length of the xref table WritePdfTableOfContents( &vecXRef, &length, &vecXRefOffset, true, false ); it = vecXRef[0].vecOffsets.begin(); it++; // skip the linearization dictionary, as it was written before the XRef table // and does already have a correct offset while( it != vecXRef[0].vecOffsets.end() ) { (*it).lOffset += pDevice->GetLength() + length.GetLength(); m_lLinearizedLastOffset = (*it).lOffset; ++it; } vecXRefOffset.clear(); WritePdfTableOfContents( &vecXRef, pDevice, &vecXRefOffset, true, false ); vecXRef.clear(); WritePdfObjects( pDevice, m_vecLinearized, &vecXRef ); vecXRef.clear(); WritePdfObjects( pDevice, *m_vecObjects, &vecXRef ); if( m_bXRefStream ) WriteXRefStream( &vecXRef, pDevice ); else WritePdfTableOfContents( &vecXRef, pDevice, &vecXRefOffset, false, m_bLinearized ); this->FillLinearizationDictionary( pLinearize, pDevice, pPage, pLast, pHint, &vecXRefOffset ); */ } void PdfWriter::WritePdfHeader( PdfOutputDevice* pDevice ) { pDevice->Print( "%s\n%%%s", s_szPdfVersions[static_cast(m_eVersion)], PDF_MAGIC ); } void PdfWriter::WritePdfObjects( PdfOutputDevice* pDevice, const PdfVecObjects& vecObjects, PdfXRef* pXref, bool bRewriteXRefTable ) { TCIVecObjects itObjects, itObjectsEnd = vecObjects.end(); for( itObjects = vecObjects.begin(); itObjects != itObjectsEnd; ++itObjects ) { PdfObject *pObject = *itObjects; if( m_bIncrementalUpdate ) { if( !pObject->IsDirty() ) { bool canSkip = !bRewriteXRefTable; if( bRewriteXRefTable ) { const PdfParserObject *parserObject = dynamic_cast(pObject); // the reference looks like "0 0 R", while the object identifier like "0 0 obj", thus add two letters int objRefLength = pObject->Reference().ToString().length() + 2; // the offset points just after the "0 0 obj" string if( parserObject && parserObject->GetOffset() - objRefLength > 0) { pXref->AddObject( pObject->Reference(), parserObject->GetOffset() - objRefLength, true ); canSkip = true; } } if( canSkip ) continue; } } pXref->AddObject( pObject->Reference(), pDevice->Tell(), true ); // Make sure that we do not encrypt the encryption dictionary! pObject->WriteObject( pDevice, m_eWriteMode, (pObject == m_pEncryptObj ? NULL : m_pEncrypt) ); } TCIPdfReferenceList itFree, itFreeEnd = vecObjects.GetFreeObjects().end(); for( itFree = vecObjects.GetFreeObjects().begin(); itFree != itFreeEnd; ++itFree ) { pXref->AddObject( *itFree, 0, false ); } } void PdfWriter::GetByteOffset( PdfObject* pObject, pdf_long* pulOffset ) { TCIVecObjects it = m_vecObjects->begin(); PdfOutputDevice deviceHeader; if( !pObject || !pulOffset ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } this->WritePdfHeader( &deviceHeader ); *pulOffset = deviceHeader.GetLength(); while( it != m_vecObjects->end() ) { if( (*it) == pObject ) break; *pulOffset += (*it)->GetObjectLength( m_eWriteMode ); ++it; } } void PdfWriter::WriteToBuffer( char** ppBuffer, pdf_long* pulLen ) { PdfOutputDevice device; if( !pulLen ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } this->Write( &device ); *pulLen = device.GetLength(); *ppBuffer = static_cast(podofo_calloc( *pulLen, sizeof(char) )); if( !*ppBuffer ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } PdfOutputDevice memDevice( *ppBuffer, *pulLen ); this->Write( &memDevice ); } /* PdfObject* PdfWriter::CreateLinearizationDictionary() { PdfObject* pLinearize = m_vecObjects->CreateObject(); // This will be overwritten later with valid data! PdfVariant place_holder( PdfData( LINEARIZATION_PADDING ) ); PdfArray array; array.push_back( place_holder ); array.push_back( place_holder ); pLinearize->GetDictionary().AddKey( "Linearized", 1.0 ); // Version pLinearize->GetDictionary().AddKey( "L", place_holder ); // File length pLinearize->GetDictionary().AddKey( "H", array ); // Hint stream offset and length as PdfArray pLinearize->GetDictionary().AddKey( "E", place_holder ); // Offset of end of first page pLinearize->GetDictionary().AddKey( "N", // Number of pages in the document static_cast(m_pPagesTree->GetTotalNumberOfPages()) ); pLinearize->GetDictionary().AddKey( "O", place_holder ); // Object number of the first page pLinearize->GetDictionary().AddKey( "T", place_holder ); // Offset of first entry in main cross reference table return pLinearize; }*/ /* void PdfWriter::ReorderObjectsLinearized( PdfObject* pLinearize, NonPublic::PdfHintStream* pHint, PdfPage* pPage, PdfObject** ppLast ) { TPdfReferenceList lstLinearizedGroup; TPdfReferenceSet setLinearizedGroup; TCIPdfReferenceList it; TIVecObjects itObjects; PdfObject* pRoot; PdfObject* pTmp = NULL; size_t index, i; // get the dependend objects that are required to display // the first page. I.e. get all objects that have to be written // at the start of the file. // Add all depencies to lstLinearizedGroup m_vecObjects->GetObjectDependencies( pPage->GetObject(), &lstLinearizedGroup ); // get the root dictionary, it has to be written at the top of the file too. pRoot = m_vecObjects->GetObject( m_pTrailer->GetDictionary().GetKey( "Root" )->GetReference() ); // add the root dictionary lstLinearizedGroup.push_back( pRoot->Reference() ); // add the first page itself lstLinearizedGroup.push_back( pPage->GetObject()->Reference() ); // add several dependencies of the root dictionary this->FindCatalogDependencies( pRoot, "ViewerPreferences", &lstLinearizedGroup, true ); this->FindCatalogDependencies( pRoot, "PageMode", &lstLinearizedGroup, true ); this->FindCatalogDependencies( pRoot, "Threads", &lstLinearizedGroup, false ); this->FindCatalogDependencies( pRoot, "OpenAction", &lstLinearizedGroup, true ); this->FindCatalogDependencies( pRoot, "AcroForm", &lstLinearizedGroup, false ); this->FindCatalogDependencies( pRoot, "Encrypt", &lstLinearizedGroup, true ); // add the hint stream lstLinearizedGroup.push_back( pHint->GetObject()->Reference() ); // add the linearization dictionary lstLinearizedGroup.push_back( pLinearize->Reference() ); // move all objects which are required to display the first page // at the front of the vector of objects. // We only swap objects inside of the vector to avoid reallocations. // This is a fast operation therefore i = m_vecObjects->GetSize()-1; it = lstLinearizedGroup.begin(); while( it != lstLinearizedGroup.end() ) { index = m_vecObjects->GetIndex( *it ); if( index < i ) { pTmp = (*m_vecObjects)[index]; (*m_vecObjects)[index] = (*m_vecObjects)[i]; (*m_vecObjects)[i] = pTmp; } i--; ++it; } // Renumber all objects according to their position in the vector. // This is the slowest (only slow) operation when creating a // linearized PDF file. Garbage collection goes along with this step. std::copy( lstLinearizedGroup.begin(), lstLinearizedGroup.end(), std::inserter(setLinearizedGroup, setLinearizedGroup.begin()) ); m_vecObjects->RenumberObjects( m_pTrailer, &setLinearizedGroup ); // reorder the objects in the file itObjects = m_vecObjects->begin(); itObjects += m_vecObjects->GetSize() - setLinearizedGroup.size(); m_vecObjects->RemoveObject( itObjects ); while( itObjects != m_vecObjects->end() ) { m_vecLinearized.push_back( *itObjects ); // reset the owner (*itObjects)->SetOwner( m_vecObjects ); m_vecObjects->RemoveObject( itObjects ); } *ppLast = m_vecLinearized.GetBack(); }*/ /* void PdfWriter::FindCatalogDependencies( PdfObject* pCatalog, const PdfName & rName, TPdfReferenceList* pList, bool bWithDependencies ) { if( pCatalog->GetDictionary().HasKey( rName ) && pCatalog->GetDictionary().GetKey( rName )->IsReference() ) { if( bWithDependencies ) m_vecObjects->GetObjectDependencies( pCatalog->GetIndirectKey( rName ), pList ); else pList->push_back( pCatalog->GetIndirectKey( rName )->Reference() ); } }*/ void PdfWriter::FillTrailerObject( PdfObject* pTrailer, pdf_long lSize, bool bOnlySizeKey ) const { pTrailer->GetDictionary().AddKey( PdfName::KeySize, static_cast(lSize) ); if( !bOnlySizeKey ) { if( m_pTrailer->GetDictionary().HasKey( "Root" ) ) pTrailer->GetDictionary().AddKey( "Root", m_pTrailer->GetDictionary().GetKey( "Root" ) ); /* DominikS: It makes no sense to simple copy an encryption key Either we have no encryption or we encrypt again by ourselves if( m_pTrailer->GetDictionary().HasKey( "Encrypt" ) ) pTrailer->GetDictionary().AddKey( "Encrypt", m_pTrailer->GetDictionary().GetKey( "Encrypt" ) ); */ if( m_pTrailer->GetDictionary().HasKey( "Info" ) ) pTrailer->GetDictionary().AddKey( "Info", m_pTrailer->GetDictionary().GetKey( "Info" ) ); if( m_pEncryptObj ) pTrailer->GetDictionary().AddKey( PdfName("Encrypt"), m_pEncryptObj->Reference() ); PdfArray array; // The ID is the same unless the PDF was incrementally updated if( m_bIncrementalUpdate && m_originalIdentifier.IsValid() && m_originalIdentifier.GetLength() > 0 ) { array.push_back( m_originalIdentifier ); } else { array.push_back( m_identifier ); } array.push_back( m_identifier ); // finally add the key to the trailer dictionary pTrailer->GetDictionary().AddKey( "ID", array ); if( m_lPrevXRefOffset > 0 ) { PdfVariant value( m_lPrevXRefOffset ); pTrailer->GetDictionary().AddKey( "Prev", value ); } } } /* void PdfWriter::FetchPagesTree() { if( !m_pPagesTree ) { // try to find the pages tree PdfObject* pRoot = m_pTrailer->GetDictionary().GetKey( "Root" ); if( !pRoot || !pRoot->IsReference() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } //printf("Fetching: %lu\n", pRoot->GetReference().ObjectNumber() ); //printf("Size : %i\n", static_cast(m_vecObjects->GetSize()) ); pRoot = m_vecObjects->GetObject( pRoot->GetReference() ); if( !pRoot ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } m_pPagesTree = new PdfPagesTree( pRoot->GetIndirectKey( "Pages" ) ); } } */ /* void PdfWriter::FillLinearizationDictionary( PdfObject* pLinearize, PdfOutputDevice* pDevice, PdfPage* pPage, PdfObject* pLast, NonPublic::PdfHintStream* pHint, TVecXRefOffset* pVecXRefOffset ) { long lFileSize = pDevice->GetLength(); PdfVariant value( 0l ); PdfArray hints; PdfObject trailer; value.SetPaddingLength( LINEARIZATION_PADDING ); value.SetNumber( lFileSize ); pLinearize->GetDictionary().AddKey( "L", value ); value.SetNumber( pPage->GetObject()->Reference().ObjectNumber() ); pLinearize->GetDictionary().AddKey( "O", value ); value.SetNumber( m_lFirstInXRef ); pLinearize->GetDictionary().AddKey( "T", value ); value.SetNumber( m_lLinearizedLastOffset + pLast->GetObjectLength() ); pLinearize->GetDictionary().AddKey( "E", value ); value.SetNumber( m_lLinearizedOffset + pLinearize->GetObjectLength() ); hints.push_back( value ); value.SetNumber( pHint->GetObject()->GetObjectLength() ); hints.push_back( value ); pLinearize->GetDictionary().AddKey( "H", hints ); pDevice->Seek( m_lLinearizedOffset ); pLinearize->WriteObject( pDevice ); pDevice->Seek( lFileSize ); m_lPrevXRefOffset = pVecXRefOffset->back(); FillTrailerObject( &trailer, pLast->Reference().ObjectNumber()+1, false ); pDevice->Seek( m_lTrailerOffset ); trailer.WriteObject( pDevice ); pDevice->Seek( lFileSize ); } */ void PdfWriter::CreateFileIdentifier( PdfString & identifier, const PdfObject* pTrailer, PdfString* pOriginalIdentifier ) const { PdfOutputDevice length; PdfObject* pInfo; char* pBuffer; bool bOriginalIdentifierFound = false; if( pOriginalIdentifier && pTrailer->GetDictionary().HasKey( "ID" )) { const PdfObject* idObj = pTrailer->GetDictionary().GetKey("ID"); TCIVariantList it = idObj->GetArray().begin(); if( it != idObj->GetArray().end() && it->GetDataType() == ePdfDataType_HexString ) { PdfVariant var = (*it); *pOriginalIdentifier = var.GetString(); bOriginalIdentifierFound = true; } } // create a dictionary with some unique information. // This dictionary is based on the PDF files information // dictionary if it exists. if( pTrailer->GetDictionary().HasKey("Info") ) { const PdfReference & rRef = pTrailer->GetDictionary().GetKey( "Info" )->GetReference(); const PdfObject* pObj = m_vecObjects->GetObject( rRef ); if( pObj ) { pInfo = new PdfObject( *pObj ); } else { std::ostringstream oss; oss << "Error while retrieving info dictionary: " << rRef.ObjectNumber() << " " << rRef.GenerationNumber() << " R" << std::endl; PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, oss.str().c_str() ); } } else { PdfDate date; PdfString dateString; date.ToString( dateString ); pInfo = new PdfObject(); pInfo->GetDictionary().AddKey( "CreationDate", dateString ); pInfo->GetDictionary().AddKey( "Creator", PdfString("PoDoFo") ); pInfo->GetDictionary().AddKey( "Producer", PdfString("PoDoFo") ); } pInfo->GetDictionary().AddKey( "Location", PdfString("SOMEFILENAME") ); pInfo->WriteObject( &length, m_eWriteMode, NULL ); pBuffer = static_cast(podofo_calloc( length.GetLength(), sizeof(char) )); if( !pBuffer ) { delete pInfo; PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } PdfOutputDevice device( pBuffer, length.GetLength() ); pInfo->WriteObject( &device, m_eWriteMode, NULL ); // calculate the MD5 Sum identifier = PdfEncryptMD5Base::GetMD5String( reinterpret_cast(pBuffer), static_cast(length.GetLength()) ); podofo_free( pBuffer ); delete pInfo; if( pOriginalIdentifier && !bOriginalIdentifierFound ) *pOriginalIdentifier = identifier; } void PdfWriter::SetEncrypted( const PdfEncrypt & rEncrypt ) { delete m_pEncrypt; m_pEncrypt = PdfEncrypt::CreatePdfEncrypt( rEncrypt ); } }; podofo-0.9.5/src/base/PdfString.cpp0000664000175000017500000011526713013650710017000 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfString.h" #include "PdfEncrypt.h" #include "PdfEncoding.h" #include "PdfEncodingFactory.h" #include "PdfFilter.h" #include "PdfTokenizer.h" #include "PdfOutputDevice.h" #include "PdfDefinesPrivate.h" #if defined(_AIX) || defined(__sun) #include #elif defined(__APPLE__) || defined(__linux) #include #elif defined(_WIN32) #include #endif #include #include #include namespace PoDoFo { namespace PdfStringNameSpace { static char g_StrEscMap[256] = { 0 }; // Generate the escape character map at runtime static const char* genStrEscMap() { const long lAllocLen = 256; char* map = static_cast(g_StrEscMap); memset( map, 0, sizeof(char) * lAllocLen ); map[static_cast('\n')] = 'n'; // Line feed (LF) map[static_cast('\r')] = 'r'; // Carriage return (CR) map[static_cast('\t')] = 't'; // Horizontal tab (HT) map[static_cast('\b')] = 'b'; // Backspace (BS) map[static_cast('\f')] = 'f'; // Form feed (FF) map[static_cast(')')] = ')'; map[static_cast('(')] = '('; map[static_cast('\\')] = '\\'; return map; } }; const char * const PdfString::m_escMap = PdfStringNameSpace::genStrEscMap(); const PdfString PdfString::StringNull = PdfString(); #ifdef _MSC_VER const char PdfString::s_pszUnicodeMarker[] = { static_cast(0xFE), static_cast(0xFF) }; #else const char PdfString::s_pszUnicodeMarker[] = { static_cast(0xFE), static_cast(0xFF) }; #endif const char* PdfString::s_pszUnicodeMarkerHex = "FEFF"; PdfString::PdfString() : m_bHex( false ), m_bUnicode( false ), m_pEncoding( NULL ) { } PdfString::PdfString( const std::string& sString, const PdfEncoding * const pEncoding ) : m_bHex( false ), m_bUnicode( false ), m_pEncoding( pEncoding ) { Init( sString.c_str(), sString.length() ); } PdfString::PdfString( const char* pszString, const PdfEncoding * const pEncoding ) : m_bHex( false ), m_bUnicode( false ), m_pEncoding( pEncoding ) { if( pszString ) Init( pszString, strlen( pszString ) ); } #if defined(_MSC_VER) && _MSC_VER <= 1200 // not for MS Visual Studio 6 #else PdfString::PdfString( const wchar_t* pszString, pdf_long lLen ) { setFromWchar_t(pszString, lLen); } #endif void PdfString::setFromWchar_t(const wchar_t* pszString, pdf_long lLen ) { m_bHex = false; m_bUnicode = true; m_pEncoding = NULL; if( pszString ) { if (lLen == -1) { lLen = wcslen( pszString ); } if( sizeof(wchar_t) == 2 ) { // We have UTF16 lLen *= sizeof(wchar_t); m_buffer = PdfRefCountedBuffer( lLen + 2 ); memcpy( m_buffer.GetBuffer(), pszString, lLen ); m_buffer.GetBuffer()[lLen] = '\0'; m_buffer.GetBuffer()[lLen+1] = '\0'; // if the buffer is a UTF-16LE string // convert it to UTF-16BE #ifdef PODOFO_IS_LITTLE_ENDIAN SwapBytes( m_buffer.GetBuffer(), lLen ); #endif // PODOFO_IS_LITTLE_ENDIA } else { // Try to convert to UTF8 pdf_long lDest = 5 * lLen; // At max 5 bytes per UTF8 char char* pDest = static_cast(podofo_malloc( lDest )); if (!pDest) { PODOFO_RAISE_ERROR(ePdfError_OutOfMemory); } size_t cnt = wcstombs(pDest, pszString, lDest); if( cnt != static_cast(-1) ) { // No error InitFromUtf8( reinterpret_cast(pDest), cnt ); podofo_free( pDest ); } else { podofo_free( pDest ); PdfError e( ePdfError_InternalLogic, __FILE__, __LINE__ ); e.SetErrorInformation( pszString ); throw e; } } } } PdfString::PdfString( const char* pszString, pdf_long lLen, bool bHex, const PdfEncoding * const pEncoding ) : m_bHex( bHex ), m_bUnicode( false ), m_pEncoding( pEncoding ) { if( pszString ) Init( pszString, lLen ); } PdfString::PdfString( const pdf_utf8* pszStringUtf8 ) : m_bHex( false ), m_bUnicode( true ), m_pEncoding( NULL ) { InitFromUtf8( pszStringUtf8, strlen( reinterpret_cast(pszStringUtf8) ) ); m_sUtf8 = reinterpret_cast(pszStringUtf8); } PdfString::PdfString( const pdf_utf8* pszStringUtf8, pdf_long lLen ) : m_bHex( false ), m_bUnicode( true ), m_pEncoding( NULL ) { InitFromUtf8( pszStringUtf8, lLen ); m_sUtf8.assign( reinterpret_cast(pszStringUtf8), lLen ); } PdfString::PdfString( const pdf_utf16be* pszStringUtf16 ) : m_bHex( false ), m_bUnicode( true ), m_pEncoding( NULL ) { pdf_long lBufLen = 0; const pdf_utf16be* pszCnt = pszStringUtf16; while( *pszCnt ) { ++pszCnt; ++lBufLen; } lBufLen *= sizeof(pdf_utf16be); m_buffer = PdfRefCountedBuffer( lBufLen + sizeof(pdf_utf16be) ); memcpy( m_buffer.GetBuffer(), reinterpret_cast(pszStringUtf16), lBufLen ); m_buffer.GetBuffer()[lBufLen] = '\0'; m_buffer.GetBuffer()[lBufLen+1] = '\0'; } PdfString::PdfString( const pdf_utf16be* pszStringUtf16, pdf_long lLen ) : m_bHex( false ), m_bUnicode( true ), m_pEncoding( NULL ) { pdf_long lBufLen = 0; const pdf_utf16be* pszCnt = pszStringUtf16; while( lLen-- ) { ++pszCnt; ++lBufLen; } lBufLen *= sizeof(pdf_utf16be); m_buffer = PdfRefCountedBuffer( lBufLen + sizeof(pdf_utf16be) ); memcpy( m_buffer.GetBuffer(), reinterpret_cast(pszStringUtf16), lBufLen ); m_buffer.GetBuffer()[lBufLen] = '\0'; m_buffer.GetBuffer()[lBufLen+1] = '\0'; } PdfString::PdfString( const PdfString & rhs ) : PdfDataType(), m_bHex( false ), m_bUnicode( false ), m_pEncoding( NULL ) { this->operator=( rhs ); } PdfString::~PdfString() { } void PdfString::SetHexData( const char* pszHex, pdf_long lLen, PdfEncrypt* pEncrypt ) { AssertMutable(); if( !pszHex ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if( lLen == -1 ) lLen = strlen( pszHex ); // Allocate a buffer large enough for the hex decoded data // and the 2 terminating zeros m_buffer = PdfRefCountedBuffer( lLen % 2 ? ((lLen + 1) >> 1) + 2 : (lLen >> 1) + 2 ); m_bHex = true; char* pBuffer = m_buffer.GetBuffer(); if ( pBuffer != NULL ) { char val; char cDecodedByte = 0; bool bLow = true; while( lLen-- ) { if( PdfTokenizer::IsWhitespace( *pszHex ) ) { ++pszHex; continue; } val = PdfTokenizer::GetHexValue( *pszHex ); if( bLow ) { cDecodedByte = (val & 0x0F); bLow = false; } else { cDecodedByte = ((cDecodedByte << 4) | val); bLow = true; *pBuffer++ = cDecodedByte; } ++pszHex; } if( !bLow ) { // an odd number of bytes was read, // so the last byte is 0 *pBuffer++ = cDecodedByte; } *pBuffer++ = '\0'; *pBuffer++ = '\0'; // If the allocated internal buffer is too big (e.g. because of whitespaces in the data) // copy to a smaller buffer so that PdfString::GetLength() will be correct lLen = pBuffer - m_buffer.GetBuffer(); if( static_cast(lLen) != m_buffer.GetSize() ) { PdfRefCountedBuffer temp( lLen ); memcpy( temp.GetBuffer(), m_buffer.GetBuffer(), lLen ); m_buffer = temp; } } if( pEncrypt ) { pdf_long outBufferLen = m_buffer.GetSize() - 2 - pEncrypt->CalculateStreamOffset(); PdfRefCountedBuffer outBuffer(outBufferLen + 16 - (outBufferLen % 16)); pEncrypt->Decrypt( reinterpret_cast(m_buffer.GetBuffer()), static_cast(m_buffer.GetSize()-2), reinterpret_cast(outBuffer.GetBuffer()), outBufferLen); // Add trailing pair of zeros outBuffer.Resize(outBufferLen + 2); outBuffer.GetBuffer()[outBufferLen] = '\0'; outBuffer.GetBuffer()[outBufferLen + 1] = '\0'; // Replace buffer with decrypted value m_buffer = outBuffer; } // Now check for the first two bytes, to see if we got a unicode string if( m_buffer.GetSize() > 4 ) { m_bUnicode = (m_buffer.GetBuffer()[0] == static_cast(0xFE) && m_buffer.GetBuffer()[1] == static_cast(0xFF)); if( m_bUnicode ) { PdfRefCountedBuffer temp( m_buffer.GetSize() - 2 ); memcpy( temp.GetBuffer(), m_buffer.GetBuffer() + 2, m_buffer.GetSize() - 2 ); m_buffer = temp; } } } void PdfString::Write ( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, const PdfEncrypt* pEncrypt ) const { // Strings in PDF documents may contain \0 especially if they are encrypted // this case has to be handled! // Peter Petrov: 17 May 2008 // Added check - m_buffer.GetSize() // Now we are not encrypting the empty strings (was access violation)! if( pEncrypt && m_buffer.GetSize() && IsValid() ) { pdf_long nInputBufferLen = m_buffer.GetSize() - 2; // Cut off the trailing pair of zeros pdf_long nUnicodeMarkerOffet = sizeof( PdfString::s_pszUnicodeMarker ); if( m_bUnicode ) nInputBufferLen += nUnicodeMarkerOffet; char * pInputBuffer = new char[nInputBufferLen]; if( m_bUnicode ) { memcpy(pInputBuffer, PdfString::s_pszUnicodeMarker, nUnicodeMarkerOffet); memcpy(&pInputBuffer[nUnicodeMarkerOffet], m_buffer.GetBuffer(), nInputBufferLen - nUnicodeMarkerOffet); } else memcpy(pInputBuffer, m_buffer.GetBuffer(), nInputBufferLen); pdf_long nOutputBufferLen = pEncrypt->CalculateStreamLength(nInputBufferLen); char* pOutputBuffer = new char [nOutputBufferLen]; pEncrypt->Encrypt(reinterpret_cast(pInputBuffer), nInputBufferLen, reinterpret_cast(pOutputBuffer), nOutputBufferLen); PdfString str( pOutputBuffer, nOutputBufferLen, true ); str.Write( pDevice, eWriteMode, NULL ); delete[] pInputBuffer; delete[] pOutputBuffer; return; } pDevice->Print( m_bHex ? "<" : "(" ); if( m_buffer.GetSize() && IsValid() ) { char* pBuf = m_buffer.GetBuffer(); pdf_long lLen = m_buffer.GetSize() - 2; // Cut off the trailing pair of zeros if( m_bHex ) { if( m_bUnicode ) pDevice->Write( PdfString::s_pszUnicodeMarkerHex, 4 ); char data[2]; while( lLen-- ) { data[0] = (*pBuf & 0xF0) >> 4; data[0] += (data[0] > 9 ? 'A' - 10 : '0'); data[1] = (*pBuf & 0x0F); data[1] += (data[1] > 9 ? 'A' - 10 : '0'); pDevice->Write( data, 2 ); ++pBuf; } } else { if( m_bUnicode ) { pDevice->Write( PdfString::s_pszUnicodeMarker, sizeof( PdfString::s_pszUnicodeMarker ) ); } while( lLen-- ) { const char & cEsc = m_escMap[static_cast(*pBuf)]; if( cEsc != 0 ) { pDevice->Write( "\\", 1 ); pDevice->Write( &cEsc, 1 ); } else { pDevice->Write( &*pBuf, 1 ); } ++pBuf; } } } pDevice->Print( m_bHex ? ">" : ")" ); } const PdfString & PdfString::operator=( const PdfString & rhs ) { this->m_bHex = rhs.m_bHex; this->m_bUnicode = rhs.m_bUnicode; this->m_buffer = rhs.m_buffer; this->m_sUtf8 = rhs.m_sUtf8; this->m_pEncoding = rhs.m_pEncoding; return *this; } bool PdfString::operator>( const PdfString & rhs ) const { if ( !this->IsValid() || !rhs.IsValid() ) { PdfError::LogMessage( eLogSeverity_Error, "PdfString::operator> LHS or RHS was invalid PdfString" ); return false; } const PdfString & str1 = *this; const PdfString & str2 = rhs; if( m_bUnicode || rhs.m_bUnicode ) { #ifdef _WIN32 std::wstring sWide_1 = str1.GetStringW(); std::wstring sWide_2 = str2.GetStringW(); return sWide_1 > sWide_2; #else std::string sUtf8_1 = str1.GetStringUtf8(); std::string sUtf8_2 = str2.GetStringUtf8(); return sUtf8_1 > sUtf8_2; #endif // _WIN32 } return (strcmp( str1.GetString(), str2.GetString() ) > 0); } bool PdfString::operator<( const PdfString & rhs ) const { if ( !this->IsValid() || !rhs.IsValid() ) { PdfError::LogMessage( eLogSeverity_Error, "PdfString::operator< LHS or RHS was invalid PdfString" ); return false; } const PdfString & str1 = *this; const PdfString & str2 = rhs; if( m_bUnicode || rhs.m_bUnicode ) { #ifdef _WIN32 std::wstring sWide_1 = str1.GetStringW(); std::wstring sWide_2 = str2.GetStringW(); return sWide_1 < sWide_2; #else std::string sUtf8_1 = str1.GetStringUtf8(); std::string sUtf8_2 = str2.GetStringUtf8(); return sUtf8_1 < sUtf8_2; #endif // _WIN32 } return (strcmp( str1.GetString(), str2.GetString() ) < 0); } bool PdfString::operator==( const PdfString & rhs ) const { if ( !this->IsValid() && !rhs.IsValid() ) { PdfError::LogMessage( eLogSeverity_Error, "PdfString::operator== LHS and RHS both invalid PdfStrings" ); return true; } else if ( !this->IsValid() || !rhs.IsValid() ) { PdfError::LogMessage( eLogSeverity_Error, "PdfString::operator== LHS or RHS was invalid PdfString" ); return false; } PdfString str1 = *this; PdfString str2 = rhs; if( m_bUnicode || rhs.m_bUnicode ) { // one or both strings are unicode: // make sure both are unicode so that // we do not loose information str1 = str1.ToUnicode(); str2 = str2.ToUnicode(); } return str1.m_buffer == str2.m_buffer; } void PdfString::Init( const char* pszString, pdf_long lLen ) { if( !pszString ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } bool bUft16LE = false; // check if it is a unicode string (UTF-16BE) // UTF-16BE strings have to start with 0xFE 0xFF if( lLen >= 2 ) { m_bUnicode = (pszString[0] == PdfString::s_pszUnicodeMarker[0] && pszString[1] == PdfString::s_pszUnicodeMarker[1]); // Check also for UTF-16LE if( !m_bUnicode && (pszString[0] == PdfString::s_pszUnicodeMarker[1] && pszString[1] == PdfString::s_pszUnicodeMarker[0]) ) { bUft16LE = true; } } // skip the first two bytes if( m_bUnicode || bUft16LE ) { lLen -= 2; pszString += 2; } m_buffer = PdfRefCountedBuffer( lLen + 2 ); memcpy( m_buffer.GetBuffer(), pszString, lLen ); m_buffer.GetBuffer()[lLen] = '\0'; m_buffer.GetBuffer()[lLen+1] = '\0'; // if the buffer is a UTF-16LE string // convert it to UTF-16BE if( bUft16LE ) { SwapBytes( m_buffer.GetBuffer(), lLen ); } } void PdfString::InitFromUtf8( const pdf_utf8* pszStringUtf8, pdf_long lLen ) { if( !pszStringUtf8 ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } pdf_long lBufLen = (lLen << 1) + sizeof(wchar_t); // twice as large buffer should always be enough std::vector bytes(lBufLen); #if (defined(_MSC_VER) && _MSC_VER < 1700) || (defined(__BORLANDC__)) // MSC before VC11 has no data member, same as BorlandC pdf_utf16be *pBuffer = reinterpret_cast(&bytes[0]); #else pdf_utf16be *pBuffer = reinterpret_cast(bytes.data()); #endif lBufLen = PdfString::ConvertUTF8toUTF16( pszStringUtf8, lLen, pBuffer, lBufLen ); lBufLen = (lBufLen-1) << 1; // lBufLen is the number of characters, we need the number of bytes now! m_buffer = PdfRefCountedBuffer( lBufLen + sizeof(pdf_utf16be) ); memcpy( m_buffer.GetBuffer(), reinterpret_cast(pBuffer), lBufLen ); m_buffer.GetBuffer()[lBufLen] = '\0'; m_buffer.GetBuffer()[lBufLen+1] = '\0'; } void PdfString::InitUtf8() { if( this->IsUnicode() ) { // we can convert UTF16 to UTF8 // UTF8 is at maximum 5 * characterlenght. pdf_long lBufferLen = (5*this->GetUnicodeLength())+2; char* pBuffer = static_cast(podofo_calloc( lBufferLen, sizeof(char) )); if( !pBuffer ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } pdf_long lUtf8 = PdfString::ConvertUTF16toUTF8( reinterpret_cast(m_buffer.GetBuffer()), this->GetUnicodeLength(), reinterpret_cast(pBuffer), lBufferLen, ePdfStringConversion_Lenient ); pBuffer[lUtf8-1] = '\0'; pBuffer[lUtf8] = '\0'; m_sUtf8 = pBuffer; podofo_free( pBuffer ); } else { PdfString sTmp = this->ToUnicode(); m_sUtf8 = sTmp.GetStringUtf8(); } } #ifdef _WIN32 const std::wstring PdfString::GetStringW() const { if ( !IsValid() ) { PdfError::LogMessage( eLogSeverity_Error, "PdfString::GetStringW invalid PdfString" ); return std::wstring(); } if( !this->IsUnicode() ) { return this->ToUnicode().GetStringW(); } PdfRefCountedBuffer buffer( m_buffer.GetSize() ); memcpy( buffer.GetBuffer(), m_buffer.GetBuffer(), m_buffer.GetSize() ); #ifdef PODOFO_IS_LITTLE_ENDIAN SwapBytes( buffer.GetBuffer(), buffer.GetSize() ); #endif // PODOFO_IS_LITTLE_ENDIA std::wstring wstr( reinterpret_cast(buffer.GetBuffer()) ); return wstr; } #endif // _WIN32 #ifdef PODOFO_PUBLIC_STRING_HEX_CODEC // never set, Decode even says REMOVE :( PdfString PdfString::HexEncode() const { if( this->IsHex() ) return *this; else { std::auto_ptr pFilter; pdf_long lLen = (m_buffer.GetSize() - 1) << 1; PdfString str; PdfRefCountedBuffer buffer( lLen + 1 ); PdfMemoryOutputStream stream( buffer.GetBuffer(), lLen ); pFilter = PdfFilterFactory::Create( ePdfFilter_ASCIIHexDecode ); pFilter->BeginEncode( &stream ); pFilter->EncodeBlock( m_buffer.GetBuffer(), (m_buffer.GetSize() - 1) ); pFilter->EndEncode(); buffer.GetBuffer()[buffer.GetSize()-1] = '\0'; str.m_buffer = buffer; str.m_bHex = true; str.m_bUnicode = m_bUnicode; return str; } } // TODO: REMOVE PdfString PdfString::HexDecode() const { if( !this->IsHex() ) return *this; else { std::auto_ptr pFilter; pdf_long lLen = m_buffer.GetSize() >> 1; PdfString str; PdfRefCountedBuffer buffer( lLen ); PdfMemoryOutputStream stream( buffer.GetBuffer(), lLen ); pFilter = PdfFilterFactory::Create( ePdfFilter_ASCIIHexDecode ); pFilter->BeginDecode( &stream ); pFilter->DecodeBlock( m_buffer.GetBuffer(), m_buffer.GetSize() ); pFilter->EndDecode(); str.m_buffer = buffer; str.m_bHex = false; str.m_bUnicode = m_bUnicode; return str; } } #endif // PODOFO_PUBLIC_STRING_HEX_CODEC PdfString PdfString::ToUnicode() const { if( this->IsUnicode() ) { return *this; } else if ( this->IsValid() ) { const PdfEncoding* const pEncoding = (m_pEncoding ? m_pEncoding : PdfEncodingFactory::GlobalPdfDocEncodingInstance()); return pEncoding->ConvertToUnicode( *this, NULL ); } else { // can't convert because PdfString is invalid and has no buffer, so return *this // which means trying to convert an invalid string returns another invalid string // and in the special case where *this is PdfString::StringNull then ToUnicode() // returns PdfString::StringNull PdfError::LogMessage( eLogSeverity_Error, "PdfString::ToUnicode invalid PdfString" ); return *this; } } void PdfString::SwapBytes( char* pBuf, pdf_long lLen ) { char cSwap; while( lLen > 1 ) { cSwap = *pBuf; *pBuf = *(pBuf+1); *(++pBuf) = cSwap; ++pBuf; lLen -= 2; } } /* * The disclaimer below applies to the Unicode conversion * functions below. The functions where adapted for use in PoDoFo. * * The original can be found at: * http://www.unicode.org/Public/PROGRAMS/CVTUTF/ */ /* * Copyright 2001-2004 Unicode, Inc. * * Disclaimer * * This source code is provided as is by Unicode, Inc. No claims are * made as to fitness for any particular purpose. No warranties of any * kind are expressed or implied. The recipient agrees to determine * applicability of information provided. If this file has been * purchased on magnetic or optical media from Unicode, Inc., the * sole remedy for any claim will be exchange of defective media * within 90 days of receipt. * * Limitations on Rights to Redistribute This Code * * Unicode, Inc. hereby grants the right to freely use the information * supplied in this file in the creation of products supporting the * Unicode Standard, and to make copies of this file in any form * for internal or external distribution as long as this notice * remains attached. */ /* --------------------------------------------------------------------- Conversions between UTF32, UTF-16, and UTF-8. Source code file. Author: Mark E. Davis, 1994. Rev History: Rick McGowan, fixes & updates May 2001. Sept 2001: fixed const & error conditions per mods suggested by S. Parent & A. Lillich. June 2002: Tim Dodd added detection and handling of incomplete source sequences, enhanced error detection, added casts to eliminate compiler warnings. July 2003: slight mods to back out aggressive FFFE detection. Jan 2004: updated switches in from-UTF8 conversions. Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. See the header file "ConvertUTF.h" for complete documentation. ------------------------------------------------------------------------ */ /* --------------------------------------------------------------------- */ /* Some fundamental constants */ #define UNI_REPLACEMENT_CHAR static_cast(0x0000FFFD) #define UNI_MAX_BMP static_cast(0x0000FFFF) #define UNI_MAX_UTF16 static_cast(0x0010FFFF) #define UNI_SUR_HIGH_START static_cast(0xD800) #define UNI_SUR_HIGH_END static_cast(0xDBFF) #define UNI_SUR_LOW_START static_cast(0xDC00) #define UNI_SUR_LOW_END static_cast(0xDFFF) static const int halfShift = 10; /* used for shifting by 10 bits */ static const unsigned long halfBase = 0x0010000UL; static const unsigned long halfMask = 0x3FFUL; /* --------------------------------------------------------------------- */ /* * Index into the table below with the first byte of a UTF-8 sequence to * get the number of trailing bytes that are supposed to follow it. * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is * left as-is for anyone who may want to do such conversion, which was * allowed in earlier algorithms. */ static const char trailingBytesForUTF8[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,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,4,4,4,4,5,5,5,5 }; /* * Magic values subtracted from a buffer value during UTF8 conversion. * This table contains as many values as there might be trailing bytes * in a UTF-8 sequence. */ static const unsigned long offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; /* * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed * into the first byte, depending on how many bytes follow. There are * as many entries in this table as there are UTF-8 sequence types. * (I.e., one byte sequence, two byte... etc.). Remember that sequencs * for *legal* UTF-8 will be 4 or fewer bytes total. */ static const pdf_utf8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; /* --------------------------------------------------------------------- */ /* * Utility routine to tell whether a sequence of bytes is legal UTF-8. * This must be called with the length pre-determined by the first byte. * If not calling this from ConvertUTF8to*, then the length can be set by: * length = trailingBytesForUTF8[*source]+1; * and the sequence is illegal right away if there aren't that many bytes * available. * If presented with a length > 4, this returns false. The Unicode * definition of UTF-8 goes up to 4-byte sequences. */ static bool isLegalUTF8(const pdf_utf8 *source, int length) { pdf_utf8 a; const pdf_utf8 *srcptr = source+length; switch (length) { default: return false; /* Everything else falls through when "true"... */ case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; case 2: if ((a = (*--srcptr)) > 0xBF) return false; switch (*source) { /* no fall-through in this inner switch */ case 0xE0: if (a < 0xA0) return false; break; case 0xED: if (a > 0x9F) return false; break; case 0xF0: if (a < 0x90) return false; break; case 0xF4: if (a > 0x8F) return false; break; default: if (a < 0x80) return false; } case 1: if (*source >= 0x80 && *source < 0xC2) return false; } if (*source > 0xF4) return false; return true; } /* --------------------------------------------------------------------- */ /* * Exported function to return whether a UTF-8 sequence is legal or not. * This is not used here; it's just exported. */ bool isLegalUTF8Sequence(const pdf_utf8 *source, const pdf_utf8 *sourceEnd) { int length = trailingBytesForUTF8[*source]+1; if (source+length > sourceEnd) { return false; } return isLegalUTF8(source, length); } pdf_long PdfString::ConvertUTF8toUTF16( const pdf_utf8* pszUtf8, pdf_utf16be* pszUtf16, pdf_long lLenUtf16 ) { return pszUtf8 ? PdfString::ConvertUTF8toUTF16( pszUtf8, strlen( reinterpret_cast(pszUtf8) ), pszUtf16, lLenUtf16 ) : 0; } pdf_long PdfString::ConvertUTF8toUTF16( const pdf_utf8* pszUtf8, pdf_long lLenUtf8, pdf_utf16be* pszUtf16, pdf_long lLenUtf16, EPdfStringConversion eConversion ) { const pdf_utf8* source = pszUtf8; const pdf_utf8* sourceEnd = pszUtf8 + lLenUtf8 + 1; // point after the last element pdf_utf16be* target = pszUtf16; pdf_utf16be* targetEnd = pszUtf16 + lLenUtf16; while (source < sourceEnd) { unsigned long ch = 0; unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; if (source + extraBytesToRead >= sourceEnd) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "The UTF8 string was to short while converting from UTF8 to UTF16." ); } // Do this check whether lenient or strict if (! isLegalUTF8(source, extraBytesToRead+1)) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "The UTF8 string was invalid while from UTF8 to UTF16." ); } /* * The cases all fall through. See "Note A" below. */ switch (extraBytesToRead) { case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ case 3: ch += *source++; ch <<= 6; case 2: ch += *source++; ch <<= 6; case 1: ch += *source++; ch <<= 6; case 0: ch += *source++; } ch -= offsetsFromUTF8[extraBytesToRead]; if (target >= targetEnd) { source -= (extraBytesToRead+1); /* Back up source pointer! */ PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ /* UTF-16 surrogate values are illegal in UTF-32 */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { if (eConversion == ePdfStringConversion_Strict) { source -= (extraBytesToRead+1); /* return to the illegal value itself */ PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); break; } else { *target++ = UNI_REPLACEMENT_CHAR; } } else { *target++ = static_cast(ch); /* normal case */ } } else if (ch > UNI_MAX_UTF16) { if (eConversion == ePdfStringConversion_Strict) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); //RG: TODO My compiler says that this is unreachable code! source -= (extraBytesToRead+1); /* return to the start */ break; /* Bail out; shouldn't continue */ } else { *target++ = UNI_REPLACEMENT_CHAR; } } else { /* target is a character in range 0xFFFF - 0x10FFFF. */ if (target + 1 >= targetEnd) { source -= (extraBytesToRead+1); /* Back up source pointer! */ PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } ch -= halfBase; *target++ = static_cast((ch >> halfShift) + UNI_SUR_HIGH_START); *target++ = static_cast((ch & halfMask) + UNI_SUR_LOW_START); } } // swap to UTF-16be on LE systems #ifdef PODOFO_IS_LITTLE_ENDIAN PdfString::SwapBytes( reinterpret_cast(pszUtf16), static_cast(target - pszUtf16) << 1 ); #endif // PODOFO_IS_LITTLE_ENDIAN // return characters written return target - pszUtf16; } pdf_long PdfString::ConvertUTF16toUTF8( const pdf_utf16be* pszUtf16, pdf_utf8* pszUtf8, pdf_long lLenUtf8 ) { pdf_long lLen = 0; const pdf_utf16be* pszStart = pszUtf16; while( *pszStart ) ++lLen; return ConvertUTF16toUTF8( pszUtf16, lLen, pszUtf8, lLenUtf8 ); } pdf_long PdfString::ConvertUTF16toUTF8( const pdf_utf16be* pszUtf16, pdf_long lLenUtf16, pdf_utf8* pszUtf8, pdf_long lLenUtf8, EPdfStringConversion eConversion ) { bool bOwnBuf = false; const pdf_utf16be* source = pszUtf16; const pdf_utf16be* sourceEnd = pszUtf16 + lLenUtf16 + 1; // point after the last element pdf_utf8* target = pszUtf8; pdf_utf8* targetEnd = pszUtf8 + lLenUtf8; // swap to UTF-16be on LE systems #ifdef PODOFO_IS_LITTLE_ENDIAN bOwnBuf = true; source = new pdf_utf16be[lLenUtf16+1]; if( !source ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } memcpy( const_cast(source), pszUtf16, lLenUtf16 * sizeof(pdf_utf16be) ); PdfString::SwapBytes( reinterpret_cast(const_cast(source)), lLenUtf16 * sizeof(pdf_utf16be) ); pszUtf16 = source; const_cast(source)[lLenUtf16] = 0; sourceEnd = pszUtf16 + lLenUtf16 + 1; // point after the last element #endif // PODOFO_IS_LITTLE_ENDIAN try { while (source < sourceEnd) { unsigned long ch; unsigned short bytesToWrite = 0; const unsigned long byteMask = 0xBF; const unsigned long byteMark = 0x80; const pdf_utf16be* oldSource = source; /* In case we have to back up because of target overflow. */ ch = *source++; /* If we have a surrogate pair, convert to UTF32 first. */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { /* If the 16 bits following the high surrogate are in the source buffer... */ if (source < sourceEnd) { unsigned long ch2 = *source; /* If it's a low surrogate, convert to UTF32. */ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) + halfBase; ++source; } else if (eConversion == ePdfStringConversion_Strict) { /* it's an unpaired high surrogate */ --source; /* return to the illegal value itself */ PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); break; } } else { /* We don't have the 16 bits following the high surrogate. */ --source; /* return to the high surrogate */ PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); break; } } else if (eConversion == ePdfStringConversion_Strict) { /* UTF-16 surrogate values are illegal in UTF-32 */ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { --source; /* return to the illegal value itself */ PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); break; } } /* Figure out how many bytes the result will require */ if (ch < static_cast(0x80)) { bytesToWrite = 1; } else if (ch < static_cast(0x800)) { bytesToWrite = 2; } else if (ch < static_cast(0x10000)) { bytesToWrite = 3; } else if (ch < static_cast(0x110000)) { bytesToWrite = 4; } else { bytesToWrite = 3; ch = UNI_REPLACEMENT_CHAR; } target += bytesToWrite; if (target > targetEnd) { source = oldSource; /* Back up source pointer! */ target -= bytesToWrite; PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); break; } switch (bytesToWrite) { /* note: everything falls through. */ case 4: *--target = static_cast((ch | byteMark) & byteMask); ch >>= 6; case 3: *--target = static_cast((ch | byteMark) & byteMask); ch >>= 6; case 2: *--target = static_cast((ch | byteMark) & byteMask); ch >>= 6; case 1: *--target = static_cast(ch | firstByteMark[bytesToWrite]); } target += bytesToWrite; } } catch( PdfError & e ) { if( bOwnBuf ) delete[] const_cast(pszUtf16); throw e; } if( bOwnBuf ) delete[] const_cast(pszUtf16); // return bytes written return target - pszUtf8; } PdfRefCountedBuffer &PdfString::GetBuffer(void) { return m_buffer; } /* --------------------------------------------------------------------- Note A. The fall-through switches in UTF-8 reading code save a temp variable, some decrements & conditionals. The switches are equivalent to the following loop: { int tmpBytesToRead = extraBytesToRead+1; do { ch += *source++; --tmpBytesToRead; if (tmpBytesToRead) ch <<= 6; } while (tmpBytesToRead > 0); } In UTF-8 writing code, the switches on "bytesToWrite" are similarly unrolled loops. --------------------------------------------------------------------- */ }; podofo-0.9.5/src/base/PdfEncrypt.h0000664000175000017500000010436713017643225016631 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDFENCRYPT_H_ #define _PDFENCRYPT_H_ #include "PdfDefines.h" #include "PdfString.h" #include "PdfReference.h" #include #ifdef PODOFO_HAVE_OPENSSL #include #endif // PODOFO_HAVE_OPENSSL namespace PoDoFo { class PdfDictionary; class PdfInputStream; class PdfObject; class PdfOutputStream; class AESCryptoEngine; #ifndef OPENSSL_NO_RC4 class RC4CryptoEngine; #endif // OPENSSL_NO_RC4 /// Class representing PDF encryption methods. (For internal use only) /// Based on code from Ulrich Telle: http://wxcode.sourceforge.net/components/wxpdfdoc/ /// Original Copyright header: /////////////////////////////////////////////////////////////////////////////// // Name: pdfencrypt.h // Purpose: // Author: Ulrich Telle // Modified by: // Created: 2005-08-16 // Copyright: (c) Ulrich Telle // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// /** A class that is used to encrypt a PDF file and * set document permisions on the PDF file. * * As a user of this class, you have only to instanciate a * object of this class and pass it to PdfWriter, PdfMemDocument, * PdfStreamedDocument or PdfImmediateWriter. * You do not have to call any other method of this class. The above * classes know how to handle encryption using Pdfencrypt. * */ class PODOFO_API PdfEncrypt { public: /** A enum specifying a valid keylength for a PDF encryption key. * Keys must be in the range 40 to 128 bit and have to be a * multiple of 8. * * Adobe Reader supports only keys with 40, 128 or 256 bits! */ typedef enum { ePdfKeyLength_40 = 40, ePdfKeyLength_56 = 56, ePdfKeyLength_80 = 80, ePdfKeyLength_96 = 96, ePdfKeyLength_128 = 128 #ifdef PODOFO_HAVE_LIBIDN ,ePdfKeyLength_256 = 256 #endif //PODOFO_HAVE_LIBIDN } EPdfKeyLength; /** Set user permissions/restrictions on a document */ typedef enum { ePdfPermissions_Print = 0x00000004, ///< Allow printing the document ePdfPermissions_Edit = 0x00000008, ///< Allow modifying the document besides annotations, form fields or chaning pages ePdfPermissions_Copy = 0x00000010, ///< Allow text and graphic extraction ePdfPermissions_EditNotes = 0x00000020, ///< Add or modify text annoations or form fields (if ePdfPermissions_Edit is set also allow to create interactive form fields including signature) ePdfPermissions_FillAndSign = 0x00000100, ///< Fill in existing form or signature fields ePdfPermissions_Accessible = 0x00000200, ///< Extract text and graphics to support user with disabillities ePdfPermissions_DocAssembly = 0x00000400, ///< Assemble the document: insert, create, rotate delete pages or add bookmarks ePdfPermissions_HighPrint = 0x00000800 ///< Print a high resolution version of the document } EPdfPermissions; /** * The encryption algorithm. */ typedef enum { #ifndef OPENSSL_NO_RC4 ePdfEncryptAlgorithm_RC4V1 = 1, ///< RC4 Version 1 encryption using a 40bit key ePdfEncryptAlgorithm_RC4V2 = 2, ///< RC4 Version 2 encryption using a key with 40-128bit #endif // OPENSSL_NO_RC4 ePdfEncryptAlgorithm_AESV2 = 4 ///< AES encryption with a 128 bit key (PDF1.6) #ifdef PODOFO_HAVE_LIBIDN ,ePdfEncryptAlgorithm_AESV3 = 8 ///< AES encryption with a 256 bit key (PDF1.7 extension 3) - Support added by P. Zent #endif //PODOFO_HAVE_LIBIDN } EPdfEncryptAlgorithm; /** Create a PdfEncrypt object which can be used to encrypt a PDF file. * * \param userPassword the user password (if empty the user does not have * to enter a password to open the document) * \param ownerPassword the owner password * \param protection several EPdfPermissions values or'ed together to set * the users permissions for this document * \param eAlgorithm the revision of the encryption algorithm to be used * \param eKeyLength the length of the encryption key ranging from 40 to 128 bits * (only used if eAlgorithm == ePdfEncryptAlgorithm_RC4V2) * * \see GenerateEncryptionKey with the documentID to generate the real * encryption key using this information */ static PdfEncrypt * CreatePdfEncrypt( const std::string & userPassword, const std::string & ownerPassword, int protection = ePdfPermissions_Print | ePdfPermissions_Edit | ePdfPermissions_Copy | ePdfPermissions_EditNotes | ePdfPermissions_FillAndSign | ePdfPermissions_Accessible | ePdfPermissions_DocAssembly | ePdfPermissions_HighPrint, EPdfEncryptAlgorithm eAlgorithm = ePdfEncryptAlgorithm_AESV2, EPdfKeyLength eKeyLength = ePdfKeyLength_40 ); /** Initialize a PdfEncrypt object from an encryption dictionary in a PDF file. * * This is required for encrypting a PDF file, but handled internally in PdfParser * for you. * * Will use only encrypting algorithms that are enabled. * * \param pObject a PDF encryption dictionary * * \see GetEnabledEncryptionAlgorithms */ static PdfEncrypt * CreatePdfEncrypt( const PdfObject* pObject ); /** Copy constructor * * \param rhs another PdfEncrypt object which is copied */ static PdfEncrypt * CreatePdfEncrypt( const PdfEncrypt & rhs ); /** * Retrieve the list of encryption algorithms that are used * when loading a PDF document. * * By default all alogrithms are enabled. * * \see IsEncryptionEnabled * \see SetEnabledEncryptionAlgorithms * * \return an or'ed together list of all enabled encryption algorithms */ static int GetEnabledEncryptionAlgorithms(); /** * Specify the list of encryption algorithms that should be used by PoDoFo * when loading a PDF document. * * This can be used to disable for example AES encryption/decryption * which is unstable in certain cases. * * \see GetEnabledEncryptionAlgorithms * \see IsEncryptionEnabled */ static void SetEnabledEncryptionAlgorithms(int nEncryptionAlgorithms); /** * Test if a certain encryption algorithm is enabled for loading PDF documents. * * \returns ture if the encryption algorithm is enabled * \see GetEnabledEncryptionAlgorithms * \see SetEnabledEncryptionAlgorithms */ static bool IsEncryptionEnabled(EPdfEncryptAlgorithm eAlgorithm); /** Destruct the PdfEncrypt object */ virtual ~PdfEncrypt() = 0; /** Generate encryption key from user and owner passwords and protection key * * \param documentId the documentId of the current document */ virtual void GenerateEncryptionKey(const PdfString & documentId) = 0; /** Fill all keys into a encryption dictionary. * This dictionary is usually added to the PDF files trailer * under the /Encryption key. * * \param rDictionary an empty dictionary which is filled with information about * the used encryption algorithm */ virtual void CreateEncryptionDictionary( PdfDictionary & rDictionary ) const = 0; /** Create a PdfOutputStream that encrypts all data written to * it using the current settings of the PdfEncrypt object. * * Warning: Currently only RC4 based encryption is supported using output streams! * * \param pOutputStream the created PdfOutputStream writes all encrypted * data to this output stream. * * \returns a PdfOutputStream that encryts all data. */ virtual PdfOutputStream* CreateEncryptionOutputStream( PdfOutputStream* pOutputStream ) = 0; /** Create a PdfInputStream that decrypts all data read from * it using the current settings of the PdfEncrypt object. * * Warning: Currently only RC4 based encryption is supported using output streams! * * \param pInputStream the created PdfInputStream reads all decrypted * data to this input stream. * * \returns a PdfInputStream that decrypts all data. */ virtual PdfInputStream* CreateEncryptionInputStream( PdfInputStream* pInputStream ) = 0; /** * Tries to authenticate a user using either the user or owner password * * \param password owner or user password * \param documentId the documentId of the PDF file * * \returns true if either the owner or user password matches password */ virtual bool Authenticate( const std::string & password, const PdfString & documentId ) = 0; /** Get the encryption algorithm of this object. * \returns the EPdfEncryptAlgorithm of this object */ inline EPdfEncryptAlgorithm GetEncryptAlgorithm() const; /** Checks if printing this document is allowed. * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to print this document * * \see PdfEncrypt to set own document permissions. */ inline bool IsPrintAllowed() const; /** Checks if modifiying this document (besides annotations, form fields or changing pages) is allowed. * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to modfiy this document * * \see PdfEncrypt to set own document permissions. */ inline bool IsEditAllowed() const; /** Checks if text and graphics extraction is allowed. * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to extract text and graphics from this document * * \see PdfEncrypt to set own document permissions. */ inline bool IsCopyAllowed() const; /** Checks if it is allowed to add or modify annotations or form fields * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to add or modify annotations or form fields * * \see PdfEncrypt to set own document permissions. */ inline bool IsEditNotesAllowed() const; /** Checks if it is allowed to fill in existing form or signature fields * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to fill in existing form or signature fields * * \see PdfEncrypt to set own document permissions. */ inline bool IsFillAndSignAllowed() const; /** Checks if it is allowed to extract text and graphics to support users with disabillities * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to extract text and graphics to support users with disabillities * * \see PdfEncrypt to set own document permissions. */ inline bool IsAccessibilityAllowed() const; /** Checks if it is allowed to insert, create, rotate, delete pages or add bookmarks * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to insert, create, rotate, delete pages or add bookmarks * * \see PdfEncrypt to set own document permissions. */ inline bool IsDocAssemblyAllowed() const; /** Checks if it is allowed to print a high quality version of this document * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to print a high quality version of this document * * \see PdfEncrypt to set own document permissions. */ inline bool IsHighPrintAllowed() const; /// Get the U object value (user) const unsigned char* GetUValue() const { return m_uValue; } /// Get the O object value (owner) const unsigned char* GetOValue() const { return m_oValue; } /// Get the encryption key value (owner) const unsigned char* GetEncryptionKey() const { return m_encryptionKey; } /// Get the P object value (protection) pdf_int32 GetPValue() const { return m_pValue; } /// Get the revision number of the encryption method int GetRevision() const { return m_rValue; } /// Get the key length of the encryption key in bits int GetKeyLength() const { return m_keyLength*8; } /// Is metadata encrypted bool IsMetadataEncrypted() const { return m_bEncryptMetadata; } /// Encrypt a wxString //void Encrypt( std::string & str, pdf_long inputLen ) const; /// Encrypt a character string // inStr: the input buffer // inLen: length of the input buffer // outStr: the output buffer // outLen: length of the output buffer virtual void Encrypt(const unsigned char* inStr, pdf_long inLen, unsigned char* outStr, pdf_long outLen) const = 0; /// Decrypt a character string // inStr: the input buffer // inLen: length of the input buffer // outStr: the output buffer // outLen: length of the output buffer virtual void Decrypt(const unsigned char* inStr, pdf_long inLen, unsigned char* outStr, pdf_long &outLen) const = 0; /// Calculate stream size virtual pdf_long CalculateStreamLength(pdf_long length) const = 0; /// Calculate stream offset virtual pdf_long CalculateStreamOffset() const = 0; /** Set the reference of the object that is currently encrypted. * * This value will be used in following calls of Encrypt * to encrypt the object. * * \see Encrypt */ inline void SetCurrentReference( const PdfReference & rRef ); protected: PdfEncrypt() : m_eAlgorithm( ePdfEncryptAlgorithm_AESV2 ), m_keyLength( 0 ), m_rValue( 0 ), m_pValue( 0 ), m_eKeyLength( ePdfKeyLength_128 ), m_bEncryptMetadata(true) { memset( m_uValue, 0, 48 ); memset( m_oValue, 0, 48 ); memset( m_encryptionKey, 0, 32 ); }; PdfEncrypt( const PdfEncrypt & rhs ); /// Check two keys for equality bool CheckKey(unsigned char key1[32], unsigned char key2[32]); EPdfEncryptAlgorithm m_eAlgorithm; ///< The used encryption algorithm int m_keyLength; ///< Length of encryption key int m_rValue; ///< Revision pdf_int32 m_pValue; ///< P entry in pdf document EPdfKeyLength m_eKeyLength; ///< The key length std::string m_userPass; ///< User password std::string m_ownerPass; ///< Owner password unsigned char m_uValue[48]; ///< U entry in pdf document unsigned char m_oValue[48]; ///< O entry in pdf document unsigned char m_encryptionKey[32]; ///< Encryption key PdfReference m_curReference; ///< Reference of the current PdfObject std::string m_documentId; ///< DocumentID of the current document bool m_bEncryptMetadata; ///< Is metadata encrypted private: static int s_nEnabledEncryptionAlgorithms; ///< Or'ed int containing the enabled encryption algorithms }; #ifdef PODOFO_HAVE_LIBIDN /** A pure virtual class that is used to encrypt a PDF file (AES-256) * This class is the base for classes that implement algorithms based on SHA hashes * * Client code is working only with PdfEncrypt class and knows nothing * about PdfEncrypt*, it is created through CreatePdfEncrypt factory method * */ class PdfEncryptSHABase : public PdfEncrypt { public: PdfEncryptSHABase() {}; // copy constructor PdfEncryptSHABase(const PdfEncrypt &rhs); /* * Destruct PdfEncryptAESV2 object */ virtual ~PdfEncryptSHABase() {}; virtual PdfInputStream* CreateEncryptionInputStream( PdfInputStream* pInputStream ) = 0; virtual PdfOutputStream* CreateEncryptionOutputStream( PdfOutputStream* pOutputStream ) = 0; virtual void CreateEncryptionDictionary( PdfDictionary & rDictionary ) const; virtual bool Authenticate( const std::string & password, const PdfString & documentId ) = 0; /// Encrypt a character string virtual void Encrypt(const unsigned char* inStr, pdf_long inLen, unsigned char* outStr, pdf_long outLen) const = 0; virtual void GenerateEncryptionKey(const PdfString & documentId) = 0; /// Get the UE object value (user) const unsigned char* GetUEValue() const { return m_ueValue; } /// Get the OE object value (owner) const unsigned char* GetOEValue() const { return m_oeValue; } /// Get the Perms object value (encrypted protection) const unsigned char* GetPermsValue() const { return m_permsValue; } virtual pdf_long CalculateStreamOffset() const = 0; virtual pdf_long CalculateStreamLength(pdf_long length) const = 0; bool Authenticate(const std::string & documentID, const std::string & password, const std::string & uValue, const std::string & ueValue, const std::string & oValue, const std::string & oeValue, int pValue, const std::string & permsValue, int lengthValue, int rValue); protected: /// Generate initial vector virtual void GenerateInitialVector(unsigned char iv[16]); /// Compute encryption key to be used with AES-256 void ComputeEncryptionKey(); /// Generate the U and UE entries void ComputeUserKey(const unsigned char * userpswd, int len); /// Generate the O and OE entries void ComputeOwnerKey(const unsigned char * userpswd, int len); /// Preprocess password for use in EAS-256 Algorithm /// outBuf needs to be at least 127 bytes long void PreprocessPassword( const std::string &password, unsigned char* outBuf, int &len); unsigned char m_ueValue[32]; ///< UE entry in pdf document unsigned char m_oeValue[32]; ///< OE entry in pdf document unsigned char m_permsValue[16]; ///< Perms entry in pdf document }; /** A pure virtual class that is used to encrypt a PDF file (RC4, AES-128) * This class is the base for classes that implement algorithms based on MD5 hashes * * Client code is working only with PdfEncrypt class and knows nothing * about PdfEncrypt*, it is created through CreatePdfEncrypt factory method * */ #endif // PODOFO_HAVE_LIBIDN /** A pure virtual class that is used to encrypt a PDF file (AES-128/256) * This class is the base for classes that implement algorithms based on AES * * Client code is working only with PdfEncrypt class and knows nothing * about PdfEncrypt*, it is created through CreatePdfEncrypt factory method * */ class PdfEncryptAESBase { public: ~PdfEncryptAESBase(); protected: PdfEncryptAESBase(); void BaseDecrypt(const unsigned char* key, int keylen, const unsigned char* iv, const unsigned char* textin, pdf_long textlen, unsigned char* textout, pdf_long &textoutlen); void BaseEncrypt(const unsigned char* key, int keylen, const unsigned char* iv, const unsigned char* textin, pdf_long textlen, unsigned char* textout, pdf_long textoutlen); AESCryptoEngine* m_aes; ///< AES encryptor }; #ifndef OPENSSL_NO_RC4 /** A pure virtual class that is used to encrypt a PDF file (RC4-40..128) * This class is the base for classes that implement algorithms based on RC4 * * Client code is working only with PdfEncrypt class and knows nothing * about PdfEncrypt*, it is created through CreatePdfEncrypt factory method * */ class PdfEncryptRC4Base { public: ~PdfEncryptRC4Base(); protected: PdfEncryptRC4Base(); /// AES encryption void RC4(const unsigned char* key, int keylen, const unsigned char* textin, pdf_long textlen, unsigned char* textout, pdf_long textoutlen); RC4CryptoEngine* m_rc4; ///< AES encryptor }; #endif // OPENSSL_NO_RC4 #ifdef OPENSSL_NO_RC4 class PdfEncryptMD5Base : public PdfEncrypt { #else class PdfEncryptMD5Base : public PdfEncrypt, public PdfEncryptRC4Base { #endif // OPENSSL_NO_RC4 public: PdfEncryptMD5Base() {}; // copy constructor PdfEncryptMD5Base(const PdfEncrypt &rhs); /* * Destruct PdfEncryptAESV2 object */ virtual ~PdfEncryptMD5Base() {}; virtual PdfInputStream* CreateEncryptionInputStream( PdfInputStream* pInputStream ) = 0; virtual PdfOutputStream* CreateEncryptionOutputStream( PdfOutputStream* pOutputStream ) = 0; virtual void CreateEncryptionDictionary( PdfDictionary & rDictionary ) const; virtual bool Authenticate( const std::string & password, const PdfString & documentId ) = 0; /// Encrypt a character string virtual void Encrypt(const unsigned char* inStr, pdf_long inLen, unsigned char* outStr, pdf_long outLen) const = 0; virtual void GenerateEncryptionKey(const PdfString & documentId) = 0; /** Create a PdfString of MD5 data generated from a buffer in memory. * \param pBuffer the buffer of which to calculate the MD5 sum * \param nLength the length of the buffer * * \returns an MD5 sum as PdfString */ static PdfString GetMD5String( const unsigned char* pBuffer, int nLength ); virtual pdf_long CalculateStreamOffset() const = 0; virtual pdf_long CalculateStreamLength(pdf_long length) const = 0; /// Calculate the binary MD5 message digest of the given data static void GetMD5Binary(const unsigned char* data, int length, unsigned char* digest); bool Authenticate(const std::string & documentID, const std::string & password, const std::string & uValue, const std::string & oValue, int pValue, int lengthValue, int rValue); protected: /// Generate initial vector virtual void GenerateInitialVector(unsigned char iv[16]); /// Compute owner key void ComputeOwnerKey(unsigned char userPad[32], unsigned char ownerPad[32], int keylength, int revision, bool authenticate, unsigned char ownerKey[32]); /// Pad a password to 32 characters void PadPassword(const std::string& password, unsigned char pswd[32]); /// Compute encryption key and user key void ComputeEncryptionKey(const std::string & documentID, unsigned char userPad[32], unsigned char ownerKey[32], int pValue, int keyLength, int revision, unsigned char userKey[32], bool bEncryptMetadata); /** Create the encryption key for the current object. * * \param objkey pointer to an array of at least MD5_HASHBYTES (=16) bytes length * \param pnKeyLen pointer to an integer where the actual keylength is stored. */ virtual void CreateObjKey( unsigned char objkey[16], int* pnKeyLen ) const; unsigned char m_rc4key[16]; ///< last RC4 key unsigned char m_rc4last[256]; ///< last RC4 state table }; /** A class that is used to encrypt a PDF file (AES-128) * * Client code is working only with PdfEncrypt class and knows nothing * about PdfEncryptAES*, it is created through CreatePdfEncrypt factory method * */ class PdfEncryptAESV2 : public PdfEncryptMD5Base, public PdfEncryptAESBase { public: /* * Constructors of PdfEncryptAESV2 */ PdfEncryptAESV2(PdfString oValue, PdfString uValue, int pValue, bool bEncryptMetadata); PdfEncryptAESV2( const PdfEncrypt & rhs ) : PdfEncryptMD5Base(rhs) {} PdfEncryptAESV2( const std::string & userPassword, const std::string & ownerPassword, int protection = ePdfPermissions_Print | ePdfPermissions_Edit | ePdfPermissions_Copy | ePdfPermissions_EditNotes | ePdfPermissions_FillAndSign | ePdfPermissions_Accessible | ePdfPermissions_DocAssembly | ePdfPermissions_HighPrint ); /* * Destruct PdfEncryptAESV2 object */ virtual ~PdfEncryptAESV2() {}; virtual PdfInputStream* CreateEncryptionInputStream( PdfInputStream* pInputStream ); virtual PdfOutputStream* CreateEncryptionOutputStream( PdfOutputStream* pOutputStream ); virtual bool Authenticate( const std::string & password, const PdfString & documentId ); /// Encrypt a character string virtual void Encrypt(const unsigned char* inStr, pdf_long inLen, unsigned char* outStr, pdf_long outLen) const; virtual void Decrypt(const unsigned char* inStr, pdf_long inLen, unsigned char* outStr, pdf_long &outLen) const; virtual void GenerateEncryptionKey(const PdfString & documentId); virtual pdf_long CalculateStreamOffset() const; virtual pdf_long CalculateStreamLength(pdf_long length) const; }; #ifdef PODOFO_HAVE_LIBIDN /** A class that is used to encrypt a PDF file (AES-256) * * Client code is working only with PdfEncrypt class and knows nothing * about PdfEncryptAES*, it is created through CreatePdfEncrypt factory method * */ class PdfEncryptAESV3 : public PdfEncryptSHABase, public PdfEncryptAESBase { public: /* * Constructors of PdfEncryptAESV3 */ PdfEncryptAESV3(PdfString oValue, PdfString oeValue, PdfString uValue, PdfString ueValue, int pValue, PdfString permsValue); PdfEncryptAESV3( const PdfEncrypt & rhs ) : PdfEncryptSHABase(rhs) {} PdfEncryptAESV3( const std::string & userPassword, const std::string & ownerPassword, int protection = ePdfPermissions_Print | ePdfPermissions_Edit | ePdfPermissions_Copy | ePdfPermissions_EditNotes | ePdfPermissions_FillAndSign | ePdfPermissions_Accessible | ePdfPermissions_DocAssembly | ePdfPermissions_HighPrint ); /* * Destruct PdfEncryptAESV3 object */ virtual ~PdfEncryptAESV3() {}; virtual PdfInputStream* CreateEncryptionInputStream( PdfInputStream* pInputStream ); virtual PdfOutputStream* CreateEncryptionOutputStream( PdfOutputStream* pOutputStream ); virtual bool Authenticate( const std::string & password, const PdfString & documentId ); /// Encrypt a character string virtual void Encrypt(const unsigned char* inStr, pdf_long inLen, unsigned char* outStr, pdf_long outLen) const; virtual void Decrypt(const unsigned char* inStr, pdf_long inLen, unsigned char* outStr, pdf_long &outLen) const; virtual void GenerateEncryptionKey(const PdfString & documentId); virtual pdf_long CalculateStreamOffset() const; virtual pdf_long CalculateStreamLength(pdf_long length) const; }; #endif // PODOFO_HAVE_LIBIDN #ifndef OPENSSL_NO_RC4 /** A class that is used to encrypt a PDF file (RC4 40-bit and 128-bit) * * Client code is working only with PdfEncrypt class and knows nothing * about PdfEncryptRC4, it is created through CreatePdfEncrypt factory method * */ class PdfEncryptRC4 : public PdfEncryptMD5Base { public: /* * Constructors of PdfEncryptRC4 objects */ PdfEncryptRC4(PdfString oValue, PdfString uValue, int pValue, int rValue, EPdfEncryptAlgorithm eAlgorithm, long length, bool bEncryptMetadata); PdfEncryptRC4( const PdfEncrypt & rhs ) : PdfEncryptMD5Base(rhs) {} PdfEncryptRC4( const std::string & userPassword, const std::string & ownerPassword, int protection = ePdfPermissions_Print | ePdfPermissions_Edit | ePdfPermissions_Copy | ePdfPermissions_EditNotes | ePdfPermissions_FillAndSign | ePdfPermissions_Accessible | ePdfPermissions_DocAssembly | ePdfPermissions_HighPrint, EPdfEncryptAlgorithm eAlgorithm = ePdfEncryptAlgorithm_RC4V1, EPdfKeyLength eKeyLength = ePdfKeyLength_40 ); /* * Destruct PdfEncryptRC4 object */ virtual ~PdfEncryptRC4() {} virtual bool Authenticate( const std::string & password, const PdfString & documentId ); /// Encrypt a character string virtual void Encrypt(const unsigned char* inStr, pdf_long inLen, unsigned char* outStr, pdf_long outLen) const; virtual void Decrypt(const unsigned char* inStr, pdf_long inLen, unsigned char* outStr, pdf_long &outLen) const; virtual PdfInputStream* CreateEncryptionInputStream( PdfInputStream* pInputStream ); virtual PdfOutputStream* CreateEncryptionOutputStream( PdfOutputStream* pOutputStream ); virtual void GenerateEncryptionKey(const PdfString & documentId); virtual pdf_long CalculateStreamOffset() const; virtual pdf_long CalculateStreamLength(pdf_long length) const; }; #endif // OPENSSL_NO_RC4 // ----------------------------------------------------- // // ----------------------------------------------------- PdfEncrypt::EPdfEncryptAlgorithm PdfEncrypt::GetEncryptAlgorithm() const { return m_eAlgorithm; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfEncrypt::SetCurrentReference( const PdfReference & rRef ) { m_curReference = rRef; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfEncrypt::IsPrintAllowed() const { return (m_pValue & ePdfPermissions_Print) == ePdfPermissions_Print; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfEncrypt::IsEditAllowed() const { return (m_pValue & ePdfPermissions_Edit) == ePdfPermissions_Edit; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfEncrypt::IsCopyAllowed() const { return (m_pValue & ePdfPermissions_Copy) == ePdfPermissions_Copy; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfEncrypt::IsEditNotesAllowed() const { return (m_pValue & ePdfPermissions_EditNotes) == ePdfPermissions_EditNotes; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfEncrypt::IsFillAndSignAllowed() const { return (m_pValue & ePdfPermissions_FillAndSign) == ePdfPermissions_FillAndSign; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfEncrypt::IsAccessibilityAllowed() const { return (m_pValue & ePdfPermissions_Accessible) == ePdfPermissions_Accessible; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfEncrypt::IsDocAssemblyAllowed() const { return (m_pValue & ePdfPermissions_DocAssembly) == ePdfPermissions_DocAssembly; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfEncrypt::IsHighPrintAllowed() const { return (m_pValue & ePdfPermissions_HighPrint) == ePdfPermissions_HighPrint; } } //end namespace PoDoFo #endif // _PDFENCRYPT_H_ podofo-0.9.5/src/base/PdfOutputDevice.h0000664000175000017500000002221213012362162017602 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_OUTPUT_DEVICE_H_ #define _PDF_OUTPUT_DEVICE_H_ #include #include #include "PdfDefines.h" #include "PdfLocale.h" #include "PdfRefCountedBuffer.h" namespace PoDoFo { /** This class provides an output device which operates * either on a file or on a buffer in memory. * Additionally it can count the bytes written to the device. * * This class is suitable for inheritance to provide output * devices of your own for PoDoFo. * Just overide the required virtual methods. */ class PODOFO_API PdfOutputDevice { public: /** Construct a new PdfOutputDevice that does not write any data. Only the length * of the data is counted. * */ PdfOutputDevice(); /** Construct a new PdfOutputDevice that writes all data to a file. * * \param pszFilename path to a file that will be opened and all data * is written to this file. * \param bTruncate whether to truncate the file after open. This is useful * for incremental updates, to not truncate the file when * writing to the same file as the loaded. Default is true. * * When the bTruncate is false, the device is automatically positioned * to the end of the file. */ PdfOutputDevice( const char* pszFilename, bool bTruncate = true ); #ifdef _WIN32 /** Construct a new PdfOutputDevice that writes all data to a file. * * \param pszFilename path to a file that will be opened and all data * is written to this file. * \param bTruncate whether to truncate the file after open. This is useful * for incremental updates, to not truncate the file when * writing to the same file as the loaded. Default is true. * * When the bTruncate is false, the device is automatically positioned * to the end of the file. * * This is an overloaded member function to allow working * with unicode characters. On Unix systes you can also path * UTF-8 to the const char* overload. */ PdfOutputDevice( const wchar_t* pszFilename, bool bTruncate = true ); #endif // _WIN32 /** Construct a new PdfOutputDevice that writes all data to a memory buffer. * The buffer will not be owned by this object and has to be allocated before. * * \param pBuffer a buffer in memory * \param lLen the length of the buffer in memory */ PdfOutputDevice( char* pBuffer, size_t lLen ); /** Construct a new PdfOutputDevice that writes all data to a std::ostream. * * WARNING: PoDoFo will change the stream's locale. It will be restored when * the PdfOutputStream controlling the stream is destroyed. * * \param pOutStream write to this std::ostream */ PdfOutputDevice( const std::ostream* pOutStream ); /** Construct a new PdfOutputDevice that writes all data to a PdfRefCountedBuffer. * This output device has the advantage that the PdfRefCountedBuffer will resize itself * if more memory is needed to hold all data. * * \param pOutBuffer write to this PdfRefCountedBuffer * * \see PdfRefCountedBuffer */ PdfOutputDevice( PdfRefCountedBuffer* pOutBuffer ); /** Destruct the PdfOutputDevice object and close any open files. */ virtual ~PdfOutputDevice(); /** The number of bytes written to this object. * \returns the number of bytes written to this object. * * \see Init */ virtual inline size_t GetLength() const; /** Write to the PdfOutputDevice. Usage is as the usage of printf. * * WARNING: Do not use this for doubles or floating point values * as the output might depend on the current locale. * * \param pszFormat a format string as you would use it with printf * * \see Write */ virtual void Print( const char* pszFormat, ... ); /** Write to the PdfOutputDevice. Usage is as the usage of printf. * * WARNING: Do not use this for doubles or floating point values * as the output might depend on the current locale. * * \param pszFormat a format string as you would use it with printf * \param lBytes length of the format string in bytes when written * \param argptr variable argument list * * \see Write */ virtual void PrintV( const char* pszFormat, long lBytes, va_list argptr ); /** * Determine the length of a format string in bytes * when written using PrintV * * \param pszFormat format string * \param args variable argument list * * \returns length in bytes * \see PrintV */ long PrintVLen( const char* pszFormat, va_list args ); /** Write data to the buffer. Use this call instead of Print if you * want to write binary data to the PdfOutputDevice. * * \param pBuffer a pointer to the data buffer * \param lLen write lLen bytes of pBuffer to the PdfOutputDevice * * \see Print */ virtual void Write( const char* pBuffer, size_t lLen ); /** Read data from the device * \param pBuffer a pointer to the data buffer * \param lLen length of the output buffer * \returns Number of read bytes. Return 0 if EOF */ virtual size_t Read( char* pBuffer, size_t lLen ); /** Seek the device to the position offset from the begining * \param offset from the beginning of the file */ virtual void Seek( size_t offset ); /** Get the current offset from the beginning of the file. * \return the offset form the beginning of the file. */ virtual inline size_t Tell() const; /** Flush the output files buffer to disk if this devices * operates on a disk. */ virtual void Flush(); private: /** Initialize all private members */ void Init(); protected: size_t m_ulLength; private: FILE* m_hFile; char* m_pBuffer; size_t m_lBufferLen; std::ostream* m_pStream; std::istream* m_pReadStream; bool m_pStreamOwned; #if USE_CXX_LOCALE std::locale m_pStreamSavedLocale; #endif PdfRefCountedBuffer* m_pRefCountedBuffer; size_t m_ulPosition; PdfRefCountedBuffer m_printBuffer; }; // ----------------------------------------------------- // // ----------------------------------------------------- size_t PdfOutputDevice::GetLength() const { return m_ulLength; } // ----------------------------------------------------- // // ----------------------------------------------------- size_t PdfOutputDevice::Tell() const { return m_ulPosition; } }; #endif // _PDF_OUTPUT_DEVICE_H_ podofo-0.9.5/src/base/PdfDefines.h0000664000175000017500000004607113035513162016553 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_DEFINES_H_ #define _PDF_DEFINES_H_ /** \file PdfDefines.h * This file should be included as the FIRST file in every header of * PoDoFo lib. It includes all standard files, defines some useful * macros, some datatypes and all important enumeration types. On * supporting platforms it will be precompiled to speed compilation. */ #include "PdfCompilerCompat.h" /** * PoDoFo version - 24-bit integer representation. * Version is 0xMMmmpp where M is major, m is minor and p is patch * eg 0.7.0 is represented as 0x000700 * eg 0.7.99 is represented as 0x000763 * * Note that the PoDoFo version is available in parts as individual 8-bit * integer literals in PODOFO_VERSION_MAJOR, PODOFO_VERSION_MINOR and * PODOFO_VERSION_PATCH . */ #define PODOFO_MAKE_VERSION_REAL(M,m,p) ( (M<<16)+(m<<8)+(p) ) #define PODOFO_MAKE_VERSION(M,m,p) PODOFO_MAKE_VERSION_REAL(M,m,p) #define PODOFO_VERSION PODOFO_MAKE_VERSION(PODOFO_VERSION_MAJOR, PODOFO_VERSION_MINOR, PODOFO_VERSION_PATCH) /** * PoDoFo version represented as a string literal, eg '0.7.99' */ // The \0 is from Win32 example resources and the other values in PoDoFo's one #define PODOFO_MAKE_VERSION_STR_REAL(M,m,p) M ## . ## m ## . ## p #define PODOFO_STR(x) #x "\0" #define PODOFO_XSTR(x) PODOFO_STR(x) #define PODOFO_MAKE_VERSION_STR(M,m,p) PODOFO_XSTR(PODOFO_MAKE_VERSION_STR_REAL(M,m,p)) #define PODOFO_VERSION_STR PODOFO_MAKE_VERSION_STR(PODOFO_VERSION_MAJOR, PODOFO_VERSION_MINOR, PODOFO_VERSION_PATCH) #ifndef PODOFO_COMPILE_RC #ifndef PODOFO_UNUSED_PARAM #define PODOFO_UNUSED_PARAM(x) #endif // Include common system files // (most are now pulled in my PdfCompilerCompat.h) #include // Include common STL files #include #include #include #include // Include common BOOST settings #ifdef PODOFO_HAVE_BOOST #include #endif // PODOFO_HAVE_BOOST /** \def PODOFO_VERBOSE_DEBUG * Debug define. Enable it, if you need * more debuf output to the commandline from PoDoFo * * Setting PDF_VERBOSE_DEBUG will make PoDoFo * EXTREMELY slow and verbose, so it's not practical * even for regular debuggin. */ #ifndef PODOFO_VERBOSE_DEBUG //#define PODOFO_VERBOSE_DEBUG #endif //PODOFO_VERBOSE_DEBUG // Should we do lots of extra (expensive) sanity checking? You should not // define this on production builds because of the runtime cost and because it // might cause the library to abort() if it notices something nasty. // It may also change the size of some objects, and is thus not binary // compatible. // // If you don't know you need this, avoid it. // #ifndef PODOFO_EXTRA_CHECKS //#define PODOFO_EXTRA_CHECKS #endif //PODOFO_EXTRA_CHECKS // Error Handling Defines #include "PdfError.h" // Memory management #include "PdfMemoryManagement.h" // Include API macro definitions #include "podofoapi.h" #ifdef DEBUG #include #define PODOFO_ASSERT( x ) assert( x ); #else #define PODOFO_ASSERT( x ) do { if (!(x)) PODOFO_RAISE_ERROR_INFO(ePdfError_InternalLogic, #x); } while (false) #endif // DEBUG // By default, PoDoFo will use C++ locale support to ensure that // it doesn't write bad PDF data - particularly floating point numbers. // If your standard library does not support locales this won't work, but // your STL probably writes all data in a POSIX-like way irrespective of // locale. If you set this to 0, you MUST use some other method to ensure // that streams used by PoDoFo will write data in a POSIX locale like manner. #ifndef USE_CXX_LOCALE #define USE_CXX_LOCALE 1 #endif /** * \namespace PoDoFo * * All classes, functions, types and enums of PoDoFo * are members of these namespace. * * If you use PoDoFo, you might want to add the line: * using namespace PoDoFo; * to your application. */ namespace PoDoFo { /* Explicitly big-endian short, suitable for unicode text */ typedef pdf_uint16 pdf_utf16be; /* Typedef to indicate utf-8 encoded data */ typedef unsigned char pdf_utf8; // Enums /** * Enum to identify diferent versions of the PDF file format */ enum EPdfVersion { ePdfVersion_1_0 = 0, /**< PDF 1.0 */ ePdfVersion_1_1, /**< PDF 1.1 */ ePdfVersion_1_2, /**< PDF 1.2 */ ePdfVersion_1_3, /**< PDF 1.3 */ ePdfVersion_1_4, /**< PDF 1.4 */ ePdfVersion_1_5, /**< PDF 1.5 */ ePdfVersion_1_6, /**< PDF 1.6 */ ePdfVersion_1_7 /**< PDF 1.7 */ }; /** The default PDF Version used by new PDF documents * in PoDoFo. */ const EPdfVersion ePdfVersion_Default = ePdfVersion_1_3; /** * Specify additional options for writing the PDF. */ enum EPdfWriteMode { ePdfWriteMode_Compact = 0x01, ///< Try to write the PDF as compact as possible (Default) ePdfWriteMode_Clean = 0x02, ///< Create a PDF that is readable in a text editor, i.e. insert spaces and linebreaks between tokens }; const EPdfWriteMode ePdfWriteMode_Default = ePdfWriteMode_Compact; /** * Every PDF datatype that can occur in a PDF file * is referenced by an own enum (e.g. Bool or String). * * \see PdfVariant * * Remember to update PdfVariant::GetDataTypeString() when adding members here. */ enum EPdfDataType PODOFO_ENUM_UINT8 { ePdfDataType_Bool, /**< Boolean datatype: Accepts the values "true" and "false" */ ePdfDataType_Number, /**< Number datatype for integer values */ ePdfDataType_Real, /**< Real datatype for floating point numbers */ ePdfDataType_String, /**< String datatype in PDF file. Strings have the form (Hallo World!) in PDF files. \see PdfString */ ePdfDataType_HexString, /**< HexString datatype in PDF file. Hex encoded strings have the form <AF00BE> in PDF files. \see PdfString */ ePdfDataType_Name, /**< Name datatype. Names are used as keys in dictionary to reference values. \see PdfName */ ePdfDataType_Array, /**< An array of other PDF data types. */ ePdfDataType_Dictionary, /**< A dictionary associates keys with values. A key can have another dictionary as value. */ //ePdfDataType_Stream, /**< A stream can be attached to a dictionary and contain additional data. \see PdfStream */ ePdfDataType_Null, /**< The null datatype is always null. */ ePdfDataType_Reference, /**< The reference datatype contains references to PDF objects in the PDF file of the form 4 0 R. \see PdfObject */ ePdfDataType_RawData, /**< Raw PDF data */ ePdfDataType_Unknown /**< The Datatype is unknown */ }; /** * Every filter that can be used to encode a stream * in a PDF file is referenced by an own enum value. * Common filters are ePdfFilter_FlateDecode (i.e. Zip) or * ePdfFilter_ASCIIHexDecode */ enum EPdfFilter { ePdfFilter_None = -1, /**< Do not use any filtering */ ePdfFilter_ASCIIHexDecode, /**< Converts data from and to hexadecimal. Increases size of the data by a factor of 2! \see PdfHexFilter */ ePdfFilter_ASCII85Decode, /**< Converts to and from Ascii85 encoding. \see PdfAscii85Filter */ ePdfFilter_LZWDecode, ePdfFilter_FlateDecode, /**< Compress data using the Flate algorithm of ZLib. This filter is recommended to be used always. \see PdfFlateFilter */ ePdfFilter_RunLengthDecode, /**< Run length decode data. \see PdfRLEFilter */ ePdfFilter_CCITTFaxDecode, ePdfFilter_JBIG2Decode, ePdfFilter_DCTDecode, ePdfFilter_JPXDecode, ePdfFilter_Crypt }; /** * Enum for the different font formats supported by PoDoFo */ enum EPdfFontType { ePdfFontType_TrueType, ePdfFontType_Type1Pfa, ePdfFontType_Type1Pfb, ePdfFontType_Type1Base14, ePdfFontType_Type3, ePdfFontType_Unknown = 0xff }; /** * Enum for the colorspaces supported * by PDF. */ enum EPdfColorSpace { ePdfColorSpace_DeviceGray, /**< Gray */ ePdfColorSpace_DeviceRGB, /**< RGB */ ePdfColorSpace_DeviceCMYK, /**< CMYK */ ePdfColorSpace_Separation, /**< Separation */ ePdfColorSpace_CieLab, /**< CIE-Lab */ ePdfColorSpace_Indexed, /**< Indexed */ ePdfColorSpace_Unknown = 0xff }; /** * Enum for text rendering mode (Tr) */ enum EPdfTextRenderingMode { ePdfTextRenderingMode_Fill = 0, /**< Default mode, fill text */ ePdfTextRenderingMode_Stroke, /**< Stroke text */ ePdfTextRenderingMode_FillAndStroke, /**< Fill, then stroke text */ ePdfTextRenderingMode_Invisible, /**< Neither fill nor stroke text (invisible) */ ePdfTextRenderingMode_FillToClipPath, /**< Fill text and add to path for clipping */ ePdfTextRenderingMode_StrokeToClipPath, /**< Stroke text and add to path for clipping */ ePdfTextRenderingMode_FillAndStrokeToClipPath, /**< Fill, then stroke text and add to path for clipping */ ePdfTextRenderingMode_ToClipPath, /**< Add text to path for clipping */ ePdfTextRenderingMode_Unknown = 0xff }; /** * Enum for the different stroke styles that can be set * when drawing to a PDF file (mostly for line drawing). */ enum EPdfStrokeStyle { ePdfStrokeStyle_Solid, ePdfStrokeStyle_Dash, ePdfStrokeStyle_Dot, ePdfStrokeStyle_DashDot, ePdfStrokeStyle_DashDotDot, ePdfStrokeStyle_Custom }; /** * Enum for predefined tiling patterns. */ enum EPdfTilingPatternType { ePdfTilingPatternType_BDiagonal = 1, ePdfTilingPatternType_Cross, ePdfTilingPatternType_DiagCross, ePdfTilingPatternType_FDiagonal, ePdfTilingPatternType_Horizontal, ePdfTilingPatternType_Vertical, ePdfTilingPatternType_Image }; /** * Enum for line cap styles when drawing. */ enum EPdfLineCapStyle { ePdfLineCapStyle_Butt = 0, ePdfLineCapStyle_Round = 1, ePdfLineCapStyle_Square = 2 }; /** * Enum for line join styles when drawing. */ enum EPdfLineJoinStyle { ePdfLineJoinStyle_Miter = 0, ePdfLineJoinStyle_Round = 1, ePdfLineJoinStyle_Bevel = 2 }; /** * Enum for vertical text alignment */ enum EPdfVerticalAlignment { ePdfVerticalAlignment_Top = 0, ePdfVerticalAlignment_Center = 1, ePdfVerticalAlignment_Bottom = 2 }; /** * Enum for text alignment */ enum EPdfAlignment { ePdfAlignment_Left = 0, ePdfAlignment_Center = 1, ePdfAlignment_Right = 2 }; /** * List of defined Rendering intents */ #define ePdfRenderingIntent_AbsoluteColorimetric "AbsoluteColorimetric" #define ePdfRenderingIntent_RelativeColorimetric "RelativeColorimetric" #define ePdfRenderingIntent_Perceptual "Perceptual" #define ePdfRenderingIntent_Saturation "Saturation" /** * List of defined transparency blending modes */ #define ePdfBlendMode_Normal "Normal" #define ePdfBlendMode_Multiply "Multiply" #define ePdfBlendMode_Screen "Screen" #define ePdfBlendMode_Overlay "Overlay" #define ePdfBlendMode_Darken "Darken" #define ePdfBlendMode_Lighten "Lighten" #define ePdfBlendMode_ColorDodge "ColorDodge" #define ePdfBlendMode_ColorBurn "ColorBurn" #define ePdfBlendMode_HardLight "HardLight" #define ePdfBlendMode_SoftLight "SoftLight" #define ePdfBlendMode_Difference "Difference" #define ePdfBlendMode_Exclusion "Exclusion" #define ePdfBlendMode_Hue "Hue" #define ePdfBlendMode_Saturation "Saturation" #define ePdfBlendMode_Color "Color" #define ePdfBlendMode_Luminosity "Luminosity" /** * Enum holding the supported page sizes by PoDoFo. * Can be used to construct a PdfRect structure with * measurements of a page object. * * \see PdfPage */ enum EPdfPageSize { ePdfPageSize_A0, /**< DIN A0 */ ePdfPageSize_A1, /**< DIN A1 */ ePdfPageSize_A2, /**< DIN A2 */ ePdfPageSize_A3, /**< DIN A3 */ ePdfPageSize_A4, /**< DIN A4 */ ePdfPageSize_A5, /**< DIN A5 */ ePdfPageSize_A6, /**< DIN A6 */ ePdfPageSize_Letter, /**< Letter */ ePdfPageSize_Legal, /**< Legal */ ePdfPageSize_Tabloid /**< Tabloid */ }; /** * Enum holding the supported of types of "PageModes" * that define which (if any) of the "panels" are opened * in Acrobat when the document is opened. * * \see PdfDocument */ enum EPdfPageMode { ePdfPageModeDontCare, ePdfPageModeUseNone, ePdfPageModeUseThumbs, ePdfPageModeUseBookmarks, ePdfPageModeFullScreen, ePdfPageModeUseOC, ePdfPageModeUseAttachments }; /** * Enum holding the supported of types of "PageLayouts" * that define how Acrobat will display the pages in * relation to each other * * \see PdfDocument */ enum EPdfPageLayout { ePdfPageLayoutIgnore, ePdfPageLayoutDefault, ePdfPageLayoutSinglePage, ePdfPageLayoutOneColumn, ePdfPageLayoutTwoColumnLeft, ePdfPageLayoutTwoColumnRight, ePdfPageLayoutTwoPageLeft, ePdfPageLayoutTwoPageRight }; /** */ const bool ePdfCreateObject = true; const bool ePdfDontCreateObject = false; // character constants #define MAX_PDF_VERSION_STRING_INDEX 7 // We use fixed bounds two dimensional arrays here so that // they go into the const data section of the library. static const char s_szPdfVersions[][9] = { "%PDF-1.0", "%PDF-1.1", "%PDF-1.2", "%PDF-1.3", "%PDF-1.4", "%PDF-1.5", "%PDF-1.6", "%PDF-1.7" }; static const char s_szPdfVersionNums[][4] = { "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7" }; /// PDF Reference, Section 3.1.1, Table 3.1, White-space characters const int s_nNumWhiteSpaces = 6; const char s_cWhiteSpaces[] = { 0x00, // NULL 0x09, // TAB 0x0A, // Line Feed 0x0C, // Form Feed 0x0D, // Carriage Return 0x20, // White Space 0x00 // end marker }; /// PDF Reference, Section 3.1.1, Character Set static const int s_nNumDelimiters = 10; static const char s_cDelimiters[] = { '(', ')', '<', '>', '[', ']', '{', '}', '/', '%', '\0' // end marker }; /** * PDF_MAX(x,y) * * \returns the maximum of x and y */ // Not actually a macro, because function-like macros are evil and // prone to nasty issues with double-evaluation of arguments. template const T PDF_MAX ( const T a, const T b ) { return (b const T PDF_MIN ( const T a, const T b ) { return (aPoDoFo
is a library to work with the PDF file format and includes also a few * tools. The name comes from the first letter of PDF (Portable Document * Format). * * The PoDoFo library is a free portable C++ library which includes * classes to parse a PDF file and modify its contents into memory. The changes * can be written back to disk easily. The parser could also be used to write a * PDF viewer. Besides parsing PoDoFo includes also very simple classes to create * your own PDF files. All classes are documented so it is easy to start writing * your own application using PoDoFo. * * The PoDoFo tools are simple tools build around the PoDoFo library. These tools * are first of all examples on how to use the PoDoFo library in your own * projects. But secondly they offer also features for working with PDF * files. More tools will come with future release and the existing tools will * gain more features. Currently there are two tools: podofoimgextract (which * extracts all jpeg images from a given PDF file) and podofouncompress (which * removes all compression filters from a PDF file - this is useful for debugging * existing PDF files). * * Additionally there is the external tool PoDoFoBrowser which is not included in * this package, but can be downloaded from the PoDoFo webpage. PoDoFoBrowser is * a Qt application for browsing the objects in a PDF file and modifying their * keys easily. It is very useful if you want to look on the internal structure * of PDF files. * * As of now PoDoFo is available for Unix, Mac OS X and Windows platforms. * * More information can be found at: http://podofo.sourceforge.net * * PoDoFo is created by Dominik Seichter , * Leonard Rosenthol and Craig Ringer * * \page Codingstyle (Codingstyle) * \verbinclude CODINGSTYLE.txt * */ #endif // !PODOFO_COMPILE_RC #endif // _PDF_DEFINES_H_ podofo-0.9.5/src/base/PdfDate.h0000664000175000017500000001327713013650710016052 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_DATE_H_ #define _PDF_DATE_H_ #include "PdfDefines.h" #include "PdfString.h" #include // a PDF date has a maximum of 26 bytes incuding the terminating \0 #define PDF_DATE_BUFFER_SIZE 26 namespace PoDoFo { /** This class is a date datatype as specified in the PDF * reference. You can easily convert from Unix time_t to * the PDF time representation and back. Dates like these * are used for example in the PDF info dictionary for the * creation time and date of the PDF file. * * PdfDate objects are immutable. * * From the PDF reference: * * PDF defines a standard date format, which closely follows * that of the international standard ASN.1 (Abstract Syntax * Notation One), defined in ISO/IEC 8824 (see the Bibliography). * A date is a string of the form * (D:YYYYMMDDHHmmSSOHH'mm') */ class PODOFO_API PdfDate { public: /** Create a PdfDate object with the current date and time. */ PdfDate(); /** Create a PdfDate with a specified date and time * \param t the date and time of this object * * Use IsValid to check wether the time_t could be * converted to a valid PdfDate object. * * \see IsValid() */ PdfDate( const time_t & t ); /** Create a PdfDate with a specified date and time * \param szDate the date and time of this object * in PDF format. It has to be a string of * the format (D:YYYYMMDDHHmmSSOHH'mm'). * Otherwise IsValid will return false. * * Use IsValid to check wether the string could be * converted to a valid PdfDate object. * * \see IsValid() */ PdfDate( const PdfString & sDate ); /** Delete the PdfDate object */ virtual ~PdfDate(); /** You can use this function to check wether the date * you passed to the constructor could be converted to * a valid pdf date string or a valid time_t. * * \returns true if the PdfDate object is valid */ inline bool IsValid() const; /** \returns the date and time of this PdfDate in * seconds since epoch. */ inline const time_t & GetTime() const; /** The value returned by this function can be used in any PdfObject * where a date is needed. * * \param rsString write the date to a PdfString */ inline void ToString( PdfString & rsString ) const; private: /** Creates the internal string representation from * a time_t value and writes it to m_szDate. */ void CreateStringRepresentation(); /** Parse fixed length number from string * \param in string to read number from * \param length of number to read * \param min minimal value of number * \param max maximal value of number * \param ret parsed number */ bool ParseFixLenNumber(const char *&in, unsigned int length, int min, int max, int &ret); private: time_t m_time; char m_szDate[PDF_DATE_BUFFER_SIZE + 1]; // include also room for a nul-terminator in the buffer bool m_bValid; }; const time_t & PdfDate::GetTime() const { return m_time; } void PdfDate::ToString( PdfString & rsString ) const { rsString = PdfString( m_szDate ); } bool PdfDate::IsValid() const { return m_bValid; } }; #endif // _PDF_DATE_H_ podofo-0.9.5/src/base/PdfEncrypt.cpp0000664000175000017500000022132313013306226017145 0ustar dominikdominik/* ********************************************************************** ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** ** ** ** License to copy and use this software is granted provided that ** ** it is identified as the "RSA Data Security, Inc. MD5 Message ** ** Digest Algorithm" in all material mentioning or referencing this ** ** software or this function. ** ** ** ** License is also granted to make and use derivative works ** ** provided that such works are identified as "derived from the RSA ** ** Data Security, Inc. MD5 Message Digest Algorithm" in all ** ** material mentioning or referencing the derived work. ** ** ** ** RSA Data Security, Inc. makes no representations concerning ** ** either the merchantability of this software or the suitability ** ** of this software for any particular purpose. It is provided "as ** ** is" without express or implied warranty of any kind. ** ** ** ** These notices must be retained in any copies of any part of this ** ** documentation and/or software. ** ********************************************************************** */ // includes #include "PdfEncrypt.h" #include "PdfDictionary.h" #include "PdfFilter.h" #include "PdfDefinesPrivate.h" #include #include #include #ifdef PODOFO_HAVE_OPENSSL // SHA-256 #ifdef PODOFO_HAVE_LIBIDN // AES-256 dependencies : // SASL #include #include #endif // PODOFO_HAVE_LIBIDN #include #include #include #endif //PODOFO_HAVE_OPENSSL namespace { //RG: TODO Could we name literal 256 and use the literal name e.g. //const size_t KEY_SIZE = 256; } namespace PoDoFo { #ifdef PODOFO_HAVE_LIBIDN int PdfEncrypt::s_nEnabledEncryptionAlgorithms = #ifndef OPENSSL_NO_RC4 ePdfEncryptAlgorithm_RC4V1 | ePdfEncryptAlgorithm_RC4V2 | #endif // OPENSSL_NO_RC4 ePdfEncryptAlgorithm_AESV2 | ePdfEncryptAlgorithm_AESV3; #else // PODOFO_HAVE_LIBIDN int PdfEncrypt::s_nEnabledEncryptionAlgorithms = #ifndef OPENSSL_NO_RC4 ePdfEncryptAlgorithm_RC4V1 | ePdfEncryptAlgorithm_RC4V2 | #endif // OPENSSL_NO_RC4 ePdfEncryptAlgorithm_AESV2; #endif // PODOFO_HAVE_LIBIDN PdfEncrypt::~PdfEncrypt() { } int PdfEncrypt::GetEnabledEncryptionAlgorithms() { return PdfEncrypt::s_nEnabledEncryptionAlgorithms; } void PdfEncrypt::SetEnabledEncryptionAlgorithms(int nEncryptionAlgorithms) { PdfEncrypt::s_nEnabledEncryptionAlgorithms = nEncryptionAlgorithms; } bool PdfEncrypt::IsEncryptionEnabled(EPdfEncryptAlgorithm eAlgorithm) { return (PdfEncrypt::s_nEnabledEncryptionAlgorithms & eAlgorithm) != 0; } #ifdef PODOFO_HAVE_OPENSSL // Default value for P (permissions) = no permission #define PERMS_DEFAULT 0xFFFFF0C0 #define AES_IV_LENGTH 16 // A class that holds the AES Crypto object class AESCryptoEngine { public: AESCryptoEngine() { #ifdef PODOFO_HAVE_OPENSSL_1_1 aes = EVP_CIPHER_CTX_new(); #else EVP_CIPHER_CTX_init(&aes); #endif } EVP_CIPHER_CTX* getEngine() { #ifdef PODOFO_HAVE_OPENSSL_1_1 return aes; #else return &aes; #endif } ~AESCryptoEngine() { #ifdef PODOFO_HAVE_OPENSSL_1_1 EVP_CIPHER_CTX_free(aes); #else EVP_CIPHER_CTX_cleanup(&aes); #endif } private: #ifdef PODOFO_HAVE_OPENSSL_1_1 EVP_CIPHER_CTX *aes; #else EVP_CIPHER_CTX aes; #endif }; #ifndef OPENSSL_NO_RC4 // A class that holds the RC4 Crypto object // Either CCCrpytor or EVP_CIPHER_CTX class RC4CryptoEngine { public: RC4CryptoEngine() { #ifdef PODOFO_HAVE_OPENSSL_1_1 rc4 = EVP_CIPHER_CTX_new(); #else EVP_CIPHER_CTX_init(&rc4); #endif } EVP_CIPHER_CTX* getEngine() { #ifdef PODOFO_HAVE_OPENSSL_1_1 return rc4; #else return &rc4; #endif } ~RC4CryptoEngine() { #ifdef PODOFO_HAVE_OPENSSL_1_1 EVP_CIPHER_CTX_free(rc4); #else EVP_CIPHER_CTX_cleanup(&rc4); #endif } private: #ifdef PODOFO_HAVE_OPENSSL_1_1 EVP_CIPHER_CTX *rc4; #else EVP_CIPHER_CTX rc4; #endif }; /** A class that can encrypt/decrpyt streamed data block wise * This is used in the input and output stream encryption implementation. * Only the RC4 encryption algorithm is supported */ class PdfRC4Stream { public: PdfRC4Stream( unsigned char rc4key[256], unsigned char rc4last[256], unsigned char* key, const size_t keylen ) : m_a( 0 ), m_b( 0 ) { size_t i; size_t j; size_t t; if (memcmp(key,rc4key,keylen) != 0) { for (i = 0; i < 256; i++) m_rc4[i] = static_cast(i); j = 0; for (i = 0; i < 256; i++) { t = static_cast(m_rc4[i]); j = (j + t + static_cast(key[i % keylen])) % 256; m_rc4[i] = m_rc4[j]; m_rc4[j] = static_cast(t); } memcpy(rc4key, key, keylen); memcpy(rc4last, m_rc4, 256); } else { memcpy(m_rc4, rc4last, 256); } } ~PdfRC4Stream() { } /** Encrypt or decrypt a block * * \param pBuffer the input/output buffer. Data is read from this buffer and also stored here * \param lLen the size of the buffer */ pdf_long Encrypt( char* pBuffer, pdf_long lLen ) { unsigned char k; pdf_long t, i; // Do not encode data with no length if( !lLen ) return lLen; for (i = 0; i < lLen; i++ ) { m_a = (m_a + 1) % 256; t = m_rc4[m_a]; m_b = (m_b + t) % 256; m_rc4[m_a] = m_rc4[m_b]; m_rc4[m_b] = static_cast(t); k = m_rc4[(m_rc4[m_a] + m_rc4[m_b]) % 256]; pBuffer[i] = pBuffer[i] ^ k; } return lLen; } private: unsigned char m_rc4[256]; int m_a; int m_b; }; /** A PdfOutputStream that encrypt all data written * using the RC4 encryption algorithm */ class PdfRC4OutputStream : public PdfOutputStream { public: PdfRC4OutputStream( PdfOutputStream* pOutputStream, unsigned char rc4key[256], unsigned char rc4last[256], unsigned char* key, int keylen ) : m_pOutputStream( pOutputStream ), m_stream( rc4key, rc4last, key, keylen ) { } virtual ~PdfRC4OutputStream() { } /** Write data to the output stream * * \param pBuffer the data is read from this buffer * \param lLen the size of the buffer */ virtual pdf_long Write( const char* pBuffer, pdf_long lLen ) { // Do not encode data with no length if( !lLen ) return lLen; char* pOutputBuffer = static_cast(podofo_calloc( lLen, sizeof(char) )); if( !pOutputBuffer ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } memcpy(pOutputBuffer, pBuffer, lLen); m_stream.Encrypt( pOutputBuffer, lLen ); m_pOutputStream->Write( pOutputBuffer, lLen ); podofo_free( pOutputBuffer ); return lLen; } /** Close the PdfOutputStream. * This method may throw exceptions and has to be called * before the descructor to end writing. * * No more data may be written to the output device * after calling close. */ virtual void Close() { } private: PdfOutputStream* m_pOutputStream; PdfRC4Stream m_stream; }; /** A PdfInputStream that decrypts all data read * using the RC4 encryption algorithm */ class PdfRC4InputStream : public PdfInputStream { public: PdfRC4InputStream( PdfInputStream* pInputStream, unsigned char rc4key[256], unsigned char rc4last[256], unsigned char* key, int keylen ) : m_pInputStream( pInputStream ), m_stream( rc4key, rc4last, key, keylen ) { } virtual ~PdfRC4InputStream() { } /** Read data from the input stream * * \param pBuffer the data will be stored into this buffer * \param lLen the size of the buffer and number of bytes * that will be read * * \returns the number of bytes read, -1 if an error ocurred * and zero if no more bytes are available for reading. */ virtual pdf_long Read( char* pBuffer, pdf_long lLen, pdf_long* ) { // Do not encode data with no length if( !lLen ) return lLen; m_pInputStream->Read( pBuffer, lLen ); m_stream.Encrypt( pBuffer, lLen ); return lLen; } private: PdfInputStream* m_pInputStream; PdfRC4Stream m_stream; }; #endif // OPENSSL_NO_RC4 /** A class that can encrypt/decrpyt streamed data block wise * This is used in the input and output stream encryption implementation. */ class PdfAESStream : public PdfEncryptAESBase { public: PdfAESStream( unsigned char* key, const size_t keylen ) : keyLen( keylen ), bFirstRead( true ), bOnlyFinalLeft( false ) { memcpy( this->key, key, keylen ); } ~PdfAESStream() {} /** Decrypt a block * * \param pBuffer the input/output buffer. Data is read from this buffer and also stored here * \param lLen the size of the buffer * \param pTotalLeft total bytes left (needed for AES IV and padding) */ pdf_long Decrypt( unsigned char* pBuffer, pdf_long lLen, pdf_long* pTotalLeft ) { if (pTotalLeft == 0) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-decryption needs pTotalLeft" ); if( lLen % 16 != 0 ) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-decryption data length not a multiple of 16" ); EVP_CIPHER_CTX* aes = m_aes->getEngine(); int lOutLen = 0, lStepOutLen; int status = 1; if( bFirstRead ) { bFirstRead = false; if( keyLen == PdfEncrypt::ePdfKeyLength_128/8 ) { status = EVP_DecryptInit_ex( aes, EVP_aes_128_cbc(), NULL, key, pBuffer ); #ifdef PODOFO_HAVE_LIBIDN } else if( keyLen == PdfEncrypt::ePdfKeyLength_256/8 ) { status = EVP_DecryptInit_ex( aes, EVP_aes_256_cbc(), NULL, key, pBuffer ); #endif } else { PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Invalid AES key length" ); } if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing AES encryption engine" ); status = EVP_DecryptUpdate( aes, pBuffer, &lOutLen, pBuffer + AES_IV_LENGTH, lLen - AES_IV_LENGTH ); } else if( !bOnlyFinalLeft ) { // Quote openssl.org: "the decrypted data buffer out passed to EVP_DecryptUpdate() should have sufficient room // for (inl + cipher_block_size) bytes unless the cipher block size is 1 in which case inl bytes is sufficient." // So we need to create a buffer that is bigger than lLen. unsigned char* tempBuffer = new unsigned char[lLen + 16]; status = EVP_DecryptUpdate( aes, tempBuffer, &lOutLen, pBuffer, lLen ); memcpy( pBuffer, tempBuffer, lOutLen ); delete[] tempBuffer; } if( status != 1 ) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-decryption data" ); if( lLen == *pTotalLeft ) { // Last chunk of the stream if( lLen == lOutLen ) { // Buffer is full, so we need an other round for EVP_DecryptFinal_ex. bOnlyFinalLeft = true; *pTotalLeft += 16; } else { status = EVP_DecryptFinal_ex( aes, pBuffer + lOutLen, &lStepOutLen ); if( status != 1 ) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-decryption data padding" ); lOutLen += lStepOutLen; } } *pTotalLeft -= lLen - lOutLen; // AES makes the resulting buffer shorter (IV and padding) return lOutLen; } private: unsigned char key[32]; const size_t keyLen; bool bFirstRead; bool bOnlyFinalLeft; }; /** A PdfAESInputStream that decrypts all data read * using the AES encryption algorithm */ class PdfAESInputStream : public PdfInputStream { public: PdfAESInputStream( PdfInputStream* pInputStream, unsigned char* key, int keylen ) : m_pInputStream( pInputStream ), m_stream( key, keylen ) { } virtual ~PdfAESInputStream() { } /** Read data from the input stream * * \param pBuffer the data will be stored into this buffer * \param lLen the size of the buffer and number of bytes * that will be read * \param pTotalLeft total bytes left (needed for AES IV and padding) * * \returns the number of bytes read, -1 if an error ocurred * and zero if no more bytes are available for reading. */ virtual pdf_long Read( char* pBuffer, pdf_long lLen, pdf_long *pTotalLeft ) { // Do not encode data with no length if( !lLen ) return lLen; m_pInputStream->Read( pBuffer, lLen ); return m_stream.Decrypt( (unsigned char*)pBuffer, lLen, pTotalLeft ); } private: PdfInputStream* m_pInputStream; PdfAESStream m_stream; }; /*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ // --------------------------- // PdfEncrypt implementation // Based on code from Ulrich Telle: http://wxcode.sourceforge.net/components/wxpdfdoc/ // --------------------------- static unsigned char padding[] = "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A"; PdfEncrypt * PdfEncrypt::CreatePdfEncrypt( const std::string & userPassword, const std::string & ownerPassword, int protection, EPdfEncryptAlgorithm eAlgorithm, EPdfKeyLength eKeyLength ) { PdfEncrypt *pdfEncrypt = NULL; switch (eAlgorithm) { case ePdfEncryptAlgorithm_AESV2: default: pdfEncrypt = new PdfEncryptAESV2(userPassword, ownerPassword, protection); break; #ifdef PODOFO_HAVE_LIBIDN case ePdfEncryptAlgorithm_AESV3: pdfEncrypt = new PdfEncryptAESV3(userPassword, ownerPassword, protection); break; #endif // PODOFO_HAVE_LIBIDN #ifndef OPENSSL_NO_RC4 case ePdfEncryptAlgorithm_RC4V2: case ePdfEncryptAlgorithm_RC4V1: pdfEncrypt = new PdfEncryptRC4(userPassword, ownerPassword, protection, eAlgorithm, eKeyLength); break; #endif // OPENSSL_NO_RC4 } return pdfEncrypt; } PdfEncrypt* PdfEncrypt::CreatePdfEncrypt( const PdfObject* pObject ) { PdfEncrypt* pdfEncrypt = NULL; if( !pObject->GetDictionary().HasKey( PdfName("Filter") ) || pObject->GetDictionary().GetKey( PdfName("Filter" ) )->GetName() != PdfName("Standard") ) { std::ostringstream oss; if( pObject->GetDictionary().HasKey( PdfName("Filter") ) ) { oss << "Unsupported encryption filter: " << pObject->GetDictionary().GetKey( PdfName("Filter" ) )->GetName().GetName(); } else { oss << "Encryption dictionary does not have a key /Filter."; } PODOFO_RAISE_ERROR_INFO( ePdfError_UnsupportedFilter, oss.str().c_str() ); } long lV; pdf_int64 lLength; int rValue; int pValue; PdfString oValue; PdfString uValue; PdfName cfmName; bool encryptMetadata = true; try { PdfString sTmp; lV = static_cast(pObject->GetDictionary().GetKey( PdfName("V") )->GetNumber()); rValue = static_cast(pObject->GetDictionary().GetKey( PdfName("R") )->GetNumber()); pValue = static_cast(pObject->GetDictionary().GetKey( PdfName("P") )->GetNumber()); oValue = pObject->GetDictionary().GetKey( PdfName("O") )->GetString(); uValue = pObject->GetDictionary().GetKey( PdfName("U") )->GetString(); if( pObject->GetDictionary().HasKey( PdfName("Length") ) ) { lLength = pObject->GetDictionary().GetKey( PdfName("Length") )->GetNumber(); } else { lLength = 0; } const PdfObject *encryptMetadataObj = pObject->GetDictionary().GetKey( PdfName("EncryptMetadata") ); if( encryptMetadataObj && encryptMetadataObj->IsBool() ) encryptMetadata = encryptMetadataObj->GetBool(); const PdfObject *stmfObj = pObject->GetDictionary().GetKey( PdfName("StmF") ); if( stmfObj && stmfObj->IsName() ) { const PdfObject *obj = pObject->GetDictionary().GetKey( PdfName("CF") ); if( obj && obj->IsDictionary() ) { obj = obj->GetDictionary().GetKey( stmfObj->GetName() ); if( obj && obj->IsDictionary() ) { obj = obj->GetDictionary().GetKey( PdfName("CFM") ); if( obj && obj->IsName() ) cfmName = obj->GetName(); } } } } catch( PdfError & e ) { e.AddToCallstack( __FILE__, __LINE__, "Invalid key in encryption dictionary" ); throw e; } #ifndef OPENSSL_NO_RC4 if( (lV == 1L) && (rValue == 2L || rValue == 3L) && PdfEncrypt::IsEncryptionEnabled( ePdfEncryptAlgorithm_RC4V1 ) ) { pdfEncrypt = new PdfEncryptRC4(oValue, uValue, pValue, rValue, ePdfEncryptAlgorithm_RC4V1, 40, encryptMetadata); } else if( (((lV == 2L) && (rValue == 3L)) || cfmName == "V2") && PdfEncrypt::IsEncryptionEnabled( ePdfEncryptAlgorithm_RC4V2 ) ) { // [Alexey] - lLength is pdf_int64. Please make changes in encryption algorithms pdfEncrypt = new PdfEncryptRC4(oValue, uValue, pValue, rValue, ePdfEncryptAlgorithm_RC4V2, static_cast(lLength), encryptMetadata); } else #endif // OPENSSL_NO_RC4 if( (lV == 4L) && (rValue == 4L) && PdfEncrypt::IsEncryptionEnabled( ePdfEncryptAlgorithm_AESV2 ) ) { pdfEncrypt = new PdfEncryptAESV2(oValue, uValue, pValue, encryptMetadata); } #ifdef PODOFO_HAVE_LIBIDN else if( (lV == 5L) && (rValue == 5L) && PdfEncrypt::IsEncryptionEnabled( ePdfEncryptAlgorithm_AESV3 ) ) { PdfString permsValue = pObject->GetDictionary().GetKey( PdfName("Perms") )->GetString(); PdfString oeValue = pObject->GetDictionary().GetKey( PdfName("OE") )->GetString(); PdfString ueValue = pObject->GetDictionary().GetKey( PdfName("UE") )->GetString(); pdfEncrypt = new PdfEncryptAESV3(oValue, oeValue, uValue, ueValue, pValue, permsValue); } #endif // PODOFO_HAVE_LIBIDN else { std::ostringstream oss; oss << "Unsupported encryption method Version=" << lV << " Revision=" << rValue; PODOFO_RAISE_ERROR_INFO( ePdfError_UnsupportedFilter, oss.str().c_str() ); } return pdfEncrypt; } PdfEncrypt * PdfEncrypt::CreatePdfEncrypt(const PdfEncrypt & rhs ) { PdfEncrypt *pdfEncrypt = NULL; if (rhs.m_eAlgorithm == ePdfEncryptAlgorithm_AESV2) pdfEncrypt = new PdfEncryptAESV2(rhs); #ifdef PODOFO_HAVE_LIBIDN else if (rhs.m_eAlgorithm == ePdfEncryptAlgorithm_AESV3) pdfEncrypt = new PdfEncryptAESV3(rhs); #endif // PODOFO_HAVE_LIBIDN #ifndef OPENSSL_NO_RC4 else pdfEncrypt = new PdfEncryptRC4(rhs); #endif // OPENSSL_NO_RC4 return pdfEncrypt; } PdfEncrypt::PdfEncrypt( const PdfEncrypt & rhs ) { m_eAlgorithm = rhs.m_eAlgorithm; m_eKeyLength = rhs.m_eKeyLength; m_pValue = rhs.m_pValue; m_rValue = rhs.m_rValue; m_keyLength = rhs.m_keyLength; m_curReference = rhs.m_curReference; m_documentId = rhs.m_documentId; m_userPass = rhs.m_userPass; m_ownerPass = rhs.m_ownerPass; m_bEncryptMetadata = rhs.m_bEncryptMetadata; } bool PdfEncrypt::CheckKey(unsigned char key1[32], unsigned char key2[32]) { // Check whether the right password had been given bool ok = true; int k; for (k = 0; ok && k < m_keyLength; k++) { ok = ok && (key1[k] == key2[k]); } return ok; } PdfEncryptMD5Base::PdfEncryptMD5Base( const PdfEncrypt & rhs ) : PdfEncrypt(rhs) { const PdfEncrypt* ptr = &rhs; memcpy( m_uValue, rhs.GetUValue(), sizeof(unsigned char) * 32 ); memcpy( m_oValue, rhs.GetOValue(), sizeof(unsigned char) * 32 ); memcpy( m_encryptionKey, rhs.GetEncryptionKey(), sizeof(unsigned char) * 16 ); memcpy( m_rc4key, static_cast(ptr)->m_rc4key, sizeof(unsigned char) * 16 ); memcpy( m_rc4last, static_cast(ptr)->m_rc4last, sizeof(unsigned char) * 256 ); m_bEncryptMetadata = static_cast(ptr)->m_bEncryptMetadata; } void PdfEncryptMD5Base::PadPassword(const std::string& password, unsigned char pswd[32]) { size_t m = password.length(); if (m > 32) m = 32; size_t j; size_t p = 0; for (j = 0; j < m; j++) { pswd[p++] = static_cast( password[j] ); } for (j = 0; p < 32 && j < 32; j++) { pswd[p++] = padding[j]; } } bool PdfEncryptMD5Base::Authenticate(const std::string& documentID, const std::string& password, const std::string& uValue, const std::string& oValue, int pValue, int lengthValue, int rValue) { m_pValue = pValue; m_keyLength = lengthValue / 8; m_rValue = rValue; memcpy(m_uValue, uValue.c_str(), 32); memcpy(m_oValue, oValue.c_str(), 32); return Authenticate(password, documentID); } void PdfEncryptMD5Base::ComputeOwnerKey(unsigned char userPad[32], unsigned char ownerPad[32], int keyLength, int revision, bool authenticate, unsigned char ownerKey[32]) { unsigned char mkey[MD5_DIGEST_LENGTH]; unsigned char digest[MD5_DIGEST_LENGTH]; MD5_CTX ctx; int status = MD5_Init(&ctx); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing MD5 hashing engine" ); status = MD5_Update(&ctx, ownerPad, 32); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error MD5-hashing data" ); status = MD5_Final(digest,&ctx); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error MD5-hashing data" ); if ((revision == 3) || (revision == 4)) { // only use for the input as many bit as the key consists of for (int k = 0; k < 50; ++k) { status = MD5_Init(&ctx); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing MD5 hashing engine" ); status = MD5_Update(&ctx, digest, keyLength); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error MD5-hashing data" ); status = MD5_Final(digest,&ctx); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error MD5-hashing data" ); } memcpy(ownerKey, userPad, 32); for (unsigned int i = 0; i < 20; ++i) { for (int j = 0; j < keyLength ; ++j) { if (authenticate) mkey[j] = static_cast(static_cast(digest[j] ^ (19-i))); else mkey[j] = static_cast(static_cast(digest[j] ^ i)); } #ifndef OPENSSL_NO_RC4 RC4(mkey, keyLength, ownerKey, 32, ownerKey, 32); #endif // OPENSSL_NO_RC4 } } #ifndef OPENSSL_NO_RC4 else { RC4(digest, 5, userPad, 32, ownerKey, 32); } #endif // OPENSSL_NO_RC4 } void PdfEncryptMD5Base::ComputeEncryptionKey(const std::string& documentId, unsigned char userPad[32], unsigned char ownerKey[32], int pValue, int keyLength, int revision, unsigned char userKey[32], bool encryptMetadata) { int j; int k; m_keyLength = keyLength / 8; MD5_CTX ctx; int status = MD5_Init(&ctx); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing MD5 hashing engine" ); status = MD5_Update(&ctx, userPad, 32); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error MD5-hashing data" ); status = MD5_Update(&ctx, ownerKey, 32); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error MD5-hashing data" ); unsigned char ext[4]; ext[0] = static_cast ( pValue & 0xff); ext[1] = static_cast ((pValue >> 8) & 0xff); ext[2] = static_cast ((pValue >> 16) & 0xff); ext[3] = static_cast ((pValue >> 24) & 0xff); status = MD5_Update(&ctx, ext, 4); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error MD5-hashing data" ); unsigned int docIdLength = static_cast(documentId.length()); unsigned char* docId = NULL; if (docIdLength > 0) { docId = new unsigned char[docIdLength]; size_t j; for (j = 0; j < docIdLength; j++) { docId[j] = static_cast( documentId[j] ); } status = MD5_Update(&ctx, docId, docIdLength); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error MD5-hashing data" ); } // If document metadata is not being encrypted, // pass 4 bytes with the value 0xFFFFFFFF to the MD5 hash function. if( !encryptMetadata ) { unsigned char noMetaAddition[4] = { 0xff, 0xff, 0xff, 0xff }; status = MD5_Update(&ctx, noMetaAddition, 4); } unsigned char digest[MD5_DIGEST_LENGTH]; status = MD5_Final(digest,&ctx); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error MD5-hashing data" ); // only use the really needed bits as input for the hash if (revision == 3 || revision == 4) { for (k = 0; k < 50; ++k) { status = MD5_Init(&ctx); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing MD5 hashing engine" ); status = MD5_Update(&ctx, digest, m_keyLength); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error MD5-hashing data" ); status = MD5_Final(digest, &ctx); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error MD5-hashing data" ); } } memcpy(m_encryptionKey, digest, m_keyLength); // Setup user key if (revision == 3 || revision == 4) { status = MD5_Init(&ctx); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing MD5 hashing engine" ); status = MD5_Update(&ctx, padding, 32); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error MD5-hashing data" ); if (docId != NULL) { status = MD5_Update(&ctx, docId, docIdLength); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error MD5-hashing data" ); } status = MD5_Final(digest, &ctx); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error MD5-hashing data" ); memcpy(userKey, digest, 16); for (k = 16; k < 32; ++k) { userKey[k] = 0; } for (k = 0; k < 20; k++) { for (j = 0; j < m_keyLength; ++j) { digest[j] = static_cast(m_encryptionKey[j] ^ k); } #ifndef OPENSSL_NO_RC4 RC4(digest, m_keyLength, userKey, 16, userKey, 16); #endif // OPENSSL_NO_RC4 } } #ifndef OPENSSL_NO_RC4 else { RC4(m_encryptionKey, m_keyLength, padding, 32, userKey, 32); } #endif // OPENSSL_NO_RC4 if (docId != NULL) { delete [] docId; } } void PdfEncryptMD5Base::CreateObjKey( unsigned char objkey[16], int* pnKeyLen ) const { const unsigned int n = static_cast(m_curReference.ObjectNumber()); const unsigned int g = static_cast(m_curReference.GenerationNumber()); unsigned char nkey[MD5_DIGEST_LENGTH+5+4]; int nkeylen = m_keyLength + 5; const size_t KEY_LENGTH_SIZE_T = static_cast(m_keyLength); for (size_t j = 0; j < KEY_LENGTH_SIZE_T; j++) { nkey[j] = m_encryptionKey[j]; } nkey[m_keyLength+0] = static_cast(0xff & n); nkey[m_keyLength+1] = static_cast(0xff & (n >> 8)); nkey[m_keyLength+2] = static_cast(0xff & (n >> 16)); nkey[m_keyLength+3] = static_cast(0xff & g); nkey[m_keyLength+4] = static_cast(0xff & (g >> 8)); if (m_eAlgorithm == ePdfEncryptAlgorithm_AESV2) { // AES encryption needs some 'salt' nkeylen += 4; nkey[m_keyLength+5] = 0x73; nkey[m_keyLength+6] = 0x41; nkey[m_keyLength+7] = 0x6c; nkey[m_keyLength+8] = 0x54; } GetMD5Binary(nkey, nkeylen, objkey); *pnKeyLen = (m_keyLength <= 11) ? m_keyLength+5 : 16; } #ifndef OPENSSL_NO_RC4 PdfEncryptRC4Base::PdfEncryptRC4Base() { m_rc4 = new RC4CryptoEngine(); } PdfEncryptRC4Base::~PdfEncryptRC4Base() { delete m_rc4; } /** * RC4 is the standard encryption algorithm used in PDF format */ void PdfEncryptRC4Base::RC4(const unsigned char* key, int keylen, const unsigned char* textin, pdf_long textlen, unsigned char* textout, pdf_long textoutlen) { EVP_CIPHER_CTX* rc4 = m_rc4->getEngine(); if(textlen != textoutlen) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing RC4 encryption engine" ); // Don't set the key because we will modify the parameters int status = EVP_EncryptInit_ex(rc4, EVP_rc4(), NULL, NULL, NULL); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing RC4 encryption engine" ); status = EVP_CIPHER_CTX_set_key_length(rc4, keylen); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing RC4 encryption engine" ); // We finished modifying parameters so now we can set the key status = EVP_EncryptInit_ex(rc4, NULL, NULL, key, NULL); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing RC4 encryption engine" ); int dataOutMoved; status = EVP_EncryptUpdate(rc4, textout, &dataOutMoved, textin, textlen); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error RC4-encrypting data" ); status = EVP_EncryptFinal_ex(rc4, &textout[dataOutMoved], &dataOutMoved); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error RC4-encrypting data" ); } #endif // OPENSSL_NO_RC4 void PdfEncryptMD5Base::GetMD5Binary(const unsigned char* data, int length, unsigned char* digest) { int status; MD5_CTX ctx; status = MD5_Init(&ctx); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing MD5 hashing engine" ); status = MD5_Update(&ctx, data, length); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error MD5-hashing data" ); status = MD5_Final(digest,&ctx); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error MD5-hashing data" ); } void PdfEncryptMD5Base::GenerateInitialVector(unsigned char iv[AES_IV_LENGTH]) { GetMD5Binary(reinterpret_cast(m_documentId.c_str()), static_cast(m_documentId.length()), iv); } PdfString PdfEncryptMD5Base::GetMD5String( const unsigned char* pBuffer, int nLength ) { char data[MD5_DIGEST_LENGTH]; GetMD5Binary( pBuffer, nLength, reinterpret_cast(data) ); return PdfString( data, MD5_DIGEST_LENGTH, true ); } void PdfEncryptMD5Base::CreateEncryptionDictionary( PdfDictionary & rDictionary ) const { rDictionary.AddKey( PdfName("Filter"), PdfName("Standard") ); if(m_eAlgorithm == ePdfEncryptAlgorithm_AESV2 || !m_bEncryptMetadata) { PdfDictionary cf; PdfDictionary stdCf; #ifndef OPENSSL_NO_RC4 if(m_eAlgorithm == ePdfEncryptAlgorithm_RC4V2) stdCf.AddKey( PdfName("CFM"), PdfName("V2") ); else #endif // OPENSSL_NO_RC4 stdCf.AddKey( PdfName("CFM"), PdfName("AESV2") ); stdCf.AddKey( PdfName("Length"), static_cast(PODOFO_LL_LITERAL(16)) ); rDictionary.AddKey( PdfName("O"), PdfString( reinterpret_cast(this->GetOValue()), 32, true ) ); rDictionary.AddKey( PdfName("U"), PdfString( reinterpret_cast(this->GetUValue()), 32, true ) ); stdCf.AddKey( PdfName("AuthEvent"), PdfName("DocOpen") ); cf.AddKey( PdfName("StdCF"), stdCf ); rDictionary.AddKey( PdfName("CF"), cf ); rDictionary.AddKey( PdfName("StrF"), PdfName("StdCF") ); rDictionary.AddKey( PdfName("StmF"), PdfName("StdCF") ); rDictionary.AddKey( PdfName("V"), static_cast(PODOFO_LL_LITERAL(4)) ); rDictionary.AddKey( PdfName("R"), static_cast(PODOFO_LL_LITERAL(4)) ); rDictionary.AddKey( PdfName("Length"), static_cast(PODOFO_LL_LITERAL(128)) ); if(!m_bEncryptMetadata) rDictionary.AddKey( PdfName("EncryptMetadata"), PdfVariant( false ) ); } #ifndef OPENSSL_NO_RC4 else if(m_eAlgorithm == ePdfEncryptAlgorithm_RC4V1) { rDictionary.AddKey( PdfName("V"), static_cast(PODOFO_LL_LITERAL(1)) ); // Can be 2 or 3 rDictionary.AddKey( PdfName("R"), static_cast(m_rValue) ); } else if(m_eAlgorithm == ePdfEncryptAlgorithm_RC4V2) { rDictionary.AddKey( PdfName("V"), static_cast(PODOFO_LL_LITERAL(2)) ); rDictionary.AddKey( PdfName("R"), static_cast(PODOFO_LL_LITERAL(3)) ); rDictionary.AddKey( PdfName("Length"), PdfVariant( static_cast(m_eKeyLength) ) ); } #endif // OPENSSL_NO_RC4 rDictionary.AddKey( PdfName("O"), PdfString( reinterpret_cast(this->GetOValue()), 32, true ) ); rDictionary.AddKey( PdfName("U"), PdfString( reinterpret_cast(this->GetUValue()), 32, true ) ); rDictionary.AddKey( PdfName("P"), PdfVariant( static_cast(this->GetPValue()) ) ); } #ifndef OPENSSL_NO_RC4 void PdfEncryptRC4::GenerateEncryptionKey(const PdfString & documentId) { unsigned char userpswd[32]; unsigned char ownerpswd[32]; // Pad passwords PadPassword( m_userPass, userpswd ); PadPassword( m_ownerPass, ownerpswd ); // Compute O value ComputeOwnerKey(userpswd, ownerpswd, m_keyLength, m_rValue, false, m_oValue); // Compute encryption key and U value m_documentId = std::string( documentId.GetString(), documentId.GetLength() ); ComputeEncryptionKey(m_documentId, userpswd, m_oValue, m_pValue, m_eKeyLength, m_rValue, m_uValue, m_bEncryptMetadata); } bool PdfEncryptRC4::Authenticate( const std::string & password, const PdfString & documentId ) { bool ok = false; m_documentId = std::string( documentId.GetString(), documentId.GetLength() ); // Pad password unsigned char userKey[32]; unsigned char pswd[32]; PadPassword( password, pswd ); // Check password: 1) as user password, 2) as owner password ComputeEncryptionKey(m_documentId, pswd, m_oValue, m_pValue, m_eKeyLength, m_rValue, userKey, m_bEncryptMetadata); ok = CheckKey(userKey, m_uValue); if (!ok) { unsigned char userpswd[32]; ComputeOwnerKey( m_oValue, pswd, m_keyLength, m_rValue, true, userpswd ); ComputeEncryptionKey( m_documentId, userpswd, m_oValue, m_pValue, m_eKeyLength, m_rValue, userKey, m_bEncryptMetadata ); ok = CheckKey( userKey, m_uValue ); if( ok ) m_ownerPass = password; } else m_userPass = password; return ok; } pdf_long PdfEncryptRC4::CalculateStreamOffset() const { return 0; } pdf_long PdfEncryptRC4::CalculateStreamLength(pdf_long length) const { return length; } void PdfEncryptRC4::Encrypt(const unsigned char* inStr, pdf_long inLen, unsigned char* outStr, pdf_long outLen) const { unsigned char objkey[MD5_DIGEST_LENGTH]; int keylen; CreateObjKey( objkey, &keylen ); const_cast(this)->RC4(objkey, keylen, inStr, inLen, outStr, outLen); } void PdfEncryptRC4::Decrypt(const unsigned char* inStr, pdf_long inLen, unsigned char* outStr, pdf_long &outLen) const { Encrypt(inStr, inLen, outStr, outLen); } PdfInputStream* PdfEncryptRC4::CreateEncryptionInputStream( PdfInputStream* pInputStream ) { unsigned char objkey[MD5_DIGEST_LENGTH]; int keylen; this->CreateObjKey( objkey, &keylen ); return new PdfRC4InputStream( pInputStream, m_rc4key, m_rc4last, objkey, keylen ); } PdfEncryptRC4::PdfEncryptRC4(PdfString oValue, PdfString uValue, int pValue, int rValue, EPdfEncryptAlgorithm eAlgorithm, long length, bool encryptMetadata) { m_pValue = pValue; m_rValue = rValue; m_eAlgorithm = eAlgorithm; m_eKeyLength = static_cast(length); m_keyLength = length/8; m_bEncryptMetadata = encryptMetadata; memcpy( m_oValue, oValue.GetString(), 32 ); memcpy( m_uValue, uValue.GetString(), 32 ); // Init buffers memset(m_rc4key, 0, 16); memset(m_rc4last, 0, 256); memset(m_encryptionKey, 0, 32); } PdfEncryptRC4::PdfEncryptRC4( const std::string & userPassword, const std::string & ownerPassword, int protection, EPdfEncryptAlgorithm eAlgorithm, EPdfKeyLength eKeyLength ) { // setup object int keyLength = static_cast(eKeyLength); m_userPass = userPassword; m_ownerPass = ownerPassword; m_eAlgorithm = eAlgorithm; m_eKeyLength = eKeyLength; switch (eAlgorithm) { case ePdfEncryptAlgorithm_RC4V2: keyLength = keyLength - keyLength % 8; keyLength = (keyLength >= 40) ? ((keyLength <= 128) ? keyLength : 128) : 40; m_rValue = 3; m_keyLength = keyLength / 8; break; case ePdfEncryptAlgorithm_RC4V1: default: m_rValue = 2; m_keyLength = 40 / 8; break; case ePdfEncryptAlgorithm_AESV2: #ifdef PODOFO_HAVE_LIBIDN case ePdfEncryptAlgorithm_AESV3: #endif // PODOFO_HAVE_LIBIDN break; } // Init buffers memset(m_rc4key, 0, 16); memset(m_oValue, 0, 48); memset(m_uValue, 0, 48); memset(m_rc4last, 0, 256); memset(m_encryptionKey, 0, 32); // Compute P value m_pValue = PERMS_DEFAULT | protection; } PdfOutputStream* PdfEncryptRC4::CreateEncryptionOutputStream( PdfOutputStream* pOutputStream ) { unsigned char objkey[MD5_DIGEST_LENGTH]; int keylen; this->CreateObjKey( objkey, &keylen ); return new PdfRC4OutputStream( pOutputStream, m_rc4key, m_rc4last, objkey, keylen ); } #endif // OPENSSL_NO_RC4 PdfEncryptAESBase::PdfEncryptAESBase() { m_aes = new AESCryptoEngine(); } PdfEncryptAESBase::~PdfEncryptAESBase() { delete m_aes; } void PdfEncryptAESBase::BaseDecrypt(const unsigned char* key, int keyLen, const unsigned char* iv, const unsigned char* textin, pdf_long textlen, unsigned char* textout, pdf_long &outLen ) { if ((textlen % 16) != 0) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-decryption data length not a multiple of 16" ); EVP_CIPHER_CTX* aes = m_aes->getEngine(); int status; if(keyLen == PdfEncrypt::ePdfKeyLength_128/8) status = EVP_DecryptInit_ex(aes, EVP_aes_128_cbc(), NULL, key, iv); #ifdef PODOFO_HAVE_LIBIDN else if (keyLen == PdfEncrypt::ePdfKeyLength_256/8) status = EVP_DecryptInit_ex(aes, EVP_aes_256_cbc(), NULL, key, iv); #endif else PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Invalid AES key length" ); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing AES decryption engine" ); int dataOutMoved; status = EVP_DecryptUpdate(aes, textout, &dataOutMoved, textin, textlen); outLen = dataOutMoved; if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-decryption data" ); status = EVP_DecryptFinal_ex(aes, textout + outLen, &dataOutMoved); outLen += dataOutMoved; if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-decryption data final" ); } void PdfEncryptAESBase::BaseEncrypt(const unsigned char* key, int keyLen, const unsigned char* iv, const unsigned char* textin, pdf_long textlen, unsigned char* textout, pdf_long ) // To avoid Wunused-parameter { EVP_CIPHER_CTX* aes = m_aes->getEngine(); int status; if(keyLen == PdfEncrypt::ePdfKeyLength_128/8) status = EVP_EncryptInit_ex(aes, EVP_aes_128_cbc(), NULL, key, iv); #ifdef PODOFO_HAVE_LIBIDN else if (keyLen == PdfEncrypt::ePdfKeyLength_256/8) status = EVP_EncryptInit_ex(aes, EVP_aes_256_cbc(), NULL, key, iv); #endif else PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Invalid AES key length" ); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing AES encryption engine" ); int dataOutMoved; status = EVP_EncryptUpdate(aes, textout, &dataOutMoved, textin, textlen); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-encrypting data" ); status = EVP_EncryptFinal_ex(aes, &textout[dataOutMoved], &dataOutMoved); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-encrypting data" ); } void PdfEncryptAESV2::GenerateEncryptionKey(const PdfString & documentId) { unsigned char userpswd[32]; unsigned char ownerpswd[32]; // Pad passwords PadPassword( m_userPass, userpswd ); PadPassword( m_ownerPass, ownerpswd ); // Compute O value ComputeOwnerKey(userpswd, ownerpswd, m_keyLength, m_rValue, false, m_oValue); // Compute encryption key and U value m_documentId = std::string( documentId.GetString(), documentId.GetLength() ); ComputeEncryptionKey(m_documentId, userpswd, m_oValue, m_pValue, m_eKeyLength, m_rValue, m_uValue, m_bEncryptMetadata); } bool PdfEncryptAESV2::Authenticate( const std::string & password, const PdfString & documentId ) { bool ok = false; m_documentId = std::string( documentId.GetString(), documentId.GetLength() ); // Pad password unsigned char userKey[32]; unsigned char pswd[32]; PadPassword( password, pswd ); // Check password: 1) as user password, 2) as owner password ComputeEncryptionKey(m_documentId, pswd, m_oValue, m_pValue, m_eKeyLength, m_rValue, userKey, m_bEncryptMetadata); ok = CheckKey(userKey, m_uValue); if (!ok) { unsigned char userpswd[32]; ComputeOwnerKey( m_oValue, pswd, m_keyLength, m_rValue, true, userpswd ); ComputeEncryptionKey( m_documentId, userpswd, m_oValue, m_pValue, m_eKeyLength, m_rValue, userKey, m_bEncryptMetadata ); ok = CheckKey( userKey, m_uValue ); if( ok ) m_ownerPass = password; } else m_userPass = password; return ok; } pdf_long PdfEncryptAESV2::CalculateStreamOffset() const { return AES_IV_LENGTH; } void PdfEncryptAESV2::Encrypt(const unsigned char* inStr, pdf_long inLen, unsigned char* outStr, pdf_long outLen) const { unsigned char objkey[MD5_DIGEST_LENGTH]; int keylen; CreateObjKey( objkey, &keylen ); pdf_long offset = CalculateStreamOffset(); const_cast(this)->GenerateInitialVector(outStr); const_cast(this)->BaseEncrypt(objkey, keylen, outStr, inStr, inLen, &outStr[offset], outLen-offset); } void PdfEncryptAESV2::Decrypt(const unsigned char* inStr, pdf_long inLen, unsigned char* outStr, pdf_long &outLen) const { unsigned char objkey[MD5_DIGEST_LENGTH]; int keylen; CreateObjKey( objkey, &keylen ); pdf_long offset = CalculateStreamOffset(); if( inLen <= offset ) { // Is empty outLen = 0; return; } const_cast(this)->BaseDecrypt(objkey, keylen, inStr, &inStr[offset], inLen-offset, outStr, outLen); } PdfEncryptAESV2::PdfEncryptAESV2( const std::string & userPassword, const std::string & ownerPassword, int protection) : PdfEncryptAESBase() { // setup object m_userPass = userPassword; m_ownerPass = ownerPassword; m_eAlgorithm = ePdfEncryptAlgorithm_AESV2; m_rValue = 4; m_eKeyLength = ePdfKeyLength_128; m_keyLength = ePdfKeyLength_128 / 8; // Init buffers memset(m_rc4key, 0 ,16); memset(m_rc4last, 0 ,256); memset(m_oValue, 0 ,48); memset(m_uValue, 0 ,48); memset(m_encryptionKey, 0 ,32); // Compute P value m_pValue = PERMS_DEFAULT | protection; } PdfEncryptAESV2::PdfEncryptAESV2(PdfString oValue, PdfString uValue, int pValue, bool encryptMetadata) : PdfEncryptAESBase() { m_pValue = pValue; m_eAlgorithm = ePdfEncryptAlgorithm_AESV2; m_eKeyLength = ePdfKeyLength_128; m_keyLength = ePdfKeyLength_128 / 8; m_rValue = 4; m_bEncryptMetadata = encryptMetadata; memcpy( m_oValue, oValue.GetString(), 32 ); memcpy( m_uValue, uValue.GetString(), 32 ); // Init buffers memset(m_rc4key, 0 ,16); memset(m_rc4last, 0 ,256); memset(m_encryptionKey, 0 ,32); } pdf_long PdfEncryptAESV2::CalculateStreamLength(pdf_long length) const { pdf_long realLength = ((length + 15) & ~15) + AES_IV_LENGTH; if (length % 16 == 0) { realLength += 16; } return realLength; } PdfInputStream* PdfEncryptAESV2::CreateEncryptionInputStream( PdfInputStream* pInputStream ) { unsigned char objkey[MD5_DIGEST_LENGTH]; int keylen; this->CreateObjKey( objkey, &keylen ); return new PdfAESInputStream( pInputStream, objkey, keylen ); } PdfOutputStream* PdfEncryptAESV2::CreateEncryptionOutputStream( PdfOutputStream* ) { /*unsigned char objkey[MD5_DIGEST_LENGTH]; int keylen; this->CreateObjKey( objkey, &keylen );*/ PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "CreateEncryptionOutputStream does not yet support AESV2" ); } #ifdef PODOFO_HAVE_LIBIDN PdfEncryptSHABase::PdfEncryptSHABase( const PdfEncrypt & rhs ) : PdfEncrypt(rhs) { const PdfEncrypt* ptr = &rhs; memcpy( m_uValue, rhs.GetUValue(), sizeof(unsigned char) * 48 ); memcpy( m_oValue, rhs.GetOValue(), sizeof(unsigned char) * 48 ); memcpy( m_encryptionKey, rhs.GetEncryptionKey(), sizeof(unsigned char) * 32 ); memcpy( m_permsValue, static_cast(ptr)->m_permsValue, sizeof(unsigned char) * 16 ); memcpy( m_ueValue, static_cast(ptr)->m_ueValue, sizeof(unsigned char) * 32 ); memcpy( m_oeValue, static_cast(ptr)->m_oeValue, sizeof(unsigned char) * 32 ); } void PdfEncryptSHABase::ComputeUserKey(const unsigned char * userpswd, int len) { // Generate User Salts unsigned char vSalt[8]; unsigned char kSalt[8]; for(int i=0; i< 8 ; i++) { vSalt[i] = rand()%255; kSalt[i] = rand()%255; } // Generate hash for U unsigned char hashValue[32]; SHA256_CTX context; SHA256_Init(&context); SHA256_Update(&context, userpswd, len); SHA256_Update(&context, vSalt, 8); SHA256_Final(hashValue, &context); // U = hash + validation salt + key salt memcpy(m_uValue, hashValue, 32); memcpy(m_uValue+32, vSalt, 8); memcpy(m_uValue+32+8, kSalt, 8); // Generate hash for UE SHA256_Init(&context); SHA256_Update(&context, userpswd, len); SHA256_Update(&context, kSalt, 8); SHA256_Final(hashValue, &context); // UE = AES-256 encoded file encryption key with key=hash // CBC mode, no padding, init vector=0 EVP_CIPHER_CTX *aes; #ifdef PODOFO_HAVE_OPENSSL_1_1 aes = EVP_CIPHER_CTX_new(); #else EVP_CIPHER_CTX aes_local; EVP_CIPHER_CTX_init(&aes_local); aes = &aes_local; #endif int status = EVP_EncryptInit_ex(aes, EVP_aes_256_cbc(), NULL, hashValue, NULL); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing AES encryption engine" ); EVP_CIPHER_CTX_set_padding(aes, 0); // disable padding int dataOutMoved; status = EVP_EncryptUpdate(aes, m_ueValue, &dataOutMoved, m_encryptionKey, m_keyLength); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-encrypting data" ); status = EVP_EncryptFinal_ex(aes, &m_ueValue[dataOutMoved], &dataOutMoved); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-encrypting data" ); #ifdef PODOFO_HAVE_OPENSSL_1_1 EVP_CIPHER_CTX_free(aes); #else EVP_CIPHER_CTX_cleanup(&aes_local); #endif } void PdfEncryptSHABase::ComputeOwnerKey(const unsigned char * ownerpswd, int len) { // Generate User Salts unsigned char vSalt[8]; unsigned char kSalt[8]; for(int i=0; i< 8 ; i++) { vSalt[i] = rand()%255; kSalt[i] = rand()%255; } // Generate hash for O unsigned char hashValue[32]; SHA256_CTX context; SHA256_Init(&context); SHA256_Update(&context, ownerpswd, len); SHA256_Update(&context, vSalt, 8); SHA256_Update(&context, m_uValue, 48); SHA256_Final(hashValue, &context); // O = hash + validation salt + key salt memcpy(m_oValue, hashValue, 32); memcpy(m_oValue+32, vSalt, 8); memcpy(m_oValue+32+8, kSalt, 8); // Generate hash for OE SHA256_Init(&context); SHA256_Update(&context, ownerpswd, len); SHA256_Update(&context, kSalt, 8); SHA256_Update(&context, m_uValue, 48); SHA256_Final(hashValue, &context); // OE = AES-256 encoded file encryption key with key=hash // CBC mode, no padding, init vector=0 EVP_CIPHER_CTX *aes; #ifdef PODOFO_HAVE_OPENSSL_1_1 aes = EVP_CIPHER_CTX_new(); #else EVP_CIPHER_CTX aes_local; EVP_CIPHER_CTX_init(&aes_local); aes = &aes_local; #endif int status = EVP_EncryptInit_ex(aes, EVP_aes_256_cbc(), NULL, hashValue, NULL); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing AES encryption engine" ); EVP_CIPHER_CTX_set_padding(aes, 0); // disable padding int dataOutMoved; status = EVP_EncryptUpdate(aes, m_oeValue, &dataOutMoved, m_encryptionKey, m_keyLength); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-encrypting data" ); status = EVP_EncryptFinal_ex(aes, &m_oeValue[dataOutMoved], &dataOutMoved); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-encrypting data" ); #ifdef PODOFO_HAVE_OPENSSL_1_1 EVP_CIPHER_CTX_free(aes); #else EVP_CIPHER_CTX_cleanup(&aes_local); #endif } void PdfEncryptSHABase::PreprocessPassword( const std::string &password, unsigned char* outBuf, int &len) { char* password_sasl; if (stringprep_profile(password.c_str(), &password_sasl, "SASLprep", STRINGPREP_NO_UNASSIGNED) != STRINGPREP_OK) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidPassword, "Error processing password through SASLprep" ); } int l = strlen(password_sasl); len = l > 127 ? 127 : l; memcpy(outBuf, password_sasl, len); free(password_sasl); // Do not change to podofo_free, as memory is allocated by stringprep_profile } void PdfEncryptSHABase::ComputeEncryptionKey() { // Seed once for all srand ( time(NULL) ); for(int i=0; i< m_keyLength ; i++) m_encryptionKey[i] = rand()%255; } bool PdfEncryptSHABase::Authenticate(const std::string& documentID, const std::string& password, const std::string& uValue, const std::string& ueValue, const std::string& oValue, const std::string& oeValue, int pValue, const std::string& permsValue, int lengthValue, int rValue) { m_pValue = pValue; m_keyLength = lengthValue / 8; m_rValue = rValue; memcpy(m_uValue, uValue.c_str(), 48); memcpy(m_ueValue, ueValue.c_str(), 32); memcpy(m_oValue, oValue.c_str(), 48); memcpy(m_oeValue, oeValue.c_str(), 32); memcpy(m_permsValue, permsValue.c_str(), 16); return Authenticate(password, documentID); } void PdfEncryptSHABase::GenerateInitialVector(unsigned char iv[AES_IV_LENGTH]) { for (int i=0; i(PODOFO_LL_LITERAL(5)) ); rDictionary.AddKey( PdfName("R"), static_cast(PODOFO_LL_LITERAL(5)) ); rDictionary.AddKey( PdfName("Length"), static_cast(PODOFO_LL_LITERAL(256)) ); stdCf.AddKey( PdfName("CFM"), PdfName("AESV3") ); stdCf.AddKey( PdfName("Length"), static_cast(PODOFO_LL_LITERAL(32)) ); rDictionary.AddKey( PdfName("O"), PdfString( reinterpret_cast(this->GetOValue()), 48, true ) ); rDictionary.AddKey( PdfName("OE"), PdfString( reinterpret_cast(this->GetOEValue()), 32, true ) ); rDictionary.AddKey( PdfName("U"), PdfString( reinterpret_cast(this->GetUValue()), 48, true ) ); rDictionary.AddKey( PdfName("UE"), PdfString( reinterpret_cast(this->GetUEValue()), 32, true ) ); rDictionary.AddKey( PdfName("Perms"), PdfString( reinterpret_cast(this->GetPermsValue()), 16, true ) ); stdCf.AddKey( PdfName("AuthEvent"), PdfName("DocOpen") ); cf.AddKey( PdfName("StdCF"), stdCf ); rDictionary.AddKey( PdfName("CF"), cf ); rDictionary.AddKey( PdfName("StrF"), PdfName("StdCF") ); rDictionary.AddKey( PdfName("StmF"), PdfName("StdCF") ); rDictionary.AddKey( PdfName("P"), PdfVariant( static_cast(this->GetPValue()) ) ); } void PdfEncryptAESV3::GenerateEncryptionKey(const PdfString &) { // Prepare passwords unsigned char userpswd[127]; unsigned char ownerpswd[127]; int userpswdLen; int ownerpswdLen; PreprocessPassword(m_userPass, userpswd, userpswdLen); PreprocessPassword(m_ownerPass, ownerpswd, ownerpswdLen); // Compute encryption key ComputeEncryptionKey(); // Compute U and UE values ComputeUserKey(userpswd, userpswdLen); // Compute O and OE value ComputeOwnerKey(ownerpswd, ownerpswdLen); // Compute Perms value unsigned char perms[16]; // First 4 bytes = 32bits permissions perms[3] = (m_pValue >> 24) & 0xff; perms[2] = (m_pValue >> 16) & 0xff; perms[1] = (m_pValue >> 8) & 0xff; perms[0] = m_pValue & 0xff; // Placeholder for future versions that may need 64-bit permissions perms[4] = 0xff; perms[5] = 0xff; perms[6] = 0xff; perms[7] = 0xff; // if EncryptMetadata is false, this value should be set to 'F' perms[8] = m_bEncryptMetadata ? 'T' : 'F'; // Next 3 bytes are mandatory perms[9] = 'a'; perms[10] = 'd'; perms[11] = 'b'; // Next 4 bytes are ignored perms[12] = 0; perms[13] = 0; perms[14] = 0; perms[15] = 0; // Encrypt Perms value EVP_CIPHER_CTX *aes; #ifdef PODOFO_HAVE_OPENSSL_1_1 aes = EVP_CIPHER_CTX_new(); #else EVP_CIPHER_CTX aes_local; EVP_CIPHER_CTX_init(&aes_local); aes = &aes_local; #endif int status = EVP_EncryptInit_ex(aes, EVP_aes_256_ecb(), NULL, m_encryptionKey, NULL); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing AES encryption engine" ); EVP_CIPHER_CTX_set_padding(aes, 0); // disable padding int dataOutMoved; status = EVP_EncryptUpdate(aes, m_permsValue, &dataOutMoved, perms, 16); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-encrypting data" ); status = EVP_EncryptFinal_ex(aes, &m_permsValue[dataOutMoved], &dataOutMoved); if(status != 1) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-encrypting data" ); #ifdef PODOFO_HAVE_OPENSSL_1_1 EVP_CIPHER_CTX_free(aes); #else EVP_CIPHER_CTX_cleanup(&aes_local); #endif } bool PdfEncryptAESV3::Authenticate( const std::string & password, const PdfString & ) { bool ok = false; // Prepare password unsigned char pswd_sasl[127]; int pswdLen; PreprocessPassword(password, pswd_sasl, pswdLen); // Test 1: is it the user key ? unsigned char hashValue[32]; SHA256_CTX context; SHA256_Init(&context); SHA256_Update(&context, pswd_sasl, pswdLen); // password SHA256_Update(&context, m_uValue + 32, 8); // user Validation Salt SHA256_Final(hashValue, &context); ok = CheckKey(hashValue, m_uValue); if(!ok) { // Test 2: is it the owner key ? SHA256_Init(&context); SHA256_Update(&context, pswd_sasl, pswdLen); // password SHA256_Update(&context, m_oValue + 32, 8); // owner Validation Salt SHA256_Update(&context, m_uValue, 48); // U string SHA256_Final(hashValue, &context); ok = CheckKey(hashValue, m_oValue); if(ok) { m_ownerPass = password; // ISO 32000: "Compute an intermediate owner key by computing the SHA-256 hash of // the UTF-8 password concatenated with the 8 bytes of owner Key Salt, concatenated with the 48-byte U string." SHA256_Init(&context); SHA256_Update(&context, pswd_sasl, pswdLen); // password SHA256_Update(&context, m_oValue + 40, 8); // owner Key Salt SHA256_Update(&context, m_uValue, 48); // U string SHA256_Final(hashValue, &context); // ISO 32000: "The 32-byte result is the key used to decrypt the 32-byte OE string using // AES-256 in CBC mode with no padding and an initialization vector of zero. // The 32-byte result is the file encryption key" EVP_CIPHER_CTX* aes = m_aes->getEngine(); EVP_DecryptInit_ex( aes, EVP_aes_256_cbc(), NULL, hashValue, 0 ); // iv zero EVP_CIPHER_CTX_set_padding( aes, 0 ); // no padding int lOutLen; EVP_DecryptUpdate( aes, m_encryptionKey, &lOutLen, m_oeValue, 32 ); } } else { m_userPass = password; // ISO 32000: "Compute an intermediate user key by computing the SHA-256 hash of // the UTF-8 password concatenated with the 8 bytes of user Key Salt" SHA256_Init(&context); SHA256_Update(&context, pswd_sasl, pswdLen); // password SHA256_Update(&context, m_uValue + 40, 8); // user Key Salt SHA256_Final(hashValue, &context); // ISO 32000: "The 32-byte result is the key used to decrypt the 32-byte UE string using // AES-256 in CBC mode with no padding and an initialization vector of zero. // The 32-byte result is the file encryption key" EVP_CIPHER_CTX* aes = m_aes->getEngine(); EVP_DecryptInit_ex( aes, EVP_aes_256_cbc(), NULL, hashValue, 0 ); // iv zero EVP_CIPHER_CTX_set_padding( aes, 0 ); // no padding int lOutLen; EVP_DecryptUpdate( aes, m_encryptionKey, &lOutLen, m_ueValue, 32 ); } // TODO Validate permissions (or not...) return ok; } pdf_long PdfEncryptAESV3::CalculateStreamOffset() const { return AES_IV_LENGTH; } void PdfEncryptAESV3::Encrypt(const unsigned char* inStr, pdf_long inLen, unsigned char* outStr, pdf_long outLen) const { pdf_long offset = CalculateStreamOffset(); const_cast(this)->GenerateInitialVector(outStr); const_cast(this)->BaseEncrypt(const_cast(m_encryptionKey), m_keyLength, outStr, inStr, inLen, &outStr[offset], outLen-offset); } void PdfEncryptAESV3::Decrypt(const unsigned char* inStr, pdf_long inLen, unsigned char* outStr, pdf_long &outLen) const { pdf_long offset = CalculateStreamOffset(); const_cast(this)->BaseDecrypt(const_cast(m_encryptionKey), m_keyLength, inStr, &inStr[offset], inLen-offset, outStr, outLen); } PdfEncryptAESV3::PdfEncryptAESV3( const std::string & userPassword, const std::string & ownerPassword, int protection) : PdfEncryptAESBase() { // setup object m_userPass = userPassword; m_ownerPass = ownerPassword; m_eAlgorithm = ePdfEncryptAlgorithm_AESV3; m_rValue = 5; m_eKeyLength = ePdfKeyLength_256; m_keyLength = ePdfKeyLength_256 / 8; // Init buffers memset(m_oValue, 0 ,48); memset(m_uValue, 0 ,48); memset(m_encryptionKey, 0 ,32); memset(m_ueValue, 0 ,32); memset(m_oeValue, 0 ,32); // Compute P value m_pValue = PERMS_DEFAULT | protection; } PdfEncryptAESV3::PdfEncryptAESV3(PdfString oValue,PdfString oeValue, PdfString uValue, PdfString ueValue, int pValue, PdfString permsValue) : PdfEncryptAESBase() { m_pValue = pValue; m_eAlgorithm = ePdfEncryptAlgorithm_AESV3; m_eKeyLength = ePdfKeyLength_256; m_keyLength = ePdfKeyLength_256 / 8; m_rValue = 5; memcpy( m_oValue, oValue.GetString(), 48 ); memcpy( m_oeValue, oeValue.GetString(), 32 ); memcpy( m_uValue, uValue.GetString(), 48 ); memcpy( m_ueValue, ueValue.GetString(), 32 ); memcpy( m_permsValue, permsValue.GetString(), 16 ); memset(m_encryptionKey, 0 ,32); } pdf_long PdfEncryptAESV3::CalculateStreamLength(pdf_long length) const { pdf_long realLength = ((length + 15) & ~15) + AES_IV_LENGTH; if (length % 16 == 0) { realLength += 16; } return realLength; } PdfInputStream* PdfEncryptAESV3::CreateEncryptionInputStream( PdfInputStream* pInputStream ) { return new PdfAESInputStream( pInputStream, m_encryptionKey, 32 ); } PdfOutputStream* PdfEncryptAESV3::CreateEncryptionOutputStream( PdfOutputStream* ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "CreateEncryptionOutputStream does not yet support AESV3" ); } #endif // PODOFO_HAVE_LIBIDN #else // PODOFO_HAVE_OPENSSL // ---------------- // MD4 by RSA // ---------------- // C headers for MD5 #include #include #include #include #define MD5_HASHBYTES 16 /// Structure representing an MD5 context while ecrypting. (For internal use only) typedef struct MD5Context { unsigned int buf[4]; unsigned int bits[2]; unsigned char in[64]; } MD5_CTX; static void MD5Init(MD5_CTX *context); static void MD5Update(MD5_CTX *context, unsigned char const *buf, unsigned len); static void MD5Final(unsigned char digest[MD5_HASHBYTES], MD5_CTX *context); static void MD5Transform(unsigned int buf[4], unsigned int const in[16]); /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ static void MD5Final(unsigned char digest[MD5_HASHBYTES], MD5_CTX *ctx) { unsigned count; unsigned char *p; /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ p = ctx->in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, 0, count); MD5Transform(ctx->buf, reinterpret_cast(ctx->in)); /* Now fill the next block with 56 bytes */ memset(ctx->in, 0, 56); } else { /* Pad block to 56 bytes */ memset(p, 0, count - 8); } /* Append length in bits and transform */ reinterpret_cast(ctx->in)[14] = ctx->bits[0]; reinterpret_cast(ctx->in)[15] = ctx->bits[1]; MD5Transform(ctx->buf, reinterpret_cast(ctx->in)); memcpy(digest, ctx->buf, MD5_HASHBYTES); memset( reinterpret_cast(ctx), 0, sizeof(ctx)); /* In case it's sensitive */ } static void MD5Init(MD5_CTX *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bits[0] = 0; ctx->bits[1] = 0; } static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) { unsigned int t; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = t + ( static_cast(len) << 3)) < t) { ctx->bits[1]++; /* Carry from low to high */ } ctx->bits[1] += len >> 29; t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ /* Handle any leading odd-sized chunks */ if (t) { unsigned char *p = static_cast(ctx->in) + t; t = 64 - t; if (len < t) { memcpy(p, buf, len); return; } memcpy(p, buf, t); MD5Transform(ctx->buf, reinterpret_cast(ctx->in)); buf += t; len -= t; } /* Process data in 64-byte chunks */ while (len >= 64) { memcpy(ctx->in, buf, 64); MD5Transform(ctx->buf, reinterpret_cast(ctx->in)); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memcpy(ctx->in, buf, len); } /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ static void MD5Transform(unsigned int buf[4], unsigned int const in[16]) { unsigned int a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } PdfEncrypt * PdfEncrypt::CreatePdfEncrypt( const std::string &, const std::string &, int, EPdfEncryptAlgorithm, EPdfKeyLength ) { PODOFO_RAISE_ERROR_INFO( ePdfError_NotCompiled, "PdfEncrypt::CreatePdfEncrypt: Encryption support was disabled during compile time" ); return NULL; } PdfEncrypt* PdfEncrypt::CreatePdfEncrypt( const PdfObject* ) { PODOFO_RAISE_ERROR_INFO( ePdfError_NotCompiled, "PdfEncrypt::CreatePdfEncrypt: Encryption support was disabled during compile time" ); return NULL; } PdfEncrypt * PdfEncrypt::CreatePdfEncrypt(const PdfEncrypt & ) { PODOFO_RAISE_ERROR_INFO( ePdfError_NotCompiled, "PdfEncrypt::CreatePdfEncrypt: Encryption support was disabled during compile time" ); return NULL; } void PdfEncryptMD5Base::GetMD5Binary(const unsigned char* data, int length, unsigned char* digest) { MD5_CTX ctx; MD5Init(&ctx); MD5Update(&ctx, data, length); MD5Final(digest,&ctx); } PdfString PdfEncryptMD5Base::GetMD5String( const unsigned char* pBuffer, int nLength ) { // Will be called by PdfWriter::CreateFileIdentifier, even without encryption, // so implement it with above c-functions char data[MD5_HASHBYTES]; PdfEncryptMD5Base::GetMD5Binary( pBuffer, nLength, reinterpret_cast(data) ); return PdfString( data, MD5_HASHBYTES, true ); } #endif // PODOFO_HAVE_OPENSSL } podofo-0.9.5/src/base/PdfOutputStream.cpp0000664000175000017500000001203713013650710020175 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfOutputStream.h" #include "PdfOutputDevice.h" #include "PdfRefCountedBuffer.h" #include "PdfDefinesPrivate.h" #include #include namespace PoDoFo { PdfFileOutputStream::PdfFileOutputStream( const char* pszFilename ) { m_hFile = fopen( pszFilename, "wb" ); if( !m_hFile ) { PODOFO_RAISE_ERROR_INFO( ePdfError_FileNotFound, pszFilename ); } } PdfFileOutputStream::~PdfFileOutputStream() { Close(); } pdf_long PdfFileOutputStream::Write( const char* pBuffer, pdf_long lLen ) { return fwrite( pBuffer, sizeof(char), lLen, m_hFile ); } void PdfFileOutputStream::Close() { if( m_hFile ) { fclose( m_hFile ); m_hFile = NULL; } } PdfMemoryOutputStream::PdfMemoryOutputStream( pdf_long lInitial ) : m_lLen( 0 ), m_bOwnBuffer( true ) { m_lSize = lInitial; m_pBuffer = static_cast(podofo_calloc( m_lSize, sizeof(char) )); if( !m_pBuffer ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } } PdfMemoryOutputStream::PdfMemoryOutputStream( char* pBuffer, pdf_long lLen ) : m_lLen( 0 ), m_bOwnBuffer( false ) { m_lSize = lLen; m_pBuffer = pBuffer; } PdfMemoryOutputStream::~PdfMemoryOutputStream() { if( m_bOwnBuffer ) podofo_free( m_pBuffer ); } pdf_long PdfMemoryOutputStream::Write( const char* pBuffer, pdf_long lLen ) { if( !m_pBuffer ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if( m_lLen + lLen > m_lSize ) { if( m_bOwnBuffer ) { // a reallocation is required m_lSize = PDF_MAX( (m_lLen + lLen), (m_lSize << 1 ) ); m_pBuffer = static_cast(podofo_realloc( m_pBuffer, m_lSize )); if( !m_pBuffer ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } } else { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } } memcpy( m_pBuffer + m_lLen, pBuffer, lLen ); m_lLen += lLen; return lLen; } PdfDeviceOutputStream::PdfDeviceOutputStream( PdfOutputDevice* pDevice ) : m_pDevice( pDevice ) { } pdf_long PdfDeviceOutputStream::Write( const char* pBuffer, pdf_long lLen ) { pdf_long lTell = m_pDevice->Tell(); m_pDevice->Write( pBuffer, lLen ); return m_pDevice->Tell() - lTell; } pdf_long PdfBufferOutputStream::Write( const char* pBuffer, pdf_long lLen ) { if( m_lLength + lLen >= static_cast(m_pBuffer->GetSize()) ) m_pBuffer->Resize( m_lLength + lLen ); memcpy( m_pBuffer->GetBuffer() + m_lLength, pBuffer, lLen ); m_lLength += lLen; return lLen; } }; podofo-0.9.5/src/base/PdfXRefStreamParserObject.h0000664000175000017500000001172612344436402021524 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2009 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_XREF_STREAM_PARSER_OBJECT_H_ #define _PDF_XREF_STREAM_PARSER_OBJECT_H_ #include "PdfDefines.h" #include "PdfParserObject.h" #define W_ARRAY_SIZE 3 #define W_MAX_BYTES 4 namespace PoDoFo { /** * A utility class for PdfParser that can parse * an XRef stream object. * * It is mainly here to make PdfParser more modular. */ class PdfXRefStreamParserObject : public PdfParserObject { public: /** Parse the object data from the given file handle starting at * the current position. * \param pCreator pointer to a PdfVecObjects to resolve object references * \param rDevice an open reference counted input device which is positioned in * front of the object which is going to be parsed. * \param rBuffer buffer to use for parsing to avoid reallocations * \param pOffsets XRef entries are stored into this array */ PdfXRefStreamParserObject(PdfVecObjects* pCreator, const PdfRefCountedInputDevice & rDevice, const PdfRefCountedBuffer & rBuffer, PdfParser::TVecOffsets* pOffsets ); ~PdfXRefStreamParserObject(); void Parse(); void ReadXRefTable(); /** * \returns true if there is a previous XRefStream */ inline bool HasPrevious(); /** * \returns the offset of the previous XRef table */ inline pdf_long GetPreviousOffset(); private: /** * Read the /Index key from the current dictionary * and write uit to a vector. * * \param rvecIndeces store the indeces hare * \param size default value from /Size key */ void GetIndeces( std::vector & rvecIndeces, pdf_int64 size ); /** * Parse the stream contents * * \param nW /W key * \param rvecIndeces indeces as filled by GetIndeces * * \see GetIndeces */ void ParseStream( const pdf_int64 nW[W_ARRAY_SIZE], const std::vector & rvecIndeces ); void ReadXRefStreamEntry( char* pBuffer, pdf_long, const pdf_int64 lW[W_ARRAY_SIZE], int nObjNo ); private: pdf_long m_lNextOffset; PdfParser::TVecOffsets* m_pOffsets; }; // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfXRefStreamParserObject::HasPrevious() { return (m_lNextOffset != -1); } // ----------------------------------------------------- // // ----------------------------------------------------- inline pdf_long PdfXRefStreamParserObject::GetPreviousOffset() { return m_lNextOffset; } }; #endif // _PDF_XREF_STREAM_PARSER_OBJECT_H_ podofo-0.9.5/src/base/PdfFiltersPrivate.cpp0000664000175000017500000010570613013650710020472 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfDefines.h" #include "PdfFiltersPrivate.h" #include "PdfDictionary.h" #include "PdfOutputDevice.h" #include "PdfOutputStream.h" #include "PdfTokenizer.h" #include "PdfDefinesPrivate.h" #ifdef PODOFO_HAVE_JPEG_LIB extern "C" { #include "jerror.h" } #endif // PODOFO_HAVE_JPEG_LIB #include #include #ifdef PODOFO_HAVE_TIFF_LIB extern "C" { #ifdef _WIN32 // For O_RDONLY // TODO: DS #else #include #include #include #endif } #endif // PODOFO_HAVE_TIFF_LIB #define LZW_TABLE_SIZE 4096 namespace { // Private data for PdfAscii85Filter. This will be optimised // by the compiler through compile-time constant expression // evaluation. const unsigned long sPowers85[] = { 85*85*85*85, 85*85*85, 85*85, 85, 1 }; } // end anonymous namespace namespace PoDoFo { /** * This structur contains all necessary values * for a FlateDecode and LZWDecode Predictor. * These values are normally stored in the /DecodeParams * key of a PDF dictionary. */ class PdfPredictorDecoder { public: PdfPredictorDecoder( const PdfDictionary* pDecodeParms ) { m_nPredictor = static_cast(pDecodeParms->GetKeyAsLong( "Predictor", 1L )); m_nColors = static_cast(pDecodeParms->GetKeyAsLong( "Colors", 1L )); m_nBPC = static_cast(pDecodeParms->GetKeyAsLong( "BitsPerComponent", 8L )); m_nColumns = static_cast(pDecodeParms->GetKeyAsLong( "Columns", 1L )); m_nEarlyChange = static_cast(pDecodeParms->GetKeyAsLong( "EarlyChange", 1L )); if( m_nPredictor >= 10) { m_bNextByteIsPredictor = true; m_nCurPredictor = -1; } else { m_bNextByteIsPredictor = false; m_nCurPredictor = m_nPredictor; } m_nCurRowIndex = 0; m_nBpp = (m_nBPC * m_nColors) >> 3; m_nRows = (m_nColumns * m_nColors * m_nBPC) >> 3; m_pPrev = static_cast(podofo_calloc( m_nRows, sizeof(char) )); if( !m_pPrev ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } memset( m_pPrev, 0, sizeof(char) * m_nRows ); }; ~PdfPredictorDecoder() { podofo_free( m_pPrev ); } void Decode( const char* pBuffer, pdf_long lLen, PdfOutputStream* pStream ) { if( m_nPredictor == 1 ) { pStream->Write( pBuffer, lLen ); return; } while( lLen-- ) { if( m_bNextByteIsPredictor ) { m_nCurPredictor = *pBuffer + 10; m_bNextByteIsPredictor = false; } else { switch( m_nCurPredictor ) { case 2: // Tiff Predictor { if(m_nBPC == 8) { // Same as png sub int prev = (m_nCurRowIndex - m_nBpp < 0 ? 0 : m_pPrev[m_nCurRowIndex - m_nBpp]); m_pPrev[m_nCurRowIndex] = *pBuffer + prev; break; } // TODO: implement tiff predictor for other than 8 BPC PODOFO_RAISE_ERROR( ePdfError_InvalidPredictor ); break; } case 10: // png none { m_pPrev[m_nCurRowIndex] = *pBuffer; break; } case 11: // png sub { int prev = (m_nCurRowIndex - m_nBpp < 0 ? 0 : m_pPrev[m_nCurRowIndex - m_nBpp]); m_pPrev[m_nCurRowIndex] = *pBuffer + prev; break; } case 12: // png up { m_pPrev[m_nCurRowIndex] += *pBuffer; break; } case 13: // png average { int prev = (m_nCurRowIndex - m_nBpp < 0 ? 0 : m_pPrev[m_nCurRowIndex - m_nBpp]); m_pPrev[m_nCurRowIndex] = ((prev + m_pPrev[m_nCurRowIndex]) >> 1) + *pBuffer; break; } case 14: // png paeth case 15: // png optimum PODOFO_RAISE_ERROR( ePdfError_InvalidPredictor ); break; default: { //PODOFO_RAISE_ERROR( ePdfError_InvalidPredictor ); break; } } ++m_nCurRowIndex; } ++pBuffer; if( m_nCurRowIndex >= m_nRows ) { // One line finished m_nCurRowIndex = 0; m_bNextByteIsPredictor = (m_nCurPredictor >= 10); pStream->Write( m_pPrev, m_nRows ); } } } private: int m_nPredictor; int m_nColors; int m_nBPC; //< Bytes per component int m_nColumns; int m_nEarlyChange; int m_nBpp; ///< Bytes per pixel int m_nCurPredictor; int m_nCurRowIndex; int m_nRows; bool m_bNextByteIsPredictor; char* m_pPrev; }; // ------------------------------------------------------- // Hex // ------------------------------------------------------- PdfHexFilter::PdfHexFilter() : m_cDecodedByte( 0 ), m_bLow( true ) { } void PdfHexFilter::EncodeBlockImpl( const char* pBuffer, pdf_long lLen ) { char data[2]; while( lLen-- ) { data[0] = (*pBuffer & 0xF0) >> 4; data[0] += (data[0] > 9 ? 'A' - 10 : '0'); data[1] = (*pBuffer & 0x0F); data[1] += (data[1] > 9 ? 'A' - 10 : '0'); GetStream()->Write( data, 2 ); ++pBuffer; } } void PdfHexFilter::BeginDecodeImpl( const PdfDictionary* ) { m_cDecodedByte = 0; m_bLow = true; } void PdfHexFilter::DecodeBlockImpl( const char* pBuffer, pdf_long lLen ) { char val; while( lLen-- ) { if( PdfTokenizer::IsWhitespace( *pBuffer ) ) { ++pBuffer; continue; } val = PdfTokenizer::GetHexValue( *pBuffer ); if( m_bLow ) { m_cDecodedByte = (val & 0x0F); m_bLow = false; } else { m_cDecodedByte = ((m_cDecodedByte << 4) | val); m_bLow = true; GetStream()->Write( &m_cDecodedByte, 1 ); } ++pBuffer; } } void PdfHexFilter::EndDecodeImpl() { if( !m_bLow ) { // an odd number of bytes was read, // so the last byte is 0 GetStream()->Write( &m_cDecodedByte, 1 ); } } // ------------------------------------------------------- // Ascii 85 // // based on public domain software from: // Paul Haahr - http://www.webcom.com/~haahr/ // ------------------------------------------------------- PdfAscii85Filter::PdfAscii85Filter() : m_count( 0 ), m_tuple( 0 ) { } void PdfAscii85Filter::EncodeTuple( unsigned long tuple, int count ) { int i = 5; int z = 0; char buf[5]; char out[5]; char* start = buf;; do { *start++ = static_cast(tuple % 85); tuple /= 85; } while (--i > 0); i = count; do { out[z++] = static_cast(*--start) + '!'; } while (i-- > 0); GetStream()->Write( out, z ); } void PdfAscii85Filter::BeginEncodeImpl() { m_count = 0; m_tuple = 0; } void PdfAscii85Filter::EncodeBlockImpl( const char* pBuffer, pdf_long lLen ) { unsigned int c; const char* z = "z"; while( lLen ) { c = *pBuffer & 0xff; switch (m_count++) { case 0: m_tuple |= ( c << 24); break; case 1: m_tuple |= ( c << 16); break; case 2: m_tuple |= ( c << 8); break; case 3: m_tuple |= c; if( 0 == m_tuple ) { GetStream()->Write( z, 1 ); } else { this->EncodeTuple( m_tuple, m_count ); } m_tuple = 0; m_count = 0; break; } --lLen; ++pBuffer; } } void PdfAscii85Filter::EndEncodeImpl() { if( m_count > 0 ) this->EncodeTuple( m_tuple, m_count ); //GetStream()->Write( "~>", 2 ); } void PdfAscii85Filter::BeginDecodeImpl( const PdfDictionary* ) { m_count = 0; m_tuple = 0; } void PdfAscii85Filter::DecodeBlockImpl( const char* pBuffer, pdf_long lLen ) { bool foundEndMarker = false; while( lLen && !foundEndMarker ) { switch ( *pBuffer ) { default: if ( *pBuffer < '!' || *pBuffer > 'u') { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } m_tuple += ( *pBuffer - '!') * sPowers85[m_count++]; if( m_count == 5 ) { WidePut( m_tuple, 4 ); m_count = 0; m_tuple = 0; } break; case 'z': if (m_count != 0 ) { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } this->WidePut( 0, 4 ); break; case '~': ++pBuffer; --lLen; if( lLen && *pBuffer != '>' ) { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } foundEndMarker = true; break; case '\n': case '\r': case '\t': case ' ': case '\0': case '\f': case '\b': case 0177: break; } --lLen; ++pBuffer; } } void PdfAscii85Filter::EndDecodeImpl() { if( m_count > 0 ) { m_count--; m_tuple += sPowers85[m_count]; WidePut( m_tuple, m_count ); } } void PdfAscii85Filter::WidePut( unsigned long tuple, int bytes ) const { char data[4]; switch( bytes ) { case 4: data[0] = static_cast(tuple >> 24); data[1] = static_cast(tuple >> 16); data[2] = static_cast(tuple >> 8); data[3] = static_cast(tuple); break; case 3: data[0] = static_cast(tuple >> 24); data[1] = static_cast(tuple >> 16); data[2] = static_cast(tuple >> 8); break; case 2: data[0] = static_cast(tuple >> 24); data[1] = static_cast(tuple >> 16); break; case 1: data[0] = static_cast(tuple >> 24); break; } GetStream()->Write( data, bytes ); } // ------------------------------------------------------- // Flate // ------------------------------------------------------- PdfFlateFilter::PdfFlateFilter() : m_pPredictor( 0 ) { memset( m_buffer, 0, sizeof(m_buffer) ); memset( &m_stream, 0, sizeof(m_stream) ); } PdfFlateFilter::~PdfFlateFilter() { delete m_pPredictor; } void PdfFlateFilter::BeginEncodeImpl() { m_stream.zalloc = Z_NULL; m_stream.zfree = Z_NULL; m_stream.opaque = Z_NULL; if( deflateInit( &m_stream, Z_DEFAULT_COMPRESSION ) ) { PODOFO_RAISE_ERROR( ePdfError_Flate ); } } void PdfFlateFilter::EncodeBlockImpl( const char* pBuffer, pdf_long lLen ) { this->EncodeBlockInternal( pBuffer, lLen, Z_NO_FLUSH ); } void PdfFlateFilter::EncodeBlockInternal( const char* pBuffer, pdf_long lLen, int nMode ) { int nWrittenData = 0; m_stream.avail_in = static_cast(lLen); m_stream.next_in = reinterpret_cast(const_cast(pBuffer)); do { m_stream.avail_out = PODOFO_FILTER_INTERNAL_BUFFER_SIZE; m_stream.next_out = m_buffer; if( deflate( &m_stream, nMode) == Z_STREAM_ERROR ) { FailEncodeDecode(); PODOFO_RAISE_ERROR( ePdfError_Flate ); } nWrittenData = PODOFO_FILTER_INTERNAL_BUFFER_SIZE - m_stream.avail_out; try { if( nWrittenData > 0 ) { GetStream()->Write( reinterpret_cast(m_buffer), nWrittenData ); } } catch( PdfError & e ) { // clean up after any output stream errors FailEncodeDecode(); e.AddToCallstack( __FILE__, __LINE__ ); throw e; } } while( m_stream.avail_out == 0 ); } void PdfFlateFilter::EndEncodeImpl() { this->EncodeBlockInternal( NULL, 0, Z_FINISH ); deflateEnd( &m_stream ); } // -- void PdfFlateFilter::BeginDecodeImpl( const PdfDictionary* pDecodeParms ) { m_stream.zalloc = Z_NULL; m_stream.zfree = Z_NULL; m_stream.opaque = Z_NULL; m_pPredictor = pDecodeParms ? new PdfPredictorDecoder( pDecodeParms ) : NULL; if( inflateInit( &m_stream ) != Z_OK ) { PODOFO_RAISE_ERROR( ePdfError_Flate ); } } void PdfFlateFilter::DecodeBlockImpl( const char* pBuffer, pdf_long lLen ) { int flateErr; int nWrittenData; m_stream.avail_in = static_cast(lLen); m_stream.next_in = reinterpret_cast(const_cast(pBuffer)); do { m_stream.avail_out = PODOFO_FILTER_INTERNAL_BUFFER_SIZE; m_stream.next_out = m_buffer; switch( (flateErr = inflate(&m_stream, Z_NO_FLUSH)) ) { case Z_NEED_DICT: case Z_DATA_ERROR: case Z_MEM_ERROR: { PdfError::LogMessage( eLogSeverity_Error, "Flate Decoding Error from ZLib: %i\n", flateErr ); (void)inflateEnd(&m_stream); FailEncodeDecode(); PODOFO_RAISE_ERROR( ePdfError_Flate ); } default: break; } nWrittenData = PODOFO_FILTER_INTERNAL_BUFFER_SIZE - m_stream.avail_out; try { if( m_pPredictor ) m_pPredictor->Decode( reinterpret_cast(m_buffer), nWrittenData, GetStream() ); else GetStream()->Write( reinterpret_cast(m_buffer), nWrittenData ); } catch( PdfError & e ) { // clean up after any output stream errors FailEncodeDecode(); e.AddToCallstack( __FILE__, __LINE__ ); throw e; } } while( m_stream.avail_out == 0 ); } void PdfFlateFilter::EndDecodeImpl() { delete m_pPredictor; m_pPredictor = NULL; (void)inflateEnd(&m_stream); } // ------------------------------------------------------- // RLE // ------------------------------------------------------- PdfRLEFilter::PdfRLEFilter() : m_nCodeLen( 0 ) { } void PdfRLEFilter::BeginEncodeImpl() { PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter ); } void PdfRLEFilter::EncodeBlockImpl( const char*, pdf_long ) { PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter ); } void PdfRLEFilter::EndEncodeImpl() { PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter ); } void PdfRLEFilter::BeginDecodeImpl( const PdfDictionary* ) { m_nCodeLen = 0; } void PdfRLEFilter::DecodeBlockImpl( const char* pBuffer, pdf_long lLen ) { while( lLen-- ) { if( !m_nCodeLen ) { m_nCodeLen = static_cast(*pBuffer); } else if( m_nCodeLen == 128 ) break; else if( m_nCodeLen <= 127 ) { GetStream()->Write( pBuffer, 1 ); m_nCodeLen--; } else if( m_nCodeLen >= 129 ) { m_nCodeLen = 257 - m_nCodeLen; while( m_nCodeLen-- ) GetStream()->Write( pBuffer, 1 ); } ++pBuffer; } } // ------------------------------------------------------- // LZW // ------------------------------------------------------- const unsigned short PdfLZWFilter::s_masks[] = { 0x01FF, 0x03FF, 0x07FF, 0x0FFF }; const unsigned short PdfLZWFilter::s_clear = 0x0100; // clear table const unsigned short PdfLZWFilter::s_eod = 0x0101; // end of data PdfLZWFilter::PdfLZWFilter() : m_mask(0), m_code_len(0), m_character(0), m_bFirst(false), m_pPredictor( 0 ) { } PdfLZWFilter::~PdfLZWFilter() { delete m_pPredictor; } void PdfLZWFilter::BeginEncodeImpl() { PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter ); } void PdfLZWFilter::EncodeBlockImpl( const char*, pdf_long ) { PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter ); } void PdfLZWFilter::EndEncodeImpl() { PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter ); } void PdfLZWFilter::BeginDecodeImpl( const PdfDictionary* pDecodeParms ) { m_mask = 0; m_code_len = 9; m_character = 0; m_bFirst = true; m_pPredictor = pDecodeParms ? new PdfPredictorDecoder( pDecodeParms ) : NULL; InitTable(); } void PdfLZWFilter::DecodeBlockImpl( const char* pBuffer, pdf_long lLen ) { unsigned int buffer_size = 0; const unsigned int buffer_max = 24; pdf_uint32 old = 0; pdf_uint32 code = 0; pdf_uint32 buffer = 0; TLzwItem item; std::vector data; if( m_bFirst ) { m_character = *pBuffer; m_bFirst = false; } while( lLen ) { // Fill the buffer while( buffer_size <= (buffer_max-8) && lLen ) { buffer <<= 8; buffer |= static_cast(static_cast(*pBuffer)); buffer_size += 8; ++pBuffer; lLen--; } // read from the buffer while( buffer_size >= m_code_len ) { code = (buffer >> (buffer_size - m_code_len)) & PdfLZWFilter::s_masks[m_mask]; buffer_size -= m_code_len; if( code == PdfLZWFilter::s_clear ) { m_mask = 0; m_code_len = 9; InitTable(); } else if( code == PdfLZWFilter::s_eod ) { lLen = 0; break; } else { if( code >= m_table.size() ) { if (old >= m_table.size()) { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } data = m_table[old].value; data.push_back( m_character ); } else data = m_table[code].value; // Write data to the output device if( m_pPredictor ) m_pPredictor->Decode( reinterpret_cast(&(data[0])), data.size(), GetStream() ); else GetStream()->Write( reinterpret_cast(&(data[0])), data.size()); m_character = data[0]; if( old < m_table.size() ) // fix the first loop data = m_table[old].value; data.push_back( m_character ); item.value = data; m_table.push_back( item ); old = code; switch( m_table.size() ) { case 511: case 1023: case 2047: ++m_code_len; ++m_mask; default: break; } } } } } void PdfLZWFilter::EndDecodeImpl() { delete m_pPredictor; m_pPredictor = NULL; } void PdfLZWFilter::InitTable() { int i; TLzwItem item; m_table.clear(); m_table.reserve( LZW_TABLE_SIZE ); for( i=0;i<=255;i++ ) { item.value.clear(); item.value.push_back( static_cast(i) ); m_table.push_back( item ); } // Add dummy entry, which is never used by decoder item.value.clear(); m_table.push_back( item ); } // ------------------------------------------------------- // DCTDecode // ------------------------------------------------------- #ifdef PODOFO_HAVE_JPEG_LIB /* * Handlers for errors inside the JPeg library */ extern "C" { void JPegErrorExit(j_common_ptr cinfo) { #if 1 char buffer[JMSG_LENGTH_MAX]; /* Create the message */ (*cinfo->err->format_message) (cinfo, buffer); #endif jpeg_destroy(cinfo); PODOFO_RAISE_ERROR_INFO( ePdfError_UnsupportedImageFormat, buffer); } void JPegErrorOutput(j_common_ptr, int) { } }; /* * The actual filter implementation */ PdfDCTFilter::PdfDCTFilter() : m_pDevice( NULL ) { memset( &m_cinfo, 0, sizeof( struct jpeg_decompress_struct ) ); memset( &m_jerr, 0, sizeof( struct jpeg_error_mgr ) ); } PdfDCTFilter::~PdfDCTFilter() { } void PdfDCTFilter::BeginEncodeImpl() { PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter ); } void PdfDCTFilter::EncodeBlockImpl( const char*, pdf_long ) { PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter ); } void PdfDCTFilter::EndEncodeImpl() { PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter ); } void PdfDCTFilter::BeginDecodeImpl( const PdfDictionary* ) { // Setup variables for JPEGLib m_cinfo.err = jpeg_std_error( &m_jerr ); m_jerr.error_exit = &JPegErrorExit; m_jerr.emit_message = &JPegErrorOutput; jpeg_create_decompress( &m_cinfo ); m_pDevice = new PdfOutputDevice( &m_buffer ); } void PdfDCTFilter::DecodeBlockImpl( const char* pBuffer, pdf_long lLen ) { m_pDevice->Write( pBuffer, lLen ); } void PdfDCTFilter::EndDecodeImpl() { delete m_pDevice; m_pDevice = NULL; jpeg_memory_src ( &m_cinfo, reinterpret_cast(m_buffer.GetBuffer()), m_buffer.GetSize() ); if( jpeg_read_header(&m_cinfo, TRUE) <= 0 ) { (void) jpeg_destroy_decompress(&m_cinfo); PODOFO_RAISE_ERROR( ePdfError_UnexpectedEOF ); } jpeg_start_decompress(&m_cinfo); char* pOutBuffer; JSAMPARRAY pBuffer; long lRowBytes = m_cinfo.output_width * m_cinfo.output_components; const int iComponents = m_cinfo.output_components; // pBuffer will be deleted by jpeg_destroy_decompress pBuffer = (*m_cinfo.mem->alloc_sarray)( reinterpret_cast( &m_cinfo ), JPOOL_IMAGE, lRowBytes, 1); pOutBuffer = static_cast(podofo_calloc( lRowBytes, sizeof(char)) ); if (!pOutBuffer) { PODOFO_RAISE_ERROR(ePdfError_OutOfMemory); } while( m_cinfo.output_scanline < m_cinfo.output_height ) { jpeg_read_scanlines(&m_cinfo, pBuffer, 1); if( iComponents == 4 ) { for( unsigned int i=0, c=0; i < m_cinfo.output_width; i++, c+=4 ) { pOutBuffer[c] = pBuffer[0][i*4]; pOutBuffer[c+1] = pBuffer[0][i*4+1]; pOutBuffer[c+2] = pBuffer[0][i*4+2]; pOutBuffer[c+3] = pBuffer[0][i*4+3]; } } else if( iComponents == 3 ) { for( unsigned int i=0, c=0; i < m_cinfo.output_width; i++, c+=3 ) { pOutBuffer[c] = pBuffer[0][i*3]; pOutBuffer[c+1] = pBuffer[0][i*3+1]; pOutBuffer[c+2] = pBuffer[0][i*3+2]; } } else if( iComponents == 1 ) { memcpy( pOutBuffer, pBuffer[0], m_cinfo.output_width ); } else { PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "DCTDecode unknown components" ); } GetStream()->Write( reinterpret_cast(pOutBuffer), lRowBytes ); } podofo_free( pOutBuffer ); (void) jpeg_destroy_decompress( &m_cinfo ); } // ------------------------------------------------------- // memsrc.c // ------------------------------------------------------- /* * memsrc.c * * Copyright (C) 1994-1996, Thomas G. Lane. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file contains decompression data source routines for the case of * reading JPEG data from a memory buffer that is preloaded with the entire * JPEG file. This would not seem especially useful at first sight, but * a number of people have asked for it. * This is really just a stripped-down version of jdatasrc.c. Comparison * of this code with jdatasrc.c may be helpful in seeing how to make * custom source managers for other purposes. */ /* Expanded data source object for memory input */ typedef struct { struct jpeg_source_mgr pub; /* public fields */ JOCTET eoi_buffer[2]; /* a place to put a dummy EOI */ } my_source_mgr; typedef my_source_mgr * my_src_ptr; /* * Initialize source --- called by jpeg_read_header * before any data is actually read. */ METHODDEF(void) init_source (j_decompress_ptr) { /* No work, since jpeg_memory_src set up the buffer pointer and count. * Indeed, if we want to read multiple JPEG images from one buffer, * this *must* not do anything to the pointer. */ } /* * Fill the input buffer --- called whenever buffer is emptied. * * In this application, this routine should never be called; if it is called, * the decompressor has overrun the end of the input buffer, implying we * supplied an incomplete or corrupt JPEG datastream. A simple error exit * might be the most appropriate response. * * But what we choose to do in this code is to supply dummy EOI markers * in order to force the decompressor to finish processing and supply * some sort of output image, no matter how corrupted. */ METHODDEF(boolean) fill_input_buffer (j_decompress_ptr cinfo) { my_src_ptr src = reinterpret_cast(cinfo->src); WARNMS(cinfo, JWRN_JPEG_EOF); /* Create a fake EOI marker */ src->eoi_buffer[0] = static_cast(0xFF); src->eoi_buffer[1] = static_cast(JPEG_EOI); src->pub.next_input_byte = src->eoi_buffer; src->pub.bytes_in_buffer = 2; return TRUE; } /* * Skip data --- used to skip over a potentially large amount of * uninteresting data (such as an APPn marker). * * If we overrun the end of the buffer, we let fill_input_buffer deal with * it. An extremely large skip could cause some time-wasting here, but * it really isn't supposed to happen ... and the decompressor will never * skip more than 64K anyway. */ METHODDEF(void) skip_input_data (j_decompress_ptr cinfo, long num_bytes) { my_src_ptr src = reinterpret_cast(cinfo->src); if (num_bytes > 0) { while (num_bytes > static_cast(src->pub.bytes_in_buffer) ) { num_bytes -= static_cast(src->pub.bytes_in_buffer); fill_input_buffer(cinfo); /* note we assume that fill_input_buffer will never return FALSE, * so suspension need not be handled. */ } src->pub.next_input_byte += static_cast(num_bytes); src->pub.bytes_in_buffer -= static_cast(num_bytes); } } /* * An additional method that can be provided by data source modules is the * resync_to_restart method for error recovery in the presence of RST markers. * For the moment, this source module just uses the default resync method * provided by the JPEG library. That method assumes that no backtracking * is possible. */ /* * Terminate source --- called by jpeg_finish_decompress * after all data has been read. Often a no-op. * * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding * application must deal with any cleanup that should happen even * for error exit. */ METHODDEF(void) term_source (j_decompress_ptr) { /* no work necessary here */ } /* * Prepare for input from a memory buffer. */ GLOBAL(void) jpeg_memory_src (j_decompress_ptr cinfo, const JOCTET * buffer, size_t bufsize) { my_src_ptr src; /* The source object is made permanent so that a series of JPEG images * can be read from a single buffer by calling jpeg_memory_src * only before the first one. * This makes it unsafe to use this manager and a different source * manager serially with the same JPEG object. Caveat programmer. */ if (cinfo->src == NULL) { /* first time for this JPEG object? */ cinfo->src = static_cast( (*cinfo->mem->alloc_small) ( reinterpret_cast(cinfo), JPOOL_PERMANENT, sizeof(my_source_mgr))); } src = reinterpret_cast(cinfo->src); src->pub.init_source = init_source; src->pub.fill_input_buffer = fill_input_buffer; src->pub.skip_input_data = skip_input_data; src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ src->pub.term_source = term_source; src->pub.next_input_byte = buffer; src->pub.bytes_in_buffer = bufsize; } #endif // PODOFO_HAVE_JPEG_LIB #ifdef PODOFO_HAVE_TIFF_LIB #ifdef DS_CCITT_DEVELOPMENT_CODE // ------------------------------------------------------- // // ------------------------------------------------------- static tsize_t dummy_read(thandle_t, tdata_t, tsize_t) { return 0; } // ------------------------------------------------------- // // ------------------------------------------------------- static tsize_t dummy_write(thandle_t, tdata_t, tsize_t size) { return size; } // ------------------------------------------------------- // // ------------------------------------------------------- static toff_t dummy_seek(thandle_t, toff_t, int) { } // ------------------------------------------------------- // // ------------------------------------------------------- static int dummy_close(thandle_t) { } // ------------------------------------------------------- // // ------------------------------------------------------- static toff_t dummy_size(thandle_t) { } #endif // ------------------------------------------------------- // Actual filter code below // ------------------------------------------------------- PdfCCITTFilter::PdfCCITTFilter() : m_tiff( NULL ) { } PdfCCITTFilter::~PdfCCITTFilter() { } void PdfCCITTFilter::BeginEncodeImpl() { PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter ); } void PdfCCITTFilter::EncodeBlockImpl( const char*, pdf_long ) { PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter ); } void PdfCCITTFilter::EndEncodeImpl() { PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter ); } #ifndef _MSC_VER #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif void PdfCCITTFilter::BeginDecodeImpl( const PdfDictionary* pDict ) { #ifdef DS_CCITT_DEVELOPMENT_CODE if( !pDict ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "PdfCCITTFilter required a DecodeParms dictionary" ); } m_tiff = TIFFClientOpen("podofo", "w", reinterpret_cast(-1), dummy_read, dummy_write, dummy_seek, dummy_close, dummy_size, NULL, NULL); if( !m_tiff ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "TIFFClientOpen failed" ); } m_tiff->tif_mode = O_RDONLY; TIFFSetField(m_tiff, TIFFTAG_IMAGEWIDTH, pDict->GetKeyAsLong( PdfName("Columns"), 1728 )->GetNumber() ); TIFFSetField(m_tiff, TIFFTAG_SAMPLESPERPIXEL, 1); TIFFSetField(m_tiff, TIFFTAG_BITSPERSAMPLE, 1); TIFFSetField(m_tiff, TIFFTAG_FILLORDER, FILLORDER_LSB2MSB); TIFFSetField(m_tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(m_tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE); TIFFSetField(m_tiff, TIFFTAG_YRESOLUTION, 196.); TIFFSetField(m_tiff, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); /* m_tiff->tif_scanlinesize = TIFFSetField(m_tiff ); if( pDict ) { long lEncoding = pDict->GetKeyAsLong( PdfName("K"), 0 ); if( lEncoding == 0 ) // pure 1D encoding, Group3 1D { TIFFSetField(faxTIFF,TIFFTAG_GROUP3OPTIONS, GROUP3OPT_1DENCODING); } else if( lEncoding < 0 ) // pure 2D encoding, Group4 { TIFFSetField(faxTIFF,TIFFTAG_GROUP4OPTIONS, GROUP4OPT_2DENCODING); } else //if( lEncoding > 0 ) // mixed, Group3 2D { TIFFSetField(faxTIFF,TIFFTAG_GROUP3OPTIONS, GROUP3OPT_2DENCODING); } } */ #endif // DS_CCITT_DEVELOPMENT_CODE } #ifndef _MSC_VER #pragma GCC diagnostic pop #endif void PdfCCITTFilter::DecodeBlockImpl( const char*, pdf_long ) { } void PdfCCITTFilter::EndDecodeImpl() { } #endif // PODOFO_HAVE_TIFF_LIB }; podofo-0.9.5/src/base/PdfRefCountedInputDevice.h0000664000175000017500000001277013012362162021370 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_REF_COUNTED_INPUT_DEVICE_H_ #define _PDF_REF_COUNTED_INPUT_DEVICE_H_ #include "PdfDefines.h" namespace PoDoFo { class PdfInputDevice; /** * A reference counted input device object * which is closed as soon as the last * object having access to it is deleted. */ class PODOFO_API PdfRefCountedInputDevice { public: /** Created an empty reference counted input device object * The input device will be initialize to NULL */ PdfRefCountedInputDevice(); /** Create a new PdfRefCountedInputDevice which reads from a file. * The file is opened using fopen() * \param pszFilename a filename to be passed to fopen * \param pszMode a mode string that can be passed to fopen */ PdfRefCountedInputDevice( const char* pszFilename, const char* pszMode ); #ifdef _WIN32 /** Create a new PdfRefCountedInputDevice which reads from a file. * The file is opened using fopen() * \param pszFilename a filename to be passed to fopen * \param pszMode a mode string that can be passed to fopen * * This is an overloaded member function to allow working * with unicode characters. On Unix systes you can also path * UTF-8 to the const char* overload. * */ PdfRefCountedInputDevice( const wchar_t* pszFilename, const char* pszMode ); #endif // _WIN32 /** Create a new PdfRefCountedInputDevice which operates on a in memory buffer * * \param pBuffer pointer to the buffer * \param lLen length of the buffer */ PdfRefCountedInputDevice( const char* pBuffer, size_t lLen ); /** Create a new PdfRefCountedInputDevice from an PdfInputDevice * * \param pDevice the input device. It will be owned and deleted by this object. */ PdfRefCountedInputDevice( PdfInputDevice* pDevice ); /** Copy an existing PdfRefCountedInputDevice and increase * the reference count * \param rhs the PdfRefCountedInputDevice to copy */ PdfRefCountedInputDevice( const PdfRefCountedInputDevice & rhs ); /** Decrease the reference count and close the file * if this is the last owner */ ~PdfRefCountedInputDevice(); /** Get access to the file handle * \returns the file handle */ PODOFO_NOTHROW inline PdfInputDevice* Device() const; /** Copy an existing PdfRefCountedFile and increase * the reference count * \param rhs the PdfRefCountedFile to copy * \returns the copied object */ const PdfRefCountedInputDevice & operator=( const PdfRefCountedInputDevice & rhs ); private: /** Detach from the reference counted file */ void Detach(); private: typedef struct { PdfInputDevice* m_pDevice; long m_lRefCount; } TRefCountedInputDevice; TRefCountedInputDevice* m_pDevice; }; // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfInputDevice* PdfRefCountedInputDevice::Device() const { return m_pDevice ? m_pDevice->m_pDevice : NULL; } }; #endif // _PDF_REF_COUNTED_INPUT_DEVICE_H_ podofo-0.9.5/src/base/PdfXRefStream.cpp0000664000175000017500000001205513012362162017541 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfXRefStream.h" #include "PdfObject.h" #include "PdfStream.h" #include "PdfWriter.h" #include "PdfDefinesPrivate.h" #if defined(_AIX) || defined(__sun) #include #elif defined(__APPLE__) || defined(__linux) #include #elif defined(_WIN32) #include #endif namespace PoDoFo { PdfXRefStream::PdfXRefStream( PdfVecObjects* pParent, PdfWriter* pWriter ) : m_pParent( pParent ), m_pWriter( pWriter ), m_pObject( NULL ) { m_bufferLen = 2 + sizeof( pdf_uint32 ); m_pObject = pParent->CreateObject( "XRef" ); m_offset = 0; } PdfXRefStream::~PdfXRefStream() { } void PdfXRefStream::BeginWrite( PdfOutputDevice* ) { m_pObject->GetStream()->BeginAppend(); } void PdfXRefStream::WriteSubSection( PdfOutputDevice*, pdf_objnum first, pdf_uint32 count ) { PdfError::DebugMessage("Writing XRef section: %u %u\n", first, count ); m_indeces.push_back( static_cast(first) ); m_indeces.push_back( static_cast(count) ); } void PdfXRefStream::WriteXRefEntry( PdfOutputDevice*, pdf_uint64 offset, pdf_gennum generation, char cMode, pdf_objnum objectNumber ) { std::vector bytes(m_bufferLen); #if (defined(_MSC_VER) && _MSC_VER < 1700) || (defined(__BORLANDC__)) // MSC before VC11 has no data member, same as BorlandC char * buffer = &bytes[0]; #else char * buffer = bytes.data(); #endif if( cMode == 'n' && objectNumber == m_pObject->Reference().ObjectNumber() ) m_offset = offset; buffer[0] = static_cast( cMode == 'n' ? 1 : 0 ); buffer[m_bufferLen-1] = static_cast( cMode == 'n' ? 0 : generation ); const pdf_uint32 offset_be = ::PoDoFo::compat::podofo_htonl(static_cast(offset)); memcpy( &buffer[1], reinterpret_cast(&offset_be), sizeof(pdf_uint32) ); m_pObject->GetStream()->Append( buffer, m_bufferLen ); } void PdfXRefStream::EndWrite( PdfOutputDevice* pDevice ) { PdfArray w; w.push_back( static_cast(1) ); w.push_back( static_cast(sizeof(pdf_uint32)) ); w.push_back( static_cast(1) ); // Add our self to the XRef table this->WriteXRefEntry( pDevice, pDevice->Tell(), 0, 'n' ); m_pObject->GetStream()->EndAppend(); m_pWriter->FillTrailerObject( m_pObject, this->GetSize(), false ); m_pObject->GetDictionary().AddKey( "Index", m_indeces ); m_pObject->GetDictionary().AddKey( "W", w ); pDevice->Seek( static_cast(m_offset) ); m_pObject->WriteObject( pDevice, m_pWriter->GetWriteMode(), NULL ); // DominikS: Requires encryption info?? m_indeces.Clear(); } }; podofo-0.9.5/src/base/PdfArray.h0000664000175000017500000004044213012362162016245 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_ARRAY_H_ #define _PDF_ARRAY_H_ #ifdef _WIN32 #ifdef _MSC_VER // IC: VS2008 suppress dll warning #pragma warning(disable: 4275) #endif // _MSC_VER #endif // _WIN32 #include "PdfDefines.h" #include "PdfDataType.h" #include "PdfObject.h" namespace PoDoFo { typedef std::vector PdfArrayBaseClass; /** This class represents a PdfArray * Use it for all arrays that are written to a PDF file. * * A PdfArray can hold any PdfVariant. * * \see PdfVariant */ class PODOFO_API PdfArray : private PdfArrayBaseClass, public PdfDataType { public: typedef PdfArrayBaseClass::iterator iterator; typedef PdfArrayBaseClass::const_iterator const_iterator; typedef PdfArrayBaseClass::reverse_iterator reverse_iterator; typedef PdfArrayBaseClass::const_reverse_iterator const_reverse_iterator; /** Create an empty array */ PdfArray(); /** Create an array and add one value to it. * The value is copied. * * \param var add this object to the array. */ explicit PdfArray( const PdfObject & var ); /** Deep copy an existing PdfArray * * \param rhs the array to copy */ PdfArray( const PdfArray & rhs ); virtual ~PdfArray(); /** assignment operator * * \param rhs the array to assign */ PdfArray& operator=(const PdfArray& rhs); /** * \returns the size of the array */ inline size_t GetSize() const; /** Remove all elements from the array */ inline void Clear(); /** Write the array to an output device. * This is an overloaded member function. * * \param pDevice write the object to this device * \param eWriteMode additional options for writing this object * \param pEncrypt an encryption object which is used to encrypt this object * or NULL to not encrypt this object */ virtual void Write( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, const PdfEncrypt* pEncrypt = NULL ) const; /** Utility method to determine if the array contains * contains any objects of ePdfDataType_String whose * value is the passed string. * \param cmpString the string to compare against * \returns true if success, false if not */ bool ContainsString( const std::string& cmpString ) const; /** Utility method to return the actual index in the * array which contains an object of ePdfDataType_String whose * value is the passed string. * \param cmpString the string to compare against * \returns true if success, false if not */ size_t GetStringIndex( const std::string& cmpString ) const; /** Adds a PdfObject to the array * * \param var add a PdfObject to the array * * This will set the dirty flag of this object. * \see IsDirty */ inline void push_back( const PdfObject & var ); /** * \returns the size of the array */ inline size_t size() const; /** * \returns true if the array is empty. */ inline bool empty() const; inline PdfObject & operator[](size_type __n); inline const PdfObject & operator[](size_type __n) const; /** * Resize the internal vector. * \param __n new size */ inline void resize(size_t __n, value_type __x = PdfArrayBaseClass::value_type()); /** * Returns a read/write iterator that points to the first * element in the array. Iteration is done in ordinary * element order. */ inline iterator begin(); /** * Returns a read-only (constant) iterator that points to the * first element in the array. Iteration is done in ordinary * element order. */ inline const_iterator begin() const; /** * Returns a read/write iterator that points one past the last * element in the array. Iteration is done in ordinary * element order. */ inline iterator end(); /** * Returns a read-only (constant) iterator that points one past * the last element in the array. Iteration is done in * ordinary element order. */ inline const_iterator end() const; /** * Returns a read/write reverse iterator that points to the * last element in the array. Iteration is done in reverse * element order. */ inline reverse_iterator rbegin(); /** * Returns a read-only (constant) reverse iterator that points * to the last element in the array. Iteration is done in * reverse element order. */ inline const_reverse_iterator rbegin() const; /** * Returns a read/write reverse iterator that points to one * before the first element in the array. Iteration is done * in reverse element order. */ inline reverse_iterator rend(); /** * Returns a read-only (constant) reverse iterator that points * to one before the first element in the array. Iteration * is done in reverse element order. */ inline const_reverse_iterator rend() const; #if defined(_MSC_VER) && _MSC_VER <= 1200 // workaround template-error in Visualstudio 6 inline void insert(iterator __position, iterator __first, iterator __last); #else template void insert(const iterator& __position, const _InputIterator& __first, const _InputIterator& __last); #endif inline PdfArray::iterator insert(const iterator& __position, const PdfObject & val ); inline void erase( const iterator& pos ); inline void erase( const iterator& first, const iterator& last ); inline void reserve(size_type __n); /** * \returns a read/write reference to the data at the first * element of the array. */ inline reference front(); /** * \returns a read-only (constant) reference to the data at the first * element of the array. */ inline const_reference front() const; /** * \returns a read/write reference to the data at the last * element of the array. */ inline reference back(); /** * \returns a read-only (constant) reference to the data at the * last element of the array. */ inline const_reference back() const; inline bool operator==( const PdfArray & rhs ) const; inline bool operator!=( const PdfArray & rhs ) const; /** The dirty flag is set if this variant * has been modified after construction. * * Usually the dirty flag is also set * if you call any non-const member function * as we cannot determine if you actually changed * something or not. * * \returns true if the value is dirty and has been * modified since construction */ virtual bool IsDirty() const; /** Sets the dirty flag of this PdfVariant * * \param bDirty true if this PdfVariant has been * modified from the outside * * \see IsDirty */ virtual void SetDirty( bool bDirty ); private: bool m_bDirty; ///< Indicates if this object was modified after construction }; // ----------------------------------------------------- // // ----------------------------------------------------- void PdfArray::Clear() { AssertMutable(); this->clear(); } // ----------------------------------------------------- // // ----------------------------------------------------- size_t PdfArray::GetSize() const { return this->size(); } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfArray::push_back( const PdfObject & var ) { AssertMutable(); PdfArrayBaseClass::push_back( var ); m_bDirty = true; } // ----------------------------------------------------- // // ----------------------------------------------------- size_t PdfArray::size() const { return PdfArrayBaseClass::size(); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfArray::empty() const { return PdfArrayBaseClass::empty(); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfObject& PdfArray::operator[](size_type __n) { AssertMutable(); return PdfArrayBaseClass::operator[](__n); } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfObject& PdfArray::operator[](size_type __n) const { return PdfArrayBaseClass::operator[](__n); } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfArray::resize(size_t __n, value_type __x) { PdfArrayBaseClass::resize(__n, __x); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfArray::iterator PdfArray::begin() { return PdfArrayBaseClass::begin(); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfArray::const_iterator PdfArray::begin() const { return PdfArrayBaseClass::begin(); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfArray::iterator PdfArray::end() { return PdfArrayBaseClass::end(); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfArray::const_iterator PdfArray::end() const { return PdfArrayBaseClass::end(); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfArray::reverse_iterator PdfArray::rbegin() { return PdfArrayBaseClass::rbegin(); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfArray::const_reverse_iterator PdfArray::rbegin() const { return PdfArrayBaseClass::rbegin(); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfArray::reverse_iterator PdfArray::rend() { return PdfArrayBaseClass::rend(); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfArray::const_reverse_iterator PdfArray::rend() const { return PdfArrayBaseClass::rend(); } // ----------------------------------------------------- // // ----------------------------------------------------- #if defined(_MSC_VER) && _MSC_VER <= 1200 // workaround template-error in Visualstudio 6 void PdfArray::insert(PdfArray::iterator __position, PdfArray::iterator __first, PdfArray::iterator __last) #else template void PdfArray::insert(const PdfArray::iterator& __position, const _InputIterator& __first, const _InputIterator& __last) #endif { AssertMutable(); PdfArrayBaseClass::insert( __position, __first, __last ); m_bDirty = true; } // ----------------------------------------------------- // // ----------------------------------------------------- PdfArray::iterator PdfArray::insert(const iterator& __position, const PdfObject & val ) { AssertMutable(); m_bDirty = true; return PdfArrayBaseClass::insert( __position, val ); } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfArray::erase( const iterator& pos ) { AssertMutable(); PdfArrayBaseClass::erase( pos ); m_bDirty = true; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfArray::erase( const iterator& first, const iterator& last ) { AssertMutable(); PdfArrayBaseClass::erase( first, last ); m_bDirty = true; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfArray::reserve(size_type __n) { PdfArrayBaseClass::reserve( __n ); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfObject & PdfArray::front() { return PdfArrayBaseClass::front(); } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfObject & PdfArray::front() const { return PdfArrayBaseClass::front(); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfObject & PdfArray::back() { return PdfArrayBaseClass::back(); } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfObject & PdfArray::back() const { return PdfArrayBaseClass::back(); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfArray::operator==( const PdfArray & rhs ) const { //TODO: This operator does not check for m_bDirty. Add comparison or add explanation why it should not be there return (static_cast< PdfArrayBaseClass >(*this) == static_cast< PdfArrayBaseClass >(rhs) ); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfArray::operator!=( const PdfArray & rhs ) const { //TODO: This operator does not check for m_bDirty. Add comparison or add explanation why it should not be there return (static_cast< PdfArrayBaseClass >(*this) != static_cast< PdfArrayBaseClass >(rhs) ); } typedef PdfArray TVariantList; typedef PdfArray::iterator TIVariantList; typedef PdfArray::const_iterator TCIVariantList; }; #endif // _PDF_ARRAY_H_ podofo-0.9.5/src/base/PdfVecObjects.cpp0000664000175000017500000004310613012362162017551 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfVecObjects.h" #include "PdfArray.h" #include "PdfDictionary.h" #include "PdfMemStream.h" #include "PdfObject.h" #include "PdfReference.h" #include "PdfStream.h" #include "PdfDefinesPrivate.h" #include namespace { inline bool ObjectLittle( const PoDoFo::PdfObject* p1, const PoDoFo::PdfObject* p2 ) { return *p1 < *p2; } }; namespace PoDoFo { struct ObjectComparatorPredicate { public: inline bool operator()( const PdfObject* const & pObj, const PdfObject* const & pObj2 ) const { return pObj->Reference() < pObj2->Reference(); } /* inline bool operator()( PdfObject* const & pObj, const PdfReference & ref ) const { return pObj->Reference() < ref; } inline bool operator()( const PdfReference & ref, PdfObject* const & pObj ) const { return ref < pObj->Reference(); } */ }; struct ReferenceComparatorPredicate { public: inline bool operator()( const PdfReference & pObj, const PdfReference & pObj2 ) const { return pObj < pObj2; } }; //RG: 1) Should this class not be moved to the header file class ObjectsComparator { public: ObjectsComparator( const PdfReference & ref ) : m_ref( ref ) { } bool operator()(const PdfObject* p1) const { return p1 ? (p1->Reference() == m_ref ) : false; } private: /** default constructor, not implemented */ ObjectsComparator(void); /** copy constructor, not implemented */ ObjectsComparator(const ObjectsComparator& rhs); /** assignment operator, not implemented */ ObjectsComparator& operator=(const ObjectsComparator& rhs); const PdfReference m_ref; }; PdfVecObjects::PdfVecObjects() : m_bAutoDelete( false ), m_bCanReuseObjectNumbers( true ), m_nObjectCount( 1 ), m_bSorted( true ), m_pDocument( NULL ), m_pStreamFactory( NULL ) { } PdfVecObjects::~PdfVecObjects() { this->Clear(); } void PdfVecObjects::Clear() { // always work on a copy of the vector // in case a child invalidates our iterators // with a call to attach or detach. TVecObservers copy( m_vecObservers ); TIVecObservers itObservers = copy.begin(); while( itObservers != copy.end() ) { (*itObservers)->ParentDestructed(); ++itObservers; } if( m_bAutoDelete ) { TIVecObjects it = this->begin(); while( it != this->end() ) { delete *it; ++it; } } m_vector.clear(); m_bAutoDelete = false; m_nObjectCount = 1; m_bSorted = true; // an emtpy vector is sorted m_pDocument = NULL; m_pStreamFactory = NULL; } PdfObject* PdfVecObjects::GetObject( const PdfReference & ref ) const { if( !m_bSorted ) const_cast(this)->Sort(); PdfObject refObj( ref, NULL ); std::pair it = std::equal_range( m_vector.begin(), m_vector.end(), &refObj, ObjectComparatorPredicate() ); if( it.first != it.second ) return *(it.first); /* const TCIVecObjects it ( std::find_if( this->begin(), this->end(), ObjectsComparator( ref ) ) ); if( it != this->end() ) return (*it); */ return NULL; } size_t PdfVecObjects::GetIndex( const PdfReference & ref ) const { if( !m_bSorted ) const_cast(this)->Sort(); PdfObject refObj( ref, NULL ); std::pair it = std::equal_range( m_vector.begin(), m_vector.end(), &refObj, ObjectComparatorPredicate() ); if( it.first == it.second ) { PODOFO_RAISE_ERROR( ePdfError_NoObject ); } return (it.first - this->begin()); } PdfObject* PdfVecObjects::RemoveObject( const PdfReference & ref, bool bMarkAsFree ) { if( !m_bSorted ) this->Sort(); PdfObject* pObj; PdfObject refObj( ref, NULL ); std::pair it = std::equal_range( m_vector.begin(), m_vector.end(), &refObj, ObjectComparatorPredicate() ); if( it.first != it.second ) { pObj = *(it.first); if( bMarkAsFree ) this->AddFreeObject( pObj->Reference() ); m_vector.erase( it.first ); return pObj; } return NULL; } PdfObject* PdfVecObjects::RemoveObject( const TIVecObjects & it ) { PdfObject* pObj = *it; m_vector.erase( it ); return pObj; } void PdfVecObjects::CollectGarbage( PdfObject* pTrailer ) { // We do not have any objects that have // to be on the top, like in a linearized PDF. // So we just use an empty list. TPdfReferenceSet setLinearizedGroup; this->RenumberObjects( pTrailer, &setLinearizedGroup, true ); } PdfReference PdfVecObjects::GetNextFreeObject() { PdfReference ref( static_cast(m_nObjectCount), 0 ); if( m_bCanReuseObjectNumbers && !m_lstFreeObjects.empty() ) { ref = m_lstFreeObjects.front(); m_lstFreeObjects.pop_front(); } return ref; } PdfObject* PdfVecObjects::CreateObject( const char* pszType ) { PdfReference ref = this->GetNextFreeObject(); PdfObject* pObj = new PdfObject( ref, pszType ); pObj->SetOwner( this ); this->push_back( pObj ); return pObj; } PdfObject* PdfVecObjects::CreateObject( const PdfVariant & rVariant ) { PdfReference ref = this->GetNextFreeObject(); PdfObject* pObj = new PdfObject( ref, rVariant ); pObj->SetOwner( this ); this->push_back( pObj ); return pObj; } void PdfVecObjects::AddFreeObject( const PdfReference & rReference ) { std::pair it = std::equal_range( m_lstFreeObjects.begin(), m_lstFreeObjects.end(), rReference, ReferenceComparatorPredicate() ); if( it.first != it.second && !m_lstFreeObjects.empty() ) { // Be sure that no reference is added twice to free list PdfError::DebugMessage( "Adding %d to free list, is already contained in it!", rReference.ObjectNumber() ); return; } else { // When append free objects from external doc we need plus one number objects SetObjectCount( rReference ); // Insert so that list stays sorted m_lstFreeObjects.insert( it.first, rReference ); } } void PdfVecObjects::push_back( PdfObject* pObj ) { insert_sorted( pObj ); } void PdfVecObjects::insert_sorted( PdfObject* pObj ) { SetObjectCount( pObj->Reference() ); pObj->SetOwner( this ); if( m_bSorted && !m_vector.empty() && pObj->Reference() < m_vector.back()->Reference() ) { TVecObjects::iterator i_pos = std::lower_bound(m_vector.begin(),m_vector.end(),pObj,ObjectLittle); m_vector.insert(i_pos, pObj ); } else { m_vector.push_back( pObj ); } } void PdfVecObjects::RenumberObjects( PdfObject* pTrailer, TPdfReferenceSet* pNotDelete, bool bDoGarbageCollection ) { TVecReferencePointerList list; TIVecReferencePointerList it; TIReferencePointerList itList; int i = 0; m_lstFreeObjects.clear(); if( !m_bSorted ) const_cast(this)->Sort(); // The following call slows everything down // optimization welcome BuildReferenceCountVector( &list ); InsertReferencesIntoVector( pTrailer, &list ); if( bDoGarbageCollection ) { GarbageCollection( &list, pTrailer, pNotDelete ); } it = list.begin(); while( it != list.end() ) { PdfReference ref( i+1, 0 ); m_vector[i]->m_reference = ref; itList = (*it).begin(); while( itList != (*it).end() ) { *(*itList) = ref; ++itList; } ++i; ++it; } } void PdfVecObjects::InsertOneReferenceIntoVector( const PdfObject* pObj, TVecReferencePointerList* pList ) { size_t index; PODOFO_RAISE_LOGIC_IF( !m_bSorted, "PdfVecObjects must be sorted before calling PdfVecObjects::InsertOneReferenceIntoVector!" ); // we asume that pObj is a reference - no checking here because of speed std::pair it = std::equal_range( m_vector.begin(), m_vector.end(), pObj, ObjectComparatorPredicate() ); if( it.first != it.second ) { // ignore this reference return; //PODOFO_RAISE_ERROR( ePdfError_NoObject ); } index = (it.first - this->begin()); (*pList)[index].push_back( const_cast(&(pObj->GetReference() )) ); } void PdfVecObjects::InsertReferencesIntoVector( const PdfObject* pObj, TVecReferencePointerList* pList ) { PdfArray::const_iterator itArray; TCIKeyMap itKeys; if( pObj->IsReference() ) { InsertOneReferenceIntoVector( pObj, pList ); } else if( pObj->IsArray() ) { itArray = pObj->GetArray().begin(); while( itArray != pObj->GetArray().end() ) { if( (*itArray).IsReference() ) InsertOneReferenceIntoVector( &(*itArray), pList ); else if( (*itArray).IsArray() || (*itArray).IsDictionary() ) InsertReferencesIntoVector( &(*itArray), pList ); ++itArray; } } else if( pObj->IsDictionary() ) { itKeys = pObj->GetDictionary().GetKeys().begin(); while( itKeys != pObj->GetDictionary().GetKeys().end() ) { if( (*itKeys).second->IsReference() ) InsertOneReferenceIntoVector( (*itKeys).second, pList ); // optimization as this is really slow: // Call only for dictionaries, references and arrays else if( (*itKeys).second->IsArray() || (*itKeys).second->IsDictionary() ) InsertReferencesIntoVector( (*itKeys).second, pList ); ++itKeys; } } } void PdfVecObjects::GetObjectDependencies( const PdfObject* pObj, TPdfReferenceList* pList ) const { PdfArray::const_iterator itArray; TCIKeyMap itKeys; if( pObj->IsReference() ) { std::pair itEqualRange = std::equal_range( pList->begin(), pList->end(), pObj->GetReference() ); if( itEqualRange.first == itEqualRange.second ) { pList->insert(itEqualRange.first, pObj->GetReference() ); const PdfObject* referencedObject = this->GetObject(pObj->GetReference()); if( referencedObject != NULL ) { this->GetObjectDependencies( referencedObject, pList ); } } } else if( pObj->IsArray() ) { itArray = pObj->GetArray().begin(); while( itArray != pObj->GetArray().end() ) { if( (*itArray).IsArray() || (*itArray).IsDictionary() || (*itArray).IsReference() ) GetObjectDependencies( &(*itArray), pList ); ++itArray; } } else if( pObj->IsDictionary() ) { itKeys = pObj->GetDictionary().GetKeys().begin(); while( itKeys != pObj->GetDictionary().GetKeys().end() ) { // optimization as this is really slow: // Call only for dictionaries, references and arrays if( (*itKeys).second->IsArray() || (*itKeys).second->IsDictionary() || (*itKeys).second->IsReference() ) GetObjectDependencies( (*itKeys).second, pList ); ++itKeys; } } } void PdfVecObjects::BuildReferenceCountVector( TVecReferencePointerList* pList ) { TCIVecObjects it = this->begin(); pList->clear(); pList->resize( !m_vector.empty() ); while( it != this->end() ) { if( (*it)->IsReference() ) InsertOneReferenceIntoVector( *it, pList ); // optimization as this is really slow: // Call only for dictionaries, references and arrays else if( (*it)->IsArray() || (*it)->IsDictionary() ) InsertReferencesIntoVector( *it, pList ); ++it; } } void PdfVecObjects::Sort() { if( !m_bSorted ) { std::sort( this->begin(), this->end(), ObjectLittle ); m_bSorted = true; } } void PdfVecObjects::GarbageCollection( TVecReferencePointerList* pList, PdfObject*, TPdfReferenceSet* pNotDelete ) { TIVecReferencePointerList it = pList->begin(); int pos = 0; bool bContains = false; while( it != pList->end() ) { bContains = pNotDelete ? ( pNotDelete->find( m_vector[pos]->Reference() ) != pNotDelete->end() ) : false; if( !(*it).size() && !bContains ) { m_vector.erase( this->begin() + pos ); } ++pos; ++it; } m_nObjectCount = ++pos; } void PdfVecObjects::Detach( Observer* pObserver ) { TIVecObservers it = m_vecObservers.begin(); while( it != m_vecObservers.end() ) { if( *it == pObserver ) { m_vecObservers.erase( it ); break; } else ++it; } } PdfStream* PdfVecObjects::CreateStream( PdfObject* pParent ) { PdfStream* pStream = m_pStreamFactory ? m_pStreamFactory->CreateStream( pParent ) : new PdfMemStream( pParent ); return pStream; } void PdfVecObjects::WriteObject( PdfObject* pObject ) { // Tell any observers that there are new objects to write TIVecObservers itObservers = m_vecObservers.begin(); while( itObservers != m_vecObservers.end() ) { (*itObservers)->WriteObject( pObject ); ++itObservers; } } PdfStream* PdfVecObjects::CreateStream( const PdfStream & ) { return NULL; } void PdfVecObjects::Finish() { // always work on a copy of the vector // in case a child invalidates our iterators // with a call to attach or detach. TVecObservers copy( m_vecObservers ); TIVecObservers itObservers = copy.begin(); while( itObservers != copy.end() ) { (*itObservers)->Finish(); ++itObservers; } } void PdfVecObjects::BeginAppendStream( const PdfStream* pStream ) { TIVecObservers itObservers = m_vecObservers.begin(); while( itObservers != m_vecObservers.end() ) { (*itObservers)->BeginAppendStream( pStream ); ++itObservers; } } void PdfVecObjects::EndAppendStream( const PdfStream* pStream ) { TIVecObservers itObservers = m_vecObservers.begin(); while( itObservers != m_vecObservers.end() ) { (*itObservers)->EndAppendStream( pStream ); ++itObservers; } } std::string PdfVecObjects::GetNextSubsetPrefix() { if ( m_sSubsetPrefix == "" ) { m_sSubsetPrefix = "AAAAAA+"; } else { PODOFO_ASSERT( m_sSubsetPrefix.length() == 7 ); PODOFO_ASSERT( m_sSubsetPrefix[6] == '+' ); for ( int i = 5; i >= 0; i-- ) { if ( m_sSubsetPrefix[i] < 'Z' ) { m_sSubsetPrefix[i]++; break; } m_sSubsetPrefix[i] = 'A'; } } return m_sSubsetPrefix; } void PdfVecObjects::SetCanReuseObjectNumbers( bool bCanReuseObjectNumbers ) { m_bCanReuseObjectNumbers = bCanReuseObjectNumbers; if( !m_bCanReuseObjectNumbers ) { m_lstFreeObjects.clear(); } } }; podofo-0.9.5/src/base/PdfInputStream.h0000664000175000017500000001452112344436402017447 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_INPUT_STREAM_H_ #define _PDF_INPUT_STREAM_H_ #include "PdfDefines.h" namespace PoDoFo { class PdfInputDevice; /** An interface for reading blocks of data from an * a data source. */ class PODOFO_API PdfInputStream { public: virtual ~PdfInputStream() { }; /** Read data from the input stream * * \param pBuffer the data will be stored into this buffer * \param lLen the size of the buffer and number of bytes * that will be read * \param pTotalLeft total bytes left (needed for AES IV and padding) * * \returns the number of bytes read, -1 if an error ocurred * and zero if no more bytes are available for reading. */ virtual pdf_long Read( char* pBuffer, pdf_long lLen, pdf_long *pTotalLeft = 0 ) = 0; }; /** An input stream that reads data from a file */ class PODOFO_API PdfFileInputStream : public PdfInputStream { public: /** Open a file for reading data * * \param pszFilename the filename of the file to read */ PdfFileInputStream( const char* pszFilename ); #ifdef _WIN32 /** Open a file for reading data * * \param pszFilename the filename of the file to read * * This is an overloaded member function to allow working * with unicode characters. On Unix systes you can also path * UTF-8 to the const char* overload. */ PdfFileInputStream( const wchar_t* pszFilename ); #endif // _WIN32 ~PdfFileInputStream(); /** Read data from the input stream * * \param pBuffer the data will be stored into this buffer * \param lLen the size of the buffer and number of bytes * that will be read * * \returns the number of bytes read, -1 if an error ocurred * and zero if no more bytes are available for reading. */ virtual pdf_long Read( char* pBuffer, pdf_long lLen, pdf_long* = 0 ); /** Get the length of the file. * \return the file length */ pdf_long GetFileLength(); /** Get the internal FILE handle. * \return the internal FILE handle */ FILE* GetHandle(); private: FILE* m_hFile; }; /** An input stream that reads data from a memory buffer */ class PODOFO_API PdfMemoryInputStream : public PdfInputStream { public: /** Open a file for reading data * * \param pBuffer buffer to read from * \param lBufferLen length of the buffer */ PdfMemoryInputStream( const char* pBuffer, pdf_long lBufferLen ); ~PdfMemoryInputStream(); /** Read data from the input stream * * \param pBuffer the data will be stored into this buffer * \param lLen the size of the buffer and number of bytes * that will be read * * \returns the number of bytes read, -1 if an error ocurred * and zero if no more bytes are available for reading. */ virtual pdf_long Read( char* pBuffer, pdf_long lLen, pdf_long* ); private: const char* m_pBuffer; const char* m_pCur; pdf_long m_lBufferLen; }; /** An input stream that reads data from an input device */ class PODOFO_API PdfDeviceInputStream : public PdfInputStream { public: /** * Read from an alread opened input device * * \param pDevice an input device */ PdfDeviceInputStream( PdfInputDevice* pDevice ); ~PdfDeviceInputStream(); /** Read data from the input stream * * \param pBuffer the data will be stored into this buffer * \param lLen the size of the buffer and number of bytes * that will be read * * \returns the number of bytes read, -1 if an error ocurred * and zero if no more bytes are available for reading. */ virtual pdf_long Read( char* pBuffer, pdf_long lLen, pdf_long* ); private: PdfInputDevice* m_pDevice; }; }; #endif // _PDF_INPUT_STREAM_H_ podofo-0.9.5/src/base/PdfRefCountedBuffer.cpp0000664000175000017500000002564612716100767020736 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfRefCountedBuffer.h" #include "PdfDefinesPrivate.h" #include #include namespace PoDoFo { PdfRefCountedBuffer::PdfRefCountedBuffer( char* pBuffer, size_t lSize ) : m_pBuffer( NULL ) { if( pBuffer && lSize ) { m_pBuffer = new TRefCountedBuffer(); m_pBuffer->m_lRefCount = 1; m_pBuffer->m_pHeapBuffer = pBuffer; m_pBuffer->m_bOnHeap = true; m_pBuffer->m_lBufferSize = lSize; m_pBuffer->m_lVisibleSize = lSize; m_pBuffer->m_bPossesion = true; } } void PdfRefCountedBuffer::FreeBuffer() { PODOFO_RAISE_LOGIC_IF( !m_pBuffer || m_pBuffer->m_lRefCount, "Tried to free in-use buffer" ); // last owner of the file! if( m_pBuffer->m_bOnHeap && m_pBuffer->m_bPossesion ) podofo_free( m_pBuffer->m_pHeapBuffer ); delete m_pBuffer; } void PdfRefCountedBuffer::ReallyDetach( size_t lExtraLen ) { PODOFO_RAISE_LOGIC_IF( m_pBuffer && m_pBuffer->m_lRefCount == 1, "Use Detach() rather than calling ReallyDetach() directly." ) if( !m_pBuffer ) { // throw error rather than de-referencing NULL PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } size_t lSize = m_pBuffer->m_lBufferSize + lExtraLen; TRefCountedBuffer* pBuffer = new TRefCountedBuffer(); pBuffer->m_lRefCount = 1; pBuffer->m_bOnHeap = (lSize > TRefCountedBuffer::INTERNAL_BUFSIZE); if ( pBuffer->m_bOnHeap ) pBuffer->m_pHeapBuffer = static_cast(podofo_calloc( lSize, sizeof(char) )); else pBuffer->m_pHeapBuffer = 0; pBuffer->m_lBufferSize = PDF_MAX( lSize, static_cast(+TRefCountedBuffer::INTERNAL_BUFSIZE) ); pBuffer->m_bPossesion = true; if( pBuffer->m_bOnHeap && !pBuffer->m_pHeapBuffer ) { delete pBuffer; pBuffer = NULL; PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } memcpy( pBuffer->GetRealBuffer(), this->GetBuffer(), this->GetSize() ); // Detaching the buffer should have NO visible effect to clients, so the // visible size must not change. pBuffer->m_lVisibleSize = m_pBuffer->m_lVisibleSize; // Now that we've copied the data, release our claim on the old buffer, // deleting it if needed, and link up the new one. DerefBuffer(); m_pBuffer = pBuffer; } void PdfRefCountedBuffer::ReallyResize( const size_t lSize ) { if( m_pBuffer ) { // Resizing the buffer counts as altering it, so detach as per copy on write behaviour. If the detach // actually has to do anything it'll reallocate the buffer at the new desired size. this->Detach( static_cast(m_pBuffer->m_lBufferSize) < lSize ? lSize - static_cast(m_pBuffer->m_lBufferSize) : 0 ); // We might have pre-allocated enough to service the request already if( static_cast(m_pBuffer->m_lBufferSize) < lSize ) { // Allocate more space, since we need it. We over-allocate so that clients can efficiently // request lots of small resizes if they want, but these over allocations are not visible // to clients. // const size_t lAllocSize = PDF_MAX(lSize, m_pBuffer->m_lBufferSize) << 1; if ( m_pBuffer->m_bPossesion && m_pBuffer->m_bOnHeap ) { // We have an existing on-heap buffer that we own. Realloc() // it, potentially saving us a memcpy and free(). void* temp = podofo_realloc( m_pBuffer->m_pHeapBuffer, lAllocSize ); if (!temp) { PODOFO_RAISE_ERROR_INFO( ePdfError_OutOfMemory, "PdfRefCountedBuffer::Resize failed!" ); } m_pBuffer->m_pHeapBuffer = static_cast(temp); m_pBuffer->m_lBufferSize = lAllocSize; } else { // Either we don't own the buffer or it's a local static buffer that's no longer big enough. // Either way, it's time to move to a heap-allocated buffer we own. char* pBuffer = static_cast(podofo_calloc( lAllocSize, sizeof(char) )); if( !pBuffer ) { PODOFO_RAISE_ERROR_INFO( ePdfError_OutOfMemory, "PdfRefCountedBuffer::Resize failed!" ); } // Only bother copying the visible portion of the buffer. It's completely incorrect // to rely on anything more than that, and not copying it will help catch those errors. memcpy( pBuffer, m_pBuffer->GetRealBuffer(), m_pBuffer->m_lVisibleSize ); // Record the newly allocated buffer's details. The visible size gets updated later. m_pBuffer->m_lBufferSize = lAllocSize; m_pBuffer->m_pHeapBuffer = pBuffer; m_pBuffer->m_bOnHeap = true; } } else { // Allocated buffer is large enough, do nothing } } else { // No buffer was allocated at all, so we need to make one. m_pBuffer = new TRefCountedBuffer(); m_pBuffer->m_lRefCount = 1; m_pBuffer->m_bOnHeap = (lSize > TRefCountedBuffer::INTERNAL_BUFSIZE); if ( m_pBuffer->m_bOnHeap ) { m_pBuffer->m_pHeapBuffer = static_cast(podofo_calloc( lSize, sizeof(char) )); } else { m_pBuffer->m_pHeapBuffer = 0; } m_pBuffer->m_lBufferSize = PDF_MAX( lSize, static_cast(+TRefCountedBuffer::INTERNAL_BUFSIZE) ); m_pBuffer->m_bPossesion = true; if( m_pBuffer->m_bOnHeap && !m_pBuffer->m_pHeapBuffer ) { delete m_pBuffer; m_pBuffer = NULL; PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } } m_pBuffer->m_lVisibleSize = lSize; PODOFO_RAISE_LOGIC_IF ( m_pBuffer->m_lVisibleSize > m_pBuffer->m_lBufferSize, "Buffer improperly allocated/resized"); } const PdfRefCountedBuffer & PdfRefCountedBuffer::operator=( const PdfRefCountedBuffer & rhs ) { // Self assignment is a no-op if (this == &rhs) return rhs; DerefBuffer(); m_pBuffer = rhs.m_pBuffer; if( m_pBuffer ) m_pBuffer->m_lRefCount++; return *this; } bool PdfRefCountedBuffer::operator==( const PdfRefCountedBuffer & rhs ) const { if( m_pBuffer != rhs.m_pBuffer ) { if( m_pBuffer && rhs.m_pBuffer ) { if ( m_pBuffer->m_lVisibleSize != rhs.m_pBuffer->m_lVisibleSize ) // Unequal buffer sizes cannot be equal buffers return false; // Test for byte-for-byte equality since lengths match return (memcmp( m_pBuffer->GetRealBuffer(), rhs.m_pBuffer->GetRealBuffer(), m_pBuffer->m_lVisibleSize ) == 0 ); } else // Cannot be equal if only one object has a real data buffer return false; } return true; } bool PdfRefCountedBuffer::operator<( const PdfRefCountedBuffer & rhs ) const { // equal buffers are neither smaller nor greater if( m_pBuffer == rhs.m_pBuffer ) return false; if( !m_pBuffer && rhs.m_pBuffer ) return true; else if( m_pBuffer && !rhs.m_pBuffer ) return false; else { int cmp = memcmp( m_pBuffer->GetRealBuffer(), rhs.m_pBuffer->GetRealBuffer(), PDF_MIN( m_pBuffer->m_lVisibleSize, rhs.m_pBuffer->m_lVisibleSize ) ); if (cmp == 0) // If one is a prefix of the other, ie they compare equal for the length of the shortest but one is longer, // the longer buffer is the greater one. return m_pBuffer->m_lVisibleSize < rhs.m_pBuffer->m_lVisibleSize; else return cmp < 0; } } bool PdfRefCountedBuffer::operator>( const PdfRefCountedBuffer & rhs ) const { // equal buffers are neither smaller nor greater if( m_pBuffer == rhs.m_pBuffer ) return false; if( !m_pBuffer && rhs.m_pBuffer ) return false; else if( m_pBuffer && !rhs.m_pBuffer ) return true; else { int cmp = memcmp( m_pBuffer->GetRealBuffer(), rhs.m_pBuffer->GetRealBuffer(), PDF_MIN( m_pBuffer->m_lVisibleSize, rhs.m_pBuffer->m_lVisibleSize ) ); if (cmp == 0) // If one is a prefix of the other, ie they compare equal for the length of the shortest but one is longer, // the longer buffer is the greater one. return m_pBuffer->m_lVisibleSize > rhs.m_pBuffer->m_lVisibleSize; else return cmp > 0; } } }; podofo-0.9.5/src/base/PdfFileStream.cpp0000664000175000017500000001236112347271543017570 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfFileStream.h" #include "PdfEncrypt.h" #include "PdfFilter.h" #include "PdfOutputDevice.h" #include "PdfOutputStream.h" #include "PdfDefinesPrivate.h" namespace PoDoFo { PdfFileStream::PdfFileStream( PdfObject* pParent, PdfOutputDevice* pDevice ) : PdfStream( pParent ), m_pDevice( pDevice ), m_pStream( NULL ), m_pDeviceStream( NULL ), m_pEncryptStream( NULL ), m_lLenInitial( 0 ), m_lLength( 0 ), m_pCurEncrypt( NULL ) { m_pLength = pParent->GetOwner()->CreateObject( PdfVariant(static_cast(PODOFO_LL_LITERAL(0))) ); m_pParent->GetDictionary().AddKey( PdfName::KeyLength, m_pLength->Reference() ); } PdfFileStream::~PdfFileStream() { } void PdfFileStream::Write( PdfOutputDevice*, PdfEncrypt* ) { } void PdfFileStream::BeginAppendImpl( const TVecFilters & vecFilters ) { m_pParent->GetOwner()->WriteObject( m_pParent ); m_lLenInitial = m_pDevice->GetLength(); if( vecFilters.size() ) { m_pDeviceStream = new PdfDeviceOutputStream( m_pDevice ); if( m_pCurEncrypt ) { m_pEncryptStream = m_pCurEncrypt->CreateEncryptionOutputStream( m_pDeviceStream ); m_pStream = PdfFilterFactory::CreateEncodeStream( vecFilters, m_pEncryptStream ); } else m_pStream = PdfFilterFactory::CreateEncodeStream( vecFilters, m_pDeviceStream ); } else { if( m_pCurEncrypt ) { m_pDeviceStream = new PdfDeviceOutputStream( m_pDevice ); m_pStream = m_pCurEncrypt->CreateEncryptionOutputStream( m_pDeviceStream ); } else m_pStream = new PdfDeviceOutputStream( m_pDevice ); } } void PdfFileStream::AppendImpl( const char* pszString, size_t lLen ) { m_pStream->Write( pszString, static_cast(lLen) ); } void PdfFileStream::EndAppendImpl() { if( m_pStream ) { m_pStream->Close(); delete m_pStream; m_pStream = NULL; } if( m_pEncryptStream ) { m_pEncryptStream->Close(); delete m_pEncryptStream; m_pEncryptStream = NULL; } if( m_pDeviceStream ) { m_pDeviceStream->Close(); delete m_pDeviceStream; m_pDeviceStream = NULL; } m_lLength = m_pDevice->GetLength() - m_lLenInitial; if( m_pCurEncrypt ) { m_lLength = m_pCurEncrypt->CalculateStreamLength(m_lLength); } m_pLength->SetNumber( static_cast(m_lLength) ); } void PdfFileStream::GetCopy( char**, pdf_long* ) const { PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } void PdfFileStream::GetCopy(PdfOutputStream*) const { PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } void PdfFileStream::SetEncrypted( PdfEncrypt* pEncrypt ) { m_pCurEncrypt = pEncrypt; if( m_pCurEncrypt ) m_pCurEncrypt->SetCurrentReference( m_pParent->Reference() ); } }; podofo-0.9.5/src/base/PdfEncoding.cpp0000664000175000017500000030457313035107073017263 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfEncoding.h" #include "PdfDictionary.h" #include "PdfLocale.h" #include "util/PdfMutexWrapper.h" #include "PdfDefinesPrivate.h" #include "base/PdfStream.h" #include "base/PdfContentsTokenizer.h" #include "doc/PdfFont.h" #include #include #include #include #include "PdfArray.h" #include "doc/PdfDifferenceEncoding.h" namespace PoDoFo { PdfEncoding::PdfEncoding( int nFirstChar, int nLastChar, PdfObject* pToUnicode ) : m_bToUnicodeIsLoaded(false), m_nFirstChar( nFirstChar ), m_nLastChar( nLastChar ), m_pToUnicode(pToUnicode) { if( !(m_nFirstChar < m_nLastChar) ) { PODOFO_RAISE_ERROR_INFO( ePdfError_ValueOutOfRange, "PdfEncoding: nFirstChar must be smaller than nLastChar" ); } ParseToUnicode(); } PdfEncoding::~PdfEncoding() { } PdfString PdfEncoding::ConvertToUnicode(const PdfString & rEncodedString, const PdfFont*) const { if(!m_toUnicode.empty()) { const pdf_utf16be* pStr = reinterpret_cast(rEncodedString.GetString()); const size_t lLen = rEncodedString.GetLength()/2; pdf_utf16be lCID, lUnicodeValue; pdf_utf16be* pszUtf16 = static_cast(podofo_calloc(lLen, sizeof(pdf_utf16be))); if( !pszUtf16 ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } for(size_t i = 0 ; i> 8 ); #else lCID = pStr[i]; #endif // PODOFO_IS_LITTLE_ENDIAN lUnicodeValue = this->GetUnicodeValue(lCID); #ifdef PODOFO_IS_LITTLE_ENDIAN pszUtf16[i] = (lUnicodeValue << 8) | (lUnicodeValue >> 8 ); #else pszUtf16[i] = lUnicodeValue; #endif // PODOFO_IS_LITTLE_ENDIAN } PdfString ret( pszUtf16, lLen ); podofo_free( pszUtf16 ); return ret; } else return(PdfString("\0")); } PdfRefCountedBuffer PdfEncoding::ConvertToEncoding( const PdfString & rString, const PdfFont* pFont ) const { if(!m_toUnicode.empty()) { // Get the string in UTF-16be format PdfString sStr = rString.ToUnicode(); const pdf_utf16be* pStr = sStr.GetUnicode(); pdf_utf16be lUnicodeValue, lCID; std::ostringstream out; PdfLocaleImbue(out); while( *pStr ) { #ifdef PODOFO_IS_LITTLE_ENDIAN lUnicodeValue = (*pStr << 8) | (*pStr >> 8); #else lUnicodeValue = *pStr; #endif // PODOFO_IS_LITTLE_ENDIAN lCID = this->GetCIDValue(lUnicodeValue); if (lCID == 0 && pFont) { #ifdef PODOFO_IS_LITTLE_ENDIAN lCID = static_cast(pFont->GetFontMetrics()->GetGlyphId( (((*pStr & 0xff) << 8) | ((*pStr & 0xff00) >> 8)) )); #else lCID = static_cast(pFont->GetFontMetrics()->GetGlyphId( *pStr )); #endif // PODOFO_IS_LITTLE_ENDIAN } out << static_cast((lCID & 0xff00) >> 8); out << static_cast(lCID & 0x00ff); ++pStr; } PdfRefCountedBuffer buffer( out.str().length() ); memcpy( buffer.GetBuffer(), out.str().c_str(), out.str().length() ); return buffer; } else return PdfRefCountedBuffer(); } void PdfEncoding::ParseToUnicode() { if (m_pToUnicode && m_pToUnicode->HasStream()) { std::stack stkToken; pdf_uint16 loop = 0; char *streamBuffer; const char *streamToken = NULL; EPdfTokenType *streamTokenType = NULL; pdf_long streamBufferLen; bool in_beginbfrange = 0; bool in_beginbfchar = 0; pdf_uint16 range_entries = 0; pdf_uint16 char_entries = 0; pdf_uint16 inside_hex_string = 0; pdf_uint16 inside_array = 0; pdf_uint16 range_start = 0; pdf_uint16 range_end = 0; pdf_uint16 i = 0; pdf_utf16be firstvalue = 0; const PdfStream *CIDStreamdata = m_pToUnicode->GetStream (); CIDStreamdata->GetFilteredCopy (&streamBuffer, &streamBufferLen); PdfContentsTokenizer streamTokenizer (streamBuffer, streamBufferLen); while (streamTokenizer.GetNextToken (streamToken, streamTokenType)) { stkToken.push (streamToken); if (strcmp (streamToken, ">") == 0) { if (inside_hex_string == 0) PODOFO_RAISE_ERROR_INFO(ePdfError_InvalidStream, "CMap Error, got > before <") else inside_hex_string = 0; if (inside_array == 0) { i++; } } if (strcmp (streamToken, "]") == 0) { if (inside_array == 0) PODOFO_RAISE_ERROR_INFO(ePdfError_InvalidStream, "CMap Error, got ] before [") else inside_array = 0; i++; loop++; } if (in_beginbfrange == 1) { if (loop < range_entries) { if (inside_hex_string == 1) { pdf_utf16be num_value; std::stringstream ss; ss << std::hex << streamToken; ss >> num_value; if (i % 3 == 0) range_start = num_value; if (i % 3 == 1) { range_end = num_value; } if (i % 3 == 2) { if (inside_array == 0) { for (int k = range_start; k <= range_end; k++) { m_toUnicode[k] = num_value; num_value++; } loop++; } else { m_toUnicode[range_start] = num_value; } range_start++; } } } } if (in_beginbfchar == 1) { if (loop < char_entries) { if (inside_hex_string == 1) { pdf_utf16be num_value; std::stringstream ss; ss << std::hex << streamToken; ss >> num_value; if (i % 2 == 0) { firstvalue = num_value; } if (i % 2 == 1) { m_toUnicode[firstvalue] = num_value; } } } } if (strcmp (streamToken, "<") == 0) { inside_hex_string = 1; } if (strcmp (streamToken, "[") == 0) { inside_array = 1; } if (strcmp (streamToken, "beginbfrange") == 0) { i = loop = 0; in_beginbfrange = 1; stkToken.pop (); std::stringstream ss; ss << std::hex << stkToken.top (); ss >> range_entries; } if (strcmp (streamToken, "endbfrange") == 0) { in_beginbfrange = 0; i = 0; } if (strcmp (streamToken, "beginbfchar") == 0) { i = loop = 0; in_beginbfchar = 1; stkToken.pop (); std::stringstream ss; ss << std::hex << stkToken.top (); ss >> char_entries; } if (strcmp (streamToken, "endbfchar") == 0) { in_beginbfchar = 0; i = 0; } } podofo_free(streamBuffer); m_bToUnicodeIsLoaded = true; } } pdf_utf16be PdfEncoding::GetUnicodeValue( pdf_utf16be value ) const { if(!m_toUnicode.empty()) { const std::map::const_iterator found = m_toUnicode.find(value); return (found == m_toUnicode.end() ? 0 : found->second); } return 0; } pdf_utf16be PdfEncoding::GetCIDValue( pdf_utf16be lUnicodeValue ) const { if(!m_toUnicode.empty()) { // TODO: optimize for(std::map::const_iterator it = m_toUnicode.begin(); it != m_toUnicode.end(); ++it) if(it->second == lUnicodeValue) return it->first; } return 0; } // ----------------------------------------------------- // PdfSimpleEncoding // ----------------------------------------------------- PdfSimpleEncoding::PdfSimpleEncoding( const PdfName & rName ) : PdfEncoding( 0, 255 ), m_mutex( new PoDoFo::Util::PdfMutex() ), m_name( rName ), m_pEncodingTable( NULL ) { } PdfSimpleEncoding::~PdfSimpleEncoding() { podofo_free( m_pEncodingTable ); delete m_mutex; } void PdfSimpleEncoding::InitEncodingTable() { Util::PdfMutexWrapper wrapper( *m_mutex ); const long lTableLength = 0xffff; const pdf_utf16be* cpUnicodeTable = this->GetToUnicodeTable(); if( !m_pEncodingTable ) // double check { m_pEncodingTable = static_cast(podofo_calloc(lTableLength, sizeof(char))); if (!m_pEncodingTable) { PODOFO_RAISE_ERROR(ePdfError_OutOfMemory); } // fill the table with data for( size_t i=0; i<256; i++ ) { m_pEncodingTable[ static_cast(cpUnicodeTable[i]) ] = static_cast(i); } } } void PdfSimpleEncoding::AddToDictionary( PdfDictionary & rDictionary ) const { rDictionary.AddKey( PdfName("Encoding"), m_name ); } pdf_utf16be PdfSimpleEncoding::GetCharCode( int nIndex ) const { if( nIndex < this->GetFirstChar() || nIndex > this->GetLastChar() ) { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } const pdf_utf16be* cpUnicodeTable = this->GetToUnicodeTable(); #ifdef PODOFO_IS_LITTLE_ENDIAN return ((cpUnicodeTable[nIndex] & 0xff00) >> 8) | ((cpUnicodeTable[nIndex] & 0xff) << 8); #else return cpUnicodeTable[nIndex]; #endif // PODOFO_IS_LITTLE_ENDIAN } PdfString PdfSimpleEncoding::ConvertToUnicode( const PdfString & rEncodedString, const PdfFont* pFont) const { if(m_bToUnicodeIsLoaded) { return PdfEncoding::ConvertToUnicode(rEncodedString, pFont); } else { const pdf_utf16be* cpUnicodeTable = this->GetToUnicodeTable(); pdf_long lLen = rEncodedString.GetLength(); if( lLen <= 0 ) return PdfString(L""); pdf_utf16be* pszStringUtf16 = static_cast(podofo_calloc( (lLen + 1), sizeof(pdf_utf16be))); if( !pszStringUtf16 ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } const char* pszString = rEncodedString.GetString(); for( int i=0;i(*pszString) ]; #else pszStringUtf16[i] = ((( cpUnicodeTable[ static_cast(*pszString) ] << 8 ) & 0xff00) | (( cpUnicodeTable[ static_cast(*pszString) ] >> 8 ) & 0x00ff)); #endif // PODOFO_IS_BIG_ENDIAN ++pszString; } pszStringUtf16[lLen] = 0; PdfString sStr( pszStringUtf16 ); podofo_free( pszStringUtf16 ); return sStr; } } PdfRefCountedBuffer PdfSimpleEncoding::ConvertToEncoding( const PdfString & rString, const PdfFont* pFont) const { if(m_bToUnicodeIsLoaded) { return PdfEncoding::ConvertToEncoding(rString, pFont); } else { if( !m_pEncodingTable ) const_cast(this)->InitEncodingTable(); PdfString sSrc = rString.ToUnicode(); // make sure the string is unicode and not PdfDocEncoding! pdf_long lLen = sSrc.GetCharacterLength(); if( !lLen ) return PdfRefCountedBuffer(); char* pDest = static_cast(podofo_calloc( (lLen + 1), sizeof(char) )); if( !pDest ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } const pdf_utf16be* pszUtf16 = sSrc.GetUnicode(); char* pCur = pDest; long lNewLen = 0L; for( int i=0;i> 8) | ((val & 0xff) << 8); #endif // PODOFO_IS_LITTLE_ENDIAN *pCur = m_pEncodingTable[val]; if( *pCur ) // ignore 0 characters, as they cannot be converted to the current encoding { ++pCur; ++lNewLen; } } *pCur = '\0'; PdfRefCountedBuffer cDest( lNewLen ); memcpy( cDest.GetBuffer(), pDest, lNewLen ); podofo_free( pDest ); return cDest; } } char PdfSimpleEncoding::GetUnicodeCharCode(pdf_utf16be unicodeValue) const { if( !m_pEncodingTable ) const_cast(this)->InitEncodingTable(); #ifdef PODOFO_IS_LITTLE_ENDIAN unicodeValue = ((unicodeValue & 0xff00) >> 8) | ((unicodeValue & 0xff) << 8); #endif // PODOFO_IS_LITTLE_ENDIAN return m_pEncodingTable[unicodeValue]; } // ----------------------------------------------------- // PdfDocEncoding // ----------------------------------------------------- // ----------------------------------------------------- // // ----------------------------------------------------- const pdf_utf16be* PdfDocEncoding::GetToUnicodeTable() const { return PdfDocEncoding::s_cEncoding; } const pdf_utf16be PdfDocEncoding::s_cEncoding[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0017, 0x0017, 0x02D8, 0x02C7, // dec 25 0x02C6, 0x02D9, 0x02DD, 0x02DB, 0x02DA, 0x02DC, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, // dec 57 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, // 89 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, //121 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x0000, // Undefined 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x0192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C, 0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, // dec147 0xFB02, 0x0141, 0x0152, 0x0160, 0x0178, 0x017D, 0x0131, 0x0142, 0x0153, 0x0161, 0x017E, 0x0000, // Undefined 0x20AC, // Euro 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x0000, // Undefined 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF }; // ----------------------------------------------------- // PdfWinAnsiEncoding // See: http://www.microsoft.com/globaldev/reference/sbcs/1252.mspx // ----------------------------------------------------- // ----------------------------------------------------- // // ----------------------------------------------------- void PdfWinAnsiEncoding::AddToDictionary( PdfDictionary & rDictionary ) const { PdfArray arDifferences; for (int i = 0; i < 256; i++) { if (PdfWinAnsiEncoding::GetToUnicodeTable()[i] != this->GetToUnicodeTable()[i]) { arDifferences.push_back(PdfObject((pdf_int64)i)); unsigned short shCode = this->GetToUnicodeTable()[i]; #ifdef PODOFO_IS_LITTLE_ENDIAN shCode = ((shCode & 0x00FF) << 8) | ((shCode & 0xFF00) >> 8); #endif arDifferences.push_back( PdfDifferenceEncoding::UnicodeIDToName(shCode) ); } } if (!arDifferences.empty()) { PdfDictionary dictEncoding; dictEncoding.AddKey(PdfName("BaseEncoding"), PdfWinAnsiEncoding::GetName()); dictEncoding.AddKey(PdfName("Differences"), arDifferences); rDictionary.AddKey(PdfName("Encoding"), dictEncoding); } else { PdfSimpleEncoding::AddToDictionary(rDictionary); } } const pdf_utf16be* PdfWinAnsiEncoding::GetToUnicodeTable() const { return PdfWinAnsiEncoding::s_cEncoding; } const pdf_utf16be PdfWinAnsiEncoding::s_cEncoding[256] = { 0x0000, // NULL 0x0001, // START OF HEADING 0x0002, // START OF TEXT 0x0003, // END OF TEXT 0x0004, // END OF TRANSMISSION 0x0005, // ENQUIRY 0x0006, // ACKNOWLEDGE 0x0007, // BELL 0x0008, // BACKSPACE 0x0009, // HORIZONTAL TABULATION 0x000A, // LINE FEED 0x000B, // VERTICAL TABULATION 0x000C, // FORM FEED 0x000D, // CARRIAGE RETURN 0x000E, // SHIFT OUT 0x000F, // SHIFT IN 0x0010, // DATA LINK ESCAPE 0x0011, // DEVICE CONTROL ONE 0x0012, // DEVICE CONTROL TWO 0x0013, // DEVICE CONTROL THREE 0x0014, // DEVICE CONTROL FOUR 0x0015, // NEGATIVE ACKNOWLEDGE 0x0016, // SYNCHRONOUS IDLE 0x0017, // END OF TRANSMISSION BLOCK 0x0018, // CANCEL 0x0019, // END OF MEDIUM 0x001A, // SUBSTITUTE 0x001B, // ESCAPE 0x001C, // FILE SEPARATOR 0x001D, // GROUP SEPARATOR 0x001E, // RECORD SEPARATOR 0x001F, // UNIT SEPARATOR 0x0020, // SPACE 0x0021, // EXCLAMATION MARK 0x0022, // QUOTATION MARK 0x0023, // NUMBER SIGN 0x0024, // DOLLAR SIGN 0x0025, // PERCENT SIGN 0x0026, // AMPERSAND 0x0027, // APOSTROPHE 0x0028, // LEFT PARENTHESIS 0x0029, // RIGHT PARENTHESIS 0x002A, // ASTERISK 0x002B, // PLUS SIGN 0x002C, // COMMA 0x002D, // HYPHEN-MINUS 0x002E, // FULL STOP 0x002F, // SOLIDUS 0x0030, // DIGIT ZERO 0x0031, // DIGIT ONE 0x0032, // DIGIT TWO 0x0033, // DIGIT THREE 0x0034, // DIGIT FOUR 0x0035, // DIGIT FIVE 0x0036, // DIGIT SIX 0x0037, // DIGIT SEVEN 0x0038, // DIGIT EIGHT 0x0039, // DIGIT NINE 0x003A, // COLON 0x003B, // SEMICOLON 0x003C, // LESS-THAN SIGN 0x003D, // EQUALS SIGN 0x003E, // GREATER-THAN SIGN 0x003F, // QUESTION MARK 0x0040, // COMMERCIAL AT 0x0041, // LATIN CAPITAL LETTER A 0x0042, // LATIN CAPITAL LETTER B 0x0043, // LATIN CAPITAL LETTER C 0x0044, // LATIN CAPITAL LETTER D 0x0045, // LATIN CAPITAL LETTER E 0x0046, // LATIN CAPITAL LETTER F 0x0047, // LATIN CAPITAL LETTER G 0x0048, // LATIN CAPITAL LETTER H 0x0049, // LATIN CAPITAL LETTER I 0x004A, // LATIN CAPITAL LETTER J 0x004B, // LATIN CAPITAL LETTER K 0x004C, // LATIN CAPITAL LETTER L 0x004D, // LATIN CAPITAL LETTER M 0x004E, // LATIN CAPITAL LETTER N 0x004F, // LATIN CAPITAL LETTER O 0x0050, // LATIN CAPITAL LETTER P 0x0051, // LATIN CAPITAL LETTER Q 0x0052, // LATIN CAPITAL LETTER R 0x0053, // LATIN CAPITAL LETTER S 0x0054, // LATIN CAPITAL LETTER T 0x0055, // LATIN CAPITAL LETTER U 0x0056, // LATIN CAPITAL LETTER V 0x0057, // LATIN CAPITAL LETTER W 0x0058, // LATIN CAPITAL LETTER X 0x0059, // LATIN CAPITAL LETTER Y 0x005A, // LATIN CAPITAL LETTER Z 0x005B, // LEFT SQUARE BRACKET 0x005C, // REVERSE SOLIDUS 0x005D, // RIGHT SQUARE BRACKET 0x005E, // CIRCUMFLEX ACCENT 0x005F, // LOW LINE 0x0060, // GRAVE ACCENT 0x0061, // LATIN SMALL LETTER A 0x0062, // LATIN SMALL LETTER B 0x0063, // LATIN SMALL LETTER C 0x0064, // LATIN SMALL LETTER D 0x0065, // LATIN SMALL LETTER E 0x0066, // LATIN SMALL LETTER F 0x0067, // LATIN SMALL LETTER G 0x0068, // LATIN SMALL LETTER H 0x0069, // LATIN SMALL LETTER I 0x006A, // LATIN SMALL LETTER J 0x006B, // LATIN SMALL LETTER K 0x006C, // LATIN SMALL LETTER L 0x006D, // LATIN SMALL LETTER M 0x006E, // LATIN SMALL LETTER N 0x006F, // LATIN SMALL LETTER O 0x0070, // LATIN SMALL LETTER P 0x0071, // LATIN SMALL LETTER Q 0x0072, // LATIN SMALL LETTER R 0x0073, // LATIN SMALL LETTER S 0x0074, // LATIN SMALL LETTER T 0x0075, // LATIN SMALL LETTER U 0x0076, // LATIN SMALL LETTER V 0x0077, // LATIN SMALL LETTER W 0x0078, // LATIN SMALL LETTER X 0x0079, // LATIN SMALL LETTER Y 0x007A, // LATIN SMALL LETTER Z 0x007B, // LEFT CURLY BRACKET 0x007C, // VERTICAL LINE 0x007D, // RIGHT CURLY BRACKET 0x007E, // TILDE 0x007F, // DELETE 0x20AC, // EURO SIGN 0x0000, 0x201A, // SINGLE LOW-9 QUOTATION MARK 0x0192, // LATIN SMALL LETTER F WITH HOOK 0x201E, // DOUBLE LOW-9 QUOTATION MARK 0x2026, // HORIZONTAL ELLIPSIS 0x2020, // DAGGER 0x2021, // DOUBLE DAGGER 0x02C6, // MODIFIER LETTER CIRCUMFLEX ACCENT 0x2030, // PER MILLE SIGN 0x0160, // LATIN CAPITAL LETTER S WITH CARON 0x2039, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK 0x0152, // LATIN CAPITAL LIGATURE OE 0x0000, 0x017D, // LATIN CAPITAL LETTER Z WITH CARON 0x0000, 0x0000, 0x2018, // LEFT SINGLE QUOTATION MARK 0x2019, // RIGHT SINGLE QUOTATION MARK 0x201C, // LEFT DOUBLE QUOTATION MARK 0x201D, // RIGHT DOUBLE QUOTATION MARK 0x2022, // BULLET 0x2013, // EN DASH 0x2014, // EM DASH 0x02DC, // SMALL TILDE 0x2122, // TRADE MARK SIGN 0x0161, // LATIN SMALL LETTER S WITH CARON 0x203A, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK 0x0153, // LATIN SMALL LIGATURE OE 0x0000, 0x017E, // LATIN SMALL LETTER Z WITH CARON 0x0178, // LATIN CAPITAL LETTER Y WITH DIAERESIS 0x00A0, // NO-BREAK SPACE 0x00A1, // INVERTED EXCLAMATION MARK 0x00A2, // CENT SIGN 0x00A3, // POUND SIGN 0x00A4, // CURRENCY SIGN 0x00A5, // YEN SIGN 0x00A6, // BROKEN BAR 0x00A7, // SECTION SIGN 0x00A8, // DIAERESIS 0x00A9, // COPYRIGHT SIGN 0x00AA, // FEMININE ORDINAL INDICATOR 0x00AB, // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK 0x00AC, // NOT SIGN 0x00AD, // SOFT HYPHEN 0x00AE, // REGISTERED SIGN 0x00AF, // MACRON 0x00B0, // DEGREE SIGN 0x00B1, // PLUS-MINUS SIGN 0x00B2, // SUPERSCRIPT TWO 0x00B3, // SUPERSCRIPT THREE 0x00B4, // ACUTE ACCENT 0x00B5, // MICRO SIGN 0x00B6, // PILCROW SIGN 0x00B7, // MIDDLE DOT 0x00B8, // CEDILLA 0x00B9, // SUPERSCRIPT ONE 0x00BA, // MASCULINE ORDINAL INDICATOR 0x00BB, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK 0x00BC, // VULGAR FRACTION ONE QUARTER 0x00BD, // VULGAR FRACTION ONE HALF 0x00BE, // VULGAR FRACTION THREE QUARTERS 0x00BF, // INVERTED QUESTION MARK 0x00C0, // LATIN CAPITAL LETTER A WITH GRAVE 0x00C1, // LATIN CAPITAL LETTER A WITH ACUTE 0x00C2, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX 0x00C3, // LATIN CAPITAL LETTER A WITH TILDE 0x00C4, // LATIN CAPITAL LETTER A WITH DIAERESIS 0x00C5, // LATIN CAPITAL LETTER A WITH RING ABOVE 0x00C6, // LATIN CAPITAL LETTER AE 0x00C7, // LATIN CAPITAL LETTER C WITH CEDILLA 0x00C8, // LATIN CAPITAL LETTER E WITH GRAVE 0x00C9, // LATIN CAPITAL LETTER E WITH ACUTE 0x00CA, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX 0x00CB, // LATIN CAPITAL LETTER E WITH DIAERESIS 0x00CC, // LATIN CAPITAL LETTER I WITH GRAVE 0x00CD, // LATIN CAPITAL LETTER I WITH ACUTE 0x00CE, // LATIN CAPITAL LETTER I WITH CIRCUMFLEX 0x00CF, // LATIN CAPITAL LETTER I WITH DIAERESIS 0x00D0, // LATIN CAPITAL LETTER ETH 0x00D1, // LATIN CAPITAL LETTER N WITH TILDE 0x00D2, // LATIN CAPITAL LETTER O WITH GRAVE 0x00D3, // LATIN CAPITAL LETTER O WITH ACUTE 0x00D4, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX 0x00D5, // LATIN CAPITAL LETTER O WITH TILDE 0x00D6, // LATIN CAPITAL LETTER O WITH DIAERESIS 0x00D7, // MULTIPLICATION SIGN 0x00D8, // LATIN CAPITAL LETTER O WITH STROKE 0x00D9, // LATIN CAPITAL LETTER U WITH GRAVE 0x00DA, // LATIN CAPITAL LETTER U WITH ACUTE 0x00DB, // LATIN CAPITAL LETTER U WITH CIRCUMFLEX 0x00DC, // LATIN CAPITAL LETTER U WITH DIAERESIS 0x00DD, // LATIN CAPITAL LETTER Y WITH ACUTE 0x00DE, // LATIN CAPITAL LETTER THORN 0x00DF, // LATIN SMALL LETTER SHARP S 0x00E0, // LATIN SMALL LETTER A WITH GRAVE 0x00E1, // LATIN SMALL LETTER A WITH ACUTE 0x00E2, // LATIN SMALL LETTER A WITH CIRCUMFLEX 0x00E3, // LATIN SMALL LETTER A WITH TILDE 0x00E4, // LATIN SMALL LETTER A WITH DIAERESIS 0x00E5, // LATIN SMALL LETTER A WITH RING ABOVE 0x00E6, // LATIN SMALL LETTER AE 0x00E7, // LATIN SMALL LETTER C WITH CEDILLA 0x00E8, // LATIN SMALL LETTER E WITH GRAVE 0x00E9, // LATIN SMALL LETTER E WITH ACUTE 0x00EA, // LATIN SMALL LETTER E WITH CIRCUMFLEX 0x00EB, // LATIN SMALL LETTER E WITH DIAERESIS 0x00EC, // LATIN SMALL LETTER I WITH GRAVE 0x00ED, // LATIN SMALL LETTER I WITH ACUTE 0x00EE, // LATIN SMALL LETTER I WITH CIRCUMFLEX 0x00EF, // LATIN SMALL LETTER I WITH DIAERESIS 0x00F0, // LATIN SMALL LETTER ETH 0x00F1, // LATIN SMALL LETTER N WITH TILDE 0x00F2, // LATIN SMALL LETTER O WITH GRAVE 0x00F3, // LATIN SMALL LETTER O WITH ACUTE 0x00F4, // LATIN SMALL LETTER O WITH CIRCUMFLEX 0x00F5, // LATIN SMALL LETTER O WITH TILDE 0x00F6, // LATIN SMALL LETTER O WITH DIAERESIS 0x00F7, // DIVISION SIGN 0x00F8, // LATIN SMALL LETTER O WITH STROKE 0x00F9, // LATIN SMALL LETTER U WITH GRAVE 0x00FA, // LATIN SMALL LETTER U WITH ACUTE 0x00FB, // LATIN SMALL LETTER U WITH CIRCUMFLEX 0x00FC, // LATIN SMALL LETTER U WITH DIAERESIS 0x00FD, // LATIN SMALL LETTER Y WITH ACUTE 0x00FE, // LATIN SMALL LETTER THORN 0x00FF, // LATIN SMALL LETTER Y WITH DIAERESIS }; // ----------------------------------------------------- // PdfMacRomanEncoding // ----------------------------------------------------- // ----------------------------------------------------- // // ----------------------------------------------------- const pdf_utf16be* PdfMacRomanEncoding::GetToUnicodeTable() const { return PdfMacRomanEncoding::s_cEncoding; } const pdf_utf16be PdfMacRomanEncoding::s_cEncoding[256] = { 0x0000, // NULL 0x0001, // START OF HEADING 0x0002, // START OF TEXT 0x0003, // END OF TEXT 0x0004, // END OF TRANSMISSION 0x0005, // ENQUIRY 0x0006, // ACKNOWLEDGE 0x0007, // BELL 0x0008, // BACKSPACE 0x0009, // HORIZONTAL TABULATION 0x000A, // LINE FEED 0x000B, // VERTICAL TABULATION 0x000C, // FORM FEED 0x000D, // CARRIAGE RETURN 0x000E, // SHIFT OUT 0x000F, // SHIFT IN 0x0010, // DATA LINK ESCAPE 0x0011, // DEVICE CONTROL ONE 0x0012, // DEVICE CONTROL TWO 0x0013, // DEVICE CONTROL THREE 0x0014, // DEVICE CONTROL FOUR 0x0015, // NEGATIVE ACKNOWLEDGE 0x0016, // SYNCHRONOUS IDLE 0x0017, // END OF TRANSMISSION BLOCK 0x0018, // CANCEL 0x0019, // END OF MEDIUM 0x001A, // SUBSTITUTE 0x001B, // ESCAPE 0x001C, // FILE SEPARATOR 0x001D, // GROUP SEPARATOR 0x001E, // RECORD SEPARATOR 0x001F, // UNIT SEPARATOR 0x0020, // SPACE 0x0021, // EXCLAMATION MARK 0x0022, // QUOTATION MARK 0x0023, // NUMBER SIGN 0x0024, // DOLLAR SIGN 0x0025, // PERCENT SIGN 0x0026, // AMPERSAND 0x0027, // APOSTROPHE 0x0028, // LEFT PARENTHESIS 0x0029, // RIGHT PARENTHESIS 0x002A, // ASTERISK 0x002B, // PLUS SIGN 0x002C, // COMMA 0x002D, // HYPHEN-MINUS 0x002E, // FULL STOP 0x002F, // SOLIDUS 0x0030, // DIGIT ZERO 0x0031, // DIGIT ONE 0x0032, // DIGIT TWO 0x0033, // DIGIT THREE 0x0034, // DIGIT FOUR 0x0035, // DIGIT FIVE 0x0036, // DIGIT SIX 0x0037, // DIGIT SEVEN 0x0038, // DIGIT EIGHT 0x0039, // DIGIT NINE 0x003A, // COLON 0x003B, // SEMICOLON 0x003C, // LESS-THAN SIGN 0x003D, // EQUALS SIGN 0x003E, // GREATER-THAN SIGN 0x003F, // QUESTION MARK 0x0040, // COMMERCIAL AT 0x0041, // LATIN CAPITAL LETTER A 0x0042, // LATIN CAPITAL LETTER B 0x0043, // LATIN CAPITAL LETTER C 0x0044, // LATIN CAPITAL LETTER D 0x0045, // LATIN CAPITAL LETTER E 0x0046, // LATIN CAPITAL LETTER F 0x0047, // LATIN CAPITAL LETTER G 0x0048, // LATIN CAPITAL LETTER H 0x0049, // LATIN CAPITAL LETTER I 0x004A, // LATIN CAPITAL LETTER J 0x004B, // LATIN CAPITAL LETTER K 0x004C, // LATIN CAPITAL LETTER L 0x004D, // LATIN CAPITAL LETTER M 0x004E, // LATIN CAPITAL LETTER N 0x004F, // LATIN CAPITAL LETTER O 0x0050, // LATIN CAPITAL LETTER P 0x0051, // LATIN CAPITAL LETTER Q 0x0052, // LATIN CAPITAL LETTER R 0x0053, // LATIN CAPITAL LETTER S 0x0054, // LATIN CAPITAL LETTER T 0x0055, // LATIN CAPITAL LETTER U 0x0056, // LATIN CAPITAL LETTER V 0x0057, // LATIN CAPITAL LETTER W 0x0058, // LATIN CAPITAL LETTER X 0x0059, // LATIN CAPITAL LETTER Y 0x005A, // LATIN CAPITAL LETTER Z 0x005B, // LEFT SQUARE BRACKET 0x005C, // REVERSE SOLIDUS 0x005D, // RIGHT SQUARE BRACKET 0x005E, // CIRCUMFLEX ACCENT 0x005F, // LOW LINE 0x0060, // GRAVE ACCENT 0x0061, // LATIN SMALL LETTER A 0x0062, // LATIN SMALL LETTER B 0x0063, // LATIN SMALL LETTER C 0x0064, // LATIN SMALL LETTER D 0x0065, // LATIN SMALL LETTER E 0x0066, // LATIN SMALL LETTER F 0x0067, // LATIN SMALL LETTER G 0x0068, // LATIN SMALL LETTER H 0x0069, // LATIN SMALL LETTER I 0x006A, // LATIN SMALL LETTER J 0x006B, // LATIN SMALL LETTER K 0x006C, // LATIN SMALL LETTER L 0x006D, // LATIN SMALL LETTER M 0x006E, // LATIN SMALL LETTER N 0x006F, // LATIN SMALL LETTER O 0x0070, // LATIN SMALL LETTER P 0x0071, // LATIN SMALL LETTER Q 0x0072, // LATIN SMALL LETTER R 0x0073, // LATIN SMALL LETTER S 0x0074, // LATIN SMALL LETTER T 0x0075, // LATIN SMALL LETTER U 0x0076, // LATIN SMALL LETTER V 0x0077, // LATIN SMALL LETTER W 0x0078, // LATIN SMALL LETTER X 0x0079, // LATIN SMALL LETTER Y 0x007A, // LATIN SMALL LETTER Z 0x007B, // LEFT CURLY BRACKET 0x007C, // VERTICAL LINE 0x007D, // RIGHT CURLY BRACKET 0x007E, // TILDE 0x007F, // DEL 0x00C4, // LATIN CAPITAL LETTER A WITH DIAERESIS 0x00C5, // LATIN CAPITAL LETTER A WITH RING ABOVE 0x00C7, // LATIN CAPITAL LETTER C WITH CEDILLA 0x00C9, // LATIN CAPITAL LETTER E WITH ACUTE 0x00D1, // LATIN CAPITAL LETTER N WITH TILDE 0x00D6, // LATIN CAPITAL LETTER O WITH DIAERESIS 0x00DC, // LATIN CAPITAL LETTER U WITH DIAERESIS 0x00E1, // LATIN SMALL LETTER A WITH ACUTE 0x00E0, // LATIN SMALL LETTER A WITH GRAVE 0x00E2, // LATIN SMALL LETTER A WITH CIRCUMFLEX 0x00E4, // LATIN SMALL LETTER A WITH DIAERESIS 0x00E3, // LATIN SMALL LETTER A WITH TILDE 0x00E5, // LATIN SMALL LETTER A WITH RING ABOVE 0x00E7, // LATIN SMALL LETTER C WITH CEDILLA 0x00E9, // LATIN SMALL LETTER E WITH ACUTE 0x00E8, // LATIN SMALL LETTER E WITH GRAVE 0x00EA, // LATIN SMALL LETTER E WITH CIRCUMFLEX 0x00EB, // LATIN SMALL LETTER E WITH DIAERESIS 0x00ED, // LATIN SMALL LETTER I WITH ACUTE 0x00EC, // LATIN SMALL LETTER I WITH GRAVE 0x00EE, // LATIN SMALL LETTER I WITH CIRCUMFLEX 0x00EF, // LATIN SMALL LETTER I WITH DIAERESIS 0x00F1, // LATIN SMALL LETTER N WITH TILDE 0x00F3, // LATIN SMALL LETTER O WITH ACUTE 0x00F2, // LATIN SMALL LETTER O WITH GRAVE 0x00F4, // LATIN SMALL LETTER O WITH CIRCUMFLEX 0x00F6, // LATIN SMALL LETTER O WITH DIAERESIS 0x00F5, // LATIN SMALL LETTER O WITH TILDE 0x00FA, // LATIN SMALL LETTER U WITH ACUTE 0x00F9, // LATIN SMALL LETTER U WITH GRAVE 0x00FB, // LATIN SMALL LETTER U WITH CIRCUMFLEX 0x00FC, // LATIN SMALL LETTER U WITH DIAERESIS 0x2020, // DAGGER 0x00B0, // DEGREE SIGN 0x00A2, // CENT SIGN 0x00A3, // POUND SIGN 0x00A7, // SECTION SIGN 0x2022, // BULLET 0x00B6, // PILCROW SIGN 0x00DF, // LATIN SMALL LETTER SHARP S 0x00AE, // REGISTERED SIGN 0x00A9, // COPYRIGHT SIGN 0x2122, // TRADE MARK SIGN 0x00B4, // ACUTE ACCENT 0x00A8, // DIAERESIS 0x2260, // NOT EQUAL TO 0x00C6, // LATIN CAPITAL LETTER AE 0x00D8, // LATIN CAPITAL LETTER O WITH STROKE 0x221E, // INFINITY 0x00B1, // PLUS-MINUS SIGN 0x2264, // LESS-THAN OR EQUAL TO 0x2265, // GREATER-THAN OR EQUAL TO 0x00A5, // YEN SIGN 0x00B5, // MICRO SIGN 0x2202, // PARTIAL DIFFERENTIAL 0x2211, // N-ARY SUMMATION 0x220F, // N-ARY PRODUCT 0x03C0, // GREEK SMALL LETTER PI 0x222B, // INTEGRAL 0x00AA, // FEMININE ORDINAL INDICATOR 0x00BA, // MASCULINE ORDINAL INDICATOR 0x03A9, // GREEK CAPITAL LETTER OMEGA 0x00E6, // LATIN SMALL LETTER AE 0x00F8, // LATIN SMALL LETTER O WITH STROKE 0x00BF, // INVERTED QUESTION MARK 0x00A1, // INVERTED EXCLAMATION MARK 0x00AC, // NOT SIGN 0x221A, // SQUARE ROOT 0x0192, // LATIN SMALL LETTER F WITH HOOK 0x2248, // ALMOST EQUAL TO 0x2206, // INCREMENT 0x00AB, // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK 0x00BB, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK 0x2026, // HORIZONTAL ELLIPSIS 0x00A0, // NO-BREAK SPACE 0x00C0, // LATIN CAPITAL LETTER A WITH GRAVE 0x00C3, // LATIN CAPITAL LETTER A WITH TILDE 0x00D5, // LATIN CAPITAL LETTER O WITH TILDE 0x0152, // LATIN CAPITAL LIGATURE OE 0x0153, // LATIN SMALL LIGATURE OE 0x2013, // EN DASH 0x2014, // EM DASH 0x201C, // LEFT DOUBLE QUOTATION MARK 0x201D, // RIGHT DOUBLE QUOTATION MARK 0x2018, // LEFT SINGLE QUOTATION MARK 0x2019, // RIGHT SINGLE QUOTATION MARK 0x00F7, // DIVISION SIGN 0x25CA, // LOZENGE 0x00FF, // LATIN SMALL LETTER Y WITH DIAERESIS 0x0178, // LATIN CAPITAL LETTER Y WITH DIAERESIS 0x2044, // FRACTION SLASH 0x20AC, // EURO SIGN 0x2039, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK 0x203A, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK 0xFB01, // LATIN SMALL LIGATURE FI 0xFB02, // LATIN SMALL LIGATURE FL 0x2021, // DOUBLE DAGGER 0x00B7, // MIDDLE DOT 0x201A, // SINGLE LOW-9 QUOTATION MARK 0x201E, // DOUBLE LOW-9 QUOTATION MARK 0x2030, // PER MILLE SIGN 0x00C2, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX 0x00CA, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX 0x00C1, // LATIN CAPITAL LETTER A WITH ACUTE 0x00CB, // LATIN CAPITAL LETTER E WITH DIAERESIS 0x00C8, // LATIN CAPITAL LETTER E WITH GRAVE 0x00CD, // LATIN CAPITAL LETTER I WITH ACUTE 0x00CE, // LATIN CAPITAL LETTER I WITH CIRCUMFLEX 0x00CF, // LATIN CAPITAL LETTER I WITH DIAERESIS 0x00CC, // LATIN CAPITAL LETTER I WITH GRAVE 0x00D3, // LATIN CAPITAL LETTER O WITH ACUTE 0x00D4, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX 0xF8FF, // Apple logo 0x00D2, // LATIN CAPITAL LETTER O WITH GRAVE 0x00DA, // LATIN CAPITAL LETTER U WITH ACUTE 0x00DB, // LATIN CAPITAL LETTER U WITH CIRCUMFLEX 0x00D9, // LATIN CAPITAL LETTER U WITH GRAVE 0x0131, // LATIN SMALL LETTER DOTLESS I 0x02C6, // MODIFIER LETTER CIRCUMFLEX ACCENT 0x02DC, // SMALL TILDE 0x00AF, // MACRON 0x02D8, // BREVE 0x02D9, // DOT ABOVE 0x02DA, // RING ABOVE 0x00B8, // CEDILLA 0x02DD, // DOUBLE ACUTE ACCENT 0x02DB, // OGONEK 0x02C7, // CARON }; // OC 13.08.2010 New: PdfMacExpertEncoding // ----------------------------------------------------- // PdfMacExpertEncoding // See: ghostscript-8.71/Resource/Init/gs_mex_e.ps // --> array of 256 glyphs for MacExpertEncoding // See: http://www.adobe.com/devnet/opentype/archives/glyphlist.txt // --> glyphs to unicodes // ----------------------------------------------------- // ----------------------------------------------------- // // ----------------------------------------------------- const pdf_utf16be* PdfMacExpertEncoding::GetToUnicodeTable() const { return PdfMacExpertEncoding::s_cEncoding; } const pdf_utf16be PdfMacExpertEncoding::s_cEncoding[256] = { // \00x 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // \04x 0x0020, 0xF721, 0xF6F8, 0xF7A2, 0xF724, 0xF6E4, 0xF726, 0xF7B4, 0x207D, 0x207E, 0x2025, 0x2024, 0x002C, 0x002D, 0x002E, 0x2044, 0xF730, 0xF731, 0xF732, 0xF733, 0xF734, 0xF735, 0xF736, 0xF737, 0xF738, 0xF739, 0x003A, 0x003B, 0x0000, 0xF6DE, 0x0000, 0xF73F, // \10x 0x0000, 0x0000, 0x0000, 0x0000, 0xF7F0, 0x0000, 0x0000, 0x00BC, 0x00BD, 0x00BE, 0x215B, 0x215C, 0x215D, 0x215E, 0x2153, 0x2154, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFB00, 0xFB01, 0xFB02, 0xFB03, 0xFB04, 0x208D, 0x0000, 0x208E, 0xF6F6, 0xF6E5, // \14x 0xF760, 0xF761, 0xF762, 0xF763, 0xF764, 0xF765, 0xF766, 0xF767, 0xF768, 0xF769, 0xF76A, 0xF76B, 0xF76C, 0xF76D, 0xF76E, 0xF76F, 0xF770, 0xF771, 0xF772, 0xF773, 0xF774, 0xF775, 0xF776, 0xF777, 0xF778, 0xF779, 0xF77A, 0x20A1, 0xF6DC, 0xF6DD, 0xF6FE, 0x0000, // \20x 0x0000, 0xF6E9, 0xF6E0, 0x0000, 0x0000, 0x0000, 0x0000, 0xF7E1, 0xF7E0, 0xF7E2, 0xF7E4, 0xF7E3, 0xF7E5, 0xF7E7, 0xF7E9, 0xF7E8, 0xF7EA, 0xF7EB, 0xF7ED, 0xF7EC, 0xF7EE, 0xF7EF, 0xF7F1, 0xF7F3, 0xF7F2, 0xF7F4, 0xF7F6, 0xF7F5, 0xF7FA, 0xF7F9, 0xF7FB, 0xF7FC, // \24x 0x0000, 0x2078, 0x2084, 0x2083, 0x2086, 0x2088, 0x2087, 0xF6FD, 0x0000, 0xF6DF, 0x2082, 0x0000, 0xF7A8, 0x0000, 0xF6F5, 0xF6F0, 0x2085, 0x0000, 0xF6E1, 0xF6E7, 0xF7FD, 0x0000, 0xF6E3, 0x0000, 0x0000, 0xF7FE, 0x0000, 0x2089, 0x2080, 0xF6FF, 0xF7E6, 0xF7F8, // \30x 0xF7BF, 0x2081, 0xF6F9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF7B8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF6FA, 0x2012, 0xF6E6, 0x0000, 0x0000, 0x0000, 0x0000, 0xF7A1, 0x0000, 0xF7FF, 0x0000, 0x00B9, 0x00B2, 0x00B3, 0x2074, 0x2075, 0x2076, // \34x 0x2077, 0x2079, 0x2070, 0x0000, 0xF6EC, 0xF6F1, 0xF6F3, 0x0000, 0x0000, 0xF6ED, 0xF6F2, 0xF6EB, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xF6EE, 0xF6FB, 0xF6F4, 0xF7AF, 0xF6EA, 0x207F, 0xF6EF, 0xF6E2, 0xF6E8, 0xF6F7, 0xF6FC, 0x0000, 0x0000, 0x0000, 0x0000 }; // OC 13.08.2010 New: PdfStandardEncoding // ----------------------------------------------------- // PdfStandardEncoding // See: http://unicode.org/Public/MAPPINGS/VENDORS/ADOBE/stdenc.txt // ----------------------------------------------------- // ----------------------------------------------------- // // ----------------------------------------------------- const pdf_utf16be* PdfStandardEncoding::GetToUnicodeTable() const { return PdfStandardEncoding::s_cEncoding; } const pdf_utf16be PdfStandardEncoding::s_cEncoding[256] = { //0, // uncomment to check compiler error cause of 257 members // 0x00..0x1f undefined: 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, // 20 # SPACE # space // Duplicated char, commented out // 0x00A0, // 20 # NO-BREAK SPACE # space 0x0021, // 21 # EXCLAMATION MARK # exclam 0x0022, // 22 # QUOTATION MARK # quotedbl 0x0023, // 23 # NUMBER SIGN # numbersign 0x0024, // 24 # DOLLAR SIGN # dollar 0x0025, // 25 # PERCENT SIGN # percent 0x0026, // 26 # AMPERSAND # ampersand 0x2019, // 27 # RIGHT SINGLE QUOTATION MARK # quoteright 0x0028, // 28 # LEFT PARENTHESIS # parenleft 0x0029, // 29 # RIGHT PARENTHESIS # parenright 0x002A, // 2A # ASTERISK # asterisk 0x002B, // 2B # PLUS SIGN # plus 0x002C, // 2C # COMMA # comma 0x002D, // 2D # HYPHEN-MINUS # hyphen // Duplicated char, commented out // 0x00AD, // 2D # SOFT HYPHEN # hyphen 0x002E, // 2E # FULL STOP # period 0x002F, // 2F # SOLIDUS # slash 0x0030, // 30 # DIGIT ZERO # zero 0x0031, // 31 # DIGIT ONE # one 0x0032, // 32 # DIGIT TWO # two 0x0033, // 33 # DIGIT THREE # three 0x0034, // 34 # DIGIT FOUR # four 0x0035, // 35 # DIGIT FIVE # five 0x0036, // 36 # DIGIT SIX # six 0x0037, // 37 # DIGIT SEVEN # seven 0x0038, // 38 # DIGIT EIGHT # eight 0x0039, // 39 # DIGIT NINE # nine 0x003A, // 3A # COLON # colon 0x003B, // 3B # SEMICOLON # semicolon 0x003C, // 3C # LESS-THAN SIGN # less 0x003D, // 3D # EQUALS SIGN # equal 0x003E, // 3E # GREATER-THAN SIGN # greater 0x003F, // 3F # QUESTION MARK # question 0x0040, // 40 # COMMERCIAL AT # at 0x0041, // 41 # LATIN CAPITAL LETTER A # A 0x0042, // 42 # LATIN CAPITAL LETTER B # B 0x0043, // 43 # LATIN CAPITAL LETTER C # C 0x0044, // 44 # LATIN CAPITAL LETTER D # D 0x0045, // 45 # LATIN CAPITAL LETTER E # E 0x0046, // 46 # LATIN CAPITAL LETTER F # F 0x0047, // 47 # LATIN CAPITAL LETTER G # G 0x0048, // 48 # LATIN CAPITAL LETTER H # H 0x0049, // 49 # LATIN CAPITAL LETTER I # I 0x004A, // 4A # LATIN CAPITAL LETTER J # J 0x004B, // 4B # LATIN CAPITAL LETTER K # K 0x004C, // 4C # LATIN CAPITAL LETTER L # L 0x004D, // 4D # LATIN CAPITAL LETTER M # M 0x004E, // 4E # LATIN CAPITAL LETTER N # N 0x004F, // 4F # LATIN CAPITAL LETTER O # O 0x0050, // 50 # LATIN CAPITAL LETTER P # P 0x0051, // 51 # LATIN CAPITAL LETTER Q # Q 0x0052, // 52 # LATIN CAPITAL LETTER R # R 0x0053, // 53 # LATIN CAPITAL LETTER S # S 0x0054, // 54 # LATIN CAPITAL LETTER T # T 0x0055, // 55 # LATIN CAPITAL LETTER U # U 0x0056, // 56 # LATIN CAPITAL LETTER V # V 0x0057, // 57 # LATIN CAPITAL LETTER W # W 0x0058, // 58 # LATIN CAPITAL LETTER X # X 0x0059, // 59 # LATIN CAPITAL LETTER Y # Y 0x005A, // 5A # LATIN CAPITAL LETTER Z # Z 0x005B, // 5B # LEFT SQUARE BRACKET # bracketleft 0x005C, // 5C # REVERSE SOLIDUS # backslash 0x005D, // 5D # RIGHT SQUARE BRACKET # bracketright 0x005E, // 5E # CIRCUMFLEX ACCENT # asciicircum 0x005F, // 5F # LOW LINE # underscore #if 1 0x0060, // 60 # GRAVE ACCENT #else // OC 13.08.2010: See http://unicode.org/Public/MAPPINGS/VENDORS/ADOBE/stdenc.txt // The following unicode char should be encoded here. // But i keep the identity ascii 7bit sign. 0x2018, // 60 # LEFT SINGLE QUOTATION MARK # quoteleft #endif 0x0061, // 61 # LATIN SMALL LETTER A # a 0x0062, // 62 # LATIN SMALL LETTER B # b 0x0063, // 63 # LATIN SMALL LETTER C # c 0x0064, // 64 # LATIN SMALL LETTER D # d 0x0065, // 65 # LATIN SMALL LETTER E # e 0x0066, // 66 # LATIN SMALL LETTER F # f 0x0067, // 67 # LATIN SMALL LETTER G # g 0x0068, // 68 # LATIN SMALL LETTER H # h 0x0069, // 69 # LATIN SMALL LETTER I # i 0x006A, // 6A # LATIN SMALL LETTER J # j 0x006B, // 6B # LATIN SMALL LETTER K # k 0x006C, // 6C # LATIN SMALL LETTER L # l 0x006D, // 6D # LATIN SMALL LETTER M # m 0x006E, // 6E # LATIN SMALL LETTER N # n 0x006F, // 6F # LATIN SMALL LETTER O # o 0x0070, // 70 # LATIN SMALL LETTER P # p 0x0071, // 71 # LATIN SMALL LETTER Q # q 0x0072, // 72 # LATIN SMALL LETTER R # r 0x0073, // 73 # LATIN SMALL LETTER S # s 0x0074, // 74 # LATIN SMALL LETTER T # t 0x0075, // 75 # LATIN SMALL LETTER U # u 0x0076, // 76 # LATIN SMALL LETTER V # v 0x0077, // 77 # LATIN SMALL LETTER W # w 0x0078, // 78 # LATIN SMALL LETTER X # x 0x0079, // 79 # LATIN SMALL LETTER Y # y 0x007A, // 7A # LATIN SMALL LETTER Z # z 0x007B, // 7B # LEFT CURLY BRACKET # braceleft 0x007C, // 7C # VERTICAL LINE # bar 0x007D, // 7D # RIGHT CURLY BRACKET # braceright 0x007E, // 7E # TILDE # asciitilde // 0x7f..0xA0 undefined: 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00A1, // A1 # INVERTED EXCLAMATION MARK # exclamdown 0x00A2, // A2 # CENT SIGN # cent 0x00A3, // A3 # POUND SIGN # sterling 0x2044, // A4 # FRACTION SLASH # fraction // Duplicated char, commented out // 0x2215, // A4 # DIVISION SLASH # fraction 0x00A5, // A5 # YEN SIGN # yen 0x0192, // A6 # LATIN SMALL LETTER F WITH HOOK # florin 0x00A7, // A7 # SECTION SIGN # section 0x00A4, // A8 # CURRENCY SIGN # currency 0x0027, // A9 # APOSTROPHE # quotesingle 0x201C, // AA # LEFT DOUBLE QUOTATION MARK # quotedblleft 0x00AB, // AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK # guillemotleft 0x2039, // AC # SINGLE LEFT-POINTING ANGLE QUOTATION MARK # guilsinglleft 0x203A, // AD # SINGLE RIGHT-POINTING ANGLE QUOTATION MARK # guilsinglright 0xFB01, // AE # LATIN SMALL LIGATURE FI # fi 0xFB02, // AF # LATIN SMALL LIGATURE FL # fl 0x0000, // B0 undefined 0x2013, // B1 # EN DASH # endash 0x2020, // B2 # DAGGER # dagger 0x2021, // B3 # DOUBLE DAGGER # daggerdbl 0x00B7, // B4 # MIDDLE DOT # periodcentered // 0x2219, // B4 # BULLET OPERATOR # periodcentered 0x0000, // B5 undefined 0x00B6, // B6 # PILCROW SIGN # paragraph 0x2022, // B7 # BULLET # bullet 0x201A, // B8 # SINGLE LOW-9 QUOTATION MARK # quotesinglbase 0x201E, // B9 # DOUBLE LOW-9 QUOTATION MARK # quotedblbase 0x201D, // BA # RIGHT DOUBLE QUOTATION MARK # quotedblright 0x00BB, // BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK # guillemotright 0x2026, // BC # HORIZONTAL ELLIPSIS # ellipsis 0x2030, // BD # PER MILLE SIGN # perthousand 0x0000, // BE undefined 0x00BF, // BF # INVERTED QUESTION MARK # questiondown 0x0000, // C0 undefined 0x0060, // C1 # GRAVE ACCENT # grave 0x00B4, // C2 # ACUTE ACCENT # acute 0x02C6, // C3 # MODIFIER LETTER CIRCUMFLEX ACCENT # circumflex 0x02DC, // C4 # SMALL TILDE # tilde 0x00AF, // C5 # MACRON # macron // Duplicated char, commented out //0x02C9, // C5 # MODIFIER LETTER MACRON # macron 0x02D8, // C6 # BREVE # breve 0x02D9, // C7 # DOT ABOVE # dotaccent 0x00A8, // C8 # DIAERESIS # dieresis 0x0000, // C9 undefined 0x02DA, // CA # RING ABOVE # ring 0x00B8, // CB # CEDILLA # cedilla 0x02DD, // CD # DOUBLE ACUTE ACCENT # hungarumlaut 0x02DB, // CE # OGONEK # ogonek 0x02C7, // CF # CARON # caron 0x2014, // D0 # EM DASH # emdash 0x0000, // D1 undefined 0x0000, // D2 undefined 0x0000, // D3 undefined 0x0000, // D4 undefined 0x0000, // D5 undefined 0x0000, // D6 undefined 0x0000, // D7 undefined 0x0000, // D8 undefined 0x0000, // D9 undefined 0x0000, // DA undefined 0x0000, // DB undefined 0x0000, // DC undefined 0x0000, // DD undefined 0x0000, // DE undefined 0x0000, // DF undefined 0x0000, // E0 undefined 0x00C6, // E1 # LATIN CAPITAL LETTER AE # AE 0x0000, // E2 undefined 0x00AA, // E3 # FEMININE ORDINAL INDICATOR # ordfeminine 0x0000, // E4 undefined 0x0000, // E5 undefined 0x0000, // E6 undefined 0x0000, // E7 undefined 0x0141, // E8 # LATIN CAPITAL LETTER L WITH STROKE # Lslash 0x00D8, // E9 # LATIN CAPITAL LETTER O WITH STROKE # Oslash 0x0152, // EA # LATIN CAPITAL LIGATURE OE # OE 0x00BA, // EB # MASCULINE ORDINAL INDICATOR # ordmasculine 0x0000, // EC undefined 0x0000, // ED undefined 0x0000, // EE undefined 0x0000, // EF undefined 0x0000, // F0 undefined 0x00E6, // F1 # LATIN SMALL LETTER AE # ae 0x0000, // F2 undefined 0x0000, // F3 undefined 0x0000, // F4 undefined 0x0131, // F5 # LATIN SMALL LETTER DOTLESS I # dotlessi 0x0000, // F6 undefined 0x0000, // F7 undefined 0x0142, // F8 # LATIN SMALL LETTER L WITH STROKE # lslash 0x00F8, // F9 # LATIN SMALL LETTER O WITH STROKE # oslash 0x0153, // FA # LATIN SMALL LIGATURE OE # oe 0x00DF, // FB # LATIN SMALL LETTER SHARP S # germandbls 0x0000, // FC undefined 0x0000, // FD undefined 0x0000, // FE undefined 0x0000 // FF undefined }; // OC 13.08.2010 New: PdfSymbolEncoding // ----------------------------------------------------- // PdfSymbolEncoding // See: http://unicode.org/Public/MAPPINGS/VENDORS/ADOBE/symbol.txt // ----------------------------------------------------- // ----------------------------------------------------- // // ----------------------------------------------------- const pdf_utf16be* PdfSymbolEncoding::GetToUnicodeTable() const { return PdfSymbolEncoding::s_cEncoding; } const pdf_utf16be PdfSymbolEncoding::s_cEncoding[256] = { //0, // uncomment to check compiler error cause of 257 members // 0x00..0x1f undefined: 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, // 20 # SPACE # space // 0x00A0, // 20 # NO-BREAK SPACE # space 0x0021, // 21 # EXCLAMATION MARK # exclam 0x2200, // 22 # FOR ALL # universal 0x0023, // 23 # NUMBER SIGN # numbersign 0x2203, // 24 # THERE EXISTS # existential 0x0025, // 25 # PERCENT SIGN # percent 0x0026, // 26 # AMPERSAND # ampersand 0x220B, // 27 # CONTAINS AS MEMBER # suchthat 0x0028, // 28 # LEFT PARENTHESIS # parenleft 0x0029, // 29 # RIGHT PARENTHESIS # parenright 0x2217, // 2A # ASTERISK OPERATOR # asteriskmath 0x002B, // 2B # PLUS SIGN # plus 0x002C, // 2C # COMMA # comma 0x2212, // 2D # MINUS SIGN # minus 0x002E, // 2E # FULL STOP # period 0x002F, // 2F # SOLIDUS # slash 0x0030, // 30 # DIGIT ZERO # zero 0x0031, // 31 # DIGIT ONE # one 0x0032, // 32 # DIGIT TWO # two 0x0033, // 33 # DIGIT THREE # three 0x0034, // 34 # DIGIT FOUR # four 0x0035, // 35 # DIGIT FIVE # five 0x0036, // 36 # DIGIT SIX # six 0x0037, // 37 # DIGIT SEVEN # seven 0x0038, // 38 # DIGIT EIGHT # eight 0x0039, // 39 # DIGIT NINE # nine 0x003A, // 3A # COLON # colon 0x003B, // 3B # SEMICOLON # semicolon 0x003C, // 3C # LESS-THAN SIGN # less 0x003D, // 3D # EQUALS SIGN # equal 0x003E, // 3E # GREATER-THAN SIGN # greater 0x003F, // 3F # QUESTION MARK # question 0x2245, // 40 # APPROXIMATELY EQUAL TO # congruent 0x0391, // 41 # GREEK CAPITAL LETTER ALPHA # Alpha 0x0392, // 42 # GREEK CAPITAL LETTER BETA # Beta 0x03A7, // 43 # GREEK CAPITAL LETTER CHI # Chi 0x0394, // 44 # GREEK CAPITAL LETTER DELTA # Delta // 0x2206, // 44 # INCREMENT # Delta 0x0395, // 45 # GREEK CAPITAL LETTER EPSILON # Epsilon 0x03A6, // 46 # GREEK CAPITAL LETTER PHI # Phi 0x0393, // 47 # GREEK CAPITAL LETTER GAMMA # Gamma 0x0397, // 48 # GREEK CAPITAL LETTER ETA # Eta 0x0399, // 49 # GREEK CAPITAL LETTER IOTA # Iota 0x03D1, // 4A # GREEK THETA SYMBOL # theta1 0x039A, // 4B # GREEK CAPITAL LETTER KAPPA # Kappa 0x039B, // 4C # GREEK CAPITAL LETTER LAMDA # Lambda 0x039C, // 4D # GREEK CAPITAL LETTER MU # Mu 0x039D, // 4E # GREEK CAPITAL LETTER NU # Nu 0x039F, // 4F # GREEK CAPITAL LETTER OMICRON # Omicron 0x03A0, // 50 # GREEK CAPITAL LETTER PI # Pi 0x0398, // 51 # GREEK CAPITAL LETTER THETA # Theta 0x03A1, // 52 # GREEK CAPITAL LETTER RHO # Rho 0x03A3, // 53 # GREEK CAPITAL LETTER SIGMA # Sigma 0x03A4, // 54 # GREEK CAPITAL LETTER TAU # Tau 0x03A5, // 55 # GREEK CAPITAL LETTER UPSILON # Upsilon 0x03C2, // 56 # GREEK SMALL LETTER FINAL SIGMA # sigma1 0x03A9, // 57 # GREEK CAPITAL LETTER OMEGA # Omega // 0x2126, // 57 # OHM SIGN # Omega 0x039E, // 58 # GREEK CAPITAL LETTER XI # Xi 0x03A8, // 59 # GREEK CAPITAL LETTER PSI # Psi 0x0396, // 5A # GREEK CAPITAL LETTER ZETA # Zeta 0x005B, // 5B # LEFT SQUARE BRACKET # bracketleft 0x2234, // 5C # THEREFORE # therefore 0x005D, // 5D # RIGHT SQUARE BRACKET # bracketright 0x22A5, // 5E # UP TACK # perpendicular 0x005F, // 5F # LOW LINE # underscore 0xF8E5, // 60 # RADICAL EXTENDER # radicalex (CUS) 0x03B1, // 61 # GREEK SMALL LETTER ALPHA # alpha 0x03B2, // 62 # GREEK SMALL LETTER BETA # beta 0x03C7, // 63 # GREEK SMALL LETTER CHI # chi 0x03B4, // 64 # GREEK SMALL LETTER DELTA # delta 0x03B5, // 65 # GREEK SMALL LETTER EPSILON # epsilon 0x03C6, // 66 # GREEK SMALL LETTER PHI # phi 0x03B3, // 67 # GREEK SMALL LETTER GAMMA # gamma 0x03B7, // 68 # GREEK SMALL LETTER ETA # eta 0x03B9, // 69 # GREEK SMALL LETTER IOTA # iota 0x03D5, // 6A # GREEK PHI SYMBOL # phi1 0x03BA, // 6B # GREEK SMALL LETTER KAPPA # kappa 0x03BB, // 6C # GREEK SMALL LETTER LAMDA # lambda // 0x00B5, // 6D # MICRO SIGN # mu 0x03BC, // 6D # GREEK SMALL LETTER MU # mu 0x03BD, // 6E # GREEK SMALL LETTER NU # nu 0x03BF, // 6F # GREEK SMALL LETTER OMICRON # omicron 0x03C0, // 70 # GREEK SMALL LETTER PI # pi 0x03B8, // 71 # GREEK SMALL LETTER THETA # theta 0x03C1, // 72 # GREEK SMALL LETTER RHO # rho 0x03C3, // 73 # GREEK SMALL LETTER SIGMA # sigma 0x03C4, // 74 # GREEK SMALL LETTER TAU # tau 0x03C5, // 75 # GREEK SMALL LETTER UPSILON # upsilon 0x03D6, // 76 # GREEK PI SYMBOL # omega1 0x03C9, // 77 # GREEK SMALL LETTER OMEGA # omega 0x03BE, // 78 # GREEK SMALL LETTER XI # xi 0x03C8, // 79 # GREEK SMALL LETTER PSI # psi 0x03B6, // 7A # GREEK SMALL LETTER ZETA # zeta 0x007B, // 7B # LEFT CURLY BRACKET # braceleft 0x007C, // 7C # VERTICAL LINE # bar 0x007D, // 7D # RIGHT CURLY BRACKET # braceright 0x223C, // 7E # TILDE OPERATOR # similar // 0x7f..0x9F undefined: 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x20AC, // A0 # EURO SIGN # Euro 0x03D2, // A1 # GREEK UPSILON WITH HOOK SYMBOL # Upsilon1 0x2032, // A2 # PRIME # minute 0x2264, // A3 # LESS-THAN OR EQUAL TO # lessequal 0x2044, // A4 # FRACTION SLASH # fraction // 0x2215, // A4 # DIVISION SLASH # fraction 0x221E, // A5 # INFINITY # infinity 0x0192, // A6 # LATIN SMALL LETTER F WITH HOOK # florin 0x2663, // A7 # BLACK CLUB SUIT # club 0x2666, // A8 # BLACK DIAMOND SUIT # diamond 0x2665, // A9 # BLACK HEART SUIT # heart 0x2660, // AA # BLACK SPADE SUIT # spade 0x2194, // AB # LEFT RIGHT ARROW # arrowboth 0x2190, // AC # LEFTWARDS ARROW # arrowleft 0x2191, // AD # UPWARDS ARROW # arrowup 0x2192, // AE # RIGHTWARDS ARROW # arrowright 0x2193, // AF # DOWNWARDS ARROW # arrowdown 0x00B0, // B0 # DEGREE SIGN # degree 0x00B1, // B1 # PLUS-MINUS SIGN # plusminus 0x2033, // B2 # DOUBLE PRIME # second 0x2265, // B3 # GREATER-THAN OR EQUAL TO # greaterequal 0x00D7, // B4 # MULTIPLICATION SIGN # multiply 0x221D, // B5 # PROPORTIONAL TO # proportional 0x2202, // B6 # PARTIAL DIFFERENTIAL # partialdiff 0x2022, // B7 # BULLET # bullet 0x00F7, // B8 # DIVISION SIGN # divide 0x2260, // B9 # NOT EQUAL TO # notequal 0x2261, // BA # IDENTICAL TO # equivalence 0x2248, // BB # ALMOST EQUAL TO # approxequal 0x2026, // BC # HORIZONTAL ELLIPSIS # ellipsis 0xF8E6, // BD # VERTICAL ARROW EXTENDER # arrowvertex (CUS) 0xF8E7, // BE # HORIZONTAL ARROW EXTENDER # arrowhorizex (CUS) 0x21B5, // BF # DOWNWARDS ARROW WITH CORNER LEFTWARDS # carriagereturn 0x2135, // C0 # ALEF SYMBOL # aleph 0x2111, // C1 # BLACK-LETTER CAPITAL I # Ifraktur 0x211C, // C2 # BLACK-LETTER CAPITAL R # Rfraktur 0x2118, // C3 # SCRIPT CAPITAL P # weierstrass 0x2297, // C4 # CIRCLED TIMES # circlemultiply 0x2295, // C5 # CIRCLED PLUS # circleplus 0x2205, // C6 # EMPTY SET # emptyset 0x2229, // C7 # INTERSECTION # intersection 0x222A, // C8 # UNION # union 0x2283, // C9 # SUPERSET OF # propersuperset 0x2287, // CA # SUPERSET OF OR EQUAL TO # reflexsuperset 0x2284, // CB # NOT A SUBSET OF # notsubset 0x2282, // CC # SUBSET OF # propersubset 0x2286, // CD # SUBSET OF OR EQUAL TO # reflexsubset 0x2208, // CE # ELEMENT OF # element 0x2209, // CF # NOT AN ELEMENT OF # notelement 0x2220, // D0 # ANGLE # angle 0x2207, // D1 # NABLA # gradient 0xF6DA, // D2 # REGISTERED SIGN SERIF # registerserif (CUS) 0xF6D9, // D3 # COPYRIGHT SIGN SERIF # copyrightserif (CUS) 0xF6DB, // D4 # TRADE MARK SIGN SERIF # trademarkserif (CUS) 0x220F, // D5 # N-ARY PRODUCT # product 0x221A, // D6 # SQUARE ROOT # radical 0x22C5, // D7 # DOT OPERATOR # dotmath 0x00AC, // D8 # NOT SIGN # logicalnot 0x2227, // D9 # LOGICAL AND # logicaland 0x2228, // DA # LOGICAL OR # logicalor 0x21D4, // DB # LEFT RIGHT DOUBLE ARROW # arrowdblboth 0x21D0, // DC # LEFTWARDS DOUBLE ARROW # arrowdblleft 0x21D1, // DD # UPWARDS DOUBLE ARROW # arrowdblup 0x21D2, // DE # RIGHTWARDS DOUBLE ARROW # arrowdblright 0x21D3, // DF # DOWNWARDS DOUBLE ARROW # arrowdbldown 0x25CA, // E0 # LOZENGE # lozenge 0x2329, // E1 # LEFT-POINTING ANGLE BRACKET # angleleft 0xF8E8, // E2 # REGISTERED SIGN SANS SERIF # registersans (CUS) 0xF8E9, // E3 # COPYRIGHT SIGN SANS SERIF # copyrightsans (CUS) 0xF8EA, // E4 # TRADE MARK SIGN SANS SERIF # trademarksans (CUS) 0x2211, // E5 # N-ARY SUMMATION # summation 0xF8EB, // E6 # LEFT PAREN TOP # parenlefttp (CUS) 0xF8EC, // E7 # LEFT PAREN EXTENDER # parenleftex (CUS) 0xF8ED, // E8 # LEFT PAREN BOTTOM # parenleftbt (CUS) 0xF8EE, // E9 # LEFT SQUARE BRACKET TOP # bracketlefttp (CUS) 0xF8EF, // EA # LEFT SQUARE BRACKET EXTENDER # bracketleftex (CUS) 0xF8F0, // EB # LEFT SQUARE BRACKET BOTTOM # bracketleftbt (CUS) 0xF8F1, // EC # LEFT CURLY BRACKET TOP # bracelefttp (CUS) 0xF8F2, // ED # LEFT CURLY BRACKET MID # braceleftmid (CUS) 0xF8F3, // EE # LEFT CURLY BRACKET BOTTOM # braceleftbt (CUS) 0xF8F4, // EF # CURLY BRACKET EXTENDER # braceex (CUS) 0x0000, // F0 undefined 0x232A, // F1 # RIGHT-POINTING ANGLE BRACKET # angleright 0x222B, // F2 # INTEGRAL # integral 0x2320, // F3 # TOP HALF INTEGRAL # integraltp 0xF8F5, // F4 # INTEGRAL EXTENDER # integralex (CUS) 0x2321, // F5 # BOTTOM HALF INTEGRAL # integralbt 0xF8F6, // F6 # RIGHT PAREN TOP # parenrighttp (CUS) 0xF8F7, // F7 # RIGHT PAREN EXTENDER # parenrightex (CUS) 0xF8F8, // F8 # RIGHT PAREN BOTTOM # parenrightbt (CUS) 0xF8F9, // F9 # RIGHT SQUARE BRACKET TOP # bracketrighttp (CUS) 0xF8FA, // FA # RIGHT SQUARE BRACKET EXTENDER # bracketrightex (CUS) 0xF8FB, // FB # RIGHT SQUARE BRACKET BOTTOM # bracketrightbt (CUS) 0xF8FC, // FC # RIGHT CURLY BRACKET TOP # bracerighttp (CUS) 0xF8FD, // FD # RIGHT CURLY BRACKET MID # bracerightmid (CUS) 0xF8FE, // FE # RIGHT CURLY BRACKET BOTTOM # bracerightbt (CUS) 0x0000 // FF undefined }; // OC 13.08.2010 New: PdfZapfDingbatsEncoding // ----------------------------------------------------- // PdfZapfDingbatsEncoding // See: http://unicode.org/Public/MAPPINGS/VENDORS/ADOBE/zdingbat.txt // ----------------------------------------------------- // ----------------------------------------------------- // // ----------------------------------------------------- const pdf_utf16be* PdfZapfDingbatsEncoding::GetToUnicodeTable() const { return PdfZapfDingbatsEncoding::s_cEncoding; } const pdf_utf16be PdfZapfDingbatsEncoding::s_cEncoding[256] = { //0, // uncomment to check compiler error cause of 257 members // 0x00..0x1f undefined: 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, // 20 # SPACE # space // 0x00A0, // 20 # NO-BREAK SPACE # space 0x2701, // 21 # UPPER BLADE SCISSORS # a1 0x2702, // 22 # BLACK SCISSORS # a2 0x2703, // 23 # LOWER BLADE SCISSORS # a202 0x2704, // 24 # WHITE SCISSORS # a3 0x260E, // 25 # BLACK TELEPHONE # a4 0x2706, // 26 # TELEPHONE LOCATION SIGN # a5 0x2707, // 27 # TAPE DRIVE # a119 0x2708, // 28 # AIRPLANE # a118 0x2709, // 29 # ENVELOPE # a117 0x261B, // 2A # BLACK RIGHT POINTING INDEX # a11 0x261E, // 2B # WHITE RIGHT POINTING INDEX # a12 0x270C, // 2C # VICTORY HAND # a13 0x270D, // 2D # WRITING HAND # a14 0x270E, // 2E # LOWER RIGHT PENCIL # a15 0x270F, // 2F # PENCIL # a16 0x2710, // 30 # UPPER RIGHT PENCIL # a105 0x2711, // 31 # WHITE NIB # a17 0x2712, // 32 # BLACK NIB # a18 0x2713, // 33 # CHECK MARK # a19 0x2714, // 34 # HEAVY CHECK MARK # a20 0x2715, // 35 # MULTIPLICATION X # a21 0x2716, // 36 # HEAVY MULTIPLICATION X # a22 0x2717, // 37 # BALLOT X # a23 0x2718, // 38 # HEAVY BALLOT X # a24 0x2719, // 39 # OUTLINED GREEK CROSS # a25 0x271A, // 3A # HEAVY GREEK CROSS # a26 0x271B, // 3B # OPEN CENTRE CROSS # a27 0x271C, // 3C # HEAVY OPEN CENTRE CROSS # a28 0x271D, // 3D # LATIN CROSS # a6 0x271E, // 3E # SHADOWED WHITE LATIN CROSS # a7 0x271F, // 3F # OUTLINED LATIN CROSS # a8 0x2720, // 40 # MALTESE CROSS # a9 0x2721, // 41 # STAR OF DAVID # a10 0x2722, // 42 # FOUR TEARDROP-SPOKED ASTERISK # a29 0x2723, // 43 # FOUR BALLOON-SPOKED ASTERISK # a30 0x2724, // 44 # HEAVY FOUR BALLOON-SPOKED ASTERISK # a31 0x2725, // 45 # FOUR CLUB-SPOKED ASTERISK # a32 0x2726, // 46 # BLACK FOUR POINTED STAR # a33 0x2727, // 47 # WHITE FOUR POINTED STAR # a34 0x2605, // 48 # BLACK STAR # a35 0x2729, // 49 # STRESS OUTLINED WHITE STAR # a36 0x272A, // 4A # CIRCLED WHITE STAR # a37 0x272B, // 4B # OPEN CENTRE BLACK STAR # a38 0x272C, // 4C # BLACK CENTRE WHITE STAR # a39 0x272D, // 4D # OUTLINED BLACK STAR # a40 0x272E, // 4E # HEAVY OUTLINED BLACK STAR # a41 0x272F, // 4F # PINWHEEL STAR # a42 0x2730, // 50 # SHADOWED WHITE STAR # a43 0x2731, // 51 # HEAVY ASTERISK # a44 0x2732, // 52 # OPEN CENTRE ASTERISK # a45 0x2733, // 53 # EIGHT SPOKED ASTERISK # a46 0x2734, // 54 # EIGHT POINTED BLACK STAR # a47 0x2735, // 55 # EIGHT POINTED PINWHEEL STAR # a48 0x2736, // 56 # SIX POINTED BLACK STAR # a49 0x2737, // 57 # EIGHT POINTED RECTILINEAR BLACK STAR # a50 0x2738, // 58 # HEAVY EIGHT POINTED RECTILINEAR BLACK STAR # a51 0x2739, // 59 # TWELVE POINTED BLACK STAR # a52 0x273A, // 5A # SIXTEEN POINTED ASTERISK # a53 0x273B, // 5B # TEARDROP-SPOKED ASTERISK # a54 0x273C, // 5C # OPEN CENTRE TEARDROP-SPOKED ASTERISK # a55 0x273D, // 5D # HEAVY TEARDROP-SPOKED ASTERISK # a56 0x273E, // 5E # SIX PETALLED BLACK AND WHITE FLORETTE # a57 0x273F, // 5F # BLACK FLORETTE # a58 0x2740, // 60 # WHITE FLORETTE # a59 0x2741, // 61 # EIGHT PETALLED OUTLINED BLACK FLORETTE # a60 0x2742, // 62 # CIRCLED OPEN CENTRE EIGHT POINTED STAR # a61 0x2743, // 63 # HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK # a62 0x2744, // 64 # SNOWFLAKE # a63 0x2745, // 65 # TIGHT TRIFOLIATE SNOWFLAKE # a64 0x2746, // 66 # HEAVY CHEVRON SNOWFLAKE # a65 0x2747, // 67 # SPARKLE # a66 0x2748, // 68 # HEAVY SPARKLE # a67 0x2749, // 69 # BALLOON-SPOKED ASTERISK # a68 0x274A, // 6A # EIGHT TEARDROP-SPOKED PROPELLER ASTERISK # a69 0x274B, // 6B # HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK # a70 0x25CF, // 6C # BLACK CIRCLE # a71 0x274D, // 6D # SHADOWED WHITE CIRCLE # a72 0x25A0, // 6E # BLACK SQUARE # a73 0x274F, // 6F # LOWER RIGHT DROP-SHADOWED WHITE SQUARE # a74 0x2750, // 70 # UPPER RIGHT DROP-SHADOWED WHITE SQUARE # a203 0x2751, // 71 # LOWER RIGHT SHADOWED WHITE SQUARE # a75 0x2752, // 72 # UPPER RIGHT SHADOWED WHITE SQUARE # a204 0x25B2, // 73 # BLACK UP-POINTING TRIANGLE # a76 0x25BC, // 74 # BLACK DOWN-POINTING TRIANGLE # a77 0x25C6, // 75 # BLACK DIAMOND # a78 0x2756, // 76 # BLACK DIAMOND MINUS WHITE X # a79 0x25D7, // 77 # RIGHT HALF BLACK CIRCLE # a81 0x2758, // 78 # LIGHT VERTICAL BAR # a82 0x2759, // 79 # MEDIUM VERTICAL BAR # a83 0x275A, // 7A # HEAVY VERTICAL BAR # a84 0x275B, // 7B # HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT # a97 0x275C, // 7C # HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT # a98 0x275D, // 7D # HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT # a99 0x275E, // 7E # HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT # a100 0x0000, // 7F undefined 0xF8D7, // 80 # MEDIUM LEFT PARENTHESIS ORNAMENT # a89 (CUS) 0xF8D8, // 81 # MEDIUM RIGHT PARENTHESIS ORNAMENT # a90 (CUS) 0xF8D9, // 82 # MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT # a93 (CUS) 0xF8DA, // 83 # MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT # a94 (CUS) 0xF8DB, // 84 # MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT # a91 (CUS) 0xF8DC, // 85 # MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT # a92 (CUS) 0xF8DD, // 86 # HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT # a205 (CUS) 0xF8DE, // 87 # HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT # a85 (CUS) 0xF8DF, // 88 # HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT # a206 (CUS) 0xF8E0, // 89 # HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT # a86 (CUS) 0xF8E1, // 8A # LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT # a87 (CUS) 0xF8E2, // 8B # LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT # a88 (CUS) 0xF8E3, // 8C # MEDIUM LEFT CURLY BRACKET ORNAMENT # a95 (CUS) 0xF8E4, // 8D # MEDIUM RIGHT CURLY BRACKET ORNAMENT # a96 (CUS) // 0x8E..0xA0 undefined: 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2761, // A1 # CURVED STEM PARAGRAPH SIGN ORNAMENT # a101 0x2762, // A2 # HEAVY EXCLAMATION MARK ORNAMENT # a102 0x2763, // A3 # HEAVY HEART EXCLAMATION MARK ORNAMENT # a103 0x2764, // A4 # HEAVY BLACK HEART # a104 0x2765, // A5 # ROTATED HEAVY BLACK HEART BULLET # a106 0x2766, // A6 # FLORAL HEART # a107 0x2767, // A7 # ROTATED FLORAL HEART BULLET # a108 0x2663, // A8 # BLACK CLUB SUIT # a112 0x2666, // A9 # BLACK DIAMOND SUIT # a111 0x2665, // AA # BLACK HEART SUIT # a110 0x2660, // AB # BLACK SPADE SUIT # a109 0x2460, // AC # CIRCLED DIGIT ONE # a120 0x2461, // AD # CIRCLED DIGIT TWO # a121 0x2462, // AE # CIRCLED DIGIT THREE # a122 0x2463, // AF # CIRCLED DIGIT FOUR # a123 0x2464, // B0 # CIRCLED DIGIT FIVE # a124 0x2465, // B1 # CIRCLED DIGIT SIX # a125 0x2466, // B2 # CIRCLED DIGIT SEVEN # a126 0x2467, // B3 # CIRCLED DIGIT EIGHT # a127 0x2468, // B4 # CIRCLED DIGIT NINE # a128 0x2469, // B5 # CIRCLED NUMBER TEN # a129 0x2776, // B6 # DINGBAT NEGATIVE CIRCLED DIGIT ONE # a130 0x2777, // B7 # DINGBAT NEGATIVE CIRCLED DIGIT TWO # a131 0x2778, // B8 # DINGBAT NEGATIVE CIRCLED DIGIT THREE # a132 0x2779, // B9 # DINGBAT NEGATIVE CIRCLED DIGIT FOUR # a133 0x277A, // BA # DINGBAT NEGATIVE CIRCLED DIGIT FIVE # a134 0x277B, // BB # DINGBAT NEGATIVE CIRCLED DIGIT SIX # a135 0x277C, // BC # DINGBAT NEGATIVE CIRCLED DIGIT SEVEN # a136 0x277D, // BD # DINGBAT NEGATIVE CIRCLED DIGIT EIGHT # a137 0x277E, // BE # DINGBAT NEGATIVE CIRCLED DIGIT NINE # a138 0x277F, // BF # DINGBAT NEGATIVE CIRCLED NUMBER TEN # a139 0x2780, // C0 # DINGBAT CIRCLED SANS-SERIF DIGIT ONE # a140 0x2781, // C1 # DINGBAT CIRCLED SANS-SERIF DIGIT TWO # a141 0x2782, // C2 # DINGBAT CIRCLED SANS-SERIF DIGIT THREE # a142 0x2783, // C3 # DINGBAT CIRCLED SANS-SERIF DIGIT FOUR # a143 0x2784, // C4 # DINGBAT CIRCLED SANS-SERIF DIGIT FIVE # a144 0x2785, // C5 # DINGBAT CIRCLED SANS-SERIF DIGIT SIX # a145 0x2786, // C6 # DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN # a146 0x2787, // C7 # DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT # a147 0x2788, // C8 # DINGBAT CIRCLED SANS-SERIF DIGIT NINE # a148 0x2789, // C9 # DINGBAT CIRCLED SANS-SERIF NUMBER TEN # a149 0x278A, // CA # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE # a150 0x278B, // CB # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO # a151 0x278C, // CC # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE # a152 0x278D, // CD # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR # a153 0x278E, // CE # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE # a154 0x278F, // CF # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX # a155 0x2790, // D0 # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN # a156 0x2791, // D1 # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT # a157 0x2792, // D2 # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE # a158 0x2793, // D3 # DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN # a159 0x2794, // D4 # HEAVY WIDE-HEADED RIGHTWARDS ARROW # a160 0x2192, // D5 # RIGHTWARDS ARROW # a161 0x2194, // D6 # LEFT RIGHT ARROW # a163 0x2195, // D7 # UP DOWN ARROW # a164 0x2798, // D8 # HEAVY SOUTH EAST ARROW # a196 0x2799, // D9 # HEAVY RIGHTWARDS ARROW # a165 0x279A, // DA # HEAVY NORTH EAST ARROW # a192 0x279B, // DB # DRAFTING POINT RIGHTWARDS ARROW # a166 0x279C, // DC # HEAVY ROUND-TIPPED RIGHTWARDS ARROW # a167 0x279D, // DD # TRIANGLE-HEADED RIGHTWARDS ARROW # a168 0x279E, // DE # HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW # a169 0x279F, // DF # DASHED TRIANGLE-HEADED RIGHTWARDS ARROW # a170 0x27A0, // E0 # HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW # a171 0x27A1, // E1 # BLACK RIGHTWARDS ARROW # a172 0x27A2, // E2 # THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD # a173 0x27A3, // E3 # THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD # a162 0x27A4, // E4 # BLACK RIGHTWARDS ARROWHEAD # a174 0x27A5, // E5 # HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW # a175 0x27A6, // E6 # HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW # a176 0x27A7, // E7 # SQUAT BLACK RIGHTWARDS ARROW # a177 0x27A8, // E8 # HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW # a178 0x27A9, // E9 # RIGHT-SHADED WHITE RIGHTWARDS ARROW # a179 0x27AA, // EA # LEFT-SHADED WHITE RIGHTWARDS ARROW # a193 0x27AB, // EB # BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW # a180 0x27AC, // EC # FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW # a199 0x27AD, // ED # HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW # a181 0x27AE, // EE # HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW # a200 0x27AF, // EF # NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW # a182 0x0000, // F0 undefined 0x27B1, // F1 # NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW # a201 0x27B2, // F2 # CIRCLED HEAVY WHITE RIGHTWARDS ARROW # a183 0x27B3, // F3 # WHITE-FEATHERED RIGHTWARDS ARROW # a184 0x27B4, // F4 # BLACK-FEATHERED SOUTH EAST ARROW # a197 0x27B5, // F5 # BLACK-FEATHERED RIGHTWARDS ARROW # a185 0x27B6, // F6 # BLACK-FEATHERED NORTH EAST ARROW # a194 0x27B7, // F7 # HEAVY BLACK-FEATHERED SOUTH EAST ARROW # a198 0x27B8, // F8 # HEAVY BLACK-FEATHERED RIGHTWARDS ARROW # a186 0x27B9, // F9 # HEAVY BLACK-FEATHERED NORTH EAST ARROW # a195 0x27BA, // FA # TEARDROP-BARBED RIGHTWARDS ARROW # a187 0x27BB, // FB # HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW # a188 0x27BC, // FC # WEDGE-TAILED RIGHTWARDS ARROW # a189 0x27BD, // FD # HEAVY WEDGE-TAILED RIGHTWARDS ARROW # a190 0x27BE, // FE # OPEN-OUTLINED RIGHTWARDS ARROW # a191 0x0000 // FF undefined }; // ----------------------------------------------------- // PdfWin1250Encoding // See: http://www.microsoft.com/globaldev/reference/sbcs/1250.mspx // ----------------------------------------------------- // ----------------------------------------------------- // // ----------------------------------------------------- const pdf_utf16be PdfWin1250Encoding::s_cEncoding[256] = { 0x0000, // NULL 0x0001, // START OF HEADING 0x0002, // START OF TEXT 0x0003, // END OF TEXT 0x0004, // END OF TRANSMISSION 0x0005, // ENQUIRY 0x0006, // ACKNOWLEDGE 0x0007, // BELL 0x0008, // BACKSPACE 0x0009, // HORIZONTAL TABULATION 0x000A, // LINE FEED 0x000B, // VERTICAL TABULATION 0x000C, // FORM FEED 0x000D, // CARRIAGE RETURN 0x000E, // SHIFT OUT 0x000F, // SHIFT IN 0x0010, // DATA LINK ESCAPE 0x0011, // DEVICE CONTROL ONE 0x0012, // DEVICE CONTROL TWO 0x0013, // DEVICE CONTROL THREE 0x0014, // DEVICE CONTROL FOUR 0x0015, // NEGATIVE ACKNOWLEDGE 0x0016, // SYNCHRONOUS IDLE 0x0017, // END OF TRANSMISSION BLOCK 0x0018, // CANCEL 0x0019, // END OF MEDIUM 0x001A, // SUBSTITUTE 0x001B, // ESCAPE 0x001C, // FILE SEPARATOR 0x001D, // GROUP SEPARATOR 0x001E, // RECORD SEPARATOR 0x001F, // UNIT SEPARATOR 0x0020, // SPACE 0x0021, // EXCLAMATION MARK 0x0022, // QUOTATION MARK 0x0023, // NUMBER SIGN 0x0024, // DOLLAR SIGN 0x0025, // PERCENT SIGN 0x0026, // AMPERSAND 0x0027, // APOSTROPHE 0x0028, // LEFT PARENTHESIS 0x0029, // RIGHT PARENTHESIS 0x002A, // ASTERISK 0x002B, // PLUS SIGN 0x002C, // COMMA 0x002D, // HYPHEN-MINUS 0x002E, // FULL STOP 0x002F, // SOLIDUS 0x0030, // DIGIT ZERO 0x0031, // DIGIT ONE 0x0032, // DIGIT TWO 0x0033, // DIGIT THREE 0x0034, // DIGIT FOUR 0x0035, // DIGIT FIVE 0x0036, // DIGIT SIX 0x0037, // DIGIT SEVEN 0x0038, // DIGIT EIGHT 0x0039, // DIGIT NINE 0x003A, // COLON 0x003B, // SEMICOLON 0x003C, // LESS-THAN SIGN 0x003D, // EQUALS SIGN 0x003E, // GREATER-THAN SIGN 0x003F, // QUESTION MARK 0x0040, // COMMERCIAL AT 0x0041, // LATIN CAPITAL LETTER A 0x0042, // LATIN CAPITAL LETTER B 0x0043, // LATIN CAPITAL LETTER C 0x0044, // LATIN CAPITAL LETTER D 0x0045, // LATIN CAPITAL LETTER E 0x0046, // LATIN CAPITAL LETTER F 0x0047, // LATIN CAPITAL LETTER G 0x0048, // LATIN CAPITAL LETTER H 0x0049, // LATIN CAPITAL LETTER I 0x004A, // LATIN CAPITAL LETTER J 0x004B, // LATIN CAPITAL LETTER K 0x004C, // LATIN CAPITAL LETTER L 0x004D, // LATIN CAPITAL LETTER M 0x004E, // LATIN CAPITAL LETTER N 0x004F, // LATIN CAPITAL LETTER O 0x0050, // LATIN CAPITAL LETTER P 0x0051, // LATIN CAPITAL LETTER Q 0x0052, // LATIN CAPITAL LETTER R 0x0053, // LATIN CAPITAL LETTER S 0x0054, // LATIN CAPITAL LETTER T 0x0055, // LATIN CAPITAL LETTER U 0x0056, // LATIN CAPITAL LETTER V 0x0057, // LATIN CAPITAL LETTER W 0x0058, // LATIN CAPITAL LETTER X 0x0059, // LATIN CAPITAL LETTER Y 0x005A, // LATIN CAPITAL LETTER Z 0x005B, // LEFT SQUARE BRACKET 0x005C, // REVERSE SOLIDUS 0x005D, // RIGHT SQUARE BRACKET 0x005E, // CIRCUMFLEX ACCENT 0x005F, // LOW LINE 0x0060, // GRAVE ACCENT 0x0061, // LATIN SMALL LETTER A 0x0062, // LATIN SMALL LETTER B 0x0063, // LATIN SMALL LETTER C 0x0064, // LATIN SMALL LETTER D 0x0065, // LATIN SMALL LETTER E 0x0066, // LATIN SMALL LETTER F 0x0067, // LATIN SMALL LETTER G 0x0068, // LATIN SMALL LETTER H 0x0069, // LATIN SMALL LETTER I 0x006A, // LATIN SMALL LETTER J 0x006B, // LATIN SMALL LETTER K 0x006C, // LATIN SMALL LETTER L 0x006D, // LATIN SMALL LETTER M 0x006E, // LATIN SMALL LETTER N 0x006F, // LATIN SMALL LETTER O 0x0070, // LATIN SMALL LETTER P 0x0071, // LATIN SMALL LETTER Q 0x0072, // LATIN SMALL LETTER R 0x0073, // LATIN SMALL LETTER S 0x0074, // LATIN SMALL LETTER T 0x0075, // LATIN SMALL LETTER U 0x0076, // LATIN SMALL LETTER V 0x0077, // LATIN SMALL LETTER W 0x0078, // LATIN SMALL LETTER X 0x0079, // LATIN SMALL LETTER Y 0x007A, // LATIN SMALL LETTER Z 0x007B, // LEFT CURLY BRACKET 0x007C, // VERTICAL LINE 0x007D, // RIGHT CURLY BRACKET 0x007E, // TILDE 0x007F, // DELETE 0x20AC, // EURO SIGN 0x0000, 0x201A, // SINGLE LOW-9 QUOTATION MARK 0x0000, 0x201E, // DOUBLE LOW-9 QUOTATION MARK 0x2026, // HORIZONTAL ELLIPSIS 0x2020, // DAGGER 0x2021, // DOUBLE DAGGER 0x0000, 0x2030, // PER MILLE SIGN 0x0160, // LATIN CAPITAL LETTER S WITH CARON 0x2039, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK 0x015A, // LATIN CAPITAL LETTER S WITH ACUTE 0x0164, // LATIN CAPITAL LETTER T WITH CARON 0x017D, // LATIN CAPITAL LETTER Z WITH CARON 0x0179, // LATIN CAPITAL LETTER Z WITH ACUTE 0x0000, 0x2018, // LEFT SINGLE QUOTATION MARK 0x2019, // RIGHT SINGLE QUOTATION MARK 0x201C, // LEFT DOUBLE QUOTATION MARK 0x201D, // RIGHT DOUBLE QUOTATION MARK 0x2022, // BULLET 0x2013, // EN DASH 0x2014, // EM DASH 0x0000, 0x2122, // TRADE MARK SIGN 0x0161, // LATIN SMALL LETTER S WITH CARON 0x203A, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK 0x015B, // LATIN SMALL LETTER S WITH ACUTE 0x0165, // LATIN SMALL LETTER T WITH CARON 0x017E, // LATIN SMALL LETTER Z WITH CARON 0x017A, // LATIN SMALL LETTER Z WITH ACUTE 0x00A0, // NO-BREAK SPACE 0x02C7, // CARON 0x02D8, // BREVE 0x0141, // LATIN CAPITAL LETTER L WITH STROKE 0x00A4, // CURRENCY SIGN 0x0104, // LATIN CAPITAL LETTER A WITH OGONEK 0x00A6, // BROKEN BAR 0x00A7, // SECTION SIGN 0x00A8, // DIAERESIS 0x00A9, // COPYRIGHT SIGN 0x015E, // LATIN CAPITAL LETTER S WITH CEDILLA 0x00AB, // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK 0x00AC, // NOT SIGN 0x00AD, // SOFT HYPHEN 0x00AE, // REGISTERED SIGN 0x017B, // LATIN CAPITAL LETTER Z WITH DOT ABOVE 0x00B0, // DEGREE SIGN 0x00B1, // PLUS-MINUS SIGN 0x02DB, // OGONEK 0x0142, // LATIN SMALL LETTER L WITH STROKE 0x00B4, // ACUTE ACCENT 0x00B5, // MICRO SIGN 0x00B6, // PILCROW SIGN 0x00B7, // MIDDLE DOT 0x00B8, // CEDILLA 0x0105, // LATIN SMALL LETTER A WITH OGONEK 0x015F, // LATIN SMALL LETTER S WITH CEDILLA 0x00BB, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK 0x013D, // LATIN CAPITAL LETTER L WITH CARON 0x02DD, // DOUBLE ACUTE ACCENT 0x013E, // LATIN SMALL LETTER L WITH CARON 0x017C, // LATIN SMALL LETTER Z WITH DOT ABOVE 0x0154, // LATIN CAPITAL LETTER R WITH ACUTE 0x00C1, // LATIN CAPITAL LETTER A WITH ACUTE 0x00C2, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX 0x0102, // LATIN CAPITAL LETTER A WITH BREVE 0x00C4, // LATIN CAPITAL LETTER A WITH DIAERESIS 0x0139, // LATIN CAPITAL LETTER L WITH ACUTE 0x0106, // LATIN CAPITAL LETTER C WITH ACUTE 0x00C7, // LATIN CAPITAL LETTER C WITH CEDILLA 0x010C, // LATIN CAPITAL LETTER C WITH CARON 0x00C9, // LATIN CAPITAL LETTER E WITH ACUTE 0x0118, // LATIN CAPITAL LETTER E WITH OGONEK 0x00CB, // LATIN CAPITAL LETTER E WITH DIAERESIS 0x011A, // LATIN CAPITAL LETTER E WITH CARON 0x00CD, // LATIN CAPITAL LETTER I WITH ACUTE 0x00CE, // LATIN CAPITAL LETTER I WITH CIRCUMFLEX 0x010E, // LATIN CAPITAL LETTER D WITH CARON 0x0110, // LATIN CAPITAL LETTER D WITH STROKE 0x0143, // LATIN CAPITAL LETTER N WITH ACUTE 0x0147, // LATIN CAPITAL LETTER N WITH CARON 0x00D3, // LATIN CAPITAL LETTER O WITH ACUTE 0x00D4, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX 0x0150, // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE 0x00D6, // LATIN CAPITAL LETTER O WITH DIAERESIS 0x00D7, // MULTIPLICATION SIGN 0x0158, // LATIN CAPITAL LETTER R WITH CARON 0x016E, // LATIN CAPITAL LETTER U WITH RING ABOVE 0x00DA, // LATIN CAPITAL LETTER U WITH ACUTE 0x0170, // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE 0x00DC, // LATIN CAPITAL LETTER U WITH DIAERESIS 0x00DD, // LATIN CAPITAL LETTER Y WITH ACUTE 0x0162, // LATIN CAPITAL LETTER T WITH CEDILLA 0x00DF, // LATIN SMALL LETTER SHARP S 0x0155, // LATIN SMALL LETTER R WITH ACUTE 0x00E1, // LATIN SMALL LETTER A WITH ACUTE 0x00E2, // LATIN SMALL LETTER A WITH CIRCUMFLEX 0x0103, // LATIN SMALL LETTER A WITH BREVE 0x00E4, // LATIN SMALL LETTER A WITH DIAERESIS 0x013A, // LATIN SMALL LETTER L WITH ACUTE 0x0107, // LATIN SMALL LETTER C WITH ACUTE 0x00E7, // LATIN SMALL LETTER C WITH CEDILLA 0x010D, // LATIN SMALL LETTER C WITH CARON 0x00E9, // LATIN SMALL LETTER E WITH ACUTE 0x0119, // LATIN SMALL LETTER E WITH OGONEK 0x00EB, // LATIN SMALL LETTER E WITH DIAERESIS 0x011B, // LATIN SMALL LETTER E WITH CARON 0x00ED, // LATIN SMALL LETTER I WITH ACUTE 0x00EE, // LATIN SMALL LETTER I WITH CIRCUMFLEX 0x010F, // LATIN SMALL LETTER D WITH CARON 0x0111, // LATIN SMALL LETTER D WITH STROKE 0x0144, // LATIN SMALL LETTER N WITH ACUTE 0x0148, // LATIN SMALL LETTER N WITH CARON 0x00F3, // LATIN SMALL LETTER O WITH ACUTE 0x00F4, // LATIN SMALL LETTER O WITH CIRCUMFLEX 0x0151, // LATIN SMALL LETTER O WITH DOUBLE ACUTE 0x00F6, // LATIN SMALL LETTER O WITH DIAERESIS 0x00F7, // DIVISION SIGN 0x0159, // LATIN SMALL LETTER R WITH CARON 0x016F, // LATIN SMALL LETTER U WITH RING ABOVE 0x00FA, // LATIN SMALL LETTER U WITH ACUTE 0x0171, // LATIN SMALL LETTER U WITH DOUBLE ACUTE 0x00FC, // LATIN SMALL LETTER U WITH DIAERESIS 0x00FD, // LATIN SMALL LETTER Y WITH ACUTE 0x0163, // LATIN SMALL LETTER T WITH CEDILLA 0x02D9 // DOT ABOVE }; const pdf_utf16be* PdfWin1250Encoding::GetToUnicodeTable() const { return PdfWin1250Encoding::s_cEncoding; } // ----------------------------------------------------- // PdfIso88592Encoding // See: http://unicode.org/Public/MAPPINGS/ISO8859/8859-2.TXT // ----------------------------------------------------- // ----------------------------------------------------- // // ----------------------------------------------------- const pdf_utf16be PdfIso88592Encoding::s_cEncoding[256] = { 0x0000, // NULL 0x0001, // START OF HEADING 0x0002, // START OF TEXT 0x0003, // END OF TEXT 0x0004, // END OF TRANSMISSION 0x0005, // ENQUIRY 0x0006, // ACKNOWLEDGE 0x0007, // BELL 0x0008, // BACKSPACE 0x0009, // HORIZONTAL TABULATION 0x000A, // LINE FEED 0x000B, // VERTICAL TABULATION 0x000C, // FORM FEED 0x000D, // CARRIAGE RETURN 0x000E, // SHIFT OUT 0x000F, // SHIFT IN 0x0010, // DATA LINK ESCAPE 0x0011, // DEVICE CONTROL ONE 0x0012, // DEVICE CONTROL TWO 0x0013, // DEVICE CONTROL THREE 0x0014, // DEVICE CONTROL FOUR 0x0015, // NEGATIVE ACKNOWLEDGE 0x0016, // SYNCHRONOUS IDLE 0x0017, // END OF TRANSMISSION BLOCK 0x0018, // CANCEL 0x0019, // END OF MEDIUM 0x001A, // SUBSTITUTE 0x001B, // ESCAPE 0x001C, // FILE SEPARATOR 0x001D, // GROUP SEPARATOR 0x001E, // RECORD SEPARATOR 0x001F, // UNIT SEPARATOR 0x0020, // SPACE 0x0021, // EXCLAMATION MARK 0x0022, // QUOTATION MARK 0x0023, // NUMBER SIGN 0x0024, // DOLLAR SIGN 0x0025, // PERCENT SIGN 0x0026, // AMPERSAND 0x0027, // APOSTROPHE 0x0028, // LEFT PARENTHESIS 0x0029, // RIGHT PARENTHESIS 0x002A, // ASTERISK 0x002B, // PLUS SIGN 0x002C, // COMMA 0x002D, // HYPHEN-MINUS 0x002E, // FULL STOP 0x002F, // SOLIDUS 0x0030, // DIGIT ZERO 0x0031, // DIGIT ONE 0x0032, // DIGIT TWO 0x0033, // DIGIT THREE 0x0034, // DIGIT FOUR 0x0035, // DIGIT FIVE 0x0036, // DIGIT SIX 0x0037, // DIGIT SEVEN 0x0038, // DIGIT EIGHT 0x0039, // DIGIT NINE 0x003A, // COLON 0x003B, // SEMICOLON 0x003C, // LESS-THAN SIGN 0x003D, // EQUALS SIGN 0x003E, // GREATER-THAN SIGN 0x003F, // QUESTION MARK 0x0040, // COMMERCIAL AT 0x0041, // LATIN CAPITAL LETTER A 0x0042, // LATIN CAPITAL LETTER B 0x0043, // LATIN CAPITAL LETTER C 0x0044, // LATIN CAPITAL LETTER D 0x0045, // LATIN CAPITAL LETTER E 0x0046, // LATIN CAPITAL LETTER F 0x0047, // LATIN CAPITAL LETTER G 0x0048, // LATIN CAPITAL LETTER H 0x0049, // LATIN CAPITAL LETTER I 0x004A, // LATIN CAPITAL LETTER J 0x004B, // LATIN CAPITAL LETTER K 0x004C, // LATIN CAPITAL LETTER L 0x004D, // LATIN CAPITAL LETTER M 0x004E, // LATIN CAPITAL LETTER N 0x004F, // LATIN CAPITAL LETTER O 0x0050, // LATIN CAPITAL LETTER P 0x0051, // LATIN CAPITAL LETTER Q 0x0052, // LATIN CAPITAL LETTER R 0x0053, // LATIN CAPITAL LETTER S 0x0054, // LATIN CAPITAL LETTER T 0x0055, // LATIN CAPITAL LETTER U 0x0056, // LATIN CAPITAL LETTER V 0x0057, // LATIN CAPITAL LETTER W 0x0058, // LATIN CAPITAL LETTER X 0x0059, // LATIN CAPITAL LETTER Y 0x005A, // LATIN CAPITAL LETTER Z 0x005B, // LEFT SQUARE BRACKET 0x005C, // REVERSE SOLIDUS 0x005D, // RIGHT SQUARE BRACKET 0x005E, // CIRCUMFLEX ACCENT 0x005F, // LOW LINE 0x0060, // GRAVE ACCENT 0x0061, // LATIN SMALL LETTER A 0x0062, // LATIN SMALL LETTER B 0x0063, // LATIN SMALL LETTER C 0x0064, // LATIN SMALL LETTER D 0x0065, // LATIN SMALL LETTER E 0x0066, // LATIN SMALL LETTER F 0x0067, // LATIN SMALL LETTER G 0x0068, // LATIN SMALL LETTER H 0x0069, // LATIN SMALL LETTER I 0x006A, // LATIN SMALL LETTER J 0x006B, // LATIN SMALL LETTER K 0x006C, // LATIN SMALL LETTER L 0x006D, // LATIN SMALL LETTER M 0x006E, // LATIN SMALL LETTER N 0x006F, // LATIN SMALL LETTER O 0x0070, // LATIN SMALL LETTER P 0x0071, // LATIN SMALL LETTER Q 0x0072, // LATIN SMALL LETTER R 0x0073, // LATIN SMALL LETTER S 0x0074, // LATIN SMALL LETTER T 0x0075, // LATIN SMALL LETTER U 0x0076, // LATIN SMALL LETTER V 0x0077, // LATIN SMALL LETTER W 0x0078, // LATIN SMALL LETTER X 0x0079, // LATIN SMALL LETTER Y 0x007A, // LATIN SMALL LETTER Z 0x007B, // LEFT CURLY BRACKET 0x007C, // VERTICAL LINE 0x007D, // RIGHT CURLY BRACKET 0x007E, // TILDE 0x007F, // DELETE 0x0080, // 0x0081, // 0x0082, // 0x0083, // 0x0084, // 0x0085, // 0x0086, // 0x0087, // 0x0088, // 0x0089, // 0x008A, // 0x008B, // 0x008C, // 0x008D, // 0x008E, // 0x008F, // 0x0090, // 0x0091, // 0x0092, // 0x0093, // 0x0094, // 0x0095, // 0x0096, // 0x0097, // 0x0098, // 0x0099, // 0x009A, // 0x009B, // 0x009C, // 0x009D, // 0x009E, // 0x009F, // 0x00A0, // NO-BREAK SPACE 0x0104, // LATIN CAPITAL LETTER A WITH OGONEK 0x02D8, // BREVE 0x0141, // LATIN CAPITAL LETTER L WITH STROKE 0x00A4, // CURRENCY SIGN 0x013D, // LATIN CAPITAL LETTER L WITH CARON 0x015A, // LATIN CAPITAL LETTER S WITH ACUTE 0x00A7, // SECTION SIGN 0x00A8, // DIAERESIS 0x0160, // LATIN CAPITAL LETTER S WITH CARON 0x015E, // LATIN CAPITAL LETTER S WITH CEDILLA 0x0164, // LATIN CAPITAL LETTER T WITH CARON 0x0179, // LATIN CAPITAL LETTER Z WITH ACUTE 0x00AD, // SOFT HYPHEN 0x017D, // LATIN CAPITAL LETTER Z WITH CARON 0x017B, // LATIN CAPITAL LETTER Z WITH DOT ABOVE 0x00B0, // DEGREE SIGN 0x0105, // LATIN SMALL LETTER A WITH OGONEK 0x02DB, // OGONEK 0x0142, // LATIN SMALL LETTER L WITH STROKE 0x00B4, // ACUTE ACCENT 0x013E, // LATIN SMALL LETTER L WITH CARON 0x015B, // LATIN SMALL LETTER S WITH ACUTE 0x02C7, // CARON 0x00B8, // CEDILLA 0x0161, // LATIN SMALL LETTER S WITH CARON 0x015F, // LATIN SMALL LETTER S WITH CEDILLA 0x0165, // LATIN SMALL LETTER T WITH CARON 0x017A, // LATIN SMALL LETTER Z WITH ACUTE 0x02DD, // DOUBLE ACUTE ACCENT 0x017E, // LATIN SMALL LETTER Z WITH CARON 0x017C, // LATIN SMALL LETTER Z WITH DOT ABOVE 0x0154, // LATIN CAPITAL LETTER R WITH ACUTE 0x00C1, // LATIN CAPITAL LETTER A WITH ACUTE 0x00C2, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX 0x0102, // LATIN CAPITAL LETTER A WITH BREVE 0x00C4, // LATIN CAPITAL LETTER A WITH DIAERESIS 0x0139, // LATIN CAPITAL LETTER L WITH ACUTE 0x0106, // LATIN CAPITAL LETTER C WITH ACUTE 0x00C7, // LATIN CAPITAL LETTER C WITH CEDILLA 0x010C, // LATIN CAPITAL LETTER C WITH CARON 0x00C9, // LATIN CAPITAL LETTER E WITH ACUTE 0x0118, // LATIN CAPITAL LETTER E WITH OGONEK 0x00CB, // LATIN CAPITAL LETTER E WITH DIAERESIS 0x011A, // LATIN CAPITAL LETTER E WITH CARON 0x00CD, // LATIN CAPITAL LETTER I WITH ACUTE 0x00CE, // LATIN CAPITAL LETTER I WITH CIRCUMFLEX 0x010E, // LATIN CAPITAL LETTER D WITH CARON 0x0110, // LATIN CAPITAL LETTER D WITH STROKE 0x0143, // LATIN CAPITAL LETTER N WITH ACUTE 0x0147, // LATIN CAPITAL LETTER N WITH CARON 0x00D3, // LATIN CAPITAL LETTER O WITH ACUTE 0x00D4, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX 0x0150, // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE 0x00D6, // LATIN CAPITAL LETTER O WITH DIAERESIS 0x00D7, // MULTIPLICATION SIGN 0x0158, // LATIN CAPITAL LETTER R WITH CARON 0x016E, // LATIN CAPITAL LETTER U WITH RING ABOVE 0x00DA, // LATIN CAPITAL LETTER U WITH ACUTE 0x0170, // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE 0x00DC, // LATIN CAPITAL LETTER U WITH DIAERESIS 0x00DD, // LATIN CAPITAL LETTER Y WITH ACUTE 0x0162, // LATIN CAPITAL LETTER T WITH CEDILLA 0x00DF, // LATIN SMALL LETTER SHARP S 0x0155, // LATIN SMALL LETTER R WITH ACUTE 0x00E1, // LATIN SMALL LETTER A WITH ACUTE 0x00E2, // LATIN SMALL LETTER A WITH CIRCUMFLEX 0x0103, // LATIN SMALL LETTER A WITH BREVE 0x00E4, // LATIN SMALL LETTER A WITH DIAERESIS 0x013A, // LATIN SMALL LETTER L WITH ACUTE 0x0107, // LATIN SMALL LETTER C WITH ACUTE 0x00E7, // LATIN SMALL LETTER C WITH CEDILLA 0x010D, // LATIN SMALL LETTER C WITH CARON 0x00E9, // LATIN SMALL LETTER E WITH ACUTE 0x0119, // LATIN SMALL LETTER E WITH OGONEK 0x00EB, // LATIN SMALL LETTER E WITH DIAERESIS 0x011B, // LATIN SMALL LETTER E WITH CARON 0x00ED, // LATIN SMALL LETTER I WITH ACUTE 0x00EE, // LATIN SMALL LETTER I WITH CIRCUMFLEX 0x010F, // LATIN SMALL LETTER D WITH CARON 0x0111, // LATIN SMALL LETTER D WITH STROKE 0x0144, // LATIN SMALL LETTER N WITH ACUTE 0x0148, // LATIN SMALL LETTER N WITH CARON 0x00F3, // LATIN SMALL LETTER O WITH ACUTE 0x00F4, // LATIN SMALL LETTER O WITH CIRCUMFLEX 0x0151, // LATIN SMALL LETTER O WITH DOUBLE ACUTE 0x00F6, // LATIN SMALL LETTER O WITH DIAERESIS 0x00F7, // DIVISION SIGN 0x0159, // LATIN SMALL LETTER R WITH CARON 0x016F, // LATIN SMALL LETTER U WITH RING ABOVE 0x00FA, // LATIN SMALL LETTER U WITH ACUTE 0x0171, // LATIN SMALL LETTER U WITH DOUBLE ACUTE 0x00FC, // LATIN SMALL LETTER U WITH DIAERESIS 0x00FD, // LATIN SMALL LETTER Y WITH ACUTE 0x0163, // LATIN SMALL LETTER T WITH CEDILLA 0x02D9 // DOT ABOVE }; const pdf_utf16be* PdfIso88592Encoding::GetToUnicodeTable() const { return PdfIso88592Encoding::s_cEncoding; } }; /* namespace PoDoFo */ podofo-0.9.5/src/base/PdfReference.h0000664000175000017500000002204013037210111017050 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_REFERENCE_H_ #define _PDF_REFERENCE_H_ #include "PdfDefines.h" #include "PdfDataType.h" namespace PoDoFo { typedef pdf_uint32 pdf_objnum; /* Technically a generation number must be able to represent 99999 so 65535 isn't good enough. * In practice Adobe's implementation notes suggest that they use a uint16 internally, and PDFs * with greater object numbers won't work on many viewers. So we'll stick with uint16. * * If you change this you'll need to change PdfReference::Write(...) to use the apppropriate * format, too. */ typedef pdf_uint16 pdf_gennum; class PdfOutputDevice; /** * A reference is a pointer to a object in the PDF file of the form * "4 0 R", where 4 is the object number and 0 is the generation number. * Every object in the PDF file can be identified this way. * * This class is a indirect reference in a PDF file. */ class PODOFO_API PdfReference : public PdfDataType { public: /** * Create a PdfReference with object number and generation number * initialized to 0. */ PdfReference() : m_nGenerationNo( 0 ), m_nObjectNo( 0 ) { } /** * Create a PdfReference to an object with a given object and generation number. * * \param nObjectNo the object number * \param nGenerationNo the generation number */ PdfReference( const pdf_objnum nObjectNo, const pdf_gennum nGenerationNo ) : m_nGenerationNo( nGenerationNo ), m_nObjectNo( nObjectNo ) { } /** * Create a copy of an existing PdfReference. * * \param rhs the object to copy */ PdfReference( const PdfReference & rhs ) : PdfDataType() { this->operator=( rhs ); } PODOFO_NOTHROW virtual ~PdfReference() { } /** Convert the reference to a string. * \returns a string representation of the object. * * \see PdfVariant::ToString */ const std::string ToString() const; /** * Assign the value of another object to this PdfReference. * * \param rhs the object to copy */ PODOFO_NOTHROW inline const PdfReference & operator=( const PdfReference & rhs ); /** Write the complete variant to an output device. * This is an overloaded member function. * * \param pDevice write the object to this device * \param eWriteMode additional options for writing this object * \param pEncrypt an encryption object which is used to encrypt this object * or NULL to not encrypt this object */ void Write( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, const PdfEncrypt* pEncrypt = NULL ) const; /** * Compare to PdfReference objects. * \returns true if both reference the same object */ PODOFO_NOTHROW inline bool operator==( const PdfReference & rhs ) const; /** * Compare to PdfReference objects. * \returns false if both reference the same object */ PODOFO_NOTHROW inline bool operator!=( const PdfReference & rhs ) const; /** * Compare to PdfReference objects. * \returns true if this reference has a smaller object and generation number */ PODOFO_NOTHROW inline bool operator<( const PdfReference & rhs ) const; /** Set the object number of this object * \param o the new object number */ PODOFO_NOTHROW inline void SetObjectNumber( pdf_objnum o ); /** Get the object number. * \returns the object number of this PdfReference */ PODOFO_NOTHROW inline pdf_objnum ObjectNumber() const; /** Set the generation number of this object * \param g the new generation number */ PODOFO_NOTHROW inline void SetGenerationNumber( const pdf_gennum g ); /** Get the generation number. * \returns the generation number of this PdfReference */ PODOFO_NOTHROW inline pdf_gennum GenerationNumber() const; /** Allows to check if a reference points to an indirect * object. * * A reference is indirect if object number and generation * number are both not equal 0. * * \returns true if this reference is the reference of * an indirect object. */ PODOFO_NOTHROW inline bool IsIndirect() const; private: // pdf_gennum (2 bytes) should appear before pdf_objnum (4 bytes) // because this reduces sizeof(PdfObject) from 64 bytes to 56 bytes // on 64-bit platforms by eliminating compiler alignment padding // order has no effect on structure size on 32-bit platforms // can save up 12.5% on some documents pdf_gennum m_nGenerationNo; pdf_objnum m_nObjectNo; }; // ----------------------------------------------------- // // ----------------------------------------------------- const PdfReference & PdfReference::operator=( const PdfReference & rhs ) { m_nObjectNo = rhs.m_nObjectNo; m_nGenerationNo = rhs.m_nGenerationNo; return *this; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfReference::operator<( const PdfReference & rhs ) const { return m_nObjectNo == rhs.m_nObjectNo ? m_nGenerationNo < rhs.m_nGenerationNo : m_nObjectNo < rhs.m_nObjectNo; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfReference::operator==( const PdfReference & rhs ) const { return ( m_nObjectNo == rhs.m_nObjectNo && m_nGenerationNo == rhs.m_nGenerationNo); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfReference::operator!=( const PdfReference & rhs ) const { return !this->operator==( rhs ); } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfReference::SetObjectNumber( pdf_objnum o ) { m_nObjectNo = o; } // ----------------------------------------------------- // // ----------------------------------------------------- pdf_objnum PdfReference::ObjectNumber() const { return m_nObjectNo; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfReference::SetGenerationNumber( pdf_gennum g ) { m_nGenerationNo = g; } // ----------------------------------------------------- // // ----------------------------------------------------- pdf_gennum PdfReference::GenerationNumber() const { return m_nGenerationNo; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfReference::IsIndirect() const { return !( !m_nObjectNo && !m_nGenerationNo ); } }; #endif // _PDF_REFERENCE_H_ podofo-0.9.5/src/base/PdfLocale.cpp0000664000175000017500000000151413013650710016716 0ustar dominikdominik#include "PdfDefines.h" #include "PdfLocale.h" #include "PdfError.h" #include "PdfDefinesPrivate.h" #include #include #include namespace PoDoFo { void PdfLocaleImbue(std::ios_base& s) { #if USE_CXX_LOCALE static const std::locale cachedLocale( PdfIOLocale ); try { s.imbue( cachedLocale ); } catch (const std::runtime_error & e) { std::ostringstream err; err << "Failed to set safe locale on stream being used for PDF I/O."; err << "Locale set was: \"" << PdfIOLocale << "\"."; err << "Error reported by STL std::locale: \"" << e.what() << "\""; // The info string is copied by PdfError so we're ok to just: PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, err.str().c_str() ); } #endif } }; podofo-0.9.5/src/base/PdfStream.cpp0000664000175000017500000002173013013650710016754 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfStream.h" #include "PdfArray.h" #include "PdfFilter.h" #include "PdfInputStream.h" #include "PdfOutputStream.h" #include "PdfOutputDevice.h" #include "PdfDefinesPrivate.h" #include #include using namespace std; namespace PoDoFo { enum EPdfFilter PdfStream::eDefaultFilter = ePdfFilter_FlateDecode; PdfStream::PdfStream( PdfObject* pParent ) : m_pParent( pParent ), m_bAppend( false ) { } PdfStream::~PdfStream() { } void PdfStream::GetFilteredCopy( PdfOutputStream* pStream ) const { TVecFilters vecFilters = PdfFilterFactory::CreateFilterList( m_pParent ); if( vecFilters.size() ) { PdfOutputStream* pDecodeStream = PdfFilterFactory::CreateDecodeStream( vecFilters, pStream, m_pParent ? &(m_pParent->GetDictionary()) : NULL ); try { pDecodeStream->Write( const_cast(this->GetInternalBuffer()), this->GetInternalBufferSize() ); pDecodeStream->Close(); } catch( PdfError & e ) { delete pDecodeStream; throw e; } delete pDecodeStream; } else { // Also work on unencoded streams pStream->Write( const_cast(this->GetInternalBuffer()), this->GetInternalBufferSize() ); } } void PdfStream::GetFilteredCopy( char** ppBuffer, pdf_long* lLen ) const { TVecFilters vecFilters = PdfFilterFactory::CreateFilterList( m_pParent ); PdfMemoryOutputStream stream; if( vecFilters.size() ) { // Use std::auto_ptr so that pDecodeStream is deleted // even in the case of an exception std::auto_ptr pDecodeStream( PdfFilterFactory::CreateDecodeStream( vecFilters, &stream, m_pParent ? &(m_pParent->GetDictionary()) : NULL ) ); pDecodeStream->Write( this->GetInternalBuffer(), this->GetInternalBufferSize() ); pDecodeStream->Close(); } else { // Also work on unencoded streams stream.Write( const_cast(this->GetInternalBuffer()), this->GetInternalBufferSize() ); stream.Close(); } *lLen = stream.GetLength(); *ppBuffer = stream.TakeBuffer(); } const PdfStream & PdfStream::operator=( const PdfStream & rhs ) { PdfMemoryInputStream stream( rhs.GetInternalBuffer(), rhs.GetInternalBufferSize() ); this->SetRawData( &stream ); if( m_pParent ) m_pParent->GetDictionary().AddKey( PdfName::KeyLength, PdfVariant(static_cast(rhs.GetInternalBufferSize()))); return (*this); } void PdfStream::Set( const char* szBuffer, pdf_long lLen, const TVecFilters & vecFilters ) { this->BeginAppend( vecFilters ); this->Append( szBuffer, lLen ); this->EndAppend(); } void PdfStream::Set( const char* szBuffer, pdf_long lLen ) { this->BeginAppend(); this->Append( szBuffer, lLen ); this->EndAppend(); } void PdfStream::Set( PdfInputStream* pStream ) { TVecFilters vecFilters; if( eDefaultFilter != ePdfFilter_None ) vecFilters.push_back( eDefaultFilter ); this->Set( pStream, vecFilters ); } void PdfStream::Set( PdfInputStream* pStream, const TVecFilters & vecFilters ) { const int BUFFER_SIZE = 4096; pdf_long lLen = 0; char buffer[BUFFER_SIZE]; this->BeginAppend( vecFilters ); do { lLen = pStream->Read( buffer, BUFFER_SIZE ); this->Append( buffer, lLen ); } while( lLen == BUFFER_SIZE ); this->EndAppend(); } void PdfStream::SetRawData( PdfInputStream* pStream, pdf_long lLen ) { const pdf_long BUFFER_SIZE = 4096; char buffer[BUFFER_SIZE]; pdf_long lRead; TVecFilters vecEmpty; // TODO: DS, give begin append a size hint so that it knows // how many data has to be allocated this->BeginAppend( vecEmpty, true, false ); if( lLen == -1 ) { do { lRead = pStream->Read( buffer, BUFFER_SIZE ); this->Append( buffer, lRead ); } while( lRead > 0 ); } else { do { lRead = pStream->Read( buffer, PDF_MIN( BUFFER_SIZE, lLen ), &lLen ); lLen -= lRead; this->Append( buffer, lRead ); } while( lLen && lRead > 0 ); } this->EndAppend(); } void PdfStream::BeginAppend( bool bClearExisting ) { TVecFilters vecFilters; if( eDefaultFilter != ePdfFilter_None ) vecFilters.push_back( eDefaultFilter ); this->BeginAppend( vecFilters, bClearExisting ); } void PdfStream::BeginAppend( const TVecFilters & vecFilters, bool bClearExisting, bool bDeleteFilters ) { char* pBuffer = NULL; pdf_long lLen = 0; //RG: TODO Should this variable be initialised with 0 (line 225 may fall through without initialisation!) PODOFO_RAISE_LOGIC_IF( m_bAppend, "BeginAppend() failed because EndAppend() was not yet called!" ); if( m_pParent && m_pParent->GetOwner() ) m_pParent->GetOwner()->BeginAppendStream( this ); if( !bClearExisting && this->GetLength() ) this->GetFilteredCopy( &pBuffer, &lLen ); if( !vecFilters.size() && bDeleteFilters && m_pParent) { m_pParent->GetDictionary().RemoveKey( PdfName::KeyFilter ); } if( vecFilters.size() == 1 && m_pParent) { m_pParent->GetDictionary().AddKey( PdfName::KeyFilter, PdfName( PdfFilterFactory::FilterTypeToName( vecFilters.front() ) ) ); } else if( vecFilters.size() > 1 && m_pParent) { PdfArray filters; TCIVecFilters it = vecFilters.begin(); while( it != vecFilters.end() ) { filters.push_back( PdfName( PdfFilterFactory::FilterTypeToName( *it ) ) ); ++it; } m_pParent->GetDictionary().AddKey( PdfName::KeyFilter, filters ); } this->BeginAppendImpl( vecFilters ); m_bAppend = true; if( pBuffer ) { this->Append( pBuffer, lLen ); podofo_free( pBuffer ); } } void PdfStream::EndAppend() { PODOFO_RAISE_LOGIC_IF( !m_bAppend, "EndAppend() failed because BeginAppend() was not yet called!" ); m_bAppend = false; this->EndAppendImpl(); if( m_pParent && m_pParent->GetOwner() ) m_pParent->GetOwner()->EndAppendStream( this ); } }; podofo-0.9.5/src/base/PdfError.h0000664000175000017500000005346713023513022016266 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_ERROR_H_ #define _PDF_ERROR_H_ // PdfError.h should not include PdfDefines.h, since it is included by it. // It should avoid depending on anything defined in PdfDefines.h . #include "podofoapi.h" #include #include #include #if defined(_MSC_VER) && _MSC_VER <= 1200 // same pragma as in PdfDefines.h which we cannot include here #pragma warning(disable: 4251) #pragma warning(disable: 4275) #endif /** \file PdfError.h * Error information and logging is implemented in this file. */ namespace PoDoFo { /** Error Code defines which are used in PdfError to describe the error. * * If you add an error code to this enum, please also add it to PdfError::ErrorName() * and PdfError::ErrorMessage(). * * \see PdfError */ enum EPdfError { ePdfError_ErrOk = 0, /**< The default value indicating no error. */ ePdfError_TestFailed, /**< Used in PoDoFo tests, to indicate that a test failed for some reason. */ ePdfError_InvalidHandle, /**< Null pointer was passed, but null pointer is not allowed. */ ePdfError_FileNotFound, /**< A file was not found or cannot be opened. */ ePdfError_InvalidDeviceOperation, /**< Tried to do something unsupported to an I/O device like seek a non-seekable input device */ ePdfError_UnexpectedEOF, /**< End of file was reached but data was expected. */ ePdfError_OutOfMemory, /**< Not enough memory to complete an operation. */ ePdfError_ValueOutOfRange, /**< The specified memory is out of the allowed range. */ ePdfError_InternalLogic, /**< An internal sanity check or assertion failed. */ ePdfError_InvalidEnumValue, /**< An invalid enum value was specified. */ ePdfError_PageNotFound, /**< The requested page could not be found in the PDF. */ ePdfError_NoPdfFile, /**< The file is no PDF file. */ ePdfError_NoXRef, /**< The PDF file has no or an invalid XRef table. */ ePdfError_NoTrailer, /**< The PDF file has no or an invalid trailer. */ ePdfError_NoNumber, /**< A number was expected in the PDF file, but the read string is no number. */ ePdfError_NoObject, /**< A object was expected and none was found. */ ePdfError_NoEOFToken, /**< The PDF file has no or an invalid EOF marker. */ ePdfError_InvalidTrailerSize, /**< The trailer size is invalid. */ ePdfError_InvalidLinearization, /**< The linearization directory of a web-optimized PDF file is invalid. */ ePdfError_InvalidDataType, /**< The passed datatype is invalid or was not recognized */ ePdfError_InvalidXRef, /**< The XRef table is invalid */ ePdfError_InvalidXRefStream, /**< A XRef steam is invalid */ ePdfError_InvalidXRefType, /**< The XRef type is invalid or was not found */ ePdfError_InvalidPredictor, /**< Invalid or unimplemented predictor */ ePdfError_InvalidStrokeStyle, /**< Invalid stroke style during drawing */ ePdfError_InvalidHexString, /**< Invalid hex string */ ePdfError_InvalidStream, /**< The stream is invalid */ ePdfError_InvalidStreamLength, /**< The stream length is invalid */ ePdfError_InvalidKey, /**< The specified key is invalid */ ePdfError_InvalidName, /**< The specified Name is not valid in this context */ ePdfError_InvalidEncryptionDict, /**< The encryption dictionary is invalid or misses a required key */ ePdfError_InvalidPassword, /**< The password used to open the PDF file was invalid */ ePdfError_InvalidFontFile, /**< The font file is invalid */ ePdfError_InvalidContentStream, /**< The content stream is invalid due to mismatched context pairing or other problems */ ePdfError_UnsupportedFilter, /**< The requested filter is not yet implemented. */ ePdfError_UnsupportedFontFormat, /**< This font format is not supported by PoDoFo. */ ePdfError_ActionAlreadyPresent, /**< An Action was already present when trying to add a Destination */ ePdfError_WrongDestinationType, /**< The requested field is not available for the given destination type */ ePdfError_MissingEndStream, /**< The required token endstream was not found. */ ePdfError_Date, /**< Date/time error */ ePdfError_Flate, /**< Error in zlib */ ePdfError_FreeType, /**< Error in FreeType */ ePdfError_SignatureError, /**< Error in signature */ ePdfError_MutexError, /**< Error during a mutex operation */ ePdfError_UnsupportedImageFormat, /**< This image format is not supported by PoDoFo. */ ePdfError_CannotConvertColor, /**< This color format cannot be converted. */ ePdfError_NotImplemented, /**< This feature is currently not implemented. */ ePdfError_DestinationAlreadyPresent,/**< A destination was already present when trying to add an Action */ ePdfError_ChangeOnImmutable, /**< Changing values on immutable objects is not allowed. */ ePdfError_NotCompiled, /**< This feature was disabled at compile time. */ ePdfError_OutlineItemAlreadyPresent,/**< An outline item to be inserted was already in that outlines tree. */ ePdfError_NotLoadedForUpdate, /**< The document had not been loaded for update. */ ePdfError_CannotEncryptedForUpdate, /**< Cannot load encrypted documents for update. */ ePdfError_Unknown = 0xffff /**< Unknown error */ }; /** * Used in PdfError::LogMessage to specify the log level. * * \see PdfError::LogMessage */ enum ELogSeverity { eLogSeverity_Critical, /**< Critical unexpected error */ eLogSeverity_Error, /**< Error */ eLogSeverity_Warning, /**< Warning */ eLogSeverity_Information, /**< Information message */ eLogSeverity_Debug, /**< Debug information */ eLogSeverity_None, /**< No specified level */ eLogSeverity_Unknown = 0xffff /**< Unknown log level */ }; /** \def PODOFO_RAISE_ERROR( x ) * * Set the value of the variable eCode (which has to exist in the current function) to x * and return the eCode. */ #define PODOFO_RAISE_ERROR( x ) throw ::PoDoFo::PdfError( x, __FILE__, __LINE__ ); /** \def PODOFO_RAISE_ERROR_INFO( x, y ) * * Set the value of the variable eCode (which has to exist in the current function) to x * and return the eCode. Additionally additional information on the error y is set. y has * to be an c-string. */ #define PODOFO_RAISE_ERROR_INFO( x, y ) throw ::PoDoFo::PdfError( x, __FILE__, __LINE__, y ); /** \def PODOFO_RAISE_LOGIC_IF( x, y ) * * Evaluate `x' as a binary predicate and if it is true, raise a logic error with the * info string `y' . * * This macro will be undefined when NDEBUG is set, so it's compiled out for release * builds. Use it for expensive or extremely frequent sanity checking. * * We define it then UNDEF it to help out doxygen. */ #ifndef NDEBUG // Woo for double-negatives. We define PODOFO_RAISE_LOGIC_IF unless we've been told not to by NDEBUG. #define PODOFO_RAISE_LOGIC_IF( x, y ) { if (x) throw ::PoDoFo::PdfError( ePdfError_InternalLogic, __FILE__, __LINE__, y ); }; #else #define PODOFO_RAISE_LOGIC_IF( x, y ) {}; #endif class PODOFO_API PdfErrorInfo { public: PdfErrorInfo(); PdfErrorInfo( int line, const char* pszFile, const char* pszInfo ); PdfErrorInfo( int line, const char* pszFile, const wchar_t* pszInfo ); PdfErrorInfo( const PdfErrorInfo & rhs ); const PdfErrorInfo & operator=( const PdfErrorInfo & rhs ); inline int GetLine() const { return m_nLine; } inline const std::string & GetFilename() const { return m_sFile; } inline const std::string & GetInformation() const { return m_sInfo; } inline const std::wstring & GetInformationW() const { return m_swInfo; } inline void SetInformation( const char* pszInfo ) { m_sInfo = pszInfo ? pszInfo : ""; } inline void SetInformation( const wchar_t* pszInfo ) { m_swInfo = pszInfo ? pszInfo : L""; } private: int m_nLine; std::string m_sFile; std::string m_sInfo; std::wstring m_swInfo; }; typedef std::deque TDequeErrorInfo; typedef TDequeErrorInfo::iterator TIDequeErrorInfo; typedef TDequeErrorInfo::const_iterator TCIDequeErrorInfo; // This is required to generate the documentation with Doxygen. // Without this define doxygen thinks we have a class called PODOFO_EXCEPTION_API(PODOFO_API) ... #define PODOFO_EXCEPTION_API_DOXYGEN PODOFO_EXCEPTION_API(PODOFO_API) /** The error handling class of PoDoFo lib. * Whenever a function encounters an error * a PdfError object is returned. * * A PdfError with Error() == ErrOk means * successfull execution. * * This class provides also meaningfull * error descriptions. */ class PODOFO_EXCEPTION_API_DOXYGEN PdfError { public: // OC 17.08.2010 New to optionally replace stderr output by a callback: class LogMessageCallback { public: virtual ~LogMessageCallback() {} // every class with virtual methods needs a virtual destructor virtual void LogMessage( ELogSeverity eLogSeverity, const char* pszPrefix, const char* pszMsg, va_list & args ) = 0; virtual void LogMessage( ELogSeverity eLogSeverity, const wchar_t* pszPrefix, const wchar_t* pszMsg, va_list & args ) = 0; }; /** Set a global static LogMessageCallback functor to repleace stderr output in LogMessageInternal * \param fLogMessageCallback the pointer to the new callback functor object * \returns the pointer to the previous callback functor object */ static LogMessageCallback* SetLogMessageCallback(LogMessageCallback* fLogMessageCallback); /** Create a PdfError object initialized to ErrOk */ PdfError(); /** Create a PdfError object with a given error code. * \param eCode the error code of this object * \param pszFile the file in which the error has occured. * Use the compiler macro __FILE__ to initialize the field. * \param line the line in which the error has occured. * Use the compiler macro __LINE__ to initialize the field. * \param pszInformation additional information on this error which mayy * be formatted like printf */ PdfError( const EPdfError & eCode, const char* pszFile = NULL, int line = 0, const char* pszInformation = NULL ); /** Copy constructor * \param rhs copy the contents of rhs into this object */ PdfError( const PdfError & rhs ); virtual ~PdfError() throw(); /** Assignment operator * \param rhs another PdfError object * \returns this object */ const PdfError & operator=( const PdfError & rhs ); /** Overloaded assignment operator * \param eCode a EPdfError code * \returns this object */ const PdfError & operator=( const EPdfError & eCode ); /** Comparison operator compares 2 PdfError objects * \param rhs another PdfError object * \returns true if both objects have the same error code. */ bool operator==( const PdfError & rhs ); /** Overloaded comparison operator compares 2 PdfError objects * \param eCode an erroce code * \returns true if this object has the same error code. */ bool operator==( const EPdfError & eCode ); /** Comparison operator compares 2 PdfError objects * \param rhs another PdfError object * \returns true if both objects have the different error code. */ bool operator!=( const PdfError & rhs ); /** Overloaded comparison operator compares 2 PdfError objects * \param eCode an erroce code * \returns true if this object has different error code. */ bool operator!=( const EPdfError & eCode ); /** Return the error code of this object * \returns the error code of this object */ inline EPdfError GetError() const; /** Get access to the internal callstack of this error * \return the callstack */ inline const TDequeErrorInfo & GetCallstack() const; /** Set the error code of this object. * \param eCode the error code of this object * \param pszFile the filename of the source file causing * the error or NULL. Typically you will use * the gcc macro __FILE__ here. * \param line the line of source causing the error * or 0. Typically you will use the gcc * macro __LINE__ here. * \param pszInformation additional information on the error. * e.g. how to fix the error. This string is intended to * be shown to the user. */ inline void SetError( const EPdfError & eCode, const char* pszFile = NULL, int line = 0, const char* pszInformation = NULL ); /** Set additional error informatiom * \param pszInformation additional information on the error. * e.g. how to fix the error. This string is intended to * be shown to the user. */ inline void SetErrorInformation( const char* pszInformation ); /** Set additional error informatiom * \param pszInformation additional information on the error. * e.g. how to fix the error. This string is intended to * be shown to the user. */ inline void SetErrorInformation( const wchar_t* pszInformation ); /** Add callstack information to an error object. Always call this function * if you get an error object but do not handle the error but throw it again. * * \param pszFile the filename of the source file causing * the error or NULL. Typically you will use * the gcc macro __FILE__ here. * \param line the line of source causing the error * or 0. Typically you will use the gcc * macro __LINE__ here. * \param pszInformation additional information on the error. * e.g. how to fix the error. This string is intended to * be shown to the user. */ inline void AddToCallstack( const char* pszFile = NULL, int line = 0, const char* pszInformation = NULL ); /** \returns true if an error code was set * and false if the error code is ePdfError_ErrOk */ inline bool IsError() const; /** Print an error message to stderr */ void PrintErrorMsg() const; /** Obtain error description. * \returns a c string describing the error. */ const char* what() const; /** Get the name for a certain error code. * \returns the name or NULL if no name for the specified * error code is available. */ PODOFO_NOTHROW static const char* ErrorName( EPdfError eCode ); /** Get the error message for a certain error code. * \returns the error message or NULL if no error * message for the specified error code * is available. */ static const char* ErrorMessage( EPdfError eCode ); /** Log a message to the logging system defined for PoDoFo. * \param eLogSeverity the severity of the log message * \param pszMsg the message to be logged */ static void LogMessage( ELogSeverity eLogSeverity, const char* pszMsg, ... ); /** Log a message to the logging system defined for PoDoFo. * \param eLogSeverity the severity of the log message * \param pszMsg the message to be logged */ static void LogMessage( ELogSeverity eLogSeverity, const wchar_t* pszMsg, ... ); /** Enable or disable Logging * \param bEnable enable (true) or disable (false) */ static void EnableLogging( bool bEnable ); /** Is the display of debugging messages enabled or not? */ static bool LoggingEnabled(); /** Log a message to the logging system defined for PoDoFo for debugging * \param pszMsg the message to be logged */ static void DebugMessage( const char* pszMsg, ... ); /** Enable or disable the display of debugging messages * \param bEnable enable (true) or disable (false) */ static void EnableDebug( bool bEnable ); /** Is the display of debugging messages enabled or not? */ static bool DebugEnabled(); private: /** Log a message to the logging system defined for PoDoFo. * * This call does not check if logging is enabled and always * prints the error message. * * \param eLogSeverity the severity of the log message * \param pszMsg the message to be logged */ static void LogErrorMessage( ELogSeverity eLogSeverity, const char* pszMsg, ... ); /** Log a message to the logging system defined for PoDoFo. * * This call does not check if logging is enabled and always * prints the error message * * \param eLogSeverity the severity of the log message * \param pszMsg the message to be logged */ static void LogErrorMessage( ELogSeverity eLogSeverity, const wchar_t* pszMsg, ... ); static void LogMessageInternal( ELogSeverity eLogSeverity, const char* pszMsg, va_list & args ); static void LogMessageInternal( ELogSeverity eLogSeverity, const wchar_t* pszMsg, va_list & args ); private: EPdfError m_error; TDequeErrorInfo m_callStack; static bool s_DgbEnabled; static bool s_LogEnabled; // OC 17.08.2010 New to optionally replace stderr output by a callback: static LogMessageCallback* m_fLogMessageCallback; }; // ----------------------------------------------------- // // ----------------------------------------------------- EPdfError PdfError::GetError() const { return m_error; } // ----------------------------------------------------- // // ----------------------------------------------------- const TDequeErrorInfo & PdfError::GetCallstack() const { return m_callStack; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfError::SetError( const EPdfError & eCode, const char* pszFile, int line, const char* pszInformation ) { m_error = eCode; this->AddToCallstack( pszFile, line, pszInformation ); } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfError::AddToCallstack( const char* pszFile, int line, const char* pszInformation ) { m_callStack.push_front( PdfErrorInfo( line, pszFile, pszInformation ) ); } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfError::SetErrorInformation( const char* pszInformation ) { if( m_callStack.size() ) m_callStack.front().SetInformation( pszInformation ? pszInformation : "" ); } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfError::SetErrorInformation( const wchar_t* pszInformation ) { if( m_callStack.size() ) m_callStack.front().SetInformation( pszInformation ? pszInformation : L"" ); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfError::IsError() const { return (m_error != ePdfError_ErrOk); } }; #endif /* _PDF_ERROR_H_ */ podofo-0.9.5/src/base/PdfOutputStream.h0000664000175000017500000002132413013650710017641 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_OUTPUT_STREAM_H_ #define _PDF_OUTPUT_STREAM_H_ #include "PdfDefines.h" #include "PdfRefCountedBuffer.h" #include namespace PoDoFo { #define INITIAL_SIZE 4096 class PdfOutputDevice; /** An interface for writing blocks of data to * a data source. */ class PODOFO_API PdfOutputStream { public: virtual ~PdfOutputStream() { }; /** Write data to the output stream * * \param pBuffer the data is read from this buffer * \param lLen the size of the buffer * * \returns the number of bytes written, -1 if an error ocurred */ virtual pdf_long Write( const char* pBuffer, pdf_long lLen ) = 0; /** * Helper that writes a string via Write(const char*,long) */ inline pdf_long Write( const std::string & s ); /** Close the PdfOutputStream. * This method may throw exceptions and has to be called * before the descructor to end writing. * * No more data may be written to the output device * after calling close. */ virtual void Close() = 0; }; inline pdf_long PdfOutputStream::Write( const std::string & s ) { return this->Write( s.data(), s.size() ); } /** An output stream that writes data to a file */ class PODOFO_API PdfFileOutputStream : public PdfOutputStream { public: /** Open a file for writing data * * \param pszFilename the filename of the file to read */ PdfFileOutputStream( const char* pszFilename ); virtual ~PdfFileOutputStream(); /** Write data to the output stream * * \param pBuffer the data is read from this buffer * \param lLen the size of the buffer * * \returns the number of bytes written, -1 if an error ocurred */ virtual pdf_long Write( const char* pBuffer, pdf_long lLen ); /** Close the PdfOutputStream. * This method may throw exceptions and has to be called * before the descructor to end writing. * * No more data may be written to the output device * after calling close. */ virtual void Close(); private: FILE* m_hFile; }; /** An output stream that writes data to a memory buffer * If the buffer is to small, it will be enlarged automatically. * * DS: TODO: remove in favour of PdfBufferOutputStream. */ class PODOFO_API PdfMemoryOutputStream : public PdfOutputStream { public: /** * Construct a new PdfMemoryOutputStream * \param lInitial initial size of the buffer */ PdfMemoryOutputStream( pdf_long lInitial = INITIAL_SIZE); /** * Construct a new PdfMemoryOutputStream that writes to an existing buffer * \param pBuffer handle to the buffer * \param lLen length of the buffer */ PdfMemoryOutputStream( char* pBuffer, pdf_long lLen ); ~PdfMemoryOutputStream(); /** Write data to the output stream * * \param pBuffer the data is read from this buffer * \param lLen the size of the buffer * * \returns the number of bytes written, -1 if an error ocurred */ virtual pdf_long Write( const char* pBuffer, pdf_long lLen ); /** Close the PdfOutputStream. * This method may throw exceptions and has to be called * before the descructor to end writing. * * No more data may be written to the output device * after calling close. */ virtual void Close() { } /** \returns the length of the written data */ inline pdf_long GetLength() const; /** * \returns a handle to the internal buffer. * * The internal buffer is now owned by the caller * and will not be deleted by PdfMemoryOutputStream. * Further calls to Write() are not allowed. * * The caller has to free() the returned malloc()'ed buffer! */ inline char* TakeBuffer(); private: char* m_pBuffer; pdf_long m_lLen; pdf_long m_lSize; bool m_bOwnBuffer; }; // ----------------------------------------------------- // // ----------------------------------------------------- inline pdf_long PdfMemoryOutputStream::GetLength() const { return m_lLen; } // ----------------------------------------------------- // // ----------------------------------------------------- inline char* PdfMemoryOutputStream::TakeBuffer() { char* pBuffer = m_pBuffer; m_pBuffer = NULL; return pBuffer; } /** An output stream that writes to a PdfOutputDevice */ class PODOFO_API PdfDeviceOutputStream : public PdfOutputStream { public: /** * Write to an already opened input device * * \param pDevice an output device */ PdfDeviceOutputStream( PdfOutputDevice* pDevice ); /** Write data to the output stream * * \param pBuffer the data is read from this buffer * \param lLen the size of the buffer * * \returns the number of bytes written, -1 if an error ocurred */ virtual pdf_long Write( const char* pBuffer, pdf_long lLen ); /** Close the PdfOutputStream. * This method may throw exceptions and has to be called * before the descructor to end writing. * * No more data may be written to the output device * after calling close. */ virtual void Close() {} private: PdfOutputDevice* m_pDevice; }; /** An output stream that writes to a PdfRefCountedBuffer. * * The PdfRefCountedBuffer is resized automatically if necessary. */ class PODOFO_API PdfBufferOutputStream : public PdfOutputStream { public: /** * Write to an already opened input device * * \param pBuffer data is written to this buffer */ PdfBufferOutputStream( PdfRefCountedBuffer* pBuffer ) : m_pBuffer( pBuffer ), m_lLength( pBuffer->GetSize() ) { } /** Write data to the output stream * * \param pBuffer the data is read from this buffer * \param lLen the size of the buffer * * \returns the number of bytes written, -1 if an error ocurred */ virtual pdf_long Write( const char* pBuffer, pdf_long lLen ); virtual void Close() { } /** * \returns the length of the buffers contents */ inline pdf_long GetLength() const { return m_lLength; } private: PdfRefCountedBuffer* m_pBuffer; pdf_long m_lLength; }; }; #endif // _PDF_OUTPUT_STREAM_H_ podofo-0.9.5/src/base/PdfCompilerCompatPrivate.h0000664000175000017500000001515711641323033021445 0ustar dominikdominik#ifndef _PDF_COMPILERCOMPAT_PRIVATE_H #define _PDF_COMPILERCOMPAT_PRIVATE_H #ifndef _PDF_DEFINES_PRIVATE_H_ #error Include PdfDefinesPrivate.h instead #endif #if defined(__BORLANDC__) || defined( __TURBOC__) // Borland Turbo C has a broken "" but provides a usable "math.h" // and it needs a bunch of other includes # include # include # include # include # include #else // We can use the ISO C++ headers with other compilers # include # include # include # include # include #endif #if PODOFO_HAVE_WINSOCK2_H # ifdef PODOFO_MULTI_THREAD # if defined(_WIN32) || defined(_WIN64) # ifndef _WIN32_WINNT # define _WIN32_WINNT 0x0400 // Make the TryEnterCriticalSection method available # include // This will include windows.h, so we have to define _WIN32_WINNT // if we want to use threads later. # undef _WIN32_WINNT # else # include # endif // _WIN32_WINNT # endif // _WIN32 || _WIN64 # else # include # endif // PODOFO_MULTI_THREAD #endif #if PODOFO_HAVE_ARPA_INET_H # include #endif #ifdef PODOFO_MULTI_THREAD # if defined(_WIN32) || defined(_WIN64) # if defined(_MSC_VER) && !defined(_WINSOCK2API_) # error must be included before , config problem? # endif # ifndef _WIN32_WINNT # define _WIN32_WINNT 0x0400 // Make the TryEnterCriticalSection method available # include # undef _WIN32_WINNT # else # include # endif // _WIN32_WINNT # else # include # endif // _WIN32 #endif // PODOFO_MULTI_THREAD #if defined(_WIN32) || defined(_WIN64) # if defined(GetObject) # undef GetObject // Horrible windows.h macro definition that breaks things # endif # if defined(DrawText) # undef DrawText // Horrible windows.h macro definition that breaks things # endif # if defined(CreateFont) # undef CreateFont # endif #endif namespace PoDoFo { namespace compat { // Case-insensitive string compare functions aren't very portable, and we must account // for several flavours. inline static int strcasecmp( const char * s1, const char * s2) { #if defined(_WIN32) || defined (_WIN64) # if defined(_MSC_VER) // MSVC++ return ::_stricmp(s1, s2); # else return ::stricmp(s1, s2); # endif #else // POSIX.1-2001 return ::strcasecmp(s1, s2); #endif } inline static int strncasecmp( const char * s1, const char * s2, size_t n) { #if defined(_WIN32) || defined(_WIN64) # if defined(_MSC_VER) // MSVC++ return ::_strnicmp(s1, s2, n); # else return ::strnicmp(s1, s2, n); # endif #else // POSIX.1-2001 return ::strncasecmp(s1, s2, n); #endif } inline static double logb(double x) { #if defined(_WIN32) || defined(_WIN64) return ::log(x); #else return ::logb(x); #endif } /* * We define inline wrappers for htons and friends here so that * any issues with integer types can be contained to just this * source file. * * These functions are defined to do NOTHING when * host byte order == network byte order (ie: on big endian hosts) * so you do NOT need to #ifdef them. They'll be inlined and * then optimized out with any sane compiler and C library. */ inline static pdf_uint32 podofo_ntohl(pdf_uint32 i) { #if defined(_WIN32) && defined(_MSC_VER) return (pdf_uint32)( ntohl( i ) ); #else return static_cast( ntohl( i ) ); #endif // _WIN32 } inline static pdf_uint16 podofo_ntohs(pdf_uint16 i) { #if defined(_WIN32) && defined(_MSC_VER) return (pdf_uint16)( ntohs( i ) ); #else return static_cast( ntohs( i ) ); #endif // _WIN32 } inline static pdf_uint32 podofo_htonl(pdf_uint32 i) { #if defined(_WIN32) && defined(_MSC_VER) return (pdf_uint32)( htonl( i ) ); #else return static_cast( htonl( i ) ); #endif // _WIN32 } inline static pdf_uint16 podofo_htons(pdf_uint16 i) { #if defined(_WIN32) && defined(_MSC_VER) return (pdf_uint16)( htons( i ) ); #else return static_cast( htons( i ) ); #endif // _WIN32 } };}; // end namespace PoDoFo::compat /* * This is needed to enable compilation with VC++ on Windows, which likes to prefix * many functions with underscores. * * TODO: These should probably be inline wrappers instead, and we need to consolidate * hacks from the rest of the code where other _underscore_prefixed_names are checked * for here. */ #ifdef _MSC_VER #define snprintf _snprintf #define vsnprintf _vsnprintf #endif #if defined(_WIN64) #define fseeko _fseeki64 #define ftello _ftelli64 #else #define fseeko fseek #define ftello ftell #endif /** * \def PODOFO_UNUSED( x ) * Make a certain variable to be unused * in the code, without getting a compiler * warning. */ #ifndef _WIN32 template inline void podofo_unused(T &t) { (void)t; } #define PODOFO_UNUSED( x ) podofo_unused( x ); #else #define PODOFO_UNUSED( x ) (void)x; #endif // _WIN32 // OC 17.08.2010: Activate showing the correct source for Memory Leak Detection in Visual Studio: // See: looking for _AFX_NO_DEBUG_CRT #ifdef _MSC_VER #if defined(_DEBUG) && defined(DEFINE_NEW_DEBUG_NEW) // fuer crtdbg.h und malloc.h #define _CRTDBG_MAP_ALLOC #include #include void* operator new(size_t ai_NewSize, const char* ac_File_, int ai_Line); void operator delete(void* av_Ptr_, const char* ac_File_, int ai_Line); #define DEBUG_NEW new(__FILE__, __LINE__) #define new DEBUG_NEW // doesnt work: // // _NEW_CRT is defined in // // #define new _NEW_CRT #endif // _DEBUG #endif // _MSC_VER /** * \page PoDoFo PdfCompilerCompatPrivate Header * * PdfCompilerCompatPrivate.h gathers up nastyness required for various * compiler compatibility into a central place. All compiler-specific defines, * wrappers, and the like should be included here and (if necessary) in * PdfCompilerCompatPrivate.cpp. If the must be visible to library users * they're put in PdfCompilerCompat.{cpp,h} instead. * * PdfCompilerCompatPrivate.h is private to PoDoFo's build process. It is not * used by library clients, the tools, or the unit tests. It is not installed * with PoDoFo and must never be visible in the public headers. * * Include PdfCompilerCompatPrivate.h in your .cpp sources, preferably after * including other PoDoFo headers. * * Please NEVER use symbols from this header or the PoDoFo::compat namespace in * a "using" directive. Always explicitly reference names so it's clear that * you're pulling them from the compat cruft. */ #endif podofo-0.9.5/src/base/PdfTokenizer.cpp0000664000175000017500000006523313014325624017505 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfTokenizer.h" #include "PdfArray.h" #include "PdfDictionary.h" #include "PdfEncrypt.h" #include "PdfInputDevice.h" #include "PdfName.h" #include "PdfString.h" #include "PdfReference.h" #include "PdfVariant.h" #include "PdfDefinesPrivate.h" #include #include #include #include #define PDF_BUFFER 4096 #define DICT_SEP_LENGTH 2 #define NULL_LENGTH 4 #define TRUE_LENGTH 4 #define FALSE_LENGTH 5 namespace PoDoFo { namespace PdfTokenizerNameSpace{ static const int g_MapAllocLen = 256; static char g_DelMap[g_MapAllocLen] = { 0 }; static char g_WsMap[g_MapAllocLen] = { 0 }; static char g_EscMap[g_MapAllocLen] = { 0 }; static char g_hexMap[g_MapAllocLen] = { 0 }; // Generate the delimiter character map at runtime // so that it can be derived from the more easily // maintainable structures in PdfDefines.h const char * genDelMap() { char* map = static_cast(g_DelMap); memset( map, 0, sizeof(char) * g_MapAllocLen ); for (int i = 0; i < PoDoFo::s_nNumDelimiters; ++i) { map[static_cast(PoDoFo::s_cDelimiters[i])] = 1; } return map; } // Generate the whitespace character map at runtime // so that it can be derived from the more easily // maintainable structures in PdfDefines.h const char * genWsMap() { char* map = static_cast(g_WsMap); memset( map, 0, sizeof(char) * g_MapAllocLen ); for (int i = 0; i < PoDoFo::s_nNumWhiteSpaces; ++i) { map[static_cast(PoDoFo::s_cWhiteSpaces[i])] = 1; } return map; } // Generate the escape character map at runtime const char* genEscMap() { char* map = static_cast(g_EscMap); memset( map, 0, sizeof(char) * g_MapAllocLen ); map[static_cast('n')] = '\n'; // Line feed (LF) map[static_cast('r')] = '\r'; // Carriage return (CR) map[static_cast('t')] = '\t'; // Horizontal tab (HT) map[static_cast('b')] = '\b'; // Backspace (BS) map[static_cast('f')] = '\f'; // Form feed (FF) map[static_cast(')')] = ')'; map[static_cast('(')] = '('; map[static_cast('\\')] = '\\'; return map; } // Generate the hex character map at runtime const char* genHexMap() { char* map = static_cast(g_hexMap); memset( map, PdfTokenizer::HEX_NOT_FOUND, sizeof(char) * g_MapAllocLen ); map[static_cast('0')] = 0x0; map[static_cast('1')] = 0x1; map[static_cast('2')] = 0x2; map[static_cast('3')] = 0x3; map[static_cast('4')] = 0x4; map[static_cast('5')] = 0x5; map[static_cast('6')] = 0x6; map[static_cast('7')] = 0x7; map[static_cast('8')] = 0x8; map[static_cast('9')] = 0x9; map[static_cast('a')] = 0xA; map[static_cast('b')] = 0xB; map[static_cast('c')] = 0xC; map[static_cast('d')] = 0xD; map[static_cast('e')] = 0xE; map[static_cast('f')] = 0xF; map[static_cast('A')] = 0xA; map[static_cast('B')] = 0xB; map[static_cast('C')] = 0xC; map[static_cast('D')] = 0xD; map[static_cast('E')] = 0xE; map[static_cast('F')] = 0xF; return map; } }; const unsigned int PdfTokenizer::HEX_NOT_FOUND = std::numeric_limits::max(); const char * const PdfTokenizer::s_delimiterMap = PdfTokenizerNameSpace::genDelMap(); const char * const PdfTokenizer::s_whitespaceMap = PdfTokenizerNameSpace::genWsMap(); const char * const PdfTokenizer::s_escMap = PdfTokenizerNameSpace::genEscMap(); const char * const PdfTokenizer::s_hexMap = PdfTokenizerNameSpace::genHexMap(); const char PdfTokenizer::s_octMap[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; PdfTokenizer::PdfTokenizer() : m_buffer( PDF_BUFFER ) { PdfLocaleImbue(m_doubleParser); } PdfTokenizer::PdfTokenizer( const char* pBuffer, size_t lLen ) : m_device( pBuffer, lLen ), m_buffer( PDF_BUFFER ) { PdfLocaleImbue(m_doubleParser); } PdfTokenizer::PdfTokenizer( const PdfRefCountedInputDevice & rDevice, const PdfRefCountedBuffer & rBuffer ) : m_device( rDevice ), m_buffer( rBuffer ) { PdfLocaleImbue(m_doubleParser); } PdfTokenizer::~PdfTokenizer() { } bool PdfTokenizer::GetNextToken( const char*& pszToken , EPdfTokenType* peType ) { int c; pdf_int64 counter = 0; // check first if there are queued tokens and return them first if( m_deqQueque.size() ) { TTokenizerPair pair = m_deqQueque.front(); m_deqQueque.pop_front(); if( peType ) *peType = pair.second; if ( !m_buffer.GetBuffer() || m_buffer.GetSize() == 0) { PODOFO_RAISE_ERROR(ePdfError_InvalidHandle); } // make sure buffer is \0 terminated strncpy(m_buffer.GetBuffer(), pair.first.c_str(), m_buffer.GetSize()); m_buffer.GetBuffer()[m_buffer.GetSize() - 1] = 0; pszToken = m_buffer.GetBuffer(); return true; } if( !m_device.Device() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if( peType ) *peType = ePdfTokenType_Token; while( (c = m_device.Device()->Look()) != EOF && counter < static_cast(m_buffer.GetSize()) ) { // ignore leading whitespaces if( !counter && IsWhitespace( c ) ) { // Consume the whitespace character c = m_device.Device()->GetChar(); continue; } // ignore comments else if( c == '%' ) { // Consume all characters before the next line break // 2011-04-19 Ulrich Arnold: accept 0x0D, 0x0A and oX0D 0x0A as one EOL do { c = m_device.Device()->GetChar(); } while( c != EOF && c != 0x0D && c != 0x0A ); if ( c == 0x0D ) { if ( m_device.Device()->Look() == 0x0A ) c = m_device.Device()->GetChar(); } // If we've already read one or more chars of a token, return them, since // comments are treated as token-delimiting whitespace. Otherwise keep reading // at the start of the next line. if (counter) break; } // special handling for << and >> tokens else if( !counter && (c == '<' || c == '>' ) ) { if( peType ) *peType = ePdfTokenType_Delimiter; // retrieve c really from stream c = m_device.Device()->GetChar(); m_buffer.GetBuffer()[counter] = c; ++counter; char n = m_device.Device()->Look(); // Is n another < or > , ie are we opening/closing a dictionary? // If so, consume that character too. if( n == c ) { n = m_device.Device()->GetChar(); m_buffer.GetBuffer()[counter] = n; ++counter; } // `m_buffer' contains one of < , > , << or >> ; we're done . break; } else if( counter && (IsWhitespace( c ) || IsDelimiter( c )) ) { // Next (unconsumed) character is a token-terminating char, so // we have a complete token and can return it. break; } else { // Consume the next character and add it to the token we're building. c = m_device.Device()->GetChar(); m_buffer.GetBuffer()[counter] = c; ++counter; if( IsDelimiter( c ) ) { // All delimeters except << and >> (handled above) are // one-character tokens, so if we hit one we can just return it // immediately. if( peType ) *peType = ePdfTokenType_Delimiter; break; } } } m_buffer.GetBuffer()[counter] = '\0'; if( c == EOF && !counter ) { // No characters were read before EOF, so we're out of data. // Ensure the buffer points to NULL in case someone fails to check the return value. pszToken = 0; return false; } pszToken = m_buffer.GetBuffer(); return true; } bool PdfTokenizer::IsNextToken( const char* pszToken ) { if( !pszToken ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } const char* pszRead; bool gotToken = this->GetNextToken( pszRead, NULL ); if (!gotToken) { PODOFO_RAISE_ERROR( ePdfError_UnexpectedEOF ); } return (strcmp( pszToken, pszRead ) == 0); } pdf_long PdfTokenizer::GetNextNumber() { EPdfTokenType eType; const char* pszRead; bool gotToken = this->GetNextToken( pszRead, &eType ); if( !gotToken ) { PODOFO_RAISE_ERROR_INFO( ePdfError_UnexpectedEOF, "Expected number" ); } char* end; #ifdef _WIN64 pdf_long l = _strtoui64( pszRead, &end, 10 ); #else pdf_long l = strtol( pszRead, &end, 10 ); #endif if( end == pszRead ) { // Don't consume the token this->QuequeToken( pszRead, eType ); PODOFO_RAISE_ERROR_INFO( ePdfError_NoNumber, pszRead ); } return l; } void PdfTokenizer::GetNextVariant( PdfVariant& rVariant, PdfEncrypt* pEncrypt ) { EPdfTokenType eTokenType; const char* pszRead; bool gotToken = this->GetNextToken( pszRead, &eTokenType ); if (!gotToken) { PODOFO_RAISE_ERROR_INFO( ePdfError_UnexpectedEOF, "Expected variant." ); } this->GetNextVariant( pszRead, eTokenType, rVariant, pEncrypt ); } void PdfTokenizer::GetNextVariant( const char* pszToken, EPdfTokenType eType, PdfVariant& rVariant, PdfEncrypt* pEncrypt ) { EPdfDataType eDataType = this->DetermineDataType( pszToken, eType, rVariant ); if( eDataType == ePdfDataType_Null || eDataType == ePdfDataType_Bool || eDataType == ePdfDataType_Number || eDataType == ePdfDataType_Real || eDataType == ePdfDataType_Reference ) { // the data was already read into rVariant by the DetermineDataType function return; } this->ReadDataType( eDataType, rVariant, pEncrypt ); } EPdfDataType PdfTokenizer::DetermineDataType( const char* pszToken, EPdfTokenType eTokenType, PdfVariant& rVariant ) { if( eTokenType == ePdfTokenType_Token ) { // check for the two special datatypes // null and boolean. // check for numbers if( strncmp( "null", pszToken, NULL_LENGTH ) == 0 ) { rVariant = PdfVariant(); return ePdfDataType_Null; } else if( strncmp( "true", pszToken, TRUE_LENGTH ) == 0 ) { rVariant = PdfVariant( true ); return ePdfDataType_Bool; } else if( strncmp( "false", pszToken, FALSE_LENGTH ) == 0 ) { rVariant = PdfVariant( false ); return ePdfDataType_Bool; } EPdfDataType eDataType = ePdfDataType_Number; const char* pszStart = pszToken; while( *pszStart ) { if( *pszStart == '.' ) eDataType = ePdfDataType_Real; else if( !(isdigit( static_cast(*pszStart) ) || *pszStart == '-' || *pszStart == '+' ) ) { eDataType = ePdfDataType_Unknown; break; } ++pszStart; } if( eDataType == ePdfDataType_Real ) { // DOM: strtod is locale dependend, // do not use it //double dVal = strtod( pszToken, NULL ); double dVal; m_doubleParser.clear(); // clear error state m_doubleParser.str( pszToken ); if( !(m_doubleParser >> dVal) ) { m_doubleParser.clear(); // clear error state PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, pszToken ); } rVariant = PdfVariant( dVal ); return ePdfDataType_Real; } else if( eDataType == ePdfDataType_Number ) { #ifdef _WIN64 rVariant = PdfVariant( static_cast(_strtoui64( pszToken, NULL, 10 )) ); #else rVariant = PdfVariant( static_cast(strtol( pszToken, NULL, 10 )) ); #endif // read another two tokens to see if it is a reference // we cannot be sure that there is another token // on the input device, so if we hit EOF just return // ePdfDataType_Number . EPdfTokenType eSecondTokenType; bool gotToken = this->GetNextToken( pszToken, &eSecondTokenType ); if (!gotToken) // No next token, so it can't be a reference return eDataType; if( eSecondTokenType != ePdfTokenType_Token ) { this->QuequeToken( pszToken, eSecondTokenType ); return eDataType; } pszStart = pszToken; #ifdef _WIN64 pdf_long l = _strtoui64( pszStart, const_cast(&pszToken), 10 ); #else long l = strtol( pszStart, const_cast(&pszToken), 10 ); #endif if( pszToken == pszStart ) { this->QuequeToken( pszStart, eSecondTokenType ); return eDataType; } std::string backup( pszStart ); EPdfTokenType eThirdTokenType; gotToken = this->GetNextToken( pszToken, &eThirdTokenType ); if (!gotToken) // No third token, so it can't be a reference return eDataType; if( eThirdTokenType == ePdfTokenType_Token && pszToken[0] == 'R' && pszToken[1] == '\0' ) { rVariant = PdfReference( static_cast(rVariant.GetNumber()), static_cast(l) ); return ePdfDataType_Reference; } else { this->QuequeToken( backup.c_str(), eSecondTokenType ); this->QuequeToken( pszToken, eThirdTokenType ); return eDataType; } } } else if( eTokenType == ePdfTokenType_Delimiter ) { if( strncmp( "<<", pszToken, DICT_SEP_LENGTH ) == 0 ) return ePdfDataType_Dictionary; else if( pszToken[0] == '[' ) return ePdfDataType_Array; else if( pszToken[0] == '(' ) return ePdfDataType_String; else if( pszToken[0] == '<' ) return ePdfDataType_HexString; else if( pszToken[0] == '/' ) return ePdfDataType_Name; } if( false ) { std::ostringstream ss; #if defined(_MSC_VER) && _MSC_VER <= 1200 ss << "Got unexpected PDF data in" << __FILE__ << ", line " << __LINE__ #else ss << "Got unexpected PDF data in" << PODOFO__FUNCTION__ #endif << ": \"" << pszToken << "\". Current read offset is " << m_device.Device()->Tell() << " which should be around the problem.\n"; PdfError::DebugMessage(ss.str().c_str()); } return ePdfDataType_Unknown; } void PdfTokenizer::ReadDataType( EPdfDataType eDataType, PdfVariant& rVariant, PdfEncrypt* pEncrypt ) { switch( eDataType ) { case ePdfDataType_Dictionary: this->ReadDictionary( rVariant, pEncrypt ); break; case ePdfDataType_Array: this->ReadArray( rVariant, pEncrypt ); break; case ePdfDataType_String: this->ReadString( rVariant, pEncrypt ); break; case ePdfDataType_HexString: this->ReadHexString( rVariant, pEncrypt ); break; case ePdfDataType_Name: this->ReadName( rVariant ); break; // The following datatypes are not handled by read datatype // but are already parsed by DetermineDatatype case ePdfDataType_Null: case ePdfDataType_Bool: case ePdfDataType_Number: case ePdfDataType_Real: case ePdfDataType_Reference: case ePdfDataType_Unknown: case ePdfDataType_RawData: default: { PdfError::LogMessage( eLogSeverity_Debug, "Got Datatype: %i\n", eDataType ); PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } } } void PdfTokenizer::ReadDictionary( PdfVariant& rVariant, PdfEncrypt* pEncrypt ) { PdfVariant val; PdfName key; PdfDictionary dict; EPdfTokenType eType; const char * pszToken; for( ;; ) { bool gotToken = this->GetNextToken( pszToken, &eType ); if (!gotToken) { PODOFO_RAISE_ERROR_INFO(ePdfError_UnexpectedEOF, "Expected dictionary key name or >> delim."); } if( eType == ePdfTokenType_Delimiter && strncmp( ">>", pszToken, DICT_SEP_LENGTH ) == 0 ) break; this->GetNextVariant( pszToken, eType, val, pEncrypt ); // Convert the read variant to a name; throws InvalidDataType if not a name. key = val.GetName(); // 'Contents' key of a /Type/Sig dictionary is an unencrypted Hex string bool bIsSigContents = key == PdfName( "Contents" ) && dict.HasKey( "Type" ) && dict.GetKey( "Type" )->GetDataType() == ePdfDataType_Name && dict.GetKey( "Type" )->GetName() == PdfName( "Sig" ); // Get the next variant. If there isn't one, it'll throw UnexpectedEOF. this->GetNextVariant( val, bIsSigContents ? NULL : pEncrypt ); dict.AddKey( key, val ); } rVariant = dict; } void PdfTokenizer::ReadArray( PdfVariant& rVariant, PdfEncrypt* pEncrypt ) { const char* pszToken; EPdfTokenType eType; PdfVariant var; PdfArray array; for( ;; ) { bool gotToken = this->GetNextToken( pszToken, &eType ); if (!gotToken) { PODOFO_RAISE_ERROR_INFO(ePdfError_UnexpectedEOF, "Expected array item or ] delim."); } if( eType == ePdfTokenType_Delimiter && pszToken[0] == ']' ) break; this->GetNextVariant( pszToken, eType, var, pEncrypt ); array.push_back( var ); } rVariant = array; } void PdfTokenizer::ReadString( PdfVariant& rVariant, PdfEncrypt* pEncrypt ) { int c; bool bEscape = false; bool bOctEscape = false; int nOctCount = 0; char cOctValue = 0; int nBalanceCount = 0; // Balanced parathesis do not have to be escaped in strings m_vecBuffer.clear(); while( (c = m_device.Device()->Look()) != EOF ) { // end of stream reached if( !bEscape ) { // Handle raw characters c = m_device.Device()->GetChar(); if( !nBalanceCount && c == ')' ) break; if( c == '(' ) ++nBalanceCount; else if( c == ')' ) --nBalanceCount; bEscape = (c == '\\'); if( !bEscape ) m_vecBuffer.push_back( static_cast(c) ); } else { // Handle escape sequences if( bOctEscape || s_octMap[c & 0xff] ) // The last character we have read was a '\\', // so we check now for a digit to find stuff like \005 bOctEscape = true; if( bOctEscape ) { // Handle octal escape sequences ++nOctCount; if( !s_octMap[c & 0xff] ) { // No octal character anymore, // so the octal sequence must be ended // and the character has to be treated as normal character! m_vecBuffer.push_back ( cOctValue ); bEscape = false; bOctEscape = false; nOctCount = 0; cOctValue = 0; continue; } c = m_device.Device()->GetChar(); cOctValue <<= 3; cOctValue |= ((c-'0') & 0x07); if( nOctCount > 2 ) { m_vecBuffer.push_back ( cOctValue ); bEscape = false; bOctEscape = false; nOctCount = 0; cOctValue = 0; } } else { // Handle plain escape sequences const char & code = s_escMap[m_device.Device()->GetChar() & 0xff]; if( code ) m_vecBuffer.push_back( code ); bEscape = false; } } } // In case the string ends with a octal escape sequence if( bOctEscape ) m_vecBuffer.push_back ( cOctValue ); if( m_vecBuffer.size() ) { if( pEncrypt ) { pdf_long outLen = m_vecBuffer.size() - pEncrypt->CalculateStreamOffset(); char * outBuffer = new char[outLen + 16 - (outLen % 16)]; pEncrypt->Decrypt( reinterpret_cast(&(m_vecBuffer[0])), static_cast(m_vecBuffer.size()), reinterpret_cast(outBuffer), outLen); rVariant = PdfString( outBuffer, outLen ); delete[] outBuffer; } else { rVariant = PdfString( &(m_vecBuffer[0]), m_vecBuffer.size() ); } } else { rVariant = PdfString(""); } } void PdfTokenizer::ReadHexString( PdfVariant& rVariant, PdfEncrypt* pEncrypt ) { int c; m_vecBuffer.clear(); while( (c = m_device.Device()->GetChar()) != EOF ) { // end of stream reached if( c == '>' ) break; // only a hex digits if( isdigit( c ) || ( c >= 'A' && c <= 'F') || ( c >= 'a' && c <= 'f')) m_vecBuffer.push_back( c ); } // pad to an even length if necessary if( m_vecBuffer.size() % 2 ) m_vecBuffer.push_back( '0' ); PdfString string; string.SetHexData( m_vecBuffer.size() ? &(m_vecBuffer[0]) : "", m_vecBuffer.size(), pEncrypt ); rVariant = string; } void PdfTokenizer::ReadName( PdfVariant& rVariant ) { EPdfTokenType eType; const char* pszToken; // Do special checking for empty names // as GetNextToken will ignore white spaces // and we have to take care for stuff like: // 10 0 obj / endobj // which stupid but legal PDF int c = m_device.Device()->Look(); if( IsWhitespace( c ) ) // Delimeters are handled correctly by GetNextToken { // We are an empty PdfName rVariant = PdfName(); return; } bool gotToken = this->GetNextToken( pszToken, &eType ); if( !gotToken || eType != ePdfTokenType_Token ) { // We got an empty name which is legal according to the PDF specification // Some weird PDFs even use them. rVariant = PdfName(); // Enqueue the token again if( gotToken ) QuequeToken( pszToken, eType ); } else rVariant = PdfName::FromEscaped( pszToken ); } void PdfTokenizer::QuequeToken( const char* pszToken, EPdfTokenType eType ) { m_deqQueque.push_back( TTokenizerPair( std::string( pszToken ), eType ) ); } }; podofo-0.9.5/src/base/PdfInputDevice.h0000664000175000017500000001646512365357361017435 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_INPUT_DEVICE_H_ #define _PDF_INPUT_DEVICE_H_ #include #include #include #include "PdfDefines.h" #include "PdfLocale.h" namespace PoDoFo { /** This class provides an Input device which operates * either on a file, a buffer in memory or any arbitrary std::istream * * This class is suitable for inheritance to provide input * devices of your own for PoDoFo. * Just overide the required virtual methods. */ class PODOFO_API PdfInputDevice { public: /** Construct a new PdfInputDevice that reads all data from a file. * * \param pszFilename path to a file that will be opened and all data * is read from this file. */ PdfInputDevice( const char* pszFilename ); #ifdef _WIN32 /** Construct a new PdfInputDevice that reads all data from a file. * * \param pszFilename path to a file that will be opened and all data * is read from this file. * * This is an overloaded member function to allow working * with unicode characters. On Unix systes you can also path * UTF-8 to the const char* overload. */ PdfInputDevice( const wchar_t* pszFilename ); #endif // _WIN32 /** Construct a new PdfInputDevice that reads all data from a memory buffer. * The buffer will not be owned by this object - it is COPIED. * * \param pBuffer a buffer in memory * \param lLen the length of the buffer in memory */ PdfInputDevice( const char* pBuffer, size_t lLen ); /** Construct a new PdfInputDevice that reads all data from a std::istream. * * \param pInStream read from this std::istream */ PdfInputDevice( const std::istream* pInStream ); /** Destruct the PdfInputDevice object and close any open files. */ virtual ~PdfInputDevice(); /** Close the input device. * No further operations may be performed on this device * after calling this function. */ virtual void Close(); /** Get the current position in file. * /returns the current position in the file */ virtual std::streamoff Tell() const; /** Get next char from stream. * \returns the next character from the stream */ virtual int GetChar() const; /** Peek at next char in stream. * /returns the next char in the stream */ virtual int Look() const; /** Seek the device to the position offset from the begining * \param off from the beginning of the file * \param dir where to start (start, cur, end) * * A non-seekable input device will throw an InvalidDeviceOperation. */ virtual void Seek( std::streamoff off, std::ios_base::seekdir dir = std::ios_base::beg ); /** Read a certain number of bytes from the input device. * * \param pBuffer store bytes in this buffer. * The buffer has to be large enough. * \param lLen number of bytes to read. * \returns the number of bytes that have been read. * If reading was successfull the number of read bytes * is equal to lLen. */ virtual std::streamoff Read( char* pBuffer, std::streamsize lLen ); /** * \return True if the stream is at EOF */ PODOFO_NOTHROW inline virtual bool Eof() const; /** * \return True if there was an error in an I/O operation */ PODOFO_NOTHROW inline virtual bool Bad() const; /** * Set the stream error state. By default, clears badbit, eofbit * and failbit. */ PODOFO_NOTHROW inline virtual void Clear( std::ios_base::iostate state = std::ios_base::goodbit) const; /** * \return True if the stream is seekable. Subclasses can control * this value with SetIsSeekable(bool) . */ PODOFO_NOTHROW inline bool IsSeekable() const; protected: /** * Control whether or or not this stream is flagged * seekable. */ PODOFO_NOTHROW inline void SetSeekable(bool bIsSeekable); /** CAN NOT Construct a new PdfInputDevice without an input source. * However subclasses may well need to do just that. */ PdfInputDevice(); private: /** Initialize all private members */ void Init(); private: std::istream* m_pStream; FILE * m_pFile; bool m_StreamOwned; bool m_bIsSeekable; }; bool PdfInputDevice::IsSeekable() const { return m_bIsSeekable; } void PdfInputDevice::SetSeekable(bool bIsSeekable) { m_bIsSeekable = bIsSeekable; } bool PdfInputDevice::Bad() const { if (m_pStream) return m_pStream->bad(); return m_pFile != NULL; } bool PdfInputDevice::Eof() const { if (m_pStream) return m_pStream->eof(); if (m_pFile) return feof(m_pFile) != 0; return true; } void PdfInputDevice::Clear(std::ios_base::iostate state) const { if (m_pStream) m_pStream->clear(state); } }; #endif // _PDF_INPUT_DEVICE_H_ podofo-0.9.5/src/base/PdfRect.cpp0000664000175000017500000001201212344436402016415 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfRect.h" #include "PdfArray.h" #include "PdfVariant.h" #include "PdfDefinesPrivate.h" #include #include #include namespace PoDoFo { PdfRect::PdfRect() { m_dBottom = m_dLeft = m_dWidth = m_dHeight = 0; } PdfRect::PdfRect( double dLeft, double dBottom, double dWidth, double dHeight ) { m_dBottom = dBottom; m_dLeft = dLeft; m_dWidth = dWidth; m_dHeight = dHeight; } PdfRect::PdfRect( const PdfArray& inArray ) { m_dBottom = m_dLeft = m_dWidth = m_dHeight = 0; FromArray( inArray ); } PdfRect::PdfRect( const PdfRect & rhs ) { this->operator=( rhs ); } void PdfRect::ToVariant( PdfVariant & var ) const { PdfArray array; array.push_back( PdfVariant( m_dLeft ) ); array.push_back( PdfVariant( m_dBottom ) ); array.push_back( PdfVariant( (m_dWidth+m_dLeft) ) ); array.push_back( PdfVariant( (m_dHeight+m_dBottom) ) ); var = array; } std::string PdfRect::ToString() const { PdfVariant var; std::string str; this->ToVariant( var ); var.ToString( str ); return str; /* std::ostringstream oStr; oStr << "[ "; oStr << std::setprecision( 3 ) << m_dLeft << " "; oStr << std::setprecision( 3 ) << m_dBottom << " "; oStr << std::setprecision( 3 ) << m_dWidth + m_dLeft << " "; oStr << std::setprecision( 3 ) << m_dHeight - m_dBottom << " ]"; return oStr.str(); */ } void PdfRect::FromArray( const PdfArray& inArray ) { if ( inArray.size() == 4 ) { m_dLeft = inArray[0].GetReal(); m_dBottom = inArray[1].GetReal(); m_dWidth = inArray[2].GetReal() - m_dLeft; m_dHeight = inArray[3].GetReal() - m_dBottom; } else { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } } void PdfRect::Intersect( const PdfRect & rRect ) { if( rRect.GetBottom() != 0 || rRect.GetHeight() != 0 || rRect.GetLeft() != 0 || rRect.GetWidth() != 0 ) { double diff; diff = rRect.m_dLeft - m_dLeft; if ( diff > 0.0 ) { m_dLeft += diff; m_dWidth -= diff; } diff = (m_dLeft + m_dWidth) - (rRect.m_dLeft + rRect.m_dWidth); if ( diff > 0.0 ) { m_dWidth -= diff; } diff = rRect.m_dBottom - m_dBottom; if ( diff > 0.0 ) { m_dBottom += diff; m_dHeight -= diff; } diff = (m_dBottom + m_dHeight) - (rRect.m_dBottom + rRect.m_dHeight); if ( diff > 0.0 ) { m_dHeight -= diff; } } } PdfRect & PdfRect::operator=( const PdfRect & rhs ) { this->m_dBottom = rhs.m_dBottom; this->m_dLeft = rhs.m_dLeft; this->m_dWidth = rhs.m_dWidth; this->m_dHeight = rhs.m_dHeight; return *this; } }; podofo-0.9.5/src/base/podofoapi.h0000664000175000017500000001344111536441063016523 0ustar dominikdominik#ifndef PODOFO_API_H_20061017 #define PODOFO_API_H_20061017 /* * This header provides a macro to handle correct symbol imports/exports * on platforms that require explicit instructions to make symbols public, * or differentiate between exported and imported symbols. * * Win32 compilers use this information, and gcc4 can use it on *nix * to reduce the size of the export symbol table and get faster runtime * linking. * * All declarations of public API should be marked with the PODOFO_API macro. * Separate definitions need not be annotated, even in headers. * * Usage examples: * * class PODOFO_API PdfArray : public PdfDataType { * ... * }; * * bool PODOFO_API doThatThing(void); * * For an exception type that may be thrown across a DSO boundary, you must * use: * * class PODOFO_EXCEPTION_API(PODOFO_API) MyException * { * ... * }; * * PODOFO_LOCAL can be used on members of a class exported with PODOFO_API * to omit some members from the symbol table on supporting platforms. This * helps keep the exported API cleaner and the symbol table smaller. * * To hide a given method in an otherwise exported class: * * class PODOFO_API Myclass * { * // blah blah * private: * void privateHelper() PODOFO_LOCAL; * }; * * For information on the gcc visibility support see: * http://gcc.gnu.org/wiki/Visibility * http://people.redhat.com/drepper/dsohowto.pdf * * * * * Note that gcc has some other useful attributes: * http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Function-Attributes.html * http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Variable-Attributes.html * http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Type-Attributes.html * * including __attribute__((deprecated)) for deprecating old interfaces. * (available as PODOFO_DEPRECATED) * * __attribute__((pure)) for functions w/o side effects * (available as PODOFO_PURE_FUNCTION) * */ // Peter Petrov 26 April 2008 /* Automatically defined by CMake when building a shared library */ #if defined (podofo_EXPORTS) #define COMPILING_SHARED_PODOFO #undef USING_SHARED_PODOFO #if defined(podofo_EXPORTS) #define COMPILING_SHARED_PODOFO_BASE #define COMPILING_SHARED_PODOFO_DOC #endif #endif /* Automatically defined by CMake when building a shared library */ //#if defined(podofo_shared_EXPORTS) #if defined(podofo_shared_EXPORTS) #define COMPILING_SHARED_PODOFO #undef USING_SHARED_PODOFO #endif /* Sanity check - can't be both compiling and using shared podofo */ #if defined(COMPILING_SHARED_PODOFO) && defined(USING_SHARED_PODOFO) #error "Both COMPILING_SHARED_PODOFO and USING_SHARED_PODOFO defined!" #endif /* * Define COMPILING_SHARED_PODOFO when building the PoDoFo library as a * DLL. When building code that uses that DLL, define USING_SHARED_PODOFO. * * Building or linking to a static library does not require either * preprocessor symbol. */ #if defined(_WIN32) #if defined(COMPILING_SHARED_PODOFO) #define PODOFO_API __declspec(dllexport) #define PODOFO_DOC_API __declspec(dllexport) #elif defined(USING_SHARED_PODOFO) #define PODOFO_API __declspec(dllimport) #define PODOFO_DOC_API __declspec(dllimport) #else #define PODOFO_API #define PODOFO_DOC_API #endif /* PODOFO_LOCAL doesn't mean anything on win32, it's to exclude * symbols from the export table with gcc4. */ #define PODOFO_LOCAL #else #if defined(PODOFO_HAVE_GCC_SYMBOL_VISIBILITY) /* Forces inclusion of a symbol in the symbol table, so software outside the current library can use it. */ #define PODOFO_API __attribute__ ((visibility("default"))) #define PODOFO_DOC_API __attribute__ ((visibility("default"))) /* Within a section exported with PODOFO_API, forces a symbol to be private to the library / app. Good for private members. */ #define PODOFO_LOCAL __attribute__ ((visibility("hidden"))) /* Forces even stricter hiding of methods/functions. The function must * absolutely never be called from outside the module even via a function * pointer.*/ #define PODOFO_INTERNAL __attribute__ ((visibility("internal"))) #else #define PODOFO_API #define PODOFO_DOC_API #define PODOFO_LOCAL #define PODOFO_INTERNAL #endif #endif /* Throwable classes must always be exported by all binaries when * using gcc. Marking exception classes with PODOFO_EXCEPTION_API * ensures this. */ #ifdef _WIN32 #define PODOFO_EXCEPTION_API(api) api #elif defined(PODOFO_HAVE_GCC_SYMBOL_VISIBILITY) #define PODOFO_EXCEPTION_API(api) PODOFO_API #else #define PODOFO_EXCEPTION_API(api) #endif /* Set up some other compiler-specific but not platform-specific macros */ #if defined(__GNUC__) /* gcc will issue a warning if a function or variable so annotated is used */ #define PODOFO_DEPRECATED __attribute__((deprecated)) /* gcc can do some additional optimisations on functions annotated as pure. * See the documentation on __attribute__((pure)) in the gcc docs. */ #define PODOFO_PURE_FUNCTION __attribute__((pure)) /* PODOFO_NOTHROW can be used to tell the compiler the annotated function is * guaranteed not to throw. If it does throw, undefined behaviour will result, * so be VERY careful with this. This is NOT the same as the PODOFO_NOTHROW qualifier * (see CODINGSTYLE.txt) .*/ #define PODOFO_NOTHROW __attribute__((nothrow)) #else #define PODOFO_DEPRECATED #define PODOFO_PURE_FUNCTION #define PODOFO_NOTHROW __declspec(nothrow) #endif // Peter Petrov 27 April 2008 // Disable warnings #if defined(_WIN32) && defined(_MSC_VER) #pragma warning(disable: 4251) #pragma warning(disable: 4309) #endif // _WIN32 #endif // PODOFO_API_H podofo-0.9.5/src/base/PdfFilter.h0000664000175000017500000004735313013650710016424 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FILTER_H_ #define _PDF_FILTER_H_ #include #include #include "PdfDefines.h" #include "PdfInputStream.h" #include "PdfOutputStream.h" namespace PoDoFo { class PdfDictionary; class PdfName; class PdfObject; class PdfOutputStream; typedef std::vector TVecFilters; typedef TVecFilters::iterator TIVecFilters; typedef TVecFilters::const_iterator TCIVecFilters; /** Every filter in PoDoFo has to implement this interface. * * The two methods Encode() and Decode() have to be implemented * for every filter. * * The output buffers are podofo_malloc()'ed in the functions and have * to be podofo_free()'d by the caller. */ class PODOFO_API PdfFilter { public: /** Construct and initialize a new filter */ PdfFilter(); /** All classes with virtual functions need a virtual destructor */ inline virtual ~PdfFilter(); /** Check whether encoding is implemented for this filter. * * \returns true if the filter is able to encode data */ virtual bool CanEncode() const = 0; /** Encodes a buffer using a filter. The buffer will podofo_malloc()'d and * has to be podofo_free()'d by the caller. * * This function uses BeginEncode()/EncodeBlock()/EndEncode() * internally, so it's not safe to use when progressive encoding * is in progress. * * \param pInBuffer input buffer * \param lInLen length of the input buffer * \param ppOutBuffer receives pointer to the buffer of the encoded data * \param plOutLen pointer to where to write the output buffer's length */ void Encode( const char* pInBuffer, pdf_long lInLen, char** ppOutBuffer, pdf_long* plOutLen ) const; /** Begin progressively encoding data using this filter. * * This method sets the filter's output stream and may * perform other operations defined by particular filter * implementations. It calls BeginEncodeImpl(). * * \param pOutput Encoded data will be written to this stream. * * Call EncodeBlock() to encode blocks of data and use EndEncode() * to finish the encoding process. * * \see EncodeBlock * \see EndEncode */ inline void BeginEncode( PdfOutputStream* pOutput ); /** Encode a block of data and write it to the PdfOutputStream * specified by BeginEncode(). Ownership of the block is not taken * and remains with the caller. * * The filter implementation need not immediately process the buffer, * and might internally buffer some or all of it. However, if it does * this the buffer's contents will be copied, so it is guaranteed to be * safe to free the passed buffer after this call returns. * * This method is a wrapper around EncodeBlockImpl(). * * BeginEncode() must be called before this function. * * \param pBuffer pointer to a buffer with data to encode * \param lLen length of data to encode. * * Call EndEncode() after all data has been encoded. * * \see BeginEncode * \see EndEncode */ inline void EncodeBlock( const char* pBuffer, pdf_long lLen ); /** * Finish encoding of data and reset the stream's state. * * \see BeginEncode * \see EncodeBlock */ inline void EndEncode(); /** Check whether the decoding is implemented for this filter. * * \returns true if the filter is able to decode data */ virtual bool CanDecode() const = 0; /** Decodes a buffer using a filter. The buffer will podofo_malloc()'d and * has to be podofo_free()'d by the caller. * * \param pInBuffer input buffer * \param lInLen length of the input buffer * \param ppOutBuffer receives pointer to the buffer of the decoded data * \param plOutLen pointer to where to write the output buffer's length * \param pDecodeParms optional pointer to a decode-parameters dictionary * containing additional information to decode * the data. This pointer must be NULL if no * decode-parameters dictionary is available. */ void Decode( const char* pInBuffer, pdf_long lInLen, char** ppOutBuffer, pdf_long* plOutLen, const PdfDictionary* pDecodeParms = NULL ) const; /** Begin progressively decoding data using this filter. * * This method sets the filter's output stream and may * perform other operations defined by particular filter * implementations. It calls BeginDecodeImpl(). * * \param pOutput decoded data will be written to this stream * \param pDecodeParms a dictionary containing additional information * for decoding * * Call DecodeBlock() to decode blocks of data and use EndDecode() * to finish the decoding process. * * \see DecodeBlock * \see EndDecode */ inline void BeginDecode( PdfOutputStream* pOutput, const PdfDictionary* pDecodeParms = NULL ); /** Decode a block of data and write it to the PdfOutputStream * specified by BeginDecode(). Ownership of the block is not taken * and remains with the caller. * * The filter implementation need not immediately process the buffer, * and might internally buffer some or all of it. However, if it does * this the buffer's contents will be copied, so it is guaranteed to be * safe to free the passed buffer after this call returns. * * This method is a wrapper around DecodeBlockImpl(). * * BeginDecode() must be called before this function. * * \param pBuffer pointer to a buffer with data to encode * \param lLen length of data to encode. * * Call EndDecode() after all data has been decoded. * * \see BeginDecode * \see EndDecode */ inline void DecodeBlock( const char* pBuffer, pdf_long lLen ); /** * Finish decoding of data and reset the stream's state. * * \see BeginDecode * \see DecodeBlock */ inline void EndDecode(); /** Type of this filter. * \returns the type of this filter */ virtual EPdfFilter GetType() const = 0; PODOFO_NOTHROW inline PdfOutputStream* GetStream() const { return m_pOutputStream; } protected: /** * Indicate that the filter has failed, and will be non-functional * until BeginEncode() or BeginDecode() is next called. Call this * instead of EndEncode() or EndDecode if something went wrong. * It clears the stream output but otherwise does nothing. * * After this method is called further calls to EncodeBlock(), * DecodeBlock(), EndDecode() and EndEncode() before the next * BeginEncode() or BeginDecode() are guaranteed to throw * without calling their virtual implementations. */ PODOFO_NOTHROW inline void FailEncodeDecode(); /** Real implementation of BeginEncode(). NEVER call this method directly. * * By default this function does nothing. If your filter needs to do setup * for encoding, you should override this method. * * PdfFilter ensures that a valid stream is available when this method is * called, and that EndEncode() was called since the last BeginEncode()/ * EncodeBlock(). * \see BeginEncode */ virtual void BeginEncodeImpl( ) { } /** Real implementation of EncodeBlock(). NEVER call this method directly. * * You must method-override it to encode the buffer passed by the caller. * * You are not obliged to immediately process any or all of the data in * the passed buffer, but you must ensure that you have processed it and * written it out by the end of EndEncodeImpl(). You must copy the buffer * if you're going to store it, as ownership is not transferred to the * filter and the caller may free the buffer at any time. * * PdfFilter ensures that a valid stream is available when this method is * called, ensures that BeginEncode() has been called, and ensures that * EndEncode() has not been called since the last BeginEncode(). * * \see EncodeBlock */ virtual void EncodeBlockImpl( const char* pBuffer, pdf_long lLen ) = 0; /** Real implementation of EndEncode(). NEVER call this method directly. * * By the time this method returns, all filtered data must be written to * the stream and the filter must be in a state where BeginEncode() can * be safely called. * PdfFilter ensures that a valid stream is available when this method is * called, and ensures that BeginEncodeImpl() has been called. * * \see EndEncode */ virtual void EndEncodeImpl() { } /** Real implementation of BeginDecode(). NEVER call this method directly. * * By default this function does nothing. If your filter needs to do setup * for decoding, you should override this method. * * PdfFilter ensures that a valid stream is available when this method is * called, and that EndDecode() was called since the last BeginDecode()/ * DecodeBlock(). * \see BeginDecode */ virtual void BeginDecodeImpl( const PdfDictionary* ) { } /** Real implementation of DecodeBlock(). NEVER call this method directly. * * You must method-override it to decode the buffer passed by the caller. * * You are not obliged to immediately process any or all of the data in * the passed buffer, but you must ensure that you have processed it and * written it out by the end of EndDecodeImpl(). You must copy the buffer * if you're going to store it, as ownership is not transferred to the * filter and the caller may free the buffer at any time. * * PdfFilter ensures that a valid stream is available when this method is * called, ensures that BeginDecode() has been called, and ensures that * EndDecode() has not been called since the last BeginDecode(). * * \see DecodeBlock */ virtual void DecodeBlockImpl( const char* pBuffer, pdf_long lLen ) = 0; /** Real implementation of EndDecode(). NEVER call this method directly. * * By the time this method returns, all filtered data must be written to * the stream and the filter must be in a state where BeginDecode() can be * safely called. * PdfFilter ensures that a valid stream is available when this method is * called, and ensures that BeginDecodeImpl() has been called. * * \see EndDecode */ virtual void EndDecodeImpl() { } private: PdfOutputStream* m_pOutputStream; }; // ----------------------------------------------------- // // ----------------------------------------------------- void PdfFilter::BeginEncode( PdfOutputStream* pOutput ) { PODOFO_RAISE_LOGIC_IF( m_pOutputStream, "BeginEncode() on failed filter or without EndEncode()" ); m_pOutputStream = pOutput; try { BeginEncodeImpl(); } catch( PdfError & e ) { // Clean up and close stream this->FailEncodeDecode(); throw e; } } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfFilter::EncodeBlock( const char* pBuffer, pdf_long lLen ) { PODOFO_RAISE_LOGIC_IF( !m_pOutputStream, "EncodeBlock() without BeginEncode() or on failed filter" ); try { EncodeBlockImpl(pBuffer, lLen); } catch( PdfError & e ) { // Clean up and close stream this->FailEncodeDecode(); throw e; } } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfFilter::EndEncode() { PODOFO_RAISE_LOGIC_IF( !m_pOutputStream, "EndEncode() without BeginEncode() or on failed filter" ); try { EndEncodeImpl(); } catch( PdfError & e ) { // Clean up and close stream this->FailEncodeDecode(); throw e; } m_pOutputStream->Close(); m_pOutputStream = NULL; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfFilter::BeginDecode( PdfOutputStream* pOutput, const PdfDictionary* pDecodeParms ) { PODOFO_RAISE_LOGIC_IF( m_pOutputStream, "BeginDecode() on failed filter or without EndDecode()" ); m_pOutputStream = pOutput; try { BeginDecodeImpl( pDecodeParms ); } catch( PdfError & e ) { // Clean up and close stream this->FailEncodeDecode(); throw e; } } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfFilter::DecodeBlock( const char* pBuffer, pdf_long lLen ) { PODOFO_RAISE_LOGIC_IF( !m_pOutputStream, "DecodeBlock() without BeginDecode() or on failed filter" ) try { DecodeBlockImpl(pBuffer, lLen); } catch( PdfError & e ) { // Clean up and close stream this->FailEncodeDecode(); throw e; } } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfFilter::EndDecode() { PODOFO_RAISE_LOGIC_IF( !m_pOutputStream, "EndDecode() without BeginDecode() or on failed filter" ) try { EndDecodeImpl(); } catch( PdfError & e ) { // Clean up and close stream this->FailEncodeDecode(); throw e; } if( m_pOutputStream ) { m_pOutputStream->Close(); m_pOutputStream = NULL; } } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfFilter::FailEncodeDecode() { if ( m_pOutputStream != NULL ) // OC 19.08.2010 BugFix: Sometimes FailEncodeDecode() is called twice m_pOutputStream->Close(); m_pOutputStream = NULL; } // ----------------------------------------------------- // // ----------------------------------------------------- PdfFilter::~PdfFilter() { // Whoops! Didn't call EndEncode() before destroying the filter! // Note that we can't do this for the user, since EndEncode() might // throw and we can't safely have that in a dtor. That also means // we can't throw here, but must abort. assert( !m_pOutputStream ); } /** A factory to create a filter object for a filter type (as GetType() gives) * from the EPdfFilter enum. * All filters should be created using this factory. */ class PODOFO_API PdfFilterFactory { public: /** Create a filter from an enum. * * Ownership is transferred to the caller, who should let the auto_ptr * the filter is returned in take care of freeing it when they're done * with it. * * \param eFilter return value of GetType() for filter to be created * * \returns a new PdfFilter allocated using new, or NULL if no * filter is available for this type. */ static std::auto_ptr Create( const EPdfFilter eFilter ); /** Create a PdfOutputStream that applies a list of filters * on all data written to it. * * \param filters a list of filters * \param pStream write all data to this PdfOutputStream after it has been * encoded * \returns a new PdfOutputStream that has to be deleted by the caller. * * \see PdfFilterFactory::CreateFilterList */ static PdfOutputStream* CreateEncodeStream( const TVecFilters & filters, PdfOutputStream* pStream ); /** Create a PdfOutputStream that applies a list of filters * on all data written to it. * * \param filters a list of filters * \param pStream write all data to this PdfOutputStream * after it has been decoded. * \param pDictionary pointer to a dictionary that might * contain additional parameters for stream decoding. * This method will look for a key named DecodeParms * in this dictionary and pass the information found * in that dictionary to the filters. * \returns a new PdfOutputStream that has to be deleted by the caller. * * \see PdfFilterFactory::CreateFilterList */ static PdfOutputStream* CreateDecodeStream( const TVecFilters & filters, PdfOutputStream* pStream, const PdfDictionary* pDictionary = NULL ); /** Converts a filter name to the corresponding enum * \param name of the filter without leading * \param bSupportShortNames The PDF Reference supports several * short names for filters (e.g. AHx for AsciiHexDecode), if true * support for these short names will be enabled. * This is often used in inline images. * \returns the filter as enum */ static EPdfFilter FilterNameToType( const PdfName & name, bool bSupportShortNames = true ); /** Converts a filter type enum to the corresponding PdfName * \param eFilter a filter type * \returns the filter as name */ static const char* FilterTypeToName( EPdfFilter eFilter ); /** The passed PdfObject has to be a dictionary with a Filters key, * a (possibly empty) array of filter names or a filter name. * * \param pObject must define a filter or list of filters (can be * empty, although then you should use TVecFilters' default) * * \returns a list of filters */ static TVecFilters CreateFilterList( const PdfObject* pObject ); private: // prohibit instantiation of all-methods-static factory from outside PdfFilterFactory(); }; }; #endif /* _PDF_FILTER_H_ */ podofo-0.9.5/src/base/PdfDataType.cpp0000664000175000017500000000527612344436402017251 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfDataType.h" #include "PdfDefinesPrivate.h" namespace PoDoFo { PdfDataType::PdfDataType() : m_bImmutable(false) { } PdfDataType::~PdfDataType() { } bool PdfDataType::IsDirty() const { return false; } void PdfDataType::SetDirty( bool ) { // Ignore } }; podofo-0.9.5/src/base/PdfWriter.h0000664000175000017500000003724513012362162016452 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_WRITER_H_ #define _PDF_WRITER_H_ #include "PdfDefines.h" #include "PdfInputDevice.h" #include "PdfOutputDevice.h" #include "PdfVecObjects.h" #include "PdfEncrypt.h" namespace PoDoFo { class PdfDictionary; class PdfName; class PdfObject; class PdfPage; class PdfPagesTree; class PdfParser; class PdfVecObjects; class PdfXRef; namespace NonPublic { class PdfHintStream; } /** The PdfWriter class writes a list of PdfObjects as PDF file. * The XRef section (which is the required table of contents for any * PDF file) is created automatically. * * It does not know about pages but only about PdfObjects. * * Most users will want to use PdfDocument. */ class PODOFO_API PdfWriter { public: /** Create a PdfWriter object from a PdfParser object * \param pParser a pdf parser object */ PdfWriter( PdfParser* pParser ); /** Create a new pdf file, from an vector of PdfObjects * and a trailer object. * \param pVecObjects the vector of objects * \param pTrailer a valid trailer object */ PdfWriter( PdfVecObjects* pVecObjects, const PdfObject* pTrailer ); virtual ~PdfWriter(); /** Writes the complete document to a PDF file. * * \param pszFilename filename of a PDF file. */ void Write( const char* pszFilename ); #ifdef _WIN32 /** Writes the complete document to a PDF file. * * \param pszFilename filename of a PDF file. * * This is an overloaded member function to allow working * with unicode characters. On Unix systems you can also path * UTF-8 to the const char* overload. */ void Write( const wchar_t* pszFilename ); #endif // _WIN32 /** Writes the complete document to a PdfOutputDevice * * \param pDevice write to the specified device * * \see WriteUpdate */ void Write( PdfOutputDevice* pDevice ); /** Writes the document changes to an output device * * \param pDevice write to the specified device * \param pSourceInputDevice where to copy original content from; can be NULL * \param bRewriteXRefTable whether to rewrite whole XRef table * * Writes an incremental update to the pDevice, using the pSourceInputDevice * content as the original file content. * When the pSourceInputDevice is NULL, the caller is responsible to have the pDevice * filled with the previous content and to have it positioned at the end of the stream. * * Calling this also switches the writer to the incremental update mode. * * \see SetIncrementalUpdate */ void WriteUpdate( PdfOutputDevice* pDevice, PdfInputDevice* pSourceInputDevice, bool bRewriteXRefTable ); /** Set the write mode to use when writing the PDF. * \param eWriteMode write mode */ void SetWriteMode( EPdfWriteMode eWriteMode ) { m_eWriteMode = eWriteMode; } /** Get the write mode used for wirting the PDF * \returns the write mode */ EPdfWriteMode GetWriteMode() const { return m_eWriteMode; } /** Set the PDF Version of the document. Has to be called before Write() to * have an effect. * \param eVersion version of the pdf document */ void SetPdfVersion( EPdfVersion eVersion ) { m_eVersion = eVersion; } /** Get the PDF version of the document * \returns EPdfVersion version of the pdf document */ EPdfVersion GetPdfVersion() const { return m_eVersion; } /** Enabled linearization for this document. * I.e. optimize it for web usage. Default is false. * \param bLinearize if true create a web optimized PDF file */ inline void SetLinearized( bool bLinearize ); /** * \returns true if this PDF file is web optimized. */ inline bool GetLinearized() const; /** Create a XRef stream which is in some case * more compact but requires at least PDF 1.5 * Default is false. * \param bStream if true a XRef stream object will be created */ inline void SetUseXRefStream( bool bStream ); /** * \returns wether a XRef stream is used or not */ inline bool GetUseXRefStream() const; /** Sets an offset to the previous XRef table. Set it to lower than * or equal to 0, to not write a reference to the previous XRef table. * The default is 0. * \param lPrevXRefOffset the previous XRef table offset */ inline void SetPrevXRefOffset( pdf_int64 lPrevXRefOffset ); /** * \returns offset to the previous XRef table, as previously set * by SetPrevXRefOffset. * * \see SetPrevXRefOffset */ inline pdf_int64 GetPrevXRefOffset() const; /** Set whether writing an incremental update. * Default is false. * \param bIncrementalUpdate if true an incremental update will be written */ inline void SetIncrementalUpdate( bool bIncrementalUpdate ); /** * \returns whether writing an incremental update */ inline bool GetIncrementalUpdate( void ) const; /** Get the file format version of the pdf * \returns the file format version as string */ const char* GetPdfVersionString() const { return s_szPdfVersionNums[static_cast(m_eVersion)]; } /** Set the written document to be encrypted using a PdfEncrypt object * * \param rEncrypt an encryption object which is used to encrypt the written PDF file */ void SetEncrypted( const PdfEncrypt & rEncrypt ); /** * \returns true if this PdfWriter creates an encrypted PDF file */ bool GetEncrypted() const { return (m_pEncrypt != NULL); } /** Calculate the byte offset of the object pObject in the PDF file * if the file was written to disk at the moment of calling this function. * * This function is very calculation intensive! * * \param pObject object to calculate the byte offset (has to be a * child of this PdfWriter) * \param pulOffset pointer to an unsigned long to save the offset */ void GetByteOffset( PdfObject* pObject, pdf_long* pulOffset ); /** Write the whole document to a buffer in memory. * * Better use a PdfOutputDevice that writes to a PdfRefCountedBuffer. * * \param ppBuffer where this points the address of the buffer will * be written after that being malloc()'d and the document * will be written to that buffer. * \param pulLen the buffer length will be returned in this parameter * * \see Write */ void WriteToBuffer( char** ppBuffer, pdf_long* pulLen ); /** Add required keys to a trailer object * \param pTrailer add keys to this object * \param lSize number of objects in the PDF file * \param bOnlySizeKey write only the size key */ void FillTrailerObject( PdfObject* pTrailer, pdf_long lSize, bool bOnlySizeKey ) const; protected: /** * Create a PdfWriter from a PdfVecObjects */ PdfWriter( PdfVecObjects* pVecObjects ); /** Writes the pdf header to the current file. * \param pDevice write to this output device */ void PODOFO_LOCAL WritePdfHeader( PdfOutputDevice* pDevice ); /** Write pdf objects to file * \param pDevice write to this output device * \param vecObjects write all objects in this vector to the file * \param pXref add all written objects to this XRefTable * \param bRewriteXRefTable whether will rewrite whole XRef table (used only if GetIncrementalUpdate() returns true) */ void WritePdfObjects( PdfOutputDevice* pDevice, const PdfVecObjects& vecObjects, PdfXRef* pXref, bool bRewriteXRefTable = false ) PODOFO_LOCAL; /** Creates a file identifier which is required in several * PDF workflows. * All values from the files document information dictionary are * used to create a unique MD5 key which is added to the trailer dictionary. * * \param identifier write the identifier to this string * \param pTrailer trailer object * \param pOriginalIdentifier write the original identifier (when using incremental update) to this string */ void CreateFileIdentifier( PdfString& identifier, const PdfObject* pTrailer, PdfString* pOriginalIdentifier = NULL ) const PODOFO_LOCAL; /** Internal implementation of the Write() call with the common code * \param pDevice write to this output device * \param bRewriteXRefTable whether will rewrite whole XRef table (used only if GetIncrementalUpdate() returns true) */ void Write( PdfOutputDevice* pDevice, bool bRewriteXRefTable ); protected: /** Writes a linearized PDF file * \param pDevice write to this output device */ void PODOFO_LOCAL WriteLinearized( PdfOutputDevice* pDevice ); /** Create a linearization dictionary for the current * document and return a pointer to it after inserting * it into the vector of PdfObjects * * \returns a pointer to the linearization dictionary */ PdfObject* CreateLinearizationDictionary() PODOFO_LOCAL; /** Reorder and renumber all object as required for linearized PDF files. * This function is very slow. * * \param pLinearize linearization dictionary * \param pHint primary hint stream dictionary * \param pPage first page to display in the document * \param ppLast the pointer will be initialized to the last object * belonging to the first page */ //void ReorderObjectsLinearized( PdfObject* pLinearize, NonPublic::PdfHintStream* pHint, PdfPage* pPage, PdfObject** ppLast ) PODOFO_LOCAL; /** Initialize m_pPagesTree with its correct value * Always call this function befre accessing the pages tree. */ //void FetchPagesTree(); /** Find dependencies required for creating a linearized PDF of the catalog dictionary. */ //void FindCatalogDependencies( PdfObject* pCatalog, const PdfName & rName, TPdfReferenceList* pList, bool bWithDependencies ) PODOFO_LOCAL; /** Fill all keys in the linearization dictionary with their values * \param pLinearize a linearization dictionary * \param pHint the hint stream * \param pPage the first page in the linerarized PDF file * \param pLast pointer of the last object belonging to the first page * \param pVecXRefOffset xref table entries for previous entry */ // void FillLinearizationDictionary( PdfObject* pLinearize, PdfOutputDevice* pDevice, PdfPage* pPage, PdfObject* pLast, NonPublic::PdfHintStream* pHint, TVecXRefOffset* pVecXRefOffset ) PODOFO_LOCAL; protected: PdfVecObjects* m_vecObjects; PdfObject* m_pTrailer; bool m_bXRefStream; PdfEncrypt* m_pEncrypt; ///< If not NULL encrypt all strings and streams and create an encryption dictionary in the trailer PdfObject* m_pEncryptObj; ///< Used to temporarly store the encryption dictionary PdfString m_identifier; PdfString m_originalIdentifier; // used for incremental update private: EPdfWriteMode m_eWriteMode; EPdfVersion m_eVersion; pdf_int64 m_lPrevXRefOffset; bool m_bIncrementalUpdate; bool m_bLinearized; /** * This value is required when writing * a linearized PDF file. * It represents the offset of the whitespace * character before the first line in the XRef * section. */ size_t m_lFirstInXRef; size_t m_lLinearizedOffset; size_t m_lLinearizedLastOffset; size_t m_lTrailerOffset; PdfVecObjects m_vecLinearized; }; // ----------------------------------------------------- // // ----------------------------------------------------- void PdfWriter::SetLinearized( bool bLinearize ) { m_bLinearized = bLinearize; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfWriter::GetLinearized() const { return m_bLinearized; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfWriter::SetUseXRefStream( bool bStream ) { if( bStream && this->GetPdfVersion() < ePdfVersion_1_5 ) this->SetPdfVersion( ePdfVersion_1_5 ); m_bXRefStream = bStream; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfWriter::GetUseXRefStream() const { return m_bXRefStream; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfWriter::SetPrevXRefOffset( pdf_int64 lPrevXRefOffset ) { m_lPrevXRefOffset = lPrevXRefOffset; } // ----------------------------------------------------- // // ----------------------------------------------------- pdf_int64 PdfWriter::GetPrevXRefOffset() const { return m_lPrevXRefOffset; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfWriter::SetIncrementalUpdate( bool bIncrementalUpdate ) { m_bIncrementalUpdate = bIncrementalUpdate; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfWriter::GetIncrementalUpdate( void ) const { return m_bIncrementalUpdate; } }; #endif // _PDF_WRITER_H_ podofo-0.9.5/src/base/PdfFilter.cpp0000664000175000017500000003311213013650710016743 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfDefines.h" #include "PdfFilter.h" #include "PdfArray.h" #include "PdfDictionary.h" #include "PdfFiltersPrivate.h" #include "PdfOutputStream.h" #include "PdfDefinesPrivate.h" namespace PoDoFo { // All known filters static const char* aszFilters[] = { "ASCIIHexDecode", "ASCII85Decode", "LZWDecode", "FlateDecode", "RunLengthDecode", "CCITTFaxDecode", "JBIG2Decode", "DCTDecode", "JPXDecode", "Crypt", NULL }; static const char* aszShortFilters[] = { "AHx", "A85", "LZW", "Fl", "RL", "CCF", "", ///< There is no shortname for JBIG2Decode "DCT", "", ///< There is no shortname for JPXDecode "", ///< There is no shortname for Crypt NULL }; /** Create a filter that is a PdfOutputStream. * * All data written to this stream is encoded using a * filter and written to another PdfOutputStream. * * The passed output stream is owned by this PdfOutputStream * and deleted along with it. */ class PdfFilteredEncodeStream : public PdfOutputStream{ public: /** Create a filtered output stream. * * All data written to this stream is encoded using the passed filter type * and written to the passed output stream which will be deleted * by this PdfFilteredEncodeStream. * * \param pOutputStream write all data to this output stream after encoding the data. * \param eFilter use this filter for encoding. * \param bOwnStream if true pOutputStream will be deleted along with this filter */ PdfFilteredEncodeStream( PdfOutputStream* pOutputStream, const EPdfFilter eFilter, bool bOwnStream ) : m_pOutputStream( pOutputStream ) { m_filter = PdfFilterFactory::Create( eFilter ); if( !m_filter.get() ) { PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter ); } m_filter->BeginEncode( pOutputStream ); if( !bOwnStream ) m_pOutputStream = NULL; } virtual ~PdfFilteredEncodeStream() { delete m_pOutputStream; } /** Write data to the output stream * * \param pBuffer the data is read from this buffer * \param lLen the size of the buffer */ virtual pdf_long Write( const char* pBuffer, pdf_long lLen ) { m_filter->EncodeBlock( pBuffer, lLen ); return 0; } virtual void Close() { m_filter->EndEncode(); } private: PdfOutputStream* m_pOutputStream; std::auto_ptr m_filter; }; /** Create a filter that is a PdfOutputStream. * * All data written to this stream is decoded using a * filter and written to another PdfOutputStream. * * The passed output stream is owned by this PdfOutputStream * and deleted along with it. */ class PdfFilteredDecodeStream : public PdfOutputStream { public: /** Create a filtered output stream. * * All data written to this stream is decoded using the passed filter type * and written to the passed output stream which will be deleted * by this PdfFilteredEncodeStream. * * \param pOutputStream write all data to this output stream after decoding the data. * The PdfOutputStream is deleted along with this object. * \param eFilter use this filter for decoding. * \param bOwnStream if true pOutputStream will be deleted along with this filter * \param pDecodeParms additional parameters for decoding */ PdfFilteredDecodeStream( PdfOutputStream* pOutputStream, const EPdfFilter eFilter, bool bOwnStream, const PdfDictionary* pDecodeParms = NULL ) : m_pOutputStream( pOutputStream ), m_bFilterFailed( false ) { m_filter = PdfFilterFactory::Create( eFilter ); if( !m_filter.get() ) { PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter ); } m_filter->BeginDecode( pOutputStream, pDecodeParms ); if( !bOwnStream ) m_pOutputStream = NULL; } virtual ~PdfFilteredDecodeStream() { delete m_pOutputStream; } /** Write data to the output stream * * \param pBuffer the data is read from this buffer * \param lLen the size of the buffer */ virtual pdf_long Write( const char* pBuffer, pdf_long lLen ) { try { m_filter->DecodeBlock( pBuffer, lLen ); } catch( PdfError & e ) { m_bFilterFailed = true; throw e; } return 0; } virtual void Close() { if( !m_bFilterFailed ) { m_filter->EndDecode(); } } private: PdfOutputStream* m_pOutputStream; std::auto_ptr m_filter; bool m_bFilterFailed; }; // ----------------------------------------------------- // Actual PdfFilter code // ----------------------------------------------------- PdfFilter::PdfFilter() : m_pOutputStream( NULL ) { } void PdfFilter::Encode( const char* pInBuffer, pdf_long lInLen, char** ppOutBuffer, pdf_long* plOutLen ) const { if( !this->CanEncode() ) { PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter ); } PdfMemoryOutputStream stream; const_cast(this)->BeginEncode( &stream ); const_cast(this)->EncodeBlock( pInBuffer, lInLen ); const_cast(this)->EndEncode(); *ppOutBuffer = stream.TakeBuffer(); *plOutLen = stream.GetLength(); } void PdfFilter::Decode( const char* pInBuffer, pdf_long lInLen, char** ppOutBuffer, pdf_long* plOutLen, const PdfDictionary* pDecodeParms ) const { if( !this->CanDecode() ) { PODOFO_RAISE_ERROR( ePdfError_UnsupportedFilter ); } PdfMemoryOutputStream stream; const_cast(this)->BeginDecode( &stream, pDecodeParms ); const_cast(this)->DecodeBlock( pInBuffer, lInLen ); const_cast(this)->EndDecode(); *ppOutBuffer = stream.TakeBuffer(); *plOutLen = stream.GetLength(); } // ----------------------------------------------------- // PdfFilterFactory code // ----------------------------------------------------- PdfFilterFactory::PdfFilterFactory() { } std::auto_ptr PdfFilterFactory::Create( const EPdfFilter eFilter ) { PdfFilter* pFilter = NULL; switch( eFilter ) { case ePdfFilter_None: break; case ePdfFilter_ASCIIHexDecode: pFilter = new PdfHexFilter(); break; case ePdfFilter_ASCII85Decode: pFilter = new PdfAscii85Filter(); break; case ePdfFilter_LZWDecode: pFilter = new PdfLZWFilter(); break; case ePdfFilter_FlateDecode: pFilter = new PdfFlateFilter(); break; case ePdfFilter_RunLengthDecode: pFilter = new PdfRLEFilter(); break; case ePdfFilter_DCTDecode: #ifdef PODOFO_HAVE_JPEG_LIB pFilter = new PdfDCTFilter(); break; #else break; #endif // PODOFO_HAVE_JPEG_LIB case ePdfFilter_CCITTFaxDecode: #ifdef PODOFO_HAVE_TIFF_LIB pFilter = new PdfCCITTFilter(); break; #else break; #endif // PODOFO_HAVE_TIFF_LIB case ePdfFilter_JBIG2Decode: case ePdfFilter_JPXDecode: case ePdfFilter_Crypt: default: break; } return std::auto_ptr(pFilter); } PdfOutputStream* PdfFilterFactory::CreateEncodeStream( const TVecFilters & filters, PdfOutputStream* pStream ) { TVecFilters::const_iterator it = filters.begin(); PODOFO_RAISE_LOGIC_IF( !filters.size(), "Cannot create an EncodeStream from an empty list of filters" ); PdfFilteredEncodeStream* pFilter = new PdfFilteredEncodeStream( pStream, *it, false ); ++it; while( it != filters.end() ) { pFilter = new PdfFilteredEncodeStream( pFilter, *it, true ); ++it; } return pFilter; } PdfOutputStream* PdfFilterFactory::CreateDecodeStream( const TVecFilters & filters, PdfOutputStream* pStream, const PdfDictionary* pDictionary ) { TVecFilters::const_reverse_iterator it = filters.rbegin(); PODOFO_RAISE_LOGIC_IF( !filters.size(), "Cannot create an DecodeStream from an empty list of filters" ); // TODO: support arrays and indirect objects here and the short name /DP if( pDictionary && pDictionary->HasKey( "DecodeParms" ) && pDictionary->GetKey( "DecodeParms" )->IsDictionary() ) pDictionary = &(pDictionary->GetKey( "DecodeParms" )->GetDictionary()); PdfFilteredDecodeStream* pFilter = new PdfFilteredDecodeStream( pStream, *it, false, pDictionary ); ++it; while( it != filters.rend() ) { pFilter = new PdfFilteredDecodeStream( pFilter, *it, true, pDictionary ); ++it; } return pFilter; } EPdfFilter PdfFilterFactory::FilterNameToType( const PdfName & name, bool bSupportShortNames ) { int i = 0; while( aszFilters[i] ) { if( name == aszFilters[i] ) return static_cast(i); ++i; } if( bSupportShortNames ) { i = 0; while( aszShortFilters[i] ) { if( name == aszShortFilters[i] ) return static_cast(i); ++i; } } PODOFO_RAISE_ERROR_INFO( ePdfError_UnsupportedFilter, name.GetName().c_str() ); } const char* PdfFilterFactory::FilterTypeToName( EPdfFilter eFilter ) { return aszFilters[static_cast(eFilter)]; } TVecFilters PdfFilterFactory::CreateFilterList( const PdfObject* pObject ) { TVecFilters filters; const PdfObject* pObj = NULL; if( pObject->IsDictionary() && pObject->GetDictionary().HasKey( "Filter" ) ) pObj = pObject->GetDictionary().GetKey( "Filter" ); else if( pObject->IsArray() ) pObj = pObject; else if( pObject->IsName() ) pObj = pObject; if (!pObj) // Object had no /Filter key . Return a null filter list. return filters; if( pObj->IsName() ) filters.push_back( PdfFilterFactory::FilterNameToType( pObj->GetName() ) ); else if( pObj->IsArray() ) { TCIVariantList it = pObj->GetArray().begin(); while( it != pObj->GetArray().end() ) { if ( (*it).IsName() ) { filters.push_back( PdfFilterFactory::FilterNameToType( (*it).GetName() ) ); } else if ( (*it).IsReference() ) { PdfObject* pFilter = pObject->GetOwner()->GetObject( (*it).GetReference() ); if( pFilter == NULL ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Filter array contained unexpected reference" ); } filters.push_back( PdfFilterFactory::FilterNameToType( pFilter->GetName() ) ); } else { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Filter array contained unexpected non-name type" ); } ++it; } } return filters; } }; podofo-0.9.5/src/base/Pdf3rdPtyForwardDecl.h0000664000175000017500000000217711641323033020474 0ustar dominikdominik#ifndef PDF_FT_FORWARD_DECL #define PDF_FT_FORWARD_DECL /** * \page Pdf3rdPartyForwardDecl.h * * Forward declare some types that we use in our public API but don't want to * include the headers for directly. We can't do a nice simple forward * declaration because most of these libraries have typedefs everywhere. * * We don't want to include things like freetype directly in our public headers * because: * * - They dump a huge amount of cruft into the top level namespace * * - Programs that haven't gone through the apallingly convoluted process required * to add freetype's header path can't include podofo's headers even if they have no * intention of using any freetype-related font features. */ #ifdef __cplusplus extern "C" { #endif // Provide access to FT_Library struct FT_LibraryRec_; typedef struct FT_LibraryRec_ *FT_Library; // Provide access to FT_Face struct FT_FaceRec_; typedef struct FT_FaceRec_* FT_Face; #if defined(PODOFO_HAVE_FONTCONFIG) // Fontconfig struct _FcConfig; typedef struct _FcConfig FcConfig; #endif #ifdef __cplusplus }; // end extern "C" #endif // end PDF_FT_FORWARD_DECL #endif podofo-0.9.5/src/base/PdfImmediateWriter.cpp0000664000175000017500000001566313013650710020624 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfImmediateWriter.h" #include "PdfFileStream.h" #include "PdfMemStream.h" #include "PdfObject.h" #include "PdfXRef.h" #include "PdfXRefStream.h" #include "PdfDefinesPrivate.h" namespace PoDoFo { PdfImmediateWriter::PdfImmediateWriter( PdfOutputDevice* pDevice, PdfVecObjects* pVecObjects, const PdfObject* pTrailer, EPdfVersion eVersion, PdfEncrypt* pEncrypt, EPdfWriteMode eWriteMode ) : PdfWriter( pVecObjects ), m_pParent( pVecObjects ), m_pDevice( pDevice ), m_pLast( NULL ), m_bOpenStream( false ) { if( m_pTrailer ) delete m_pTrailer; m_pTrailer = new PdfObject( *pTrailer ); // register as observer for PdfVecObjects m_pParent->Attach( this ); // register as stream factory for PdfVecObjects m_pParent->SetStreamFactory( this ); this->CreateFileIdentifier( m_identifier, m_pTrailer ); // setup encryption if( pEncrypt ) { this->SetEncrypted( *pEncrypt ); m_pEncrypt->GenerateEncryptionKey( m_identifier ); } // start with writing the header this->SetPdfVersion( eVersion ); this->SetWriteMode( eWriteMode ); this->WritePdfHeader( m_pDevice ); m_pXRef = m_bXRefStream ? new PdfXRefStream( m_vecObjects, this ) : new PdfXRef(); } PdfImmediateWriter::~PdfImmediateWriter() { if( m_pParent ) m_pParent->Detach( this ); delete m_pXRef; } void PdfImmediateWriter::WriteObject( const PdfObject* pObject ) { const int endObjLenght = 7; this->FinishLastObject(); m_pXRef->AddObject( pObject->Reference(), m_pDevice->Tell(), true ); pObject->WriteObject( m_pDevice, this->GetWriteMode(), m_pEncrypt ); // Make sure, no one will add keys now to the object const_cast(pObject)->SetImmutable(true); // Let's cheat a bit: // pObject has written an "endobj\n" as last data to the file. // we simply overwrite this string with "stream\n" which // has excatly the same length. m_pDevice->Seek( m_pDevice->Tell() - endObjLenght ); m_pDevice->Print( "stream\n" ); m_pLast = const_cast(pObject); } void PdfImmediateWriter::ParentDestructed() { m_pParent = NULL; } void PdfImmediateWriter::Finish() { // write all objects which are still in RAM this->FinishLastObject(); // setup encrypt dictionary if( m_pEncrypt ) { // Add our own Encryption dictionary m_pEncryptObj = m_vecObjects->CreateObject(); m_pEncrypt->CreateEncryptionDictionary( m_pEncryptObj->GetDictionary() ); } this->WritePdfObjects( m_pDevice, *m_pParent, m_pXRef ); // write the XRef pdf_long lXRefOffset = m_pDevice->Tell(); m_pXRef->Write( m_pDevice ); // XRef streams contain the trailer in the XRef if( !m_bXRefStream ) { PdfObject trailer; // if we have a dummy offset we write also a prev entry to the trailer FillTrailerObject( &trailer, m_pXRef->GetSize(), false ); m_pDevice->Print("trailer\n"); trailer.WriteObject( m_pDevice, this->GetWriteMode(), NULL ); } m_pDevice->Print( "startxref\n%li\n%%%%EOF\n", lXRefOffset ); m_pDevice->Flush(); // we are done now m_pParent->Detach( this ); m_pParent = NULL; } PdfStream* PdfImmediateWriter::CreateStream( PdfObject* pParent ) { return m_bOpenStream ? static_cast(new PdfMemStream( pParent )) : static_cast(new PdfFileStream( pParent, m_pDevice )); } void PdfImmediateWriter::FinishLastObject() { if( m_pLast ) { m_pDevice->Print( "\nendstream\n" ); m_pDevice->Print( "endobj\n" ); delete m_pParent->RemoveObject( m_pLast->Reference(), false ); m_pLast = NULL; } } void PdfImmediateWriter::BeginAppendStream( const PdfStream* pStream ) { const PdfFileStream* pFileStream = dynamic_cast(pStream ); if( pFileStream ) { // Only one open file stream is allowed at a time PODOFO_ASSERT( !m_bOpenStream ); m_bOpenStream = true; if( m_pEncrypt ) const_cast(pFileStream)->SetEncrypted( m_pEncrypt ); } } void PdfImmediateWriter::EndAppendStream( const PdfStream* pStream ) { const PdfFileStream* pFileStream = dynamic_cast(pStream ); if( pFileStream ) { // A PdfFileStream has to be opened before PODOFO_ASSERT( m_bOpenStream ); m_bOpenStream = false; } } }; podofo-0.9.5/src/base/PdfDictionary.cpp0000664000175000017500000002375313012362162017635 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfDictionary.h" #include "PdfOutputDevice.h" #include "PdfDefinesPrivate.h" namespace PoDoFo { PdfDictionary::PdfDictionary() : m_bDirty( false ) { } PdfDictionary::PdfDictionary( const PdfDictionary & rhs ) : PdfDataType() { this->operator=( rhs ); m_bDirty = false; } PdfDictionary::~PdfDictionary() { this->SetImmutable(false); // Destructor may change things, i.e. delete this->Clear(); } const PdfDictionary & PdfDictionary::operator=( const PdfDictionary & rhs ) { TCIKeyMap it; this->Clear(); it = rhs.m_mapKeys.begin(); while( it != rhs.m_mapKeys.end() ) { m_mapKeys[(*it).first] = new PdfObject( *(*it).second ); ++it; } m_bDirty = true; return *this; } bool PdfDictionary::operator==( const PdfDictionary& rhs ) const { if (this == &rhs) return true; if ( m_mapKeys.size() != rhs.m_mapKeys.size() ) return false; // It's not enough to test that our internal maps are equal, because // we store variants by pointer not value. However, since a dictionary's // keys are stored in a SORTED map, and there may be only one instance of // every key, we can do lockstep iteration and compare that way. const TCIKeyMap thisIt = m_mapKeys.begin(); const TCIKeyMap thisEnd = m_mapKeys.end(); const TCIKeyMap rhsIt = rhs.m_mapKeys.begin(); const TCIKeyMap rhsEnd = rhs.m_mapKeys.end(); while ( thisIt != thisEnd && rhsIt != rhsEnd ) { if ( (*thisIt).first != (*rhsIt).first ) // Name mismatch. Since the keys are sorted that means that there's a key present // in one dictionary but not the other. return false; if ( *(*thisIt).second != *(*rhsIt).second ) // Value mismatch on same-named keys. return false; } // BOTH dictionaries must now be on their end iterators - since we checked that they were // the same size initially, we know they should run out of keys at the same time. PODOFO_RAISE_LOGIC_IF( thisIt != thisEnd || rhsIt != rhsEnd, "Dictionary compare error" ); // We didn't find any mismatches return true; } void PdfDictionary::Clear() { AssertMutable(); if( !m_mapKeys.empty() ) { TIKeyMap it; it = m_mapKeys.begin(); while( it != m_mapKeys.end() ) { delete (*it).second; ++it; } m_mapKeys.clear(); m_bDirty = true; } } void PdfDictionary::AddKey( const PdfName & identifier, const PdfObject & rObject ) { AssertMutable(); // Empty PdfNames are legal according to the PDF specification // weird but true. As a reason we cannot throw an error here /* if( !identifier.GetLength() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } */ if( m_mapKeys.find( identifier ) != m_mapKeys.end() ) { delete m_mapKeys[identifier]; m_mapKeys.erase( identifier ); } m_mapKeys[identifier] = new PdfObject( rObject ); m_bDirty = true; } void PdfDictionary::AddKey( const PdfName & identifier, const PdfObject* pObject ) { this->AddKey( identifier, *pObject ); } const PdfObject* PdfDictionary::GetKey( const PdfName & key ) const { TCIKeyMap it; if( HasKey( key ) ) { it = m_mapKeys.find( key ); return (*it).second; } return NULL; } PdfObject* PdfDictionary::GetKey( const PdfName & key ) { TIKeyMap it; if( HasKey( key ) ) { it = m_mapKeys.find( key ); return (*it).second; } return NULL; } pdf_int64 PdfDictionary::GetKeyAsLong( const PdfName & key, pdf_int64 lDefault ) const { const PdfObject* pObject = GetKey( key ); if( pObject && pObject->GetDataType() == ePdfDataType_Number ) { return pObject->GetNumber(); } return lDefault; } double PdfDictionary::GetKeyAsReal( const PdfName & key, double dDefault ) const { const PdfObject* pObject = GetKey( key ); if( pObject && ( pObject->GetDataType() == ePdfDataType_Real || pObject->GetDataType() == ePdfDataType_Number)) { return pObject->GetReal(); } return dDefault; } bool PdfDictionary::GetKeyAsBool( const PdfName & key, bool bDefault ) const { const PdfObject* pObject = GetKey( key ); if( pObject && pObject->GetDataType() == ePdfDataType_Bool ) { return pObject->GetBool(); } return bDefault; } PdfName PdfDictionary::GetKeyAsName( const PdfName & key ) const { const PdfObject* pObject = GetKey( key ); if( pObject && pObject->GetDataType() == ePdfDataType_Name ) { return pObject->GetName(); } return PdfName(""); // return an empty name } bool PdfDictionary::HasKey( const PdfName & key ) const { if( !key.GetLength() ) return false; return ( m_mapKeys.find( key ) != m_mapKeys.end() ); } bool PdfDictionary::RemoveKey( const PdfName & identifier ) { if( HasKey( identifier ) ) { AssertMutable(); delete m_mapKeys[identifier]; m_mapKeys.erase( identifier ); m_bDirty = true; return true; } return false; } void PdfDictionary::Write( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, const PdfEncrypt* pEncrypt, const PdfName & keyStop ) const { TCIKeyMap itKeys; if( (eWriteMode & ePdfWriteMode_Clean) == ePdfWriteMode_Clean ) { pDevice->Print( "<<\n" ); } else { pDevice->Print( "<<" ); } itKeys = m_mapKeys.begin(); if( keyStop != PdfName::KeyNull && keyStop.GetLength() && keyStop == PdfName::KeyType ) return; if( this->HasKey( PdfName::KeyType ) ) { // Type has to be the first key in any dictionary if( (eWriteMode & ePdfWriteMode_Clean) == ePdfWriteMode_Clean ) { pDevice->Print( "/Type " ); } else { pDevice->Print( "/Type" ); } this->GetKey( PdfName::KeyType )->Write( pDevice, eWriteMode, pEncrypt ); if( (eWriteMode & ePdfWriteMode_Clean) == ePdfWriteMode_Clean ) { pDevice->Print( "\n" ); } } while( itKeys != m_mapKeys.end() ) { if( (*itKeys).first != PdfName::KeyType ) { if( keyStop != PdfName::KeyNull && keyStop.GetLength() && (*itKeys).first == keyStop ) return; (*itKeys).first.Write( pDevice, eWriteMode ); if( (eWriteMode & ePdfWriteMode_Clean) == ePdfWriteMode_Clean ) { pDevice->Write( " ", 1 ); // write a separator } (*itKeys).second->Write( pDevice, eWriteMode, pEncrypt ); if( (eWriteMode & ePdfWriteMode_Clean) == ePdfWriteMode_Clean ) { pDevice->Write( "\n", 1 ); } } ++itKeys; } pDevice->Print( ">>" ); } bool PdfDictionary::IsDirty() const { // If the dictionary itself is dirty // return immediately // otherwise check all children. if( m_bDirty ) return m_bDirty; TKeyMap::const_iterator it = this->GetKeys().begin(); while( it != this->GetKeys().end() ) { if( (*it).second->IsDirty() ) return true; ++it; } return false; } void PdfDictionary::SetDirty( bool bDirty ) { m_bDirty = bDirty; if( !m_bDirty ) { // Propagate state to all subclasses TKeyMap::iterator it = this->GetKeys().begin(); while( it != this->GetKeys().end() ) { (*it).second->SetDirty( m_bDirty ); ++it; } } } }; podofo-0.9.5/src/base/util/0000775000175000017500000000000013044451160015337 5ustar dominikdominikpodofo-0.9.5/src/base/util/PdfMutexImpl_noop.h0000664000175000017500000000654112344436402021133 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter, Craig Ringer * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "../PdfDefines.h" #include "../PdfDefinesPrivate.h" #if defined(PODOFO_MULTI_THREAD) #error "Multi-thread build, a real PdfMutex implementation should be used instead" #endif namespace PoDoFo { namespace Util { /** * A platform independent non-reentrant mutex, no-op implementation. * This version is used if PoDoFo is built without threading support. * * PdfMutex is *NOT* part of PoDoFo's public API. */ class PdfMutexImpl { public: /** Construct a new mutex */ inline PdfMutexImpl() { } inline ~PdfMutexImpl() { } /** * Lock the mutex */ inline void Lock() { } /** * Try locking the mutex. * * \returns true if the mutex was locked * \returns false if the mutex is already locked * by some other thread */ inline bool TryLock() { return true; } /** * Unlock the mutex */ inline void UnLock() { } }; }; // Util }; // PoDoFo podofo-0.9.5/src/base/util/PdfMutexImpl_pthread.h0000664000175000017500000001042212344436402021600 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter, Craig Ringer * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "../PdfDefines.h" #include "../PdfDefinesPrivate.h" #if ! defined(PODOFO_MULTI_THREAD) #error "Not a multi-thread build. PdfMutex_null.h should be used instead" #endif #if defined(_WIN32) #error "win32 build. PdfMutex_win32.h should be used instead" #endif #include #include namespace PoDoFo { namespace Util { /** * A platform independent reentrant mutex, pthread implementation. * * PdfMutex is *NOT* part of PoDoFo's public API. * * This is the pthread implementation, which is * entirely inline. */ class PdfMutexImpl { pthread_mutex_t m_mutex; public: inline PdfMutexImpl(); inline ~PdfMutexImpl(); inline void Init( const pthread_mutexattr_t *attr ); /** * Lock the mutex */ inline void Lock(); /** * Try locking the mutex. * * \returns true if the mutex was locked * \returns false if the mutex is already locked * by some other thread */ inline bool TryLock(); /** * Unlock the mutex */ inline void UnLock(); }; PdfMutexImpl::PdfMutexImpl() { pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init( &m_mutex, &attr ); } PdfMutexImpl::~PdfMutexImpl() { pthread_mutex_destroy( &m_mutex ); } void PdfMutexImpl::Lock() { if( pthread_mutex_lock( &m_mutex ) != 0 ) { PODOFO_RAISE_ERROR( ePdfError_MutexError ); } } bool PdfMutexImpl::TryLock() { int nRet = pthread_mutex_trylock( &m_mutex ); if( nRet == 0 ) return true; else if( nRet == EBUSY ) return false; else { PODOFO_RAISE_ERROR( ePdfError_MutexError ); } } void PdfMutexImpl::UnLock() { if( pthread_mutex_unlock( &m_mutex ) != 0 ) { PODOFO_RAISE_ERROR( ePdfError_MutexError ); } } }; // Util }; // PoDoFo podofo-0.9.5/src/base/util/PdfMutexWrapper.h0000664000175000017500000000747113013650710020614 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_MUTEX_WRAPPER_H_ #define _PDF_MUTEX_WRAPPER_H_ #include "../PdfDefines.h" #include "PdfMutex.h" namespace PoDoFo { namespace Util { /** * A wrapper around PdfMutex. * The mutex is locked in the constructor * and unlocked in the destructor. * * In debug builds all exceptions thrown by the mutex implementation * are caught and logged before being rethrown. * * Note that PdfMutexWrapper is *not* part of PoDoFo's public API. */ class PdfMutexWrapper { public: /** Lock a mutex. * * \param rMutex the mutex to be locked. */ PODOFO_NOTHROW inline PdfMutexWrapper( PdfMutex & rMutex ); /** Unlocks the mutex on destruction */ inline ~PdfMutexWrapper(); private: /** default constructor, not implemented */ PdfMutexWrapper(void); /** copy constructor, not implemented */ PdfMutexWrapper(const PdfMutexWrapper& rhs); /** assignment operator, not implemented */ PdfMutexWrapper& operator=(const PdfMutexWrapper& rhs); PdfMutex& m_rMutex; }; PdfMutexWrapper::PdfMutexWrapper( PdfMutex & rMutex ) : m_rMutex( rMutex ) { m_rMutex.Lock(); } PdfMutexWrapper::~PdfMutexWrapper() { #if defined(DEBUG) try { m_rMutex.UnLock(); } catch( PdfError & rError ) { rError.PrintErrorMsg(); throw rError; } #else m_rMutex.UnLock(); #endif } }; // Util }; // PoDoFo #endif // _PDF_MUTEX_H_ podofo-0.9.5/src/base/util/PdfMutex.h0000664000175000017500000000761612344436402017262 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter, Craig Ringer * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef PDF_PDFMUTEX_H #define PDF_PDFMUTEX_H #if defined(BUILDING_PODOFO) /* Import the platform-specific implementation of PdfMutex */ #if defined(PODOFO_MULTI_THREAD) # if defined(_WIN32) # include "PdfMutexImpl_win32.h" # else # include "PdfMutexImpl_pthread.h" # endif #else # include "PdfMutexImpl_noop.h" #endif namespace PoDoFo { namespace Util { /** * Reentrant mutex implemented by win32 CRITICAL_SECTION or pthread recursive mutex. * * If PODOFO_MULTI_THREAD is not set, all operations are no-ops and always succeed. * * A held (locked) PdfMutex may not be acquired (locked) by a thread other than * the thread that currently holds it. * * The thread holding a PdfMutex may acquire it repeatedly. Every acquision must be matched * by a release. * * When a PdfMutex is not held by any thread (ie it is newly allocated or has been released) * then exactly one thread attempting to acquire it will succeed. If there is more than one * thread trying to acquire a PdfMutex, which thread will succeed is undefined. * */ class PdfMutex : public PdfMutexImpl { // This wrapper/extension class is provided so we can add platform-independent // functionality and helpers if desired. public: PdfMutex() { } ~PdfMutex() { } }; };}; #else // BUILDING_PODOFO // Only a forward-declaration is available for PdfMutex for sources outside the // PoDoFo library build its self. PdfMutex is not public API. namespace PoDoFo { namespace Util { class PdfMutex; }; }; #endif #endif podofo-0.9.5/src/base/util/PdfMutexImpl_win32.h0000664000175000017500000001024512716130004021106 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "../PdfDefines.h" #include "../PdfDefinesPrivate.h" #if ! defined(PODOFO_MULTI_THREAD) #error "Not a multi-thread build. PdfMutex_null.h should be used instead" #endif #if !defined(_WIN32) #error "Wrong PdfMutex implementation included!" #endif namespace PoDoFo { namespace Util { /** * A platform independent reentrant mutex, win32 implementation. */ class PdfMutexImpl { public: /** Construct a new mutex */ inline PdfMutexImpl(); inline ~PdfMutexImpl(); /** * Lock the mutex */ inline void Lock(); /** * Try locking the mutex. * * \returns true if the mutex was locked * \returns false if the mutex is already locked * by some other thread */ inline bool TryLock(); /** * Unlock the mutex */ inline void UnLock(); private: CRITICAL_SECTION m_cs; }; PdfMutexImpl::PdfMutexImpl() { // Visual Studio Code Analyzer warns that InitializeCriticalSection must be within try/catch block // because InitializeCriticalSection can raise a STATUS_NO_MEMORY exception in low memory conditions // on Windows XP / Server 2003. The exception was eliminated in Windows Vista / Server 2008, // so don't warn if building for Vista or later. #if ( WINVER >= _WIN32_WINNT_VISTA ) #pragma warning(disable : 28125) #endif InitializeCriticalSection( &m_cs ); #if ( WINVER >= _WIN32_WINNT_VISTA ) #pragma warning(default : 28125) #endif } PdfMutexImpl::~PdfMutexImpl() { DeleteCriticalSection( &m_cs ); } void PdfMutexImpl::Lock() { EnterCriticalSection( &m_cs ); } bool PdfMutexImpl::TryLock() { return (TryEnterCriticalSection( &m_cs ) ? true : false); } void PdfMutexImpl::UnLock() { LeaveCriticalSection( &m_cs ); } }; // Util }; // PoDoFo podofo-0.9.5/src/base/PdfName.h0000664000175000017500000002225112344436402016053 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_NAME_H_ #define _PDF_NAME_H_ #include "PdfDefines.h" #include "PdfDataType.h" namespace PoDoFo { class PdfOutputDevice; class PdfName; //std::size_t hash_value(PdfName const& name); /** This class represents a PdfName. * Whenever a key is required you have to use a PdfName object. * * PdfName are required as keys in PdfObject and PdfVariant objects. * * PdfName may have a maximum length of 127 characters. * * \see PdfObject \see PdfVariant */ class PODOFO_API PdfName : public PdfDataType { public: /** Constructor to create NULL strings. * use PdfName::KeyNull instead of this constructor */ PdfName() : PdfDataType(), m_Data("") { } /** Create a new PdfName object. * \param sName the unescaped value of this name. Please specify * the name without the leading '/'. */ PdfName( const std::string& sName ) : PdfDataType(), m_Data(sName) { } /** Create a new PdfName object. * \param pszName the unescaped value of this name. Please specify * the name without the leading '/'. * Has to be a zero terminated string. */ PdfName( const char* pszName ) : PdfDataType() { if (pszName) m_Data.assign( pszName ); } /** Create a new PdfName object. * \param pszName the unescaped value of this name. Please specify * the name without the leading '/'. * \param lLen length of the name */ PdfName( const char* pszName, long lLen ) : PdfDataType() { if( pszName ) m_Data.assign( pszName, lLen ); } /** Create a new PdfName object from a string containing an escaped * name string without the leading / . * * \param sName A string containing the escaped name * \return A new PdfName */ static PdfName FromEscaped( const std::string& sName ); /** Create a new PdfName object from a string containing an escaped * name string without the leading / . * \param pszName A string containing the escaped name * \param ilength length of the escaped string data. If a length * of 0 is passed, the string data is expected to * be a zero terminated string. * \return A new PdfName */ static PdfName FromEscaped( const char * pszName, pdf_long ilength = 0 ); /** \return an escaped representation of this name * without the leading / . * * There is no corresponding GetEscapedLength(), since * generating the return value is somewhat expensive. */ std::string GetEscapedName() const; /** Create a copy of an existing PdfName object. * \param rhs another PdfName object */ PdfName( const PdfName & rhs ) : PdfDataType(), m_Data(rhs.m_Data) { } virtual ~PdfName(); /** Write the name to an output device in PDF format. * This is an overloaded member function. * * \param pDevice write the object to this device * \param eWriteMode additional options for writing this object * \param pEncrypt an encryption object which is used to encrypt this object * or NULL to not encrypt this object */ void Write( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, const PdfEncrypt* pEncrypt = NULL) const; /** \returns the unescaped value of this name object * without the leading slash */ PODOFO_NOTHROW inline const std::string& GetName() const; /** \returns the unescaped length of this * name object */ PODOFO_NOTHROW inline size_t GetLength() const; /** Assign another name to this object * \param rhs another PdfName object */ PODOFO_NOTHROW inline const PdfName& operator=( const PdfName & rhs ); /** compare to PdfName objects. * \returns true if both PdfNames have the same value. */ PODOFO_NOTHROW inline bool operator==( const PdfName & rhs ) const; /** overloaded operator for convinience * * The string argument is treated as an unescaped name. * * \param rhs a name * \returns true if this objects name is equal to pszName */ bool operator==( const char* rhs ) const; /** overloaded operator for convinience * * The string argument is treated as an unescaped name. * * \param rhs a name * \returns true if this objects name is equal to pszName */ PODOFO_NOTHROW inline bool operator==( const std::string& rhs ) const; /** compare two PdfName objects. * \returns true if both PdfNames have different values. */ PODOFO_NOTHROW inline bool operator!=( const PdfName & rhs ) const; /** overloaded operator for convinience * * The string argument is treated as an unescaped name. * * \param rhs a name * \returns true if this objects name is not equal to pszName */ inline bool operator!=( const char* rhs ) const; /** compare two PdfName objects. * Used for sorting in lists * \returns true if this object is smaller than rhs */ PODOFO_NOTHROW inline bool operator<( const PdfName & rhs ) const; static const PdfName KeyContents; static const PdfName KeyFlags; static const PdfName KeyLength; static const PdfName KeyNull; static const PdfName KeyRect; static const PdfName KeySize; static const PdfName KeySubtype; static const PdfName KeyType; static const PdfName KeyFilter; private: // The _unescaped_ name, without leading / std::string m_Data; }; // ----------------------------------------------------- // // ----------------------------------------------------- const std::string & PdfName::GetName() const { return m_Data; } // ----------------------------------------------------- // // ----------------------------------------------------- size_t PdfName::GetLength() const { return m_Data.length(); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfName::operator!=( const PdfName & rhs ) const { return !this->operator==( rhs ); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfName::operator!=( const char* rhs ) const { return !this->operator==( rhs ); } bool PdfName::operator<( const PdfName & rhs ) const { return m_Data < rhs.m_Data; } bool PdfName::operator==( const PdfName & rhs ) const { return ( m_Data == rhs.m_Data ); } bool PdfName::operator==( const std::string & rhs ) const { return ( m_Data == rhs ); } const PdfName& PdfName::operator=( const PdfName & rhs ) { m_Data = rhs.m_Data; return *this; } }; #endif /* _PDF_NAME_H_ */ podofo-0.9.5/src/base/PdfContentsTokenizer.cpp0000664000175000017500000002424512476076116021233 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfContentsTokenizer.h" #include "PdfCanvas.h" #include "PdfInputDevice.h" #include "PdfOutputStream.h" #include "PdfStream.h" #include "PdfVecObjects.h" #include "PdfData.h" #include "PdfDefinesPrivate.h" #include namespace PoDoFo { PdfContentsTokenizer::PdfContentsTokenizer( PdfCanvas* pCanvas ) : PdfTokenizer(), m_readingInlineImgData(false) { if( !pCanvas ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } PdfObject* pContents = pCanvas->GetContents(); if( pContents && pContents->IsArray() ) { PdfArray& a = pContents->GetArray(); for ( PdfArray::iterator it = a.begin(); it != a.end() ; ++it ) { if ( !(*it).IsReference() ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "/Contents array contained non-references" ); } if ( !pContents->GetOwner()->GetObject( (*it).GetReference() ) ) { // some damaged PDFs may have dangling references PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "/Contents array NULL reference" ); } m_lstContents.push_back( pContents->GetOwner()->GetObject( (*it).GetReference() ) ); } } else if ( pContents && pContents->HasStream() ) { m_lstContents.push_back( pContents ); } else if ( pContents && pContents->IsDictionary() ) { m_lstContents.push_back( pContents ); PdfError::LogMessage(eLogSeverity_Information, "PdfContentsTokenizer: found canvas-dictionary without stream => empty page"); // OC 18.09.2010 BugFix: Found an empty page in a PDF document: // 103 0 obj // << // /Type /Page // /MediaBox [ 0 0 595 842 ] // /Parent 3 0 R // /Resources << // /ProcSet [ /PDF ] // >> // /Rotate 0 // >> // endobj } else { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Page /Contents not stream or array of streams" ); } if( m_lstContents.size() ) { SetCurrentContentsStream( m_lstContents.front() ); m_lstContents.pop_front(); } } void PdfContentsTokenizer::SetCurrentContentsStream( PdfObject* pObject ) { PODOFO_RAISE_LOGIC_IF( pObject == NULL, "Content stream object == NULL!" ); PdfStream* pStream = pObject->GetStream(); PdfRefCountedBuffer buffer; PdfBufferOutputStream stream( &buffer ); pStream->GetFilteredCopy( &stream ); m_device = PdfRefCountedInputDevice( buffer.GetBuffer(), buffer.GetSize() ); } bool PdfContentsTokenizer::GetNextToken( const char*& pszToken , EPdfTokenType* peType ) { bool result = PdfTokenizer::GetNextToken(pszToken, peType); while (!result) { if( !m_lstContents.size() ) return false; SetCurrentContentsStream( m_lstContents.front() ); m_lstContents.pop_front(); result = PdfTokenizer::GetNextToken(pszToken, peType); } return result; } bool PdfContentsTokenizer::ReadNext( EPdfContentsType& reType, const char*& rpszKeyword, PdfVariant & rVariant ) { if (m_readingInlineImgData) return ReadInlineImgData(reType, rpszKeyword, rVariant); EPdfTokenType eTokenType; EPdfDataType eDataType; const char* pszToken; // While officially the keyword pointer is undefined if not needed, it // costs us practically nothing to zero it (in case someone fails to check // the return value and/or reType). Do so. We won't nullify the variant // since that has a real cost. //rpszKeyword = 0; // If we've run out of data in this stream and there's another one to read, // switch to reading the next stream. //if( m_device.Device() && m_device.Device()->Eof() && m_lstContents.size() ) //{ // SetCurrentContentsStream( m_lstContents.front() ); // m_lstContents.pop_front(); //} bool gotToken = this->GetNextToken( pszToken, &eTokenType ); if ( !gotToken ) { if ( m_lstContents.size() ) { // We ran out of tokens in this stream. Switch to the next stream // and try again. SetCurrentContentsStream( m_lstContents.front() ); m_lstContents.pop_front(); return ReadNext( reType, rpszKeyword, rVariant ); } else { // No more content stream tokens to read. return false; } } eDataType = this->DetermineDataType( pszToken, eTokenType, rVariant ); // asume we read a variant unless we discover otherwise later. reType = ePdfContentsType_Variant; switch( eDataType ) { case ePdfDataType_Null: case ePdfDataType_Bool: case ePdfDataType_Number: case ePdfDataType_Real: // the data was already read into rVariant by the DetermineDataType function break; case ePdfDataType_Reference: { // references are invalid in content streams PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "references are invalid in content streams" ); break; } case ePdfDataType_Dictionary: this->ReadDictionary( rVariant, NULL ); break; case ePdfDataType_Array: this->ReadArray( rVariant, NULL ); break; case ePdfDataType_String: this->ReadString( rVariant, NULL ); break; case ePdfDataType_HexString: this->ReadHexString( rVariant, NULL ); break; case ePdfDataType_Name: this->ReadName( rVariant ); break; case ePdfDataType_Unknown: case ePdfDataType_RawData: default: // Assume we have a keyword reType = ePdfContentsType_Keyword; rpszKeyword = pszToken; break; } std::string idKW ("ID"); if ((reType == ePdfContentsType_Keyword) && (idKW.compare(rpszKeyword) == 0) ) m_readingInlineImgData = true; return true; } bool PdfContentsTokenizer::ReadInlineImgData( EPdfContentsType& reType, const char*&, PdfVariant & rVariant ) { int c; pdf_int64 counter = 0; if( !m_device.Device() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } // consume the only whitespace between ID and data c = m_device.Device()->Look(); if( PdfTokenizer::IsWhitespace( c ) ) { c = m_device.Device()->GetChar(); } while((c = m_device.Device()->Look()) != EOF) { c = m_device.Device()->GetChar(); if (c=='E' && m_device.Device()->Look()=='I') { // Consume character m_device.Device()->GetChar(); int w = m_device.Device()->Look(); if (w==EOF || PdfTokenizer::IsWhitespace(w)) { // EI is followed by whitespace => stop m_device.Device()->Seek(-2, std::ios::cur); // put back "EI" m_buffer.GetBuffer()[counter] = '\0'; rVariant = PdfData(m_buffer.GetBuffer(), static_cast(counter)); reType = ePdfContentsType_ImageData; m_readingInlineImgData = false; return true; } else { // no whitespace after EI => do not stop m_device.Device()->Seek(-1, std::ios::cur); // put back "I" m_buffer.GetBuffer()[counter] = c; ++counter; } } else { m_buffer.GetBuffer()[counter] = c; ++counter; } if (counter == static_cast(m_buffer.GetSize())) { // image is larger than buffer => resize buffer m_buffer.Resize(m_buffer.GetSize()*2); } } return false; } }; podofo-0.9.5/src/base/PdfParser.h0000664000175000017500000006172712730052013016431 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_PARSER_H_ #define _PDF_PARSER_H_ #include "PdfDefines.h" #include "PdfTokenizer.h" #include "PdfVecObjects.h" #define W_ARRAY_SIZE 3 #define W_MAX_BYTES 4 namespace PoDoFo { typedef std::map TMapObjects; typedef TMapObjects::iterator TIMapObjects; typedef TMapObjects::const_iterator TCIMapObjects; class PdfEncrypt; class PdfString; /** * PdfParser reads a PDF file into memory. * The file can be modified in memory and written back using * the PdfWriter class. * Most PDF features are supported */ class PODOFO_API PdfParser : public PdfTokenizer { friend class PdfDocument; friend class PdfWriter; public: struct TXRefEntry { inline TXRefEntry() : lOffset(0), lGeneration(0), cUsed('\x00'), bParsed(false) { } pdf_long lOffset; long lGeneration; char cUsed; bool bParsed; }; typedef std::vector TVecOffsets; typedef TVecOffsets::iterator TIVecOffsets; typedef TVecOffsets::const_iterator TCIVecOffsets; /** Create a new PdfParser object * You have to open a PDF file using ParseFile later. * \param pVecObjects vector to write the parsed PdfObjects to * * \see ParseFile */ PdfParser( PdfVecObjects* pVecObjects ); /** Create a new PdfParser object and open a PDF file and parse * it into memory. * * \param pVecObjects vector to write the parsed PdfObjects to * \param pszFilename filename of the file which is going to be parsed * \param bLoadOnDemand If true all objects will be read from the file at * the time they are accessed first. * If false all objects will be read immediately. * This is faster if you do not need the complete PDF * file in memory. * * This might throw a PdfError( ePdfError_InvalidPassword ) exception * if a password is required to read this PDF. * Call SetPassword() with the correct password in this case. * * \see SetPassword */ PdfParser( PdfVecObjects* pVecObjects, const char* pszFilename, bool bLoadOnDemand = true ); #ifdef _WIN32 #if defined(_MSC_VER) && _MSC_VER <= 1200 // not for MS Visual Studio 6 #else /** Create a new PdfParser object and open a PDF file and parse * it into memory. * * \param pVecObjects vector to write the parsed PdfObjects to * \param pszFilename filename of the file which is going to be parsed * \param bLoadOnDemand If true all objects will be read from the file at * the time they are accessed first. * If false all objects will be read immediately. * This is faster if you do not need the complete PDF * file in memory. * * This might throw a PdfError( ePdfError_InvalidPassword ) exception * if a password is required to read this PDF. * Call SetPassword() with the correct password in this case. * * This is an overloaded member function to allow working * with unicode characters. On Unix systems you can also pass * UTF-8 to the const char* overload. * * \see SetPassword */ PdfParser( PdfVecObjects* pVecObjects, const wchar_t* pszFilename, bool bLoadOnDemand = true ); #endif #endif // _WIN32 /** Create a new PdfParser object and open a PDF file and parse * it into memory. * * \param pVecObjects vector to write the parsed PdfObjects to * \param pBuffer buffer containing a PDF file in memory * \param lLen length of the buffer containing the PDF file * \param bLoadOnDemand If true all objects will be read from the file at * the time they are accessed first. * If false all objects will be read immediately. * This is faster if you do not need the complete PDF * file in memory. * * This might throw a PdfError( ePdfError_InvalidPassword ) exception * if a password is required to read this PDF. * Call SetPassword() with the correct password in this case. * * \see SetPassword */ PdfParser( PdfVecObjects* pVecObjects, const char* pBuffer, long lLen, bool bLoadOnDemand = true ); /** Create a new PdfParser object and open a PDF file and parse * it into memory. * * \param pVecObjects vector to write the parsed PdfObjects to * \param rDevice read from this PdfRefCountedInputDevice * \param bLoadOnDemand If true all objects will be read from the file at * the time they are accessed first. * If false all objects will be read immediately. * This is faster if you do not need the complete PDF * file in memory. * * This might throw a PdfError( ePdfError_InvalidPassword ) exception * if a password is required to read this PDF. * Call SetPassword() with the correct password in this case. * * \see SetPassword */ PdfParser( PdfVecObjects* pVecObjects, const PdfRefCountedInputDevice & rDevice, bool bLoadOnDemand = true ); /** Delete the PdfParser and all PdfObjects */ virtual ~PdfParser(); /** Open a PDF file and parse it. * * \param pszFilename filename of the file which is going to be parsed * \param bLoadOnDemand If true all objects will be read from the file at * the time they are accessed first. * If false all objects will be read immediately. * This is faster if you do not need the complete PDF * file in memory. * * * This might throw a PdfError( ePdfError_InvalidPassword ) exception * if a password is required to read this PDF. * Call SetPassword() with the correct password in this case. * * \see SetPassword */ void ParseFile( const char* pszFilename, bool bLoadOnDemand = true ); #ifdef _WIN32 /** Open a PDF file and parse it. * * \param pszFilename filename of the file which is going to be parsed * \param bLoadOnDemand If true all objects will be read from the file at * the time they are accesed first. * If false all objects will be read immediately. * This is faster if you do not need the complete PDF * file in memory. * * * This might throw a PdfError( ePdfError_InvalidPassword ) exception * if a password is required to read this PDF. * Call SetPassword with the correct password in this case. * * This is an overloaded member function to allow working * with unicode characters. On Unix systes you can also path * UTF-8 to the const char* overload. * * \see SetPassword */ void ParseFile( const wchar_t* pszFilename, bool bLoadOnDemand = true ); #endif // _WIN32 /** Open a PDF file and parse it. * * \param pBuffer buffer containing a PDF file in memory * \param lLen length of the buffer containing the PDF file * \param bLoadOnDemand If true all objects will be read from the file at * the time they are accessed first. * If false all objects will be read immediately. * This is faster if you do not need the complete PDF * file in memory. * * * This might throw a PdfError( ePdfError_InvalidPassword ) exception * if a password is required to read this PDF. * Call SetPassword() with the correct password in this case. * * \see SetPassword */ void ParseFile( const char* pBuffer, long lLen, bool bLoadOnDemand = true ); /** Open a PDF file and parse it. * * \param rDevice the input device to read from * \param bLoadOnDemand If true all objects will be read from the file at * the time they are accessed first. * If false all objects will be read immediately. * This is faster if you do not need the complete PDF * file in memory. * * * This might throw a PdfError( ePdfError_InvalidPassword ) exception * if a password is required to read this PDF. * Call SetPassword() with the correct password in this case. * * \see SetPassword */ void ParseFile( const PdfRefCountedInputDevice & rDevice, bool bLoadOnDemand = true ); /** Quick method to detect secured PDF files, i.e. * a PDF with an /Encrypt key in the trailer directory. * * \returns true if document is secured, false otherwise */ bool QuickEncryptedCheck( const char* pszFilename ); /** * Retrieve the number of incremental updates that * have been applied to the last parsed PDF file. * * 0 means no update has been applied. * * \returns the number of incremental updates to the parsed PDF. */ inline int GetNumberOfIncrementalUpdates() const; /** Get a reference to the sorted internal objects vector. * \returns the internal objects vector. */ inline const PdfVecObjects* GetObjects() const; /** Get the file format version of the pdf * \returns the file format version as enum */ inline EPdfVersion GetPdfVersion() const; /** Get the file format version of the pdf * \returns the file format version as string */ const char* GetPdfVersionString() const; /** Get the trailer dictionary * which can be written unmodified to a pdf file. */ inline const PdfObject* GetTrailer() const; /** \returns true if this PdfParser loads all objects on demand at * the time they are accessed for the first time. * The default is to load all object immediately. * In this case false is returned. */ inline bool GetLoadOnDemand() const; /** \returns whether the parsed document contains linearization tables */ bool IsLinearized() const { return m_pLinearization != NULL; } /** \returns the length of the file */ size_t GetFileSize() const { return m_nFileSize; } /** * \returns true if this PdfWriter creates an encrypted PDF file */ bool GetEncrypted() const { return (m_pEncrypt != NULL); } /** * \returns the parsers encryption object or NULL if the read PDF file was not encrypted */ const PdfEncrypt* GetEncrypt() const { return m_pEncrypt; } /** * Gives the encryption object from the parser. The internal handle will be set * to NULL and the ownership of the object is given to the caller. * * Only call this if you need access to the encryption object * before deleting the parser. * * \returns the parser's encryption object, or NULL if the read PDF file was not encrypted. */ inline PdfEncrypt* TakeEncrypt(); /** If you try to open an encrypted PDF file, which requires * a password to open, PoDoFo will throw a PdfError( ePdfError_InvalidPassword ) * exception. * * If you got such an exception, you have to set a password * which should be used for opening the PDF. * * The usual way will be to ask the user for the password * and set the password using this method. * * PdfParser will immediately continue to read the PDF file. * * \param sPassword a user or owner password which can be used to open an encrypted PDF file * If the password is invalid, a PdfError( ePdfError_InvalidPassword ) exception is thrown! */ void SetPassword( const std::string & sPassword ); /** * \returns true if strict parsing mode is enabled * * \see SetStringParsing */ inline bool IsStrictParsing() const; /** * Enable/disable strict parsing mode. * Strict parsing is by default disabled. * * If you enable strict parsing, PoDoFo will fail * on a few more common PDF failures. Please note * that PoDoFo's parser is by default very strict * already and does not recover from e.g. wrong XREF * tables. * * \param bStrict new setting for strict parsing mode. */ inline void SetStrictParsing( bool bStrict ); /** * \return if broken objects are ignored while parsing */ inline bool GetIgnoreBrokenObjects(); /** * Specify if the parser should ignore broken * objects, i.e. XRef entries that do not point * to valid objects. * * Default is to not ignore broken objects and * throw an exception if one is found. * * \param bBroken if true broken objects will be ignored */ inline void SetIgnoreBrokenObjects( bool bBroken ); /** * \return maximum object count to read (default is LONG_MAX * which means no limit) */ inline static long GetMaxObjectCount(); /** * Specify the maximum number of objects the parser should * read. An exception is thrown if document contains more * objects than this. Use to avoid problems with very large * documents with millions of objects, which use 500MB of * working set and spend 15 mins in Load() before throwing * an out of memory exception. * * \param nMaxObjects set max number of objects */ inline static void SetMaxObjectCount( long nMaxObjects ); inline pdf_long GetXRefOffset(void); bool HasXRefStream(); protected: /** Searches backwards from the end of the file * and tries to find a token. * The current file is positioned right after the token. * * \param pszToken a token to find * \param lRange range in bytes in which to search * begining at the end of the file */ void FindToken( const char* pszToken, const long lRange ); // Peter Petrov 23 December 2008 /** Searches backwards from the specified position of the file * and tries to find a token. * The current file is positioned right after the token. * * \param pszToken a token to find * \param lRange range in bytes in which to search * begining at the specified position of the file * \param searchEnd specifies position */ void FindToken2( const char* pszToken, const long lRange, size_t searchEnd ); /** Reads the xref sections and the trailers of the file * in the correct order in the memory * and takes care for linearized pdf files. */ void ReadDocumentStructure(); /** Checks wether this pdf is linearized or not. * Initializes the linearization directory on sucess. */ void HasLinearizationDict(); /** Merge the information of this trailer object * in the parsers main trailer object. * \param pTrailer take the keys to merge from this dictionary. */ void MergeTrailer( const PdfObject* pTrailer ); /** Read the trailer directory at the end of the file. */ void ReadTrailer(); /** Looks for a startxref entry at the current file position * and saves its byteoffset to pXRefOffset. * \param pXRefOffset store the byte offset of the xref section into this variable. */ void ReadXRef( pdf_long* pXRefOffset ); /** Reads the xref table from a pdf file. * If there is no xref table, ReadXRefStreamContents() is called. * \param lOffset read the table from this offset * \param bPositionAtEnd if true the xref table is not read, but the * file stream is positioned directly * after the table, which allows reading * a following trailer dictionary. */ void ReadXRefContents( pdf_long lOffset, bool bPositionAtEnd = false ); /** Read a xref subsection * * Throws ePdfError_NoXref if the number of objects read was not * the number specified by the subsection header (as passed in * `nNumObjects'). * * \param nFirstObject object number of the first object * \param nNumObjects how many objects should be read from this section */ void ReadXRefSubsection( pdf_int64 & nFirstObject, pdf_int64 & nNumObjects ); /** Reads a xref stream contens object * \param lOffset read the stream from this offset * \param bReadOnlyTrailer only the trailer is skipped over, the contents * of the xref stream are not parsed */ void ReadXRefStreamContents( pdf_long lOffset, bool bReadOnlyTrailer ); /** Reads all objects from the pdf into memory * from the offsets listed in m_vecOffsets. * * If required an encryption object is setup first. * * The actual reading happens in ReadObjectsInternal() * either if no encryption is required or a correct * encryption object was initialized from SetPassword. */ void ReadObjects(); /** Reads all objects from the pdf into memory * from the offsets listed in m_vecOffsets. * * Requires a correctly setup PdfEncrypt object * with correct password. * * This method is called from ReadObjects * or SetPassword. * * \see ReadObjects * \see SetPassword */ void ReadObjectsInternal(); /** Read the object with index nIndex from the object stream nObjNo * and push it on the objects vector m_vecOffsets. * * All objects are read from this stream and the stream object * is free'd from memory. Further calls who try to read from the * same stream simply do nothing. * * \param nObjNo object number of the stream object * \param nIndex index of the object which should be parsed * */ void ReadObjectFromStream( int nObjNo, int nIndex ); /** Checks the magic number at the start of the pdf file * and sets the m_ePdfVersion member to the correct version * of the pdf file. * * \returns true if this is a pdf file, otherwise false */ bool IsPdfFile(); void ReadNextTrailer(); /** Checks for the existence of the %%EOF marker at the end of the file. * When strict mode is off it will also attempt to setup the parser to ignore * any garbage after the last %%EOF marker. * Simply raises an error if there is a problem with the marker. * */ void CheckEOFMarker(); private: /** Free all internal data structures */ void Clear(); /** Initializes all private members * with their initial values. */ void Init(); /** Small helper method to retrieve the document id from the trailer * * \returns the document id of this PDF document */ const PdfString & GetDocumentId(); /** Determines the correct version of the PDF * from the document catalog (if available), * as PDF > 1.4 allows updating the version. * * If no catalog dictionary is present or no /Version * key is available, the version from the file header will * be used. */ void UpdateDocumentVersion(); private: EPdfVersion m_ePdfVersion; bool m_bLoadOnDemand; pdf_long m_nXRefOffset; long m_nFirstObject; long m_nNumObjects; pdf_long m_nXRefLinearizedOffset; size_t m_nFileSize; pdf_long m_lLastEOFOffset; TVecOffsets m_offsets; PdfVecObjects* m_vecObjects; PdfObject* m_pTrailer; PdfObject* m_pLinearization; PdfEncrypt* m_pEncrypt; bool m_xrefSizeUnknown; std::set m_setObjectStreams; bool m_bStrictParsing; bool m_bIgnoreBrokenObjects; int m_nIncrementalUpdates; int m_nReadNextTrailerLevel; static long s_nMaxObjects; }; // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfParser::GetLoadOnDemand() const { return m_bLoadOnDemand; } // ----------------------------------------------------- // // ----------------------------------------------------- EPdfVersion PdfParser::GetPdfVersion() const { return m_ePdfVersion; } // ----------------------------------------------------- // // ----------------------------------------------------- int PdfParser::GetNumberOfIncrementalUpdates() const { return m_nIncrementalUpdates; } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfVecObjects* PdfParser::GetObjects() const { return m_vecObjects; } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfObject* PdfParser::GetTrailer() const { return m_pTrailer; } // ----------------------------------------------------- // // ----------------------------------------------------- PdfEncrypt* PdfParser::TakeEncrypt() { PdfEncrypt* pEncrypt = m_pEncrypt; m_pEncrypt = NULL; return pEncrypt; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfParser::IsStrictParsing() const { return m_bStrictParsing; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfParser::SetStrictParsing( bool bStrict ) { m_bStrictParsing = bStrict; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfParser::GetIgnoreBrokenObjects() { return m_bIgnoreBrokenObjects; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfParser::SetIgnoreBrokenObjects( bool bBroken ) { m_bIgnoreBrokenObjects = bBroken; } // ----------------------------------------------------- // // ----------------------------------------------------- long PdfParser::GetMaxObjectCount() { return PdfParser::s_nMaxObjects; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfParser::SetMaxObjectCount( long nMaxObjects ) { PdfParser::s_nMaxObjects = nMaxObjects; } // ----------------------------------------------------- // // ----------------------------------------------------- pdf_long PdfParser::GetXRefOffset() { return m_nXRefOffset; } }; #endif // _PDF_PARSER_H_ podofo-0.9.5/src/base/PdfInputStream.cpp0000664000175000017500000001246413013650710020000 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfInputStream.h" #include "PdfInputDevice.h" #include "PdfDefinesPrivate.h" #include #include #include namespace PoDoFo { PdfFileInputStream::PdfFileInputStream( const char* pszFilename ) { m_hFile = fopen( pszFilename, "rb" ); if( !m_hFile ) { PODOFO_RAISE_ERROR_INFO( ePdfError_FileNotFound, pszFilename ); } } #ifdef _WIN32 PdfFileInputStream::PdfFileInputStream( const wchar_t* pszFilename ) { m_hFile = _wfopen( pszFilename, L"rb" ); if( !m_hFile ) { PdfError e( ePdfError_FileNotFound, __FILE__, __LINE__ ); e.SetErrorInformation( pszFilename ); throw e; } } #endif // _WIN32 PdfFileInputStream::~PdfFileInputStream() { if( m_hFile ) fclose( m_hFile ); } pdf_long PdfFileInputStream::Read( char* pBuffer, pdf_long lLen, pdf_long* ) { if( !pBuffer ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } // return zero if EOF is reached if( feof( m_hFile ) ) return 0; // return the number of bytes read and read the data // into pBuffer return fread( pBuffer, sizeof(char), lLen, m_hFile ); } pdf_long PdfFileInputStream::GetFileLength() { pdf_long lOffset = ftello( m_hFile ); pdf_long lLen; if( lOffset == -1 ) PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to read current position in the file" ); if( fseeko( m_hFile, 0L, SEEK_END ) == -1 ) PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to seek at the end of the file" ); lLen = ftello( m_hFile ); if( lLen == -1 ) PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to read file length" ); if( fseeko( m_hFile, lOffset, SEEK_SET ) == -1 ) PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to seek back to the previous position of the file" ); return lLen; } FILE* PdfFileInputStream::GetHandle() { return m_hFile; } PdfMemoryInputStream::PdfMemoryInputStream( const char* pBuffer, pdf_long lBufferLen ) : m_pBuffer( pBuffer ), m_pCur( pBuffer ), m_lBufferLen( lBufferLen ) { } PdfMemoryInputStream::~PdfMemoryInputStream() { } pdf_long PdfMemoryInputStream::Read( char* pBuffer, pdf_long lLen, pdf_long* ) { if( !pBuffer ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } pdf_long lRead = m_pCur - m_pBuffer; // return zero if EOF is reached if( lRead == m_lBufferLen ) return 0; lLen = ( lRead + lLen <= m_lBufferLen ? lLen : m_lBufferLen - lRead ); memcpy( pBuffer, m_pCur, lLen ); m_pCur += lLen; return lLen; } PdfDeviceInputStream::PdfDeviceInputStream( PdfInputDevice* pDevice ) : m_pDevice( pDevice ) { } PdfDeviceInputStream::~PdfDeviceInputStream() { } pdf_long PdfDeviceInputStream::Read( char* pBuffer, pdf_long lLen, pdf_long* ) { return m_pDevice->Read( pBuffer, lLen ); } }; podofo-0.9.5/src/base/PdfOutputDevice.cpp0000664000175000017500000002633313017566505020161 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfOutputDevice.h" #include "PdfRefCountedBuffer.h" #include "PdfDefinesPrivate.h" #include #include namespace PoDoFo { PdfOutputDevice::PdfOutputDevice() { this->Init(); } PdfOutputDevice::PdfOutputDevice( const char* pszFilename, bool bTruncate ) { this->Init(); if( !pszFilename ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } std::ios_base::openmode openmode = std::fstream::binary | std::ios_base::in | std::ios_base::out; if( bTruncate ) openmode |= std::ios_base::trunc; std::fstream *pStream = new std::fstream( pszFilename, openmode ); if( pStream->fail() ) { delete pStream; PODOFO_RAISE_ERROR_INFO( ePdfError_FileNotFound, pszFilename ); } m_pStream = pStream; m_pReadStream = pStream; PdfLocaleImbue( *m_pStream ); if( !bTruncate ) { m_pStream->seekp( 0, std::ios_base::end ); m_ulPosition = m_pStream->tellp(); m_ulLength = m_ulPosition; } } #ifdef _WIN32 PdfOutputDevice::PdfOutputDevice( const wchar_t* pszFilename, bool bTruncate ) { this->Init(); if( !pszFilename ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } m_hFile = _wfopen( pszFilename, bTruncate ? L"w+b" : L"r+b" ); if( !m_hFile ) { PdfError e( ePdfError_FileNotFound, __FILE__, __LINE__ ); e.SetErrorInformation( pszFilename ); throw e; } if( !bTruncate ) { if( fseeko( m_hFile, 0, SEEK_END ) == -1 ) { PODOFO_RAISE_ERROR_INFO( ePdfError_ValueOutOfRange, "Failed to seek to the end of the file" ); } m_ulPosition = ftello( m_hFile ); m_ulLength = m_ulPosition; } } #endif // _WIN32 PdfOutputDevice::PdfOutputDevice( char* pBuffer, size_t lLen ) { this->Init(); if( !pBuffer ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } m_lBufferLen = lLen; m_pBuffer = pBuffer; } PdfOutputDevice::PdfOutputDevice( const std::ostream* pOutStream ) { this->Init(); m_pStream = const_cast< std::ostream* >( pOutStream ); m_pStreamOwned = false; #if USE_CXX_LOCALE m_pStreamSavedLocale = m_pStream->getloc(); PdfLocaleImbue(*m_pStream); #endif } PdfOutputDevice::PdfOutputDevice( PdfRefCountedBuffer* pOutBuffer ) { this->Init(); m_pRefCountedBuffer = pOutBuffer; } PdfOutputDevice::~PdfOutputDevice() { if( m_pStreamOwned ) // remember, deleting a null pointer is safe delete m_pStream; // will call close #if USE_CXX_LOCALE if( !m_pStreamOwned ) m_pStream->imbue(m_pStreamSavedLocale); #endif if( m_hFile ) fclose( m_hFile ); } void PdfOutputDevice::Init() { m_ulLength = 0; m_hFile = NULL; m_pBuffer = NULL; m_pStream = NULL; m_pReadStream = NULL; m_pRefCountedBuffer = NULL; m_lBufferLen = 0; m_ulPosition = 0; m_pStreamOwned = true; } void PdfOutputDevice::Print( const char* pszFormat, ... ) { va_list args; long lBytes; va_start( args, pszFormat ); lBytes = PrintVLen(pszFormat, args); va_end( args ); va_start( args, pszFormat ); PrintV(pszFormat, lBytes, args); va_end( args ); } long PdfOutputDevice::PrintVLen( const char* pszFormat, va_list args ) { long lBytes; if( !pszFormat ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if( m_hFile ) { if( (lBytes = vfprintf( m_hFile, pszFormat, args )) < 0 ) { perror( NULL ); PODOFO_RAISE_ERROR( ePdfError_UnexpectedEOF ); } } else { // OC 17.08.2010: Use new function _vscprintf to get the number of characters: // visual c++ 8.0 == 1400 (Visual Studio 2005) // i am not shure if 1300 is ok here, but who cares this cruel compiler version #if (defined _MSC_VER && _MSC_VER >= 1400 ) lBytes = _vscprintf( pszFormat, args ); #elif (defined _MSC_VER || defined __hpux) // vsnprintf without buffer does not work with MS-VC or HPUX int len = 1024; do { char * temp = new char[len+1]; // OC 17.08.2010 BugFix: +1 avoids corrupted heap lBytes = vsnprintf( temp, len+1, pszFormat, args ); delete[] temp; len *= 2; } while (lBytes < 0 ); #else lBytes = vsnprintf( NULL, 0, pszFormat, args ); #endif } return lBytes; } void PdfOutputDevice::PrintV( const char* pszFormat, long lBytes, va_list args ) { if( !pszFormat ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if( m_pBuffer ) { if( m_ulPosition + lBytes <= m_lBufferLen ) { vsnprintf( m_pBuffer + m_ulPosition, m_lBufferLen - m_ulPosition, pszFormat, args ); } else { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } } else if( m_pStream || m_pRefCountedBuffer ) { ++lBytes; m_printBuffer.Resize( lBytes ); char* data = m_printBuffer.GetBuffer(); if( !data ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } vsnprintf( data, lBytes, pszFormat, args ); if( lBytes ) --lBytes; if( m_pStream ) { std::string str; str.assign( data, lBytes ); *m_pStream << str; } else // if( m_pRefCountedBuffer ) { if( m_ulPosition + lBytes > static_cast(m_pRefCountedBuffer->GetSize()) ) { m_pRefCountedBuffer->Resize( m_ulPosition + lBytes ); } memcpy( m_pRefCountedBuffer->GetBuffer() + m_ulPosition, data, lBytes ); } } m_ulPosition += static_cast(lBytes); if(m_ulPosition>m_ulLength) { m_ulLength = m_ulPosition; } } size_t PdfOutputDevice::Read( char* pBuffer, size_t lLen ) { size_t numRead = 0; if( m_hFile ) { numRead = fread( pBuffer, sizeof(char), lLen, m_hFile ); if(ferror(m_hFile)!=0) { PODOFO_RAISE_ERROR( ePdfError_InvalidDeviceOperation ); } } else if( m_pBuffer ) { if( m_ulPosition <= m_ulLength ) { numRead = PODOFO_MIN(lLen, m_ulLength-m_ulPosition); memcpy( pBuffer, m_pBuffer + m_ulPosition, numRead); } } else if( m_pReadStream ) { size_t iPos = m_pReadStream->tellg(); m_pReadStream->read( pBuffer, lLen ); if(m_pReadStream->fail()&&!m_pReadStream->eof()) { PODOFO_RAISE_ERROR( ePdfError_InvalidDeviceOperation ); } numRead = m_pReadStream->tellg(); numRead -= iPos; } else if( m_pRefCountedBuffer ) { if( m_ulPosition <= m_ulLength ) { numRead = PODOFO_MIN(lLen, m_ulLength-m_ulPosition); memcpy( pBuffer, m_pRefCountedBuffer->GetBuffer() + m_ulPosition, numRead ); } } m_ulPosition += static_cast(numRead); return numRead; } void PdfOutputDevice::Write( const char* pBuffer, size_t lLen ) { if( m_hFile ) { if( fwrite( pBuffer, sizeof(char), lLen, m_hFile ) != static_cast(lLen) ) { PODOFO_RAISE_ERROR( ePdfError_UnexpectedEOF ); } } else if( m_pBuffer ) { if( m_ulPosition + lLen <= m_lBufferLen ) { memcpy( m_pBuffer + m_ulPosition, pBuffer, lLen ); } else { PODOFO_RAISE_ERROR_INFO( ePdfError_OutOfMemory, "Allocated buffer to small for PdfOutputDevice. Cannot write!" ); } } else if( m_pStream ) { m_pStream->write( pBuffer, lLen ); } else if( m_pRefCountedBuffer ) { if( m_ulPosition + lLen > m_pRefCountedBuffer->GetSize() ) m_pRefCountedBuffer->Resize( m_ulPosition + lLen ); memcpy( m_pRefCountedBuffer->GetBuffer() + m_ulPosition, pBuffer, lLen ); } m_ulPosition += static_cast(lLen); if(m_ulPosition>m_ulLength) m_ulLength = m_ulPosition; } void PdfOutputDevice::Seek( size_t offset ) { if( m_hFile ) { if( fseeko( m_hFile, offset, SEEK_SET ) == -1 ) { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } } else if( m_pBuffer ) { if( offset >= m_lBufferLen ) { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } } else if( m_pStream ) { m_pStream->seekp( offset, std::ios_base::beg ); } else if( m_pRefCountedBuffer ) { m_ulPosition = offset; } m_ulPosition = offset; // Seek should not change the length of the device // m_ulLength = offset; } void PdfOutputDevice::Flush() { if( m_hFile ) { if( fflush( m_hFile ) ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } } else if( m_pStream ) { m_pStream->flush(); } } }; podofo-0.9.5/src/base/PdfMemStream.h0000664000175000017500000001752512715357362017106 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_MEM_STREAM_H_ #define _PDF_MEM_STREAM_H_ #include "PdfDefines.h" #include "PdfStream.h" #include "PdfDictionary.h" #include "PdfRefCountedBuffer.h" namespace PoDoFo { class PdfBufferOutputStream; class PdfName; class PdfObject; /** A PDF stream can be appended to any PdfObject * and can contain abitrary data. * * A PDF memory stream is held completely in memory. * * Most of the time it will contain either drawing commands * to draw onto a page or binary data like a font or an image. * * A PdfMemStream is implicitly shared and can therefore be copied very quickly. */ class PODOFO_API PdfMemStream : public PdfStream { friend class PdfVecObjects; public: /** Create a new PdfStream object which has a parent PdfObject. * The stream will be deleted along with the parent. * This constructor will be called by PdfObject::Stream() for you. * \param pParent parent object */ PdfMemStream( PdfObject* pParent ); /** Create a shallow copy of a PdfStream object * * \param rhs the object to clone */ PdfMemStream( const PdfMemStream & rhs ); ~PdfMemStream(); /** Write the stream to an output device * \param pDevice write to this outputdevice. * \param pEncrypt encrypt stream data using this object */ virtual void Write( PdfOutputDevice* pDevice, PdfEncrypt* pEncrypt = NULL ); /** Get a malloced buffer of the current stream. * No filters will be applied to the buffer, so * if the stream is Flate compressed the compressed copy * will be returned. * * The caller has to podofo_free() the buffer. * * \param pBuffer pointer to where the buffer's address will be stored * \param lLen pointer to the buffer length (output parameter) */ virtual void GetCopy( char** pBuffer, pdf_long* lLen ) const; /** Get a copy of a the stream and write it to a PdfOutputStream * * \param pStream data is written to this stream. */ virtual void GetCopy( PdfOutputStream* pStream ) const; /** Get a read-only handle to the current stream data. * The data will not be filtered before being returned, so (eg) calling * Get() on a Flate compressed stream will return a pointer to the * Flate-compressed buffer. * * \warning Do not retain pointers to the stream's internal buffer, * as it may be reallocated with any non-const operation. * * \returns a read-only handle to the streams data */ inline const char* Get() const; /** Get the stream's length. The length is that of the internal * stream buffer, so (eg) for a Flate-compressed stream it will be * the length of the compressed data. * * \returns the length of the internal buffer * \see Get() */ virtual pdf_long GetLength() const; /** This function compresses any currently set stream * using the FlateDecode(ZIP) algorithm. JPEG compressed streams * will not be compressed again using this function. * Entries to the filter dictionary will be added if necessary. */ void FlateCompress(); /** This method removes all filters from the stream */ void Uncompress(); /** Empty's the stream and set the streams buffer size to 0 */ void Empty(); /** Create a copy of a PdfStream object * * \param rhs the object to clone * \returns a reference to this object */ const PdfStream & operator=( const PdfStream & rhs ); protected: /** Required for the GetFilteredCopy implementation * \returns a handle to the internal buffer */ inline virtual const char* GetInternalBuffer() const; /** Required for the GetFilteredCopy implementation * \returns the size of the internal buffer */ inline virtual pdf_long GetInternalBufferSize() const; /** Begin appending data to this stream. * Clears the current stream contents. * * \param vecFilters use this filters to encode any data written to the stream. */ virtual void BeginAppendImpl( const TVecFilters & vecFilters ); /** Append a binary buffer to the current stream contents. * * \param pszString a buffer * \param lLen length of the buffer * * \see BeginAppend * \see Append * \see EndAppend */ virtual void AppendImpl( const char* pszString, size_t lLen ); /** Finish appending data to the stream */ virtual void EndAppendImpl(); private: /** Compress the current data using the FlateDecode (zlib) algorithm * Expects that all filters are setup correctly. */ void FlateCompressStreamData(); private: PdfRefCountedBuffer m_buffer; PdfOutputStream* m_pStream; PdfBufferOutputStream* m_pBufferStream; pdf_long m_lLength; }; // ----------------------------------------------------- // // ----------------------------------------------------- const char* PdfMemStream::Get() const { return m_buffer.GetBuffer(); } // ----------------------------------------------------- // // ----------------------------------------------------- const char* PdfMemStream::GetInternalBuffer() const { return m_buffer.GetBuffer(); } // ----------------------------------------------------- // // ----------------------------------------------------- pdf_long PdfMemStream::GetInternalBufferSize() const { return m_lLength; } }; #endif // _PDF_MEM_STREAM_H_ podofo-0.9.5/src/base/PdfImmediateWriter.h0000664000175000017500000001444212560705174020276 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_IMMEDIATE_WRITER_H_ #define _PDF_IMMEDIATE_WRITER_H_ #include "PdfDefines.h" #include "PdfVecObjects.h" #include "PdfWriter.h" namespace PoDoFo { class PdfEncrypt; class PdfOutputDevice; class PdfXRef; /** A kind of PdfWriter that writes objects with streams immediately to * a PdfOutputDevice */ class PODOFO_API PdfImmediateWriter : private PdfWriter, private PdfVecObjects::Observer, private PdfVecObjects::StreamFactory { public: /** Create a new PdfWriter that writes objects with streams immediately to a PdfOutputDevice * * This has the advantage that large documents can be created without * having to keep the whole document in memory. * * @param pDevice all stream streams are immediately written to this output device * while the document is created. * @param pVecObjects a vector of objects containing the objects which are written to disk * @param pTrailer the trailer object * @param eVersion the PDF version of the document to write. * The PDF version can only be set in the constructor * as it is the first item written to the document on disk. * @param pEncrypt pointer to an encryption object or NULL. If not NULL * the PdfEncrypt object will be copied and used to encrypt the * created document. * @param eWriteMode additional options for writing the pdf */ PdfImmediateWriter( PdfOutputDevice* pDevice, PdfVecObjects* pVecObjects, const PdfObject* pTrailer, EPdfVersion eVersion = ePdfVersion_1_5, PdfEncrypt* pEncrypt = NULL, EPdfWriteMode eWriteMode = ePdfWriteMode_Default ); ~PdfImmediateWriter(); /** Get the write mode used for wirting the PDF * \returns the write mode */ inline EPdfWriteMode GetWriteMode() const; /** Get the PDF version of the document * The PDF version can only be set in the constructor * as it is the first item written to the document on disk * * \returns EPdfVersion version of the pdf document */ inline EPdfVersion GetPdfVersion() const; private: void WriteObject( const PdfObject* pObject ); /** Called when the PdfVecObjects we observer is deleted. */ void ParentDestructed(); /** Finish the PDF file. * I.e. write the XRef and close the output device. */ void Finish(); /** Called whenever appending to a stream is started. * \param pStream the stream object the user currently writes to. */ void BeginAppendStream( const PdfStream* pStream ); /** Called whenever appending to a stream has ended. * \param pStream the stream object the user currently writes to. */ void EndAppendStream( const PdfStream* pStream ); /** Creates a stream object * * \param pParent parent object * * \returns a new stream object */ PdfStream* CreateStream( PdfObject* pParent ); /** Assume the stream for the last object has * been written complete. * Therefore close the stream of the object * now so that the next object can be written * to disk */ void FinishLastObject(); private: PdfVecObjects* m_pParent; PdfOutputDevice* m_pDevice; PdfXRef* m_pXRef; PdfObject* m_pLast; bool m_bOpenStream; }; // ----------------------------------------------------- // // ----------------------------------------------------- inline EPdfWriteMode PdfImmediateWriter::GetWriteMode() const { return PdfWriter::GetWriteMode(); } // ----------------------------------------------------- // // ----------------------------------------------------- inline EPdfVersion PdfImmediateWriter::GetPdfVersion() const { return PdfWriter::GetPdfVersion(); } }; #endif /* _PDF_IMMEDIATE_WRITER_H_ */ podofo-0.9.5/src/base/PdfStream.h0000664000175000017500000003173013012364201016416 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_STREAM_H_ #define _PDF_STREAM_H_ #include "PdfDefines.h" #include "PdfDictionary.h" #include "PdfFilter.h" #include "PdfRefCountedBuffer.h" #include namespace PoDoFo { class PdfInputStream; class PdfName; class PdfObject; class PdfOutputStream; /** A PDF stream can be appended to any PdfObject * and can contain arbitrary data. * * Most of the time it will contain either drawing commands * to draw onto a page or binary data like a font or an image. * * You have to use a concrete implementation of a stream, * which can be retrieved from a StreamFactory. * \see PdfVecObjects * \see PdfMemoryStream * \see PdfFileStream */ class PODOFO_API PdfStream { public: /** The default filter to use when changing the stream content. * It's a static member and applies to all newly created/changed streams. * The default value is ePdfFilter_FlateDecode. */ static enum EPdfFilter eDefaultFilter; /** Create a new PdfStream object which has a parent PdfObject. * The stream will be deleted along with the parent. * This constructor will be called by PdfObject::Stream() for you. * \param pParent parent object */ PdfStream( PdfObject* pParent ); virtual ~PdfStream(); /** Write the stream to an output device * \param pDevice write to this outputdevice. * \param pEncrypt encrypt stream data using this object */ virtual void Write( PdfOutputDevice* pDevice, PdfEncrypt* pEncrypt = NULL ) = 0; /** Set a binary buffer as stream data. * * Use PdfFilterFactory::CreateFilterList() if you want to use the contents * of the stream dictionary's existing filter key. * * \param szBuffer buffer containing the stream data * \param lLen length of the buffer * \param vecFilters a list of filters to use when appending data */ void Set( const char* szBuffer, pdf_long lLen, const TVecFilters & vecFilters ); /** Set a binary buffer as stream data. * All data will be Flate-encoded. * * \param szBuffer buffer containing the stream data * \param lLen length of the buffer */ void Set( const char* szBuffer, pdf_long lLen ); /** Set a binary buffer whose contents are read from a PdfInputStream * All data will be Flate-encoded. * * \param pStream read stream contents from this PdfInputStream */ void Set( PdfInputStream* pStream ); /** Set a binary buffer whose contents are read from a PdfInputStream * * Use PdfFilterFactory::CreateFilterList() if you want to use the contents * of the stream dictionary's existing filter key. * * \param pStream read stream contents from this PdfInputStream * \param vecFilters a list of filters to use when appending data */ void Set( PdfInputStream* pStream, const TVecFilters & vecFilters ); /** Set a null-terminated char* buffer as the stream's contents. * * The string will be copied into a newly allocated buffer. * \param pszString a zero terminated string buffer containing only * ASCII text data */ inline void Set( const char* pszString ); /** Sets raw data for this stream which is read from an input stream. * This method does neither encode nor decode the read data. * The filters of the object are not modified and the data is expected * encoded as stated by the /Filters key in the stream's object. * * \param pStream read data from this input stream * \param lLen read exactly lLen bytes from the input stream, * if lLen = -1 read until the end of the input stream * was reached. */ void SetRawData( PdfInputStream* pStream, pdf_long lLen = -1 ); /** Start appending data to this stream. * * This method has to be called before any of the append methods. * All appended data will be Flate-encoded. * * \param bClearExisting if true any existing stream contents will * be cleared. * * \see Append * \see EndAppend * \see eDefaultFilter */ void BeginAppend( bool bClearExisting = true ); /** Start appending data to this stream. * This method has to be called before any of the append methods. * * Use PdfFilterFactory::CreateFilterList() if you want to use the contents * of the stream dictionary's existing filter key. * * \param vecFilters a list of filters to use when appending data * \param bClearExisting if true any existing stream contents will be cleared. * \param bDeleteFilters if true existing filter keys are deleted if an * empty list of filters is passed (required for SetRawData()) * * \see Append * \see EndAppend */ void BeginAppend( const TVecFilters & vecFilters, bool bClearExisting = true, bool bDeleteFilters = true ); /** Append a binary buffer to the current stream contents. * * Make sure BeginAppend() has been called before. * * \param pszString a buffer * \param lLen length of the buffer * * \see BeginAppend * \see EndAppend */ inline void Append( const char* pszString, size_t lLen ); /** Append a null-terminated string to the current stream contents. * * Make sure BeginAppend() has been called before. * * \param pszString a zero-terminated string buffer containing only * ASCII text data * * \see BeginAppend * \see EndAppend */ inline void Append( const char* pszString ); /** Append to the current stream contents. * * Make sure BeginAppend() has been called before. * * \param sString a std::string containing only ASCII text data * * \see BeginAppend * \see EndAppend */ inline void Append( const std::string& sString ); /** Finish appending data to this stream. * BeginAppend() has to be called before this method. * * \see BeginAppend * \see Append */ void EndAppend(); /** * \returns true if code is between BeginAppend() * and EndAppend() at the moment, i.e. it * is safe to call EndAppend() now. * * \see BeginAppend * \see Append */ inline bool IsAppending() const; /** Get the stream's length with all filters applied (e.g. if the stream is * Flate-compressed, the length of the compressed data stream). * * \returns the length of the internal buffer */ virtual pdf_long GetLength() const = 0; /** Get a malloc()'d buffer of the current stream. * No filters will be applied to the buffer, so * if the stream is Flate-compressed the compressed copy * will be returned. * * The caller has to podofo_free() the buffer. * * \param pBuffer pointer to the buffer * \param lLen pointer to the buffer length */ virtual void GetCopy( char** pBuffer, pdf_long* lLen ) const = 0; /** Get a copy of a the stream and write it to a PdfOutputStream * * \param pStream data is written to this stream. */ virtual void GetCopy( PdfOutputStream* pStream ) const = 0; /** Get a malloc()'d buffer of the current stream which has been * filtered by all filters as specified in the dictionary's * /Filter key. For example, if the stream is Flate-compressed, * the buffer returned from this method will have been decompressed. * * The caller has to podofo_free() the buffer. * * \param pBuffer pointer to the buffer * \param lLen pointer to the buffer length */ void GetFilteredCopy( char** pBuffer, pdf_long* lLen ) const; /** Get a filtered copy of a the stream and write it to a PdfOutputStream * * \param pStream filtered data is written to this stream. */ void GetFilteredCopy( PdfOutputStream* pStream ) const; /** Create a copy of a PdfStream object * \param rhs the object to clone * \returns a reference to this object */ const PdfStream & operator=( const PdfStream & rhs ); protected: /** Required for the GetFilteredCopy() implementation * \returns a handle to the internal buffer */ virtual const char* GetInternalBuffer() const = 0; /** Required for the GetFilteredCopy() implementation * \returns the size of the internal buffer */ virtual pdf_long GetInternalBufferSize() const = 0; /** Begin appending data to this stream. * Clears the current stream contents. * * Use PdfFilterFactory::CreateFilterList() if you want to use the contents * of the stream dictionary's existing filter key. * * \param vecFilters use these filters to encode any data written * to the stream. */ virtual void BeginAppendImpl( const TVecFilters & vecFilters ) = 0; /** Append a binary buffer to the current stream contents. * * \param pszString a buffer * \param lLen length of the buffer * * \see BeginAppend * \see Append * \see EndAppend */ virtual void AppendImpl( const char* pszString, size_t lLen ) = 0; /** Finish appending data to the stream */ virtual void EndAppendImpl() = 0; protected: PdfObject* m_pParent; bool m_bAppend; }; // ----------------------------------------------------- // // ----------------------------------------------------- void PdfStream::Set( const char* pszString ) { if( pszString ) Set( const_cast(pszString), strlen( pszString ) ); } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfStream::Append( const char* pszString, size_t lLen ) { PODOFO_RAISE_LOGIC_IF( !m_bAppend, "Append() failed because BeginAppend() was not yet called!" ); this->AppendImpl( pszString, lLen ); } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfStream::Append( const char* pszString ) { if( pszString ) Append( pszString, strlen( pszString ) ); } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfStream::Append( const std::string& sString ) { Append( sString.c_str(), sString.length() ); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfStream::IsAppending() const { return m_bAppend; } }; #endif // _PDF_STREAM_H_ podofo-0.9.5/src/base/PdfObjectStreamParserObject.h0000664000175000017500000000756712347271543022104 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_OBJECT_STREAM_PARSER_OBJECT_H_ #define _PDF_OBJECT_STREAM_PARSER_OBJECT_H_ #include "PdfDefines.h" #include "PdfRefCountedBuffer.h" namespace PoDoFo { class PdfEncrypt; class PdfParserObject; class PdfVecObjects; /** * A utility class for PdfParser that can parse * an object stream object. * * It is mainly here to make PdfParser more modular. */ class PdfObjectStreamParserObject { public: typedef std::vector ObjectIdList; /** * Create a new PdfObjectStreamParserObject from an existing * PdfParserObject. The PdfParserObject will be removed and deleted. * All objects from the object stream will be read into memory. * * \param pParser PdfParserObject for an object stream * \param pVecObjects add loaded objecs to this vector of objects * \param rBuffer use this allocated buffer for caching * \param pEncrypt encryption object used to decrypt streams */ PdfObjectStreamParserObject(PdfParserObject* pParser, PdfVecObjects* pVecObjects, const PdfRefCountedBuffer & rBuffer, PdfEncrypt* pEncrypt ); ~PdfObjectStreamParserObject(); void Parse(ObjectIdList const &); private: void ReadObjectsFromStream( char* pBuffer, pdf_long lBufferLen, pdf_int64 lNum, pdf_int64 lFirst, ObjectIdList const &); private: PdfParserObject* m_pParser; PdfVecObjects* m_vecObjects; PdfRefCountedBuffer m_buffer; PdfEncrypt* m_pEncrypt; }; }; #endif // _PDF_OBJECT_STREAM_PARSER_OBJECT_H_ podofo-0.9.5/src/base/PdfFiltersPrivate.h0000664000175000017500000007673613013650710020151 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FILTERS_PRIVATE_H_ #define _PDF_FILTERS_PRIVATE_H_ /** * \file PdfFiltersPrivate.h * * Provides implementations of various PDF stream filters. * * This is an internal header. It should not be included in podofo.h, and * should not be included directly by client applications. These filters should * only be accessed through the factory interface in PdfFilters.h . */ #include "PdfDefines.h" #include "PdfDefinesPrivate.h" #include "PdfFilter.h" #include "PdfRefCountedBuffer.h" #include #ifdef PODOFO_HAVE_JPEG_LIB extern "C" { #ifdef _WIN32 // Collision between Win32 and libjpeg headers #define XMD_H #undef FAR #ifndef HAVE_BOOLEAN #define HAVE_BOOLEAN #define PODOFO_JPEG_HAVE_BOOLEAN // not to be defined in the build system #endif #endif #include "jpeglib.h" #ifdef PODOFO_JPEG_HAVE_BOOLEAN #undef HAVE_BOOLEAN #endif } #endif // PODOFO_HAVE_JPEG_LIB #ifdef PODOFO_HAVE_TIFF_LIB extern "C" { #include "tiffio.h" #ifdef _WIN32 // Collision between tiff and jpeg-headers #define XMD_H #undef FAR #endif } #endif // PODOFO_HAVE_TIFF_LIB namespace PoDoFo { #define PODOFO_FILTER_INTERNAL_BUFFER_SIZE 4096 class PdfPredictorDecoder; class PdfOutputDevice; /** The ascii hex filter. */ class PdfHexFilter : public PdfFilter { public: PdfHexFilter(); virtual ~PdfHexFilter() { } /** Check wether the encoding is implemented for this filter. * * \returns true if the filter is able to encode data */ inline virtual bool CanEncode() const; /** Encode a block of data and write it to the PdfOutputStream * specified by BeginEncodeImpl. * * BeginEncodeImpl() has to be called before this function. * * \param pBuffer pointer to a buffer with data to encode * \param lLen length of data to encode. * * Call EndEncodeImpl() after all data has been encoded * * * \see BeginEncodeImpl * \see EndEncodeImpl */ virtual void EncodeBlockImpl( const char* pBuffer, pdf_long lLen ); /** Check wether the decoding is implemented for this filter. * * \returns true if the filter is able to decode data */ inline virtual bool CanDecode() const; /** Real implementation of `BeginDecode()'. NEVER call this method directly. * * By default this function does nothing. If your filter needs to do setup for decoding, * you should override this method. * * PdfFilter ensures that a valid stream is available when this method is called, and * that EndDecode() was called since the last BeginDecode()/DecodeBlock(). * * \see BeginDecode */ virtual void BeginDecodeImpl( const PdfDictionary* ); /** Real implementation of `DecodeBlock()'. NEVER call this method directly. * * You must override this method to decode the buffer passed by the caller. * * You are not obliged to immediately process any or all of the data in * the passed buffer, but you must ensure that you have processed it and * written it out by the end of EndDecodeImpl(). You must copy the buffer * if you're going to store it, as ownership is not transferred to the * filter and the caller may free the buffer at any time. * * PdfFilter ensures that a valid stream is available when this method is * called, ensures that BeginDecode() has been called, and ensures that * EndDecode() has not been called since the last BeginDecode(). * * \see DecodeBlock */ virtual void DecodeBlockImpl( const char* pBuffer, pdf_long lLen ); /** Real implementation of `EndDecode()'. NEVER call this method directly. * * By the time this method returns, all filtered data must be written to the stream * and the filter must be in a state where BeginDecode() can be safely called. * * PdfFilter ensures that a valid stream is available when this method is * called, and ensures that BeginDecodeImpl() has been called. * * \see EndDecode */ virtual void EndDecodeImpl(); /** GetType of this filter. * \returns the GetType of this filter */ inline virtual EPdfFilter GetType() const; private: char m_cDecodedByte; bool m_bLow; }; // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfHexFilter::CanEncode() const { return true; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfHexFilter::CanDecode() const { return true; } // ----------------------------------------------------- // // ----------------------------------------------------- EPdfFilter PdfHexFilter::GetType() const { return ePdfFilter_ASCIIHexDecode; } /** The Ascii85 filter. */ class PdfAscii85Filter : public PdfFilter { public: PdfAscii85Filter(); virtual ~PdfAscii85Filter() { } /** Check wether the encoding is implemented for this filter. * * \returns true if the filter is able to encode data */ inline virtual bool CanEncode() const; /** Begin encoding data using this filter. Called by PdfFilter::BeginEncode. * * \see EncodeBlockImpl * \see EndEncodeImpl * \see PdfFilter::BeginEncode */ virtual void BeginEncodeImpl(); /** Encode a block of data and write it to the PdfOutputStream * specified by BeginEncodeImpl. * * BeginEncodeImpl() has to be called before this function. * * \param pBuffer pointer to a buffer with data to encode * \param lLen length of data to encode. * * Call EndEncodeImpl() after all data has been encoded * * * \see BeginEncodeImpl * \see EndEncodeImpl */ virtual void EncodeBlockImpl( const char* pBuffer, pdf_long lLen ); /** * Finish encoding of data. * * \see BeginEncodeImpl * \see EncodeBlockImpl */ virtual void EndEncodeImpl(); /** Check wether the decoding is implemented for this filter. * * \returns true if the filter is able to decode data */ inline virtual bool CanDecode() const; /** Real implementation of `BeginDecode()'. NEVER call this method directly. * * By default this function does nothing. If your filter needs to do setup for decoding, * you should override this method. * * PdfFilter ensures that a valid stream is available when this method is called, and * that EndDecode() was called since the last BeginDecode()/DecodeBlock(). * * \see BeginDecode */ virtual void BeginDecodeImpl( const PdfDictionary* ); /** Real implementation of `DecodeBlock()'. NEVER call this method directly. * * You must override this method to decode the buffer passed by the caller. * * You are not obliged to immediately process any or all of the data in * the passed buffer, but you must ensure that you have processed it and * written it out by the end of EndDecodeImpl(). You must copy the buffer * if you're going to store it, as ownership is not transferred to the * filter and the caller may free the buffer at any time. * * PdfFilter ensures that a valid stream is available when this method is * called, ensures that BeginDecode() has been called, and ensures that * EndDecode() has not been called since the last BeginDecode(). * * \see DecodeBlock */ virtual void DecodeBlockImpl( const char* pBuffer, pdf_long lLen ); /** Real implementation of `EndDecode()'. NEVER call this method directly. * * By the time this method returns, all filtered data must be written to the stream * and the filter must be in a state where BeginDecode() can be safely called. * * PdfFilter ensures that a valid stream is available when this method is * called, and ensures that BeginDecodeImpl() has been called. * * \see EndDecode */ virtual void EndDecodeImpl(); /** GetType of this filter. * \returns the GetType of this filter */ inline virtual EPdfFilter GetType() const; private: void EncodeTuple ( unsigned long tuple, int bytes ); void WidePut( unsigned long tuple, int bytes ) const; private: int m_count; unsigned long m_tuple; }; // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfAscii85Filter::CanEncode() const { return true; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfAscii85Filter::CanDecode() const { return true; } // ----------------------------------------------------- // // ----------------------------------------------------- EPdfFilter PdfAscii85Filter::GetType() const { return ePdfFilter_ASCII85Decode; } /** The flate filter. */ class PdfFlateFilter : public PdfFilter { public: PdfFlateFilter(); virtual ~PdfFlateFilter(); /** Check wether the encoding is implemented for this filter. * * \returns true if the filter is able to encode data */ inline virtual bool CanEncode() const; /** Begin encoding data using this filter. Called by PdfFilter::BeginEncode. * * \see EncodeBlockImpl * \see EndEncodeImpl * \see PdfFilter::BeginEncode */ virtual void BeginEncodeImpl(); /** Encode a block of data and write it to the PdfOutputStream * specified by BeginEncodeImpl. * * BeginEncodeImpl() has to be called before this function. * * \param pBuffer pointer to a buffer with data to encode * \param lLen length of data to encode. * * Call EndEncodeImpl() after all data has been encoded * * * \see BeginEncodeImpl * \see EndEncodeImpl */ virtual void EncodeBlockImpl( const char* pBuffer, pdf_long lLen ); /** * Finish encoding of data. * * \see BeginEncodeImpl * \see EncodeBlockImpl */ virtual void EndEncodeImpl(); /** Check wether the decoding is implemented for this filter. * * \returns true if the filter is able to decode data */ inline virtual bool CanDecode() const; /** Real implementation of `BeginDecode()'. NEVER call this method directly. * * By default this function does nothing. If your filter needs to do setup for decoding, * you should override this method. * * PdfFilter ensures that a valid stream is available when this method is called, and * that EndDecode() was called since the last BeginDecode()/DecodeBlock(). * * \param pDecodeParms additional parameters for decoding data * * \see BeginDecode */ virtual void BeginDecodeImpl( const PdfDictionary* pDecodeParms ); /** Real implementation of `DecodeBlock()'. NEVER call this method directly. * * You must override this method to decode the buffer passed by the caller. * * You are not obliged to immediately process any or all of the data in * the passed buffer, but you must ensure that you have processed it and * written it out by the end of EndDecodeImpl(). You must copy the buffer * if you're going to store it, as ownership is not transferred to the * filter and the caller may free the buffer at any time. * * PdfFilter ensures that a valid stream is available when this method is * called, ensures that BeginDecode() has been called, and ensures that * EndDecode() has not been called since the last BeginDecode(). * * \see DecodeBlock */ virtual void DecodeBlockImpl( const char* pBuffer, pdf_long lLen ); /** Real implementation of `EndDecode()'. NEVER call this method directly. * * By the time this method returns, all filtered data must be written to the stream * and the filter must be in a state where BeginDecode() can be safely called. * * PdfFilter ensures that a valid stream is available when this method is * called, and ensures that BeginDecodeImpl() has been called. * * \see EndDecode */ virtual void EndDecodeImpl(); /** GetType of this filter. * \returns the GetType of this filter */ inline virtual EPdfFilter GetType() const; private: void EncodeBlockInternal( const char* pBuffer, pdf_long lLen, int nMode ); private: unsigned char m_buffer[PODOFO_FILTER_INTERNAL_BUFFER_SIZE]; z_stream m_stream; PdfPredictorDecoder* m_pPredictor; }; // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfFlateFilter::CanEncode() const { return true; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfFlateFilter::CanDecode() const { return true; } // ----------------------------------------------------- // // ----------------------------------------------------- EPdfFilter PdfFlateFilter::GetType() const { return ePdfFilter_FlateDecode; } /** The RLE filter. */ class PdfRLEFilter : public PdfFilter { public: PdfRLEFilter(); virtual ~PdfRLEFilter() {} /** Check wether the encoding is implemented for this filter. * * \returns true if the filter is able to encode data */ inline virtual bool CanEncode() const; virtual void BeginEncodeImpl(); /** Encode a block of data and write it to the PdfOutputStream * specified by BeginEncodeImpl. * * BeginEncodeImpl() has to be called before this function. * * \param pBuffer pointer to a buffer with data to encode * \param lLen length of data to encode. * * Call EndEncodeImpl() after all data has been encoded * * * \see BeginEncodeImpl * \see EndEncodeImpl */ virtual void EncodeBlockImpl( const char* pBuffer, pdf_long lLen ); /** * Finish encoding of data. * * \see BeginEncodeImpl * \see EncodeBlockImpl */ virtual void EndEncodeImpl(); /** Check wether the decoding is implemented for this filter. * * \returns true if the filter is able to decode data */ inline virtual bool CanDecode() const; /** Real implementation of `BeginDecode()'. NEVER call this method directly. * * By default this function does nothing. If your filter needs to do setup for decoding, * you should override this method. * * PdfFilter ensures that a valid stream is available when this method is called, and * that EndDecode() was called since the last BeginDecode()/DecodeBlock(). * * \see BeginDecode */ virtual void BeginDecodeImpl( const PdfDictionary* ); /** Real implementation of `DecodeBlock()'. NEVER call this method directly. * * You must override this method to decode the buffer passed by the caller. * * You are not obliged to immediately process any or all of the data in * the passed buffer, but you must ensure that you have processed it and * written it out by the end of EndDecodeImpl(). You must copy the buffer * if you're going to store it, as ownership is not transferred to the * filter and the caller may free the buffer at any time. * * PdfFilter ensures that a valid stream is available when this method is * called, ensures that BeginDecode() has been called, and ensures that * EndDecode() has not been called since the last BeginDecode(). * * \see DecodeBlock */ virtual void DecodeBlockImpl( const char* pBuffer, pdf_long lLen ); /** GetType of this filter. * \returns the GetType of this filter */ inline virtual EPdfFilter GetType() const; private: int m_nCodeLen; }; // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfRLEFilter::CanEncode() const { return false; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfRLEFilter::CanDecode() const { return true; } // ----------------------------------------------------- // // ----------------------------------------------------- EPdfFilter PdfRLEFilter::GetType() const { return ePdfFilter_RunLengthDecode; } /** The LZW filter. */ class PdfLZWFilter : public PdfFilter { struct TLzwItem { std::vector value; }; typedef std::vector TLzwTable; typedef TLzwTable::iterator TILzwTable; typedef TLzwTable::const_iterator TCILzwTable; public: PdfLZWFilter(); virtual ~PdfLZWFilter(); /** Check wether the encoding is implemented for this filter. * * \returns true if the filter is able to encode data */ inline virtual bool CanEncode() const; /** Begin encoding data using this filter. Called by PdfFilter::BeginEncode. * * \see EncodeBlockImpl * \see EndEncodeImpl * \see PdfFilter::BeginEncode */ virtual void BeginEncodeImpl(); /** Encode a block of data and write it to the PdfOutputStream * specified by BeginEncodeImpl. * * BeginEncodeImpl() has to be called before this function. * * \param pBuffer pointer to a buffer with data to encode * \param lLen length of data to encode. * * Call EndEncodeImpl() after all data has been encoded * * * \see BeginEncodeImpl * \see EndEncodeImpl */ virtual void EncodeBlockImpl( const char* pBuffer, pdf_long lLen ); /** * Finish encoding of data. * * \see BeginEncodeImpl * \see EncodeBlockImpl */ virtual void EndEncodeImpl(); /** Check wether the decoding is implemented for this filter. * * \returns true if the filter is able to decode data */ inline virtual bool CanDecode() const; /** Real implementation of `BeginDecode()'. NEVER call this method directly. * * By default this function does nothing. If your filter needs to do setup for decoding, * you should override this method. * * PdfFilter ensures that a valid stream is available when this method is called, and * that EndDecode() was called since the last BeginDecode()/DecodeBlock(). * * \see BeginDecode */ virtual void BeginDecodeImpl( const PdfDictionary* ); /** Real implementation of `DecodeBlock()'. NEVER call this method directly. * * You must override this method to decode the buffer passed by the caller. * * You are not obliged to immediately process any or all of the data in * the passed buffer, but you must ensure that you have processed it and * written it out by the end of EndDecodeImpl(). You must copy the buffer * if you're going to store it, as ownership is not transferred to the * filter and the caller may free the buffer at any time. * * PdfFilter ensures that a valid stream is available when this method is * called, ensures that BeginDecode() has been called, and ensures that * EndDecode() has not been called since the last BeginDecode(). * * \see DecodeBlock */ virtual void DecodeBlockImpl( const char* pBuffer, pdf_long lLen ); /** Real implementation of `EndDecode()'. NEVER call this method directly. * * By the time this method returns, all filtered data must be written to the stream * and the filter must be in a state where BeginDecode() can be safely called. * * PdfFilter ensures that a valid stream is available when this method is * called, and ensures that BeginDecodeImpl() has been called. * * \see EndDecode */ virtual void EndDecodeImpl(); /** GetType of this filter. * \returns the GetType of this filter */ inline virtual EPdfFilter GetType() const; private: /** Initialize an lzw table. */ void InitTable(); private: static const unsigned short s_masks[4]; static const unsigned short s_clear; static const unsigned short s_eod; TLzwTable m_table; unsigned int m_mask; unsigned int m_code_len; unsigned char m_character; bool m_bFirst; PdfPredictorDecoder* m_pPredictor; }; // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfLZWFilter::CanEncode() const { return false; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfLZWFilter::CanDecode() const { return true; } // ----------------------------------------------------- // // ----------------------------------------------------- EPdfFilter PdfLZWFilter::GetType() const { return ePdfFilter_LZWDecode; } #ifdef PODOFO_HAVE_JPEG_LIB void PODOFO_API jpeg_memory_src (j_decompress_ptr cinfo, const JOCTET * buffer, size_t bufsize); extern "C" { void JPegErrorExit(j_common_ptr cinfo); void JPegErrorOutput(j_common_ptr, int); }; /** The DCT filter can decoded JPEG compressed data. * * This filter requires JPEG lib to be available */ class PdfDCTFilter : public PdfFilter { public: PdfDCTFilter(); virtual ~PdfDCTFilter(); /** Check wether the encoding is implemented for this filter. * * \returns true if the filter is able to encode data */ inline virtual bool CanEncode() const; /** Begin encoding data using this filter. Called by PdfFilter::BeginEncode. * * \see EncodeBlockImpl * \see EndEncodeImpl * \see PdfFilter::BeginEncode */ virtual void BeginEncodeImpl(); /** Encode a block of data and write it to the PdfOutputStream * specified by BeginEncodeImpl. * * BeginEncodeImpl() has to be called before this function. * * \param pBuffer pointer to a buffer with data to encode * \param lLen length of data to encode. * * Call EndEncodeImpl() after all data has been encoded * * * \see BeginEncodeImpl * \see EndEncodeImpl */ virtual void EncodeBlockImpl( const char* pBuffer, pdf_long lLen ); /** * Finish encoding of data. * * \see BeginEncodeImpl * \see EncodeBlockImpl */ virtual void EndEncodeImpl(); /** Check wether the decoding is implemented for this filter. * * \returns true if the filter is able to decode data */ inline virtual bool CanDecode() const; /** Real implementation of `BeginDecode()'. NEVER call this method directly. * * By default this function does nothing. If your filter needs to do setup for decoding, * you should override this method. * * PdfFilter ensures that a valid stream is available when this method is called, and * that EndDecode() was called since the last BeginDecode()/DecodeBlock(). * * \see BeginDecode */ virtual void BeginDecodeImpl( const PdfDictionary* ); /** Real implementation of `DecodeBlock()'. NEVER call this method directly. * * You must override this method to decode the buffer passed by the caller. * * You are not obliged to immediately process any or all of the data in * the passed buffer, but you must ensure that you have processed it and * written it out by the end of EndDecodeImpl(). You must copy the buffer * if you're going to store it, as ownership is not transferred to the * filter and the caller may free the buffer at any time. * * PdfFilter ensures that a valid stream is available when this method is * called, ensures that BeginDecode() has been called, and ensures that * EndDecode() has not been called since the last BeginDecode(). * * \see DecodeBlock */ virtual void DecodeBlockImpl( const char* pBuffer, pdf_long lLen ); /** Real implementation of `EndDecode()'. NEVER call this method directly. * * By the time this method returns, all filtered data must be written to the stream * and the filter must be in a state where BeginDecode() can be safely called. * * PdfFilter ensures that a valid stream is available when this method is * called, and ensures that BeginDecodeImpl() has been called. * * \see EndDecode */ virtual void EndDecodeImpl(); /** GetType of this filter. * \returns the GetType of this filter */ inline virtual EPdfFilter GetType() const; private: struct jpeg_decompress_struct m_cinfo; struct jpeg_error_mgr m_jerr; PdfRefCountedBuffer m_buffer; PdfOutputDevice* m_pDevice; }; // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfDCTFilter::CanEncode() const { return false; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfDCTFilter::CanDecode() const { return true; } // ----------------------------------------------------- // // ----------------------------------------------------- EPdfFilter PdfDCTFilter::GetType() const { return ePdfFilter_DCTDecode; } #endif // PODOFO_HAVE_JPEG_LIB #ifdef PODOFO_HAVE_TIFF_LIB /** The CCITT filter can decoded CCITTFaxDecode compressed data. * * This filter requires TIFFlib to be available */ class PdfCCITTFilter : public PdfFilter { public: PdfCCITTFilter(); virtual ~PdfCCITTFilter(); /** Check wether the encoding is implemented for this filter. * * \returns true if the filter is able to encode data */ inline virtual bool CanEncode() const; /** Begin encoding data using this filter. Called by PdfFilter::BeginEncode. * * \see EncodeBlockImpl * \see EndEncodeImpl * \see PdfFilter::BeginEncode */ virtual void BeginEncodeImpl(); /** Encode a block of data and write it to the PdfOutputStream * specified by BeginEncodeImpl. * * BeginEncodeImpl() has to be called before this function. * * \param pBuffer pointer to a buffer with data to encode * \param lLen length of data to encode. * * Call EndEncodeImpl() after all data has been encoded * * * \see BeginEncodeImpl * \see EndEncodeImpl */ virtual void EncodeBlockImpl( const char* pBuffer, pdf_long lLen ); /** * Finish encoding of data. * * \see BeginEncodeImpl * \see EncodeBlockImpl */ virtual void EndEncodeImpl(); /** Check wether the decoding is implemented for this filter. * * \returns true if the filter is able to decode data */ inline virtual bool CanDecode() const; /** Real implementation of `BeginDecode()'. NEVER call this method directly. * * By default this function does nothing. If your filter needs to do setup for decoding, * you should override this method. * * PdfFilter ensures that a valid stream is available when this method is called, and * that EndDecode() was called since the last BeginDecode()/DecodeBlock(). * * \see BeginDecode */ virtual void BeginDecodeImpl( const PdfDictionary* ); /** Real implementation of `DecodeBlock()'. NEVER call this method directly. * * You must override this method to decode the buffer passed by the caller. * * You are not obliged to immediately process any or all of the data in * the passed buffer, but you must ensure that you have processed it and * written it out by the end of EndDecodeImpl(). You must copy the buffer * if you're going to store it, as ownership is not transferred to the * filter and the caller may free the buffer at any time. * * PdfFilter ensures that a valid stream is available when this method is * called, ensures that BeginDecode() has been called, and ensures that * EndDecode() has not been called since the last BeginDecode(). * * \see DecodeBlock */ virtual void DecodeBlockImpl( const char* pBuffer, pdf_long lLen ); /** Real implementation of `EndDecode()'. NEVER call this method directly. * * By the time this method returns, all filtered data must be written to the stream * and the filter must be in a state where BeginDecode() can be safely called. * * PdfFilter ensures that a valid stream is available when this method is * called, and ensures that BeginDecodeImpl() has been called. * * \see EndDecode */ virtual void EndDecodeImpl(); /** GetType of this filter. * \returns the GetType of this filter */ inline virtual EPdfFilter GetType() const; private: TIFF* m_tiff; }; // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfCCITTFilter::CanEncode() const { return false; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfCCITTFilter::CanDecode() const { return true; } // ----------------------------------------------------- // // ----------------------------------------------------- EPdfFilter PdfCCITTFilter::GetType() const { return ePdfFilter_CCITTFaxDecode; } #endif // PODOFO_HAVE_TIFF_LIB }; #endif /* _PDF_FILTERS_PRIVATE_H_ */ podofo-0.9.5/src/base/PdfVariant.h0000664000175000017500000010106413013650710016571 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_VARIANT_H_ #define _PDF_VARIANT_H_ #if defined(__BORLANDC__) || defined( __TURBOC__) #include #else #include #endif #include "PdfDefines.h" #include "PdfRefCountedBuffer.h" #include "PdfString.h" namespace PoDoFo { class PdfArray; class PdfData; class PdfDataType; class PdfDictionary; class PdfEncrypt; class PdfName; class PdfOutputDevice; class PdfString; class PdfReference; /** * A variant data type which supports all data types supported by the PDF standard. * The data can be parsed directly from a string or set by one of the members. * One can also convert the variant back to a string after setting the values. * * \warning All methods not marked otherwise may trigger a deferred load. This means * that they are unsafe to call while a deferred load is already in progress * (as recursion will occurr). * * TODO: domseichter: Make this class implicitly shared */ class PODOFO_API PdfVariant { friend class PdfArray; friend class PdfDictionary; public: static PdfVariant NullValue; /** Construct an empty variant type * IsNull() will return true. */ PdfVariant(); /** Construct a PdfVariant that is a bool. * \param b the boolean value of this PdfVariant */ PdfVariant( bool b ); /** Construct a PdfVariant that is a number. * \param l the value of the number. */ PdfVariant( pdf_int64 l ); /** Construct a PdfVariant that is a real number. * \param d the value of the real number. */ PdfVariant( double d ); /** Construct a PdfVariant that is a string. The argument * string will be escaped where necessary, so it should be * passed in unescaped form. * * \param rsString the value of the string */ PdfVariant( const PdfString & rsString ); /** Construct a PdfVariant that is a name. * \param rName the value of the name */ PdfVariant( const PdfName & rName ); /** Construct a PdfVariant that is a name. * \param rRef the value of the name */ PdfVariant( const PdfReference & rRef ); /** Construct a PdfVariant object with array data. * The variant will automatically get the datatype * ePdfDataType_Array. This constructor is the fastest * way to create a new PdfVariant that is an array. * * \param tList a list of variants */ PdfVariant( const PdfArray & tList ); /** Construct a PdfVariant that is a dictionary. * \param rDict the value of the dictionary. */ PdfVariant( const PdfDictionary & rDict ); /** Construct a PdfVariant that contains raw PDF data. * \param rData raw and valid PDF data. */ PdfVariant( const PdfData & rData ); /** Constructs a new PdfVariant which has the same * contents as rhs. * \param rhs an existing variant which is copied. */ PdfVariant( const PdfVariant & rhs ); virtual ~PdfVariant(); /** \returns true if this PdfVariant is empty. * i.e. m_eDataType == ePdfDataType_Null */ inline bool IsEmpty() const; /** Clear all internal member variables and free the memory * they have allocated. * Sets the datatype to ePdfDataType_Null * * This will reset the dirty flag of this object to be clean. * \see IsDirty */ void Clear(); /** \returns the datatype of this object or ePdfDataType_Unknown * if it does not have a value. */ inline EPdfDataType GetDataType() const; /** \returns a human readable string representation of GetDataType() * The returned string must not be free'd. */ const char * GetDataTypeString() const; /** \returns true if this variant is a bool (i.e. GetDataType() == ePdfDataType_Bool) */ inline bool IsBool() const { return GetDataType() == ePdfDataType_Bool; } /** \returns true if this variant is a number (i.e. GetDataType() == ePdfDataType_Number) */ inline bool IsNumber() const { return GetDataType() == ePdfDataType_Number; } /** \returns true if this variant is a real (i.e. GetDataType() == ePdfDataType_Real) */ inline bool IsReal() const { return GetDataType() == ePdfDataType_Real; } /** \returns true if this variant is a string (i.e. GetDataType() == ePdfDataType_String) */ inline bool IsString() const { return GetDataType() == ePdfDataType_String; } /** \returns true if this variant is a hex-string (i.e. GetDataType() == ePdfDataType_HexString) */ inline bool IsHexString() const { return GetDataType() == ePdfDataType_HexString; } /** \returns true if this variant is a name (i.e. GetDataType() == ePdfDataType_Name) */ inline bool IsName() const { return GetDataType() == ePdfDataType_Name; } /** \returns true if this variant is an array (i.e. GetDataType() == ePdfDataType_Array) */ inline bool IsArray() const { return GetDataType() == ePdfDataType_Array; } /** \returns true if this variant is a dictionary (i.e. GetDataType() == ePdfDataType_Dictionary) */ inline bool IsDictionary() const { return GetDataType() == ePdfDataType_Dictionary; } /** \returns true if this variant is raw data (i.e. GetDataType() == ePdfDataType_RawData */ inline bool IsRawData() const { return GetDataType() == ePdfDataType_RawData; } /** \returns true if this variant is null (i.e. GetDataType() == ePdfDataType_Null) */ inline bool IsNull() const { return GetDataType() == ePdfDataType_Null; } /** \returns true if this variant is a reference (i.e. GetDataType() == ePdfDataType_Reference) */ inline bool IsReference() const { return GetDataType() == ePdfDataType_Reference; } /** Write the complete variant to an output device. * This is an overloaded member function. * * \param pDevice write the object to this device * \param eWriteMode additional options for writing this object * \param pEncrypt an encryption object which is used to encrypt this object * or NULL to not encrypt this object */ void Write( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, const PdfEncrypt* pEncrypt = NULL ) const; /** Write the complete variant to an output device. * \param pDevice write the object to this device * \param eWriteMode additional options for writing this object * \param pEncrypt an encryption object which is used to encrypt this object * or NULL to not encrypt this object * \param keyStop if not KeyNull and a key == keyStop is found * writing will stop right before this key! * if IsDictionary returns true. */ virtual void Write( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, const PdfEncrypt* pEncrypt, const PdfName & keyStop ) const; /** Converts the current object into a string representation * which can be written directly to a PDF file on disc. * \param rsData the object string is returned in this object. * \param eWriteMode additional options for writing to a string */ void ToString( std::string & rsData, EPdfWriteMode eWriteMode = ePdfWriteMode_Clean ) const; /** Set the value of this object as bool * \param b the value as bool. * * This will set the dirty flag of this object. * \see IsDirty */ inline void SetBool( bool b ); /** Get the value if this object is a bool. * \returns the bool value. */ inline bool GetBool() const; /** Set the value of this object as long * \param l the value as long. * * This will set the dirty flag of this object. * \see IsDirty */ inline void SetNumber( long l ); /** Get the value of the object as long. * \return the value of the number */ inline pdf_int64 GetNumber() const; /** Set the value of this object as double * \param d the value as double. * * This will set the dirty flag of this object. * \see IsDirty */ inline void SetReal( double d ); /** Get the value of the object as double. * \return the value of the number */ inline double GetReal() const; /** \returns the value of the object as string. */ inline const PdfString & GetString() const; /** \returns the value of the object as name */ inline const PdfName & GetName() const; /** Returns the value of the object as array * \returns a array */ inline const PdfArray & GetArray() const; /** Returns the value of the object as array * \returns a array */ inline PdfArray & GetArray(); /** Returns the dictionary value of this object * \returns a PdfDictionary */ inline const PdfDictionary & GetDictionary() const; /** Returns the dictionary value of this object * \returns a PdfDictionary */ inline PdfDictionary & GetDictionary(); /** Get the reference values of this object. * \returns a PdfReference */ inline const PdfReference & GetReference() const; /** Get the reference values of this object. * \returns a reference to the PdfData instance. */ inline const PdfData & GetRawData() const; /** Get the reference values of this object. * \returns a reference to the PdfData instance. */ inline PdfData & GetRawData(); /** Assign the values of another PdfVariant to this one. * \param rhs an existing variant which is copied. * * This will set the dirty flag of this object. * \see IsDirty */ const PdfVariant & operator=( const PdfVariant & rhs ); /** * Test to see if the value contained by this variant is the same * as the value of the other variant. */ bool operator==( const PdfVariant & rhs ) const; /** * \see operator== */ inline bool operator!=( const PdfVariant & rhs) const; /** The dirty flag is set if this variant * has been modified after construction. * * Usually the dirty flag is also set * if you call any non-const member function * (e.g. GetDictionary()) as PdfVariant cannot * determine if you actually changed the dictionary * or not. * * \returns true if the value is dirty and has been * modified since construction */ inline bool IsDirty() const; /** * Sets this object to immutable, * so that no keys can be edited or changed. * * @param bImmutable if true set the object to be immutable * * This is used by PdfImmediateWriter and PdfStreamedDocument so * that no keys can be added to an object after setting stream data on it. * */ inline void SetImmutable(bool bImmutable); /** * Retrieve if an object is immutable. * * This is used by PdfImmediateWriter and PdfStreamedDocument so * that no keys can be added to an object after setting stream data on it. * * \returns true if the object is immutable */ inline bool GetImmutable() const; protected: /** * Will throw an exception if called on an immutable object, * so this should be called before actually changing a value! * */ inline void AssertMutable() const; /** Sets the dirty flag of this PdfVariant * * \param bDirty true if this PdfVariant has been * modified from the outside * * \see IsDirty */ inline void SetDirty( bool bDirty ); /** * Dynamically load the contents of this object from a PDF file by calling * the virtual method DelayedLoadImpl() if the object is not already loaded. * * For objects complete created in memory and those that do not support * deferred loading this function does nothing, since deferred loading * will not be enabled. */ inline void DelayedLoad() const; /** Flag the object incompletely loaded. DelayedLoad() will be called * when any method that requires more information than is currently * available is loaded. * * All constructors initialize a PdfVariant with delayed loading disabled . * If you want delayed loading you must ask for it. If you do so, call * this method early in your ctor and be sure to override DelayedLoadImpl(). */ inline void EnableDelayedLoading(); /** Load all data of the object if delayed loading is enabled. * * Never call this method directly; use DelayedLoad() instead. * * You should override this to control deferred loading in your subclass. * Note that this method should not load any associated streams, just the * base object. * * The default implementation throws. It should never be called, since * objects that do not support delayed loading should not enable it. * * While this method is not `const' it may be called from a const context, * so be careful what you mess with. */ inline virtual void DelayedLoadImpl(); /** * Returns true if delayed loading is disabled, or if it is enabled * and loading has completed. External callers should never need to * see this, it's an internal state flag only. */ PODOFO_NOTHROW inline bool DelayedLoadDone() const; // Rather than having deferred load triggering disabled while deferred // loading is in progress, causing public methods to potentially return // invalid data, we provide special methods that won't trigger a deferred // load for use during deferred loading. They're not for general use and // not available for use except by subclasses. // /** Version of GetDictionary() that doesn't trigger a delayed load * \returns a PdfDictionary */ inline const PdfDictionary & GetDictionary_NoDL() const; /** Version of GetDictionary() that doesn't trigger a delayed load * \returns a PdfDictionary */ inline PdfDictionary & GetDictionary_NoDL(); /** Version of GetArray() that doesn't trigger a delayed load * \returns a PdfArray */ inline const PdfArray & GetArray_NoDL() const; /** Version of GetArray() that doesn't trigger a delayed load. * \returns a PdfArray */ inline PdfArray & GetArray_NoDL(); private: /** * It's an easy mistake to pass a pointer to a PdfVariant when trying to * copy a PdfVariant, especially with heap allocators like `new'. This can * produce confusing and unexpected results like getting a PdfVariant(bool). * * A similar issue can arise when the user passes a `char*' and expects a PdfName * or PdfString based variant to be created. We can't know which they wanted, so * we should fail, especially since the compiler tends to convert pointers to bool * for extra confusion value. * * We provide this overload so that such attempts will fail with an error about * a private ctor. If you're reading this, you wrote: * * PdfVariant( my_ptr_to_something ) * *... not ... * * PdfVariant( *my_ptr_to_something ) * * If you need to modify PdfVariant to legitimately take a pointer in the future, * you can do so by providing a template specialization, or by removing this check * and replacing it with a couple of overloads specific to PdfObject*, PdfVariant*, * and char* (at least). */ template PdfVariant(T*); /** To reduce memory usage of this very often used class, * we use a union here, as there is always only * one of those members used. */ typedef union { /** Holds references, strings, * names, dictionaries and arrays */ PdfDataType* pData; bool bBoolValue; double dNumber; pdf_int64 nNumber; } UVariant; UVariant m_Data; bool m_bDirty; ///< Indicates if this object was modified after construction bool m_bImmutable; ///< Indicates if this object maybe modified /** Datatype of the variant. * required to access the correct member of * the union UVariant. */ EPdfDataType m_eDataType; // No touchy. Only for use by PdfVariant's internal tracking of the delayed // loading state. Use DelayedLoadDone() to test this if you need to. mutable bool m_bDelayedLoadDone; // Helper for ctor PODOFO_NOTHROW void Init(); #if defined(PODOFO_EXTRA_CHECKS) protected: PODOFO_NOTHROW bool DelayedLoadInProgress() const { return m_bDelayedLoadInProgress; } private: mutable bool m_bDelayedLoadInProgress; #endif }; // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfVariant::DelayedLoad() const { #if defined(PODOFO_EXTRA_CHECKS) // Whoops! Delayed loading triggered during delayed loading. Someone probably // used a public method that calls DelayedLoad() from a delayed load. if (m_bDelayedLoadInProgress) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Recursive DelayedLoad() detected" ); #endif if( !m_bDelayedLoadDone) { #if defined(PODOFO_EXTRA_CHECKS) m_bDelayedLoadInProgress = true; #endif const_cast(this)->DelayedLoadImpl(); // Nothing was thrown, so if the implementer of DelayedLoadImpl() // following the rules we're done. m_bDelayedLoadDone = true; #if defined(PODOFO_EXTRA_CHECKS) m_bDelayedLoadInProgress = false; #endif } } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfVariant::IsEmpty() const { DelayedLoad(); return (m_eDataType == ePdfDataType_Null); } // ----------------------------------------------------- // // ----------------------------------------------------- EPdfDataType PdfVariant::GetDataType() const { DelayedLoad(); return m_eDataType; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfVariant::SetBool( bool b ) { DelayedLoad(); if( !IsBool() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } AssertMutable(); m_Data.bBoolValue = b; SetDirty( true ); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfVariant::GetBool() const { DelayedLoad(); if( !IsBool() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } return m_Data.bBoolValue; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfVariant::SetNumber( long l ) { DelayedLoad(); if( !IsReal() && !IsNumber() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } AssertMutable(); if ( IsReal() ) m_Data.dNumber = static_cast(l); else m_Data.nNumber = l; SetDirty( true ); } // ----------------------------------------------------- // // ----------------------------------------------------- pdf_int64 PdfVariant::GetNumber() const { DelayedLoad(); if( !IsReal() && !IsNumber() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } if ( IsReal() ) return static_cast(floor( m_Data.dNumber )); else return m_Data.nNumber; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfVariant::SetReal( double d ) { DelayedLoad(); if( !IsReal() && !IsNumber() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } AssertMutable(); if ( IsReal() ) m_Data.dNumber = d; else m_Data.nNumber = static_cast(floor( d )); SetDirty( true ); } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfVariant::GetReal() const { DelayedLoad(); if( !IsReal() && !IsNumber() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } if ( IsReal() ) return m_Data.dNumber; else return static_cast(m_Data.nNumber); } // ----------------------------------------------------- // // ----------------------------------------------------- #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #endif // __GNUC__ const PdfData & PdfVariant::GetRawData() const { DelayedLoad(); if( !IsRawData() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } // Do not change this to an reinterpret_cast // We need a c-style casts here to avoid crashes // because a reinterpret_cast might point to a different position. return *((PdfData*)m_Data.pData); } #ifdef __GNUC__ #pragma GCC diagnostic pop #endif // __GNUC__ PdfData & PdfVariant::GetRawData() { DelayedLoad(); if( !IsRawData() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } // Do not change this to an reinterpret_cast // We need a c-style casts here to avoid crashes // because a reinterpret_cast might point to a different position. return *((PdfData*)m_Data.pData); } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfString & PdfVariant::GetString() const { DelayedLoad(); if( !IsString() && !IsHexString() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } // Do not change this to an reinterpret_cast // We need a c-style casts here to avoid crashes // because a reinterpret_cast might point to a different position. return *((PdfString*)m_Data.pData); } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfName & PdfVariant::GetName() const { DelayedLoad(); if( !IsName() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } // Do not change this to an reinterpret_cast // We need a c-style casts here to avoid crashes // because a reinterpret_cast might point to a different position. return *((PdfName*)m_Data.pData); } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfArray & PdfVariant::GetArray() const { DelayedLoad(); return GetArray_NoDL(); } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfArray & PdfVariant::GetArray_NoDL() const { // Test against eDataType directly not GetDataType() since // we don't want to trigger a delayed load (and if required one has // already been triggered). if( m_eDataType != ePdfDataType_Array ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } // Do not change this to an reinterpret_cast // We need a c-style casts here to avoid crashes // because a reinterpret_cast might point to a different position. return *((PdfArray*)m_Data.pData); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfArray & PdfVariant::GetArray() { DelayedLoad(); return GetArray_NoDL(); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfArray & PdfVariant::GetArray_NoDL() { // Test against eDataType directly not GetDataType() since // we don't want to trigger a delayed load (and if required one has // already been triggered). if( m_eDataType != ePdfDataType_Array ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } // Do not change this to an reinterpret_cast // We need a c-style casts here to avoid crashes // because a reinterpret_cast might point to a different position. return *((PdfArray*)m_Data.pData); } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfDictionary & PdfVariant::GetDictionary() const { DelayedLoad(); return GetDictionary_NoDL(); } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfDictionary & PdfVariant::GetDictionary_NoDL() const { // Test against eDataType directly not GetDataType() since // we don't want to trigger a delayed load (and if required one has // already been triggered). if( m_eDataType != ePdfDataType_Dictionary ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } // Do not change this to an reinterpret_cast // We need a c-style casts here to avoid crashes // because a reinterpret_cast might point to a different position. return *((PdfDictionary*)m_Data.pData); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfDictionary & PdfVariant::GetDictionary() { DelayedLoad(); return GetDictionary_NoDL(); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfDictionary & PdfVariant::GetDictionary_NoDL() { // Test against eDataType directly not GetDataType() since // we don't want to trigger a delayed load (and if required one has // already been triggered). if( m_eDataType != ePdfDataType_Dictionary ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } // Do not change this to an reinterpret_cast // We need a c-style casts here to avoid crashes // because a reinterpret_cast might point to a different position. return *((PdfDictionary*)m_Data.pData); } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfReference & PdfVariant::GetReference() const { DelayedLoad(); if( !IsReference() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } // Do not change this to an reinterpret_cast // We need a c-style casts here to avoid crashes // because a reinterpret_cast might point to a different position. return *((PdfReference*)m_Data.pData); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfVariant::DelayedLoadDone() const { return m_bDelayedLoadDone; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfVariant::EnableDelayedLoading() { m_bDelayedLoadDone = false; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfVariant::DelayedLoadImpl() { // Default implementation of virtual void DelayedLoadImpl() throws, since delayed // loading should not be enabled except by types that support it. PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfVariant::operator!=( const PdfVariant & rhs) const { return !(*this == rhs); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfVariant::IsDirty() const { // If this is a object with // stream, the streams dirty // flag might be set. if( m_bDirty ) return m_bDirty; switch( m_eDataType ) { case ePdfDataType_Array: case ePdfDataType_Dictionary: // Arrays and Dictionaries // handle dirty status by themselfes return m_Data.pData->IsDirty(); case ePdfDataType_Bool: case ePdfDataType_Number: case ePdfDataType_Real: case ePdfDataType_HexString: case ePdfDataType_String: case ePdfDataType_Name: case ePdfDataType_RawData: case ePdfDataType_Reference: case ePdfDataType_Null: case ePdfDataType_Unknown: default: return m_bDirty; }; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfVariant::SetDirty( bool bDirty ) { m_bDirty = bDirty; if( !m_bDirty ) { // Propogate new dirty state to subclasses switch( m_eDataType ) { case ePdfDataType_Array: case ePdfDataType_Dictionary: // Arrays and Dictionaries // handle dirty status by themselfes m_Data.pData->SetDirty( m_bDirty ); case ePdfDataType_Bool: case ePdfDataType_Number: case ePdfDataType_Real: case ePdfDataType_HexString: case ePdfDataType_String: case ePdfDataType_Name: case ePdfDataType_RawData: case ePdfDataType_Reference: case ePdfDataType_Null: case ePdfDataType_Unknown: default: break; }; } } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfVariant::SetImmutable(bool bImmutable) { m_bImmutable = bImmutable; switch( m_eDataType ) { case ePdfDataType_Array: case ePdfDataType_Dictionary: // Arrays and Dictionaries // handle dirty status by themselfes m_Data.pData->SetImmutable( m_bImmutable ); case ePdfDataType_Bool: case ePdfDataType_Number: case ePdfDataType_Real: case ePdfDataType_HexString: case ePdfDataType_String: case ePdfDataType_Name: case ePdfDataType_RawData: case ePdfDataType_Reference: case ePdfDataType_Null: case ePdfDataType_Unknown: default: break; }; } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfVariant::GetImmutable() const { return m_bImmutable; } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfVariant::AssertMutable() const { if(m_bImmutable) { PODOFO_RAISE_ERROR( ePdfError_ChangeOnImmutable ); } } }; #endif // _PDF_VARIANT_H_ podofo-0.9.5/src/base/PdfRect.h0000664000175000017500000001471412344436402016075 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_RECT_H_ #define _PDF_RECT_H_ #include "PdfDefines.h" namespace PoDoFo { class PdfArray; class PdfPage; class PdfVariant; /** A rectangle as defined by the PDF reference */ class PODOFO_API PdfRect { public: /** Create an empty rectangle with bottom=left=with=height=0 */ PdfRect(); /** Create a rectangle with a given size and position * All values are in PDF units * NOTE: since PDF is bottom-left origined, we pass the bottom instead of the top */ PdfRect( double left, double bottom, double width, double height ); /** Create a rectangle from an array * All values are in PDF units */ PdfRect( const PdfArray& inArray ); /** Copy constructor */ PdfRect( const PdfRect & rhs ); /** Converts the rectangle into an array * based on PDF units and adds the array into an variant. * \param var the variant to store the Rect */ void ToVariant( PdfVariant & var ) const; /** Returns a string representation of the PdfRect * \returns std::string representation as [ left bottom right top ] */ std::string ToString() const; /** Assigns the values of this PdfRect from the 4 values in the array * \param inArray the array to load the values from */ void FromArray( const PdfArray& inArray ); /** Intersect with another rect * \param rRect the rect to intersect with */ void Intersect( const PdfRect & rRect ); /** Get the bottom coordinate of the rectangle * \returns bottom */ inline double GetBottom() const; /** Set the bottom coordinate of the rectangle * \param dBottom */ inline void SetBottom( double dBottom ); /** Get the left coordinate of the rectangle * \returns left in PDF units */ inline double GetLeft() const; /** Set the left coordinate of the rectangle * \param lLeft in PDF units */ inline void SetLeft( double lLeft ); /** Get the width of the rectangle * \returns width in PDF units */ inline double GetWidth() const; /** Set the width of the rectangle * \param lWidth in PDF units */ inline void SetWidth( double lWidth ); /** Get the height of the rectangle * \returns height in PDF units */ inline double GetHeight() const; /** Set the height of the rectangle * \param lHeight in PDF units */ inline void SetHeight( double lHeight ); PdfRect & operator=( const PdfRect & rhs ); private: double m_dLeft; double m_dBottom; double m_dWidth; double m_dHeight; }; // ----------------------------------------------------- // // ----------------------------------------------------- double PdfRect::GetBottom() const { return m_dBottom; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfRect::SetBottom( double dBottom ) { m_dBottom = dBottom; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfRect::GetLeft() const { return m_dLeft; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfRect::SetLeft( double dLeft ) { m_dLeft = dLeft; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfRect::GetWidth() const { return m_dWidth; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfRect::SetWidth( double dWidth ) { m_dWidth = dWidth; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfRect::GetHeight() const { return m_dHeight; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfRect::SetHeight( double dHeight ) { m_dHeight = dHeight; } }; #endif /* _PDF_RECT_H_ */ podofo-0.9.5/src/base/PdfDefinesPrivate.h0000664000175000017500000000145111641323033020074 0ustar dominikdominik#ifndef _PDF_DEFINES_PRIVATE_H_ #define _PDF_DEFINES_PRIVATE_H_ #ifndef BUILDING_PODOFO #error PdfDefinesPrivate.h is only available for use in the core PoDoFo src/ build .cpp files #endif // Right now, just pulls in the private parts of the compiler compat hacks. #include "PdfCompilerCompatPrivate.h" /** * \page * * PdfDefinesPrivate.h contains preprocessor definitions, inline functions, templates, * compile-time const variables, and other things that must be visible across the entirety of * the PoDoFo library code base but should not be visible to users of the library's headers. * * This header is private to the library build. It is not installed with PoDoFo and must not be * referenced in any way from any public, installed header. */ #endif podofo-0.9.5/src/base/PdfInputDevice.cpp0000664000175000017500000001721413013650710017742 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfInputDevice.h" #include #include #include #include "PdfDefinesPrivate.h" namespace PoDoFo { PdfInputDevice::PdfInputDevice() { this->Init(); } PdfInputDevice::PdfInputDevice( const char* pszFilename ) { this->Init(); if( !pszFilename ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } try { m_pFile = fopen(pszFilename, "rb"); //m_pStream = new std::ifstream( pszFilename, std::ios::binary ); if( !m_pFile) { PODOFO_RAISE_ERROR_INFO( ePdfError_FileNotFound, pszFilename ); } m_StreamOwned = true; } catch(...) { // should probably check the exact error, but for now it's a good error PODOFO_RAISE_ERROR_INFO( ePdfError_FileNotFound, pszFilename ); } //PdfLocaleImbue(*m_pStream); } #ifdef _WIN32 PdfInputDevice::PdfInputDevice( const wchar_t* pszFilename ) { this->Init(); if( !pszFilename ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } try { // James McGill 16.02.2011 Fix wide character filename loading in windows m_pFile = _wfopen(pszFilename, L"rb"); if( !m_pFile) { PdfError e( ePdfError_FileNotFound, __FILE__, __LINE__ ); e.SetErrorInformation( pszFilename ); throw e; } m_StreamOwned = true; } catch(...) { // should probably check the exact error, but for now it's a good error PdfError e( ePdfError_FileNotFound, __FILE__, __LINE__ ); e.SetErrorInformation( pszFilename ); throw e; } } #endif // _WIN32 PdfInputDevice::PdfInputDevice( const char* pBuffer, size_t lLen ) { this->Init(); if( !pBuffer ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } try { m_pStream = static_cast< std::istream* >( new std::istringstream( std::string( pBuffer, lLen ), std::ios::binary ) ); if( !m_pStream || !m_pStream->good() ) { PODOFO_RAISE_ERROR( ePdfError_FileNotFound ); } m_StreamOwned = true; } catch(...) { // should probably check the exact error, but for now it's a good error PODOFO_RAISE_ERROR( ePdfError_FileNotFound ); } PdfLocaleImbue(*m_pStream); } PdfInputDevice::PdfInputDevice( const std::istream* pInStream ) { this->Init(); m_pStream = const_cast< std::istream* >( pInStream ); if( !m_pStream->good() ) { PODOFO_RAISE_ERROR( ePdfError_FileNotFound ); } PdfLocaleImbue(*m_pStream); } PdfInputDevice::~PdfInputDevice() { this->Close(); if ( m_StreamOwned ) { if (m_pStream) delete m_pStream; if (m_pFile) fclose(m_pFile); } } void PdfInputDevice::Init() { m_pStream = NULL; m_pFile = 0; m_StreamOwned = false; m_bIsSeekable = true; } void PdfInputDevice::Close() { // nothing to do here, but maybe necessary for inheriting classes } int PdfInputDevice::GetChar() const { if (m_pStream) return m_pStream->get(); if (m_pFile) return fgetc(m_pFile); return 0; } int PdfInputDevice::Look() const { if (m_pStream) return m_pStream->peek(); if (m_pFile) { pdf_long lOffset = ftello( m_pFile ); if( lOffset == -1 ) PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to read the current file position" ); int ch = GetChar(); if( fseeko( m_pFile, lOffset, SEEK_SET ) == -1 ) PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to seek back to the previous position" ); return ch; } return 0; } std::streamoff PdfInputDevice::Tell() const { if (m_pStream) return m_pStream->tellg(); if (m_pFile) return ftello(m_pFile); return 0; } /* void PdfInputDevice::Seek( std::streamoff off, std::ios_base::seekdir dir ) { if (m_bIsSeekable) m_pStream->seekg( off, dir ); else PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Tried to seek an unseekable input device." ); } */ void PdfInputDevice::Seek( std::streamoff off, std::ios_base::seekdir dir ) { if (m_bIsSeekable) { if (m_pStream) { m_pStream->seekg( off, dir ); } if (m_pFile) { int whence; switch( dir ) { default: case std::ios_base::beg: whence = SEEK_SET; break; case std::ios_base::end: whence = SEEK_END; break; case std::ios_base::cur: whence = SEEK_CUR; break; } if( fseeko( m_pFile, off, whence ) == -1) PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to seek to given position in the file" ); } } else { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Tried to seek an unseekable input device." ); } } std::streamoff PdfInputDevice::Read( char* pBuffer, std::streamsize lLen ) { if (m_pStream) { m_pStream->read( pBuffer, lLen ); return m_pStream->gcount(); } else { return fread(pBuffer, 1, lLen, m_pFile); } } }; // namespace PoDoFo podofo-0.9.5/src/base/PdfString.h0000664000175000017500000005070213035003404016431 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_STRING_H_ #define _PDF_STRING_H_ #include "PdfDefines.h" #include "PdfDataType.h" #include "PdfRefCountedBuffer.h" namespace PoDoFo { #define PDF_STRING_BUFFER_SIZE 24 class PdfEncoding; class PdfOutputDevice; enum EPdfStringConversion { ePdfStringConversion_Strict, ePdfStringConversion_Lenient }; /** A string that can be written to a PDF document. * If it contains binary data it is automatically * converted into a hex string, otherwise a normal PDF * string is written to the document. * * PdfStrings representing text are encoded either in PDFDocEncoding * (ISO Latin1) or UTF-16BE. * * PoDoFo contains methods to convert between these * encodings. For convenience conversion to UTF-8 * is possible too. Please note that strings are * always stored as UTF-16BE or ISO Latin1 (PdfDocEncoding) * in the PDF file. * * UTF-16BE strings have to start with the bytes 0xFE 0xFF * to be recognized by PoDoFo as unicode strings. * * * PdfString is an implicitly shared class. As a reason * it is very fast to copy PdfString objects. * * The internal string buffer is guaranteed to be always terminated * by 2 zero ('\0') bytes. */ class PODOFO_API PdfString : public PdfDataType { public: /** Create an empty and invalid string */ PdfString(); /** Construct a new PdfString from a std::string. * The input string will be copied. * If the first to bytes of the string are 0xFE and 0xFF * this string is treated as UTF-16BE encoded unicode string. * * \param sString the string to copy * \param pEncoding the encoding of this string, if it is no unicode string. * This is ignored for unicode strings. If NULL, PdfDocEncoding will be used as a default. */ PdfString( const std::string& sString, const PdfEncoding * const pEncoding = NULL ); /** Construct a new PdfString from a 0-terminated C-style string. * The input string will be copied. * * \param pszString the string to copy * \param pEncoding the encoding of this string, if it is no unicode string. * This is ignored for unicode strings. If NULL, PdfDocEncoding will be used as a default. */ PdfString( const char* pszString, const PdfEncoding * const pEncoding = NULL ); /** Construct a new PdfString from a 0-terminated C-style string. * The input string will be copied. * * \param pszString the string to copy */ #if defined(_MSC_VER) && _MSC_VER <= 1200 // not for MS Visual Studio 6 #else PdfString( const wchar_t* pszString, pdf_long lLen = -1 ); #endif void setFromWchar_t( const wchar_t* pszString, pdf_long lLen = -1 ); /** Construct a new PdfString from a string. * The input string will be copied. * If the first two bytes of the string are 0xFE and 0xFF * this string is treated as UTF-16BE encoded unicode string. * * \param pszString the string to copy * \param lLen length of the string data to encode * \param bHex if true the data will be hex-encoded during writing out the string and IsHex() will return true. * \param pEncoding the encoding of this string, if it is no unicode string. * This is ignored for unicode strings. If NULL, PdfDocEncoding will be used as a default. */ PdfString( const char* pszString, pdf_long lLen, bool bHex = false, const PdfEncoding * const pEncoding = NULL ); /** Construct a new PdfString from an UTF-8 encoded string. * * The string is converted to UTF-16BE internally. * * \param pszStringUtf8 an UTF-8 encoded string. */ PdfString( const pdf_utf8* pszStringUtf8 ); /** Construct a new PdfString from an UTF-16BE encoded zero-terminated C-style string. * * \param pszStringUtf16 an UTF-16BE encoded string. */ PdfString( const pdf_utf16be* pszStringUtf16 ); /** Construct a new PdfString from an UTF-8 encoded string. * * The string is converted to UTF-16BE internally. * * \param pszStringUtf8 a UTF-8 encoded string. * \param lLen number of bytes to convert */ PdfString( const pdf_utf8* pszStringUtf8, pdf_long lLen ); /** Construct a new PdfString from an UTF-16BE encoded zero-terminated string. * * \param pszStringUtf16 a UTF-16BE encoded string. * \param lLen number of words to convert */ PdfString( const pdf_utf16be* pszStringUtf16, pdf_long lLen ); /** Copy an existing PdfString * \param rhs another PdfString to copy */ PdfString( const PdfString & rhs ); ~PdfString(); /** Set hex-encoded data as the strings data. * \param pszHex must be hex-encoded data. * \param lLen length of the hex-encoded data. * if lLen == -1 then strlen( pszHex ) will * be used as length of the hex data. * pszHex has to be zero-terminated in this case. * \param pEncrypt if !NULL, assume the hex data is encrypted and should be decrypted after hex-decoding. */ void SetHexData( const char* pszHex, pdf_long lLen = -1, PdfEncrypt* pEncrypt = NULL ); /** The string is valid if no error in the constructor has occurred. * The default constructor PdfString() creates an invalid string, as do * other constructors when passed a NULL char* or NULL wchar_t*. * PdfString::StringNull uses the default constructor so is also invalid. * If it is valid it is safe to call all the other member functions. * \returns true if this is a valid initialized PdfString */ inline bool IsValid() const; /** Check if this is a hex string. * * If true the data will be hex-encoded when the string is written to * a PDF file. * * \returns true if this is a hex string. * \see GetString() will return the raw string contents (not hex-encoded) */ inline bool IsHex () const; /** * PdfStrings are either Latin1-encoded or UTF-16BE-encoded unicode strings. * * This function returns true if this is a unicode string object. * * \returns true if this is a unicode string. */ inline bool IsUnicode () const; /** The contents of the string can be read by this function. * * The returned data is never hex-encoded may contain '\0' bytes. * * If IsUnicode() returns true, the return value * points to a UTF-16BE string buffer with Length() * characters. Better use GetUnicode() in this case. * * \returns the string's contents which are guaranteed to be zero-terminated * but might also contain '\0' bytes in the string. * \see IsHex * \see IsUnicode * \see Length */ inline const char* GetString() const; /** The contents of the string can be read by this function. * * The returned data is never hex-encoded any may contain '\0' bytes. * * If IsUnicode() returns true, the return value * points to a UTF-16BE string buffer with Length() * characters. Better use GetUnicode() in this case. * * \returns the string's contents which are guaranteed to be zero-terminated * but might also contain '\0' bytes in the string, * returns NULL if PdfString::IsValid() returns false. * * \see IsHex * \see IsUnicode * \see Length */ inline const pdf_utf16be* GetUnicode() const; /** The contents of the string as UTF-8 string. * * The string's contents are always returned as * UTF-8 by this function. Works for unicode strings * and for non-unicode strings. * * This is the preferred way to access the string's contents. * * \returns the string's contents always as UTF-8, * returns NULL if PdfString::IsValid() returns false */ inline const std::string & GetStringUtf8() const; #ifdef _WIN32 /** The contents of the string as wide-character string. * * \returns the string contents as wide-character string. * returns an empty string if PdfString::IsValid() returns false */ const std::wstring GetStringW() const; #endif // _WIN32 /** The length of the string data returned by GetString() * in bytes not including terminating zero ('\0') bytes. * * \returns the length of the string, * returns zero if PdfString::IsValid() returns false * * \see GetCharacterLength to determine the number of characters in the string */ inline pdf_long GetLength() const; /** The length of the string data returned by GetUnicode() * in characters not including the terminating zero ('\0') bytes. * * \returns the length of the string, * returns zero if PdfString::IsValid() returns false * * \see GetCharacterLength to determine the number of characters in the string */ inline pdf_long GetUnicodeLength() const; /** Get the number of characters in the string. * * This function returns the correct number of characters in the string * for unicode and ANSI strings. Always use this method if you want to * know the number of characters in the string * as GetLength() will return the number of bytes used for unicode strings! * * * \returns the number of characters in the string, * returns zero if PdfString::IsValid() returns false */ inline pdf_long GetCharacterLength() const; /** Write this PdfString in PDF format to a PdfOutputDevice. * * \param pDevice the output device. * \param eWriteMode additional options for writing this object * \param pEncrypt an encryption object which is used to encrypt this object, * or NULL to not encrypt this object */ void Write ( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, const PdfEncrypt* pEncrypt = NULL ) const; /** Copy an existing PdfString * \param rhs another PdfString to copy * \returns this object */ const PdfString & operator=( const PdfString & rhs ); /** Compare two PdfString objects * \param rhs another PdfString to compare with * \returns this object */ bool operator>( const PdfString & rhs ) const; /** Compare two PdfString objects * \param rhs another PdfString to compare with * \returns this object */ bool operator<( const PdfString & rhs ) const; /** Comparison operator * * UTF-8 and UTF-16BE encoded strings of the same data compare equal. Whether * the string will be written out as hex is not considered - only the real "text" * is tested for equality. * * \param rhs compare to this string object * \returns true if both strings have the same contents */ bool operator==( const PdfString & rhs ) const; /** Comparison operator * \param rhs compare to this string object * \returns true if strings have different contents */ bool operator!=(const PdfString& rhs) const { return !operator==(rhs); } #ifdef PODOFO_PUBLIC_STRING_HEX_CODEC // never set, impl. even says REMOVE :( /** Converts this string to a hex-encoded string. * * If IsHex returns true, a copy of this string is returned * otherwise the string's data is hex-encoded and returned. * * \returns a hex-encoded version of this string, or this string if it is * already hex-encoded. * * \see IsHex */ PdfString HexEncode() const; /** Converts this string to an ASCII string (not hex-encoded) * * If IsHex returns false, a copy of this string is returned, * otherwise the string's data is hex-decoded and returned. * * \returns a plain version, which is not hex-encoded, of this string, or * this string if it is already a plain not hex-encoded string. * * \see IsHex */ PdfString HexDecode() const; #endif /** Converts this string to a unicode string * * If IsUnicode() returns true a copy of this string is returned * otherwise the string data is converted to UTF-16be and returned. * * \returns a unicode version of this string, * returns *this if if PdfString::IsValid() returns false */ PdfString ToUnicode() const; /** Returns internal buffer; do not free it, it's owned by the PdfString * * \returns internal buffer; do not free it, it's owned by the PdfString * returns a NULL zero size buffer if PdfString::IsValid() returns false */ PdfRefCountedBuffer &GetBuffer(void); static const PdfString StringNull; static pdf_long ConvertUTF8toUTF16( const pdf_utf8* pszUtf8, pdf_utf16be* pszUtf16, pdf_long lLenUtf16 ); static pdf_long ConvertUTF8toUTF16( const pdf_utf8* pszUtf8, pdf_long lLenUtf8, pdf_utf16be* pszUtf16, pdf_long lLenUtf16, EPdfStringConversion eConversion = ePdfStringConversion_Strict ); static pdf_long ConvertUTF16toUTF8( const pdf_utf16be* pszUtf16, pdf_utf8* pszUtf8, pdf_long lLenUtf8 ); static pdf_long ConvertUTF16toUTF8( const pdf_utf16be* pszUtf16, pdf_long lLenUtf16, pdf_utf8* pszUtf8, pdf_long lLenUtf8, EPdfStringConversion eConversion = ePdfStringConversion_Strict ); private: /** Allocate m_lLen data for m_pszData if data * does not fit into m_pBuffer. * Otherwise m_pszData is set to point to * m_pBuffer. */ void Allocate(); /** Frees the internal buffer * if it was allocated using podofo_malloc() */ void FreeBuffer(); /** Construct a new PdfString from a 0-terminated string. * * The input string will be copied. * if m_bHex is true the copied data will be hex-encoded. * * \param pszString the string to copy, must not be NULL * \param lLen length of the string data to copy * */ void Init( const char* pszString, pdf_long lLen ); /** Construct a new PdfString from a UTF-8 string. * * The input string will be copied and converted to UTF-16BE. * * \param pszStringUtf8 the string to copy, must not be NULL * \param lLen number of bytes of the string data to copy * */ void InitFromUtf8( const pdf_utf8* pszStringUtf8, pdf_long lLen ); /** Swap the bytes in the buffer (UTF-16BE -> UTF-16LE) * \param pBuf buffer * \param lLen length of buffer */ static void SwapBytes( char* pBuf, pdf_long lLen ); /** Initialise the data member containing a * UTF-8 version of this string. * * This is only done once and only if necessary. */ void InitUtf8(); private: static const char s_pszUnicodeMarker[]; ///< The unicode marker used to indicate unicode strings in PDF static const char* s_pszUnicodeMarkerHex; ///< The unicode marker converted to hex static const pdf_utf16be s_cPdfDocEncoding[256]; ///< conversion table from PDFDocEncoding to UTF-16 static const char * const m_escMap; ///< Mapping of escape sequences to their value private: PdfRefCountedBuffer m_buffer; ///< String data (always binary), may contain '\0' bytes bool m_bHex; ///< This string is converted to hex during writing it out bool m_bUnicode; ///< This string contains unicode data std::string m_sUtf8; ///< The UTF-8 version of the string's contents. const PdfEncoding* m_pEncoding; ///< Encoding for non-unicode strings. NULL for unicode strings. }; // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfString::IsValid() const { return (m_buffer.GetBuffer() != NULL); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfString::IsHex () const { return m_bHex; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfString::IsUnicode () const { return m_bUnicode; } // ----------------------------------------------------- // // ----------------------------------------------------- const char* PdfString::GetString() const { return m_buffer.GetBuffer(); } // ----------------------------------------------------- // // ----------------------------------------------------- const pdf_utf16be* PdfString::GetUnicode() const { return reinterpret_cast(m_buffer.GetBuffer()); } // ----------------------------------------------------- // // ----------------------------------------------------- const std::string & PdfString::GetStringUtf8() const { if( this->IsValid() && !m_sUtf8.length() && m_buffer.GetSize() - 2) const_cast(this)->InitUtf8(); return m_sUtf8; } // ----------------------------------------------------- // // ----------------------------------------------------- pdf_long PdfString::GetLength() const { if ( !IsValid() ) { PdfError::LogMessage( eLogSeverity_Error, "PdfString::GetLength invalid PdfString" ); return 0; } PODOFO_ASSERT( m_buffer.GetSize() >= 2 ); return m_buffer.GetSize() - 2; } // ----------------------------------------------------- // // ----------------------------------------------------- pdf_long PdfString::GetCharacterLength() const { return this->IsUnicode() ? this->GetUnicodeLength() : this->GetLength(); } // ----------------------------------------------------- // // ----------------------------------------------------- pdf_long PdfString::GetUnicodeLength() const { if ( !IsValid() ) { PdfError::LogMessage( eLogSeverity_Error, "PdfString::GetUnicodeLength invalid PdfString" ); return 0; } PODOFO_ASSERT( (m_buffer.GetSize() / sizeof(pdf_utf16be)) >= 1 ); return (m_buffer.GetSize() / sizeof(pdf_utf16be)) - 1; } }; #endif // _PDF_STRING_H_ podofo-0.9.5/src/base/PdfVariant.cpp0000664000175000017500000003374712712426663017155 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfVariant.h" #include "PdfArray.h" #include "PdfData.h" #include "PdfDictionary.h" #include "PdfOutputDevice.h" #include "PdfParserObject.h" #include "PdfDefinesPrivate.h" #include #include namespace PoDoFo { using namespace std; PdfVariant PdfVariant::NullValue; // Do one-off initialization that should not be repeated // in the Clear() method. Mostly useful for internal sanity checks. inline void PdfVariant::Init() { // DS: These members will be set in ::Clear() // which is called by every constructor. // m_bDelayedLoadDone = true; // m_bDirty = false; // Has to be done in Init so that Clear() works // and can delete data if necessary memset( &m_Data, 0, sizeof( UVariant ) ); // Has to be set as Clear() depends on it m_eDataType = ePdfDataType_Null; m_bImmutable = false; #if defined(PODOFO_EXTRA_CHECKS) m_bDelayedLoadInProgress=false; #endif } PdfVariant::PdfVariant() { Init(); Clear(); m_eDataType = ePdfDataType_Null; } PdfVariant::PdfVariant( bool b ) { Init(); Clear(); m_eDataType = ePdfDataType_Bool; m_Data.bBoolValue = b; } PdfVariant::PdfVariant( pdf_int64 l ) { Init(); Clear(); m_eDataType = ePdfDataType_Number; m_Data.nNumber = l; } PdfVariant::PdfVariant( double d ) { Init(); Clear(); m_eDataType = ePdfDataType_Real; m_Data.dNumber = d; } PdfVariant::PdfVariant( const PdfString & rsString ) { Init(); Clear(); m_eDataType = rsString.IsHex() ? ePdfDataType_HexString : ePdfDataType_String; m_Data.pData = new PdfString( rsString ); } PdfVariant::PdfVariant( const PdfName & rName ) { Init(); Clear(); m_eDataType = ePdfDataType_Name; m_Data.pData = new PdfName( rName ); } PdfVariant::PdfVariant( const PdfReference & rRef ) { Init(); Clear(); m_eDataType = ePdfDataType_Reference; m_Data.pData = new PdfReference( rRef ); } PdfVariant::PdfVariant( const PdfArray & rArray ) { Init(); Clear(); m_eDataType = ePdfDataType_Array; m_Data.pData = new PdfArray( rArray ); } PdfVariant::PdfVariant( const PdfDictionary & rObj ) { Init(); Clear(); m_eDataType = ePdfDataType_Dictionary; m_Data.pData = new PdfDictionary( rObj ); } PdfVariant::PdfVariant( const PdfData & rData ) { Init(); Clear(); m_eDataType = ePdfDataType_RawData; m_Data.pData = new PdfData( rData ); } PdfVariant::PdfVariant( const PdfVariant & rhs ) { Init(); this->operator=(rhs); SetDirty( false ); } PdfVariant::~PdfVariant() { m_bImmutable = false; // Destructor may change things, i.e. delete Clear(); } void PdfVariant::Clear() { switch( m_eDataType ) { case ePdfDataType_Array: case ePdfDataType_Reference: case ePdfDataType_Dictionary: case ePdfDataType_Name: case ePdfDataType_String: case ePdfDataType_HexString: case ePdfDataType_RawData: { if( m_Data.pData ) delete m_Data.pData; break; } case ePdfDataType_Bool: case ePdfDataType_Null: case ePdfDataType_Number: case ePdfDataType_Real: case ePdfDataType_Unknown: default: break; } m_bDelayedLoadDone = true; #if defined(PODOFO_EXTRA_CHECKS) m_bDelayedLoadInProgress = false; #endif m_bDirty = false; m_eDataType = ePdfDataType_Null; m_bImmutable = false; memset( &m_Data, 0, sizeof( UVariant ) ); } void PdfVariant::Write( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, const PdfEncrypt* pEncrypt ) const { this->Write( pDevice, eWriteMode, pEncrypt, PdfName::KeyNull ); } void PdfVariant::Write( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, const PdfEncrypt* pEncrypt, const PdfName & keyStop ) const { DelayedLoad(); /* Check all handles first */ if( (m_eDataType == ePdfDataType_HexString || m_eDataType == ePdfDataType_String || m_eDataType == ePdfDataType_Array || m_eDataType == ePdfDataType_Dictionary || m_eDataType == ePdfDataType_Name || m_eDataType == ePdfDataType_RawData ) && !m_Data.pData ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } switch( m_eDataType ) { case ePdfDataType_Bool: { if( (eWriteMode & ePdfWriteMode_Compact) == ePdfWriteMode_Compact ) { pDevice->Write( " ", 1 ); // Write space before true or false } if( m_Data.bBoolValue ) pDevice->Write( "true", 4 ); else pDevice->Write( "false", 5 ); break; } case ePdfDataType_Number: { if( (eWriteMode & ePdfWriteMode_Compact) == ePdfWriteMode_Compact ) { pDevice->Write( " ", 1 ); // Write space before numbers } pDevice->Print( "%" PDF_FORMAT_INT64, m_Data.nNumber ); break; } case ePdfDataType_Real: //pDevice->Print( "%g", m_Data.dNumber ); // DominikS: %g precision might write floating points // numbers in exponential form (with e) // which is not supported in PDF. // %f fixes this but might loose precision as // it defaults to a precision of 6 // pDevice->Print( "%f", m_Data.dNumber ); { if( (eWriteMode & ePdfWriteMode_Compact) == ePdfWriteMode_Compact ) { pDevice->Write( " ", 1 ); // Write space before numbers } // Use ostringstream, so that locale does not matter std::ostringstream oss; PdfLocaleImbue(oss); oss << std::fixed << m_Data.dNumber; std::string copy = oss.str(); size_t len = copy.size(); if( (eWriteMode & ePdfWriteMode_Compact) == ePdfWriteMode_Compact && copy.find('.') != string::npos ) { const char *str = copy.c_str(); while( str[len - 1] == '0' ) --len; if( str[len - 1] == '.' ) --len; if( len == 0 ) { pDevice->Write( "0", 1 ); break; } } pDevice->Write( copy.c_str(), len ); break; } case ePdfDataType_HexString: case ePdfDataType_String: case ePdfDataType_Name: case ePdfDataType_Array: case ePdfDataType_Reference: case ePdfDataType_RawData: m_Data.pData->Write( pDevice, eWriteMode, pEncrypt ); break; case ePdfDataType_Dictionary: static_cast(m_Data.pData)->Write( pDevice, eWriteMode, pEncrypt, keyStop ); break; case ePdfDataType_Null: { if( (eWriteMode & ePdfWriteMode_Compact) == ePdfWriteMode_Compact ) { pDevice->Write( " ", 1 ); // Write space before null } pDevice->Print( "null" ); break; } case ePdfDataType_Unknown: default: { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); break; } }; } void PdfVariant::ToString( std::string & rsData, EPdfWriteMode eWriteMode ) const { ostringstream out; // We don't need to this stream with the safe PDF locale because // PdfOutputDevice will do so for us. PdfOutputDevice device( &out ); this->Write( &device, eWriteMode, NULL ); rsData = out.str(); } const PdfVariant & PdfVariant::operator=( const PdfVariant & rhs ) { Clear(); rhs.DelayedLoad(); m_eDataType = rhs.m_eDataType; switch( m_eDataType ) { case ePdfDataType_Array: { if( rhs.m_Data.pData ) m_Data.pData = new PdfArray( *(static_cast(rhs.m_Data.pData)) ); break; } case ePdfDataType_Reference: { if( rhs.m_Data.pData ) m_Data.pData = new PdfReference( *(static_cast(rhs.m_Data.pData)) ); break; } case ePdfDataType_Dictionary: { if( rhs.m_Data.pData ) m_Data.pData = new PdfDictionary( *(static_cast(rhs.m_Data.pData)) ); break; } case ePdfDataType_Name: { if( rhs.m_Data.pData ) m_Data.pData = new PdfName( *(static_cast(rhs.m_Data.pData)) ); break; } case ePdfDataType_String: case ePdfDataType_HexString: { if( rhs.m_Data.pData ) m_Data.pData = new PdfString( *(static_cast(rhs.m_Data.pData)) ); break; } case ePdfDataType_RawData: { if( rhs.m_Data.pData ) m_Data.pData = new PdfData( *(static_cast(rhs.m_Data.pData)) ); break; } case ePdfDataType_Bool: case ePdfDataType_Null: case ePdfDataType_Number: case ePdfDataType_Real: m_Data = rhs.m_Data; break; case ePdfDataType_Unknown: default: break; }; SetDirty( true ); return (*this); } const char * PdfVariant::GetDataTypeString() const { switch(GetDataType()) { case ePdfDataType_Bool: return "Bool"; case ePdfDataType_Number: return "Number"; case ePdfDataType_Real: return "Real"; case ePdfDataType_String: return "String"; case ePdfDataType_HexString: return "HexString"; case ePdfDataType_Name: return "Name"; case ePdfDataType_Array: return "Array"; case ePdfDataType_Dictionary: return "Dictionary"; case ePdfDataType_Null: return "Null"; case ePdfDataType_Reference: return "Reference"; case ePdfDataType_RawData: return "RawData"; case ePdfDataType_Unknown: return "Unknown"; } return "INVALID_TYPE_ENUM"; } // // This is rather slow: // - We set up to catch an exception // - We throw & catch an exception whenever there's a type mismatch // bool PdfVariant::operator==( const PdfVariant & rhs ) const { DelayedLoad(); try { switch (m_eDataType) { case ePdfDataType_Bool: return GetBool() == rhs.GetBool(); case ePdfDataType_Number: return GetNumber() == rhs.GetNumber(); case ePdfDataType_Real: return GetReal() == rhs.GetReal(); case ePdfDataType_String: return GetString() == rhs.GetString(); case ePdfDataType_HexString: return GetString() == rhs.GetString(); case ePdfDataType_Name: return GetName() == rhs.GetName(); case ePdfDataType_Array: return GetArray() == rhs.GetArray(); case ePdfDataType_Dictionary: return GetDictionary() == rhs.GetDictionary(); case ePdfDataType_Null: return rhs.IsNull(); case ePdfDataType_Reference: return GetReference() == rhs.GetReference(); case ePdfDataType_RawData: /* fall through to end of func */ break; case ePdfDataType_Unknown: /* fall through to end of func */ break; } } catch ( PdfError& e ) { if (e.GetError() == ePdfError_InvalidDataType) return false; else throw e; } PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Tried to compare unknown/raw variant" ); } }; podofo-0.9.5/src/base/PdfParser.cpp0000664000175000017500000014472413013650710016766 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfParser.h" #include "PdfArray.h" #include "PdfDefinesPrivate.h" #include "PdfDictionary.h" #include "PdfEncrypt.h" #include "PdfInputDevice.h" #include "PdfMemStream.h" #include "PdfObjectStreamParserObject.h" #include "PdfOutputDevice.h" #include "PdfParserObject.h" #include "PdfStream.h" #include "PdfVariant.h" #include "PdfXRefStreamParserObject.h" #include #include #include #include #include #include using std::cerr; using std::endl; using std::flush; #define PDF_MAGIC_LEN 8 #define PDF_XREF_ENTRY_SIZE 20 #define PDF_XREF_BUF 512 #if defined( PTRDIFF_MAX ) #define PDF_LONG_MAX PTRDIFF_MAX #else // only old compilers don't define PTRDIFF_MAX (all 32-bit only?) #define PDF_LONG_MAX INT_MAX #endif namespace PoDoFo { long PdfParser::s_nMaxObjects = std::numeric_limits::max(); PdfParser::PdfParser( PdfVecObjects* pVecObjects ) : PdfTokenizer(), m_vecObjects( pVecObjects ), m_bStrictParsing( false ) { this->Init(); } PdfParser::PdfParser( PdfVecObjects* pVecObjects, const char* pszFilename, bool bLoadOnDemand ) : PdfTokenizer(), m_vecObjects( pVecObjects ), m_bStrictParsing( false ) { this->Init(); this->ParseFile( pszFilename, bLoadOnDemand ); } #ifdef _WIN32 #if defined(_MSC_VER) && _MSC_VER <= 1200 // not for MS Visual Studio 6 #else PdfParser::PdfParser( PdfVecObjects* pVecObjects, const wchar_t* pszFilename, bool bLoadOnDemand ) : PdfTokenizer(), m_vecObjects( pVecObjects ), m_bStrictParsing( false ) { this->Init(); this->ParseFile( pszFilename, bLoadOnDemand ); } #endif #endif // _WIN32 PdfParser::PdfParser( PdfVecObjects* pVecObjects, const char* pBuffer, long lLen, bool bLoadOnDemand ) : PdfTokenizer(), m_vecObjects( pVecObjects ), m_bStrictParsing( false ) { this->Init(); this->ParseFile( pBuffer, lLen, bLoadOnDemand ); } PdfParser::PdfParser( PdfVecObjects* pVecObjects, const PdfRefCountedInputDevice & rDevice, bool bLoadOnDemand ) : PdfTokenizer(), m_vecObjects( pVecObjects ), m_bStrictParsing( false ) { this->Init(); if( !rDevice.Device() ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "Cannot create PdfRefCountedInputDevice." ); } this->ParseFile( rDevice, bLoadOnDemand ); } PdfParser::~PdfParser() { Clear(); } void PdfParser::Init() { m_bLoadOnDemand = false; m_device = PdfRefCountedInputDevice(); m_pTrailer = NULL; m_pLinearization = NULL; m_offsets.clear(); m_pEncrypt = NULL; m_ePdfVersion = ePdfVersion_Default; m_nXRefOffset = 0; m_nFirstObject = 0; m_nNumObjects = 0; m_nXRefLinearizedOffset = 0; m_lLastEOFOffset = 0; m_bIgnoreBrokenObjects = false; m_nIncrementalUpdates = 0; m_nReadNextTrailerLevel = 0; } void PdfParser::ParseFile( const char* pszFilename, bool bLoadOnDemand ) { if( !pszFilename || !pszFilename[0] ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } PdfRefCountedInputDevice device( pszFilename, "rb" ); if( !device.Device() ) { PODOFO_RAISE_ERROR_INFO( ePdfError_FileNotFound, pszFilename ); } this->ParseFile( device, bLoadOnDemand ); } #ifdef _WIN32 #if defined(_MSC_VER) && _MSC_VER <= 1200 // not for MS Visual Studio 6 #else void PdfParser::ParseFile( const wchar_t* pszFilename, bool bLoadOnDemand ) { if( !pszFilename || !pszFilename[0] ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } PdfRefCountedInputDevice device( pszFilename, "rb" ); if( !device.Device() ) { PdfError e( ePdfError_FileNotFound, __FILE__, __LINE__ ); e.SetErrorInformation( pszFilename ); throw e; } this->ParseFile( device, bLoadOnDemand ); } #endif #endif // _WIN32 void PdfParser::ParseFile( const char* pBuffer, long lLen, bool bLoadOnDemand ) { if( !pBuffer || !lLen ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } PdfRefCountedInputDevice device( pBuffer, lLen ); if( !device.Device() ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "Cannot create PdfParser from buffer." ); } this->ParseFile( device, bLoadOnDemand ); } void PdfParser::ParseFile( const PdfRefCountedInputDevice & rDevice, bool bLoadOnDemand ) { Clear(); m_device = rDevice; m_bLoadOnDemand = bLoadOnDemand; try { if( !IsPdfFile() ) { PODOFO_RAISE_ERROR( ePdfError_NoPdfFile ); } ReadDocumentStructure(); ReadObjects(); } catch( PdfError & e ) { if( e.GetError() == ePdfError_InvalidPassword ) { // Do not clean up, expect user to call ParseFile again throw e; } // If this is being called from a constructor then the // destructor will not be called. // Clean up here Clear(); e.AddToCallstack( __FILE__, __LINE__, "Unable to load objects from file." ); throw e; } } void PdfParser::Clear() { m_setObjectStreams.clear(); m_offsets.clear(); m_device = PdfRefCountedInputDevice(); delete m_pTrailer; m_pTrailer = NULL; delete m_pLinearization; m_pLinearization = NULL; delete m_pEncrypt; m_pEncrypt = NULL; this->Init(); } void PdfParser::ReadDocumentStructure() { // Ulrich Arnold 8.9.2009, deactivated because of problems during reading xref's // HasLinearizationDict(); // position at the end of the file to search the xref table. m_device.Device()->Seek( 0, std::ios_base::end ); m_nFileSize = m_device.Device()->Tell(); // James McGill 18.02.2011, validate the eof marker and when not in strict mode accept garbage after it try { CheckEOFMarker(); } catch( PdfError & e ) { e.AddToCallstack( __FILE__, __LINE__, "EOF marker could not be found." ); throw e; } try { ReadXRef( &m_nXRefOffset ); } catch( PdfError & e ) { e.AddToCallstack( __FILE__, __LINE__, "Unable to find startxref entry in file." ); throw e; } try { ReadTrailer(); } catch( PdfError & e ) { e.AddToCallstack( __FILE__, __LINE__, "Unable to find trailer in file." ); throw e; } if( m_pLinearization ) { try { ReadXRefContents( m_nXRefOffset, true ); } catch( PdfError & e ) { e.AddToCallstack( __FILE__, __LINE__, "Unable to skip xref dictionary." ); throw e; } // another trailer directory is to follow right after this XRef section try { ReadNextTrailer(); } catch( PdfError & e ) { if( e != ePdfError_NoTrailer ) throw e; } } if( m_pTrailer->IsDictionary() && m_pTrailer->GetDictionary().HasKey( PdfName::KeySize ) ) { m_nNumObjects = static_cast(m_pTrailer->GetDictionary().GetKeyAsLong( PdfName::KeySize )); } else { PdfError::LogMessage( eLogSeverity_Warning, "PDF Standard Violation: No /Size key was specified in the trailer directory. Will attempt to recover." ); // Treat the xref size as unknown, and expand the xref dynamically as we read it. m_nNumObjects = 0; } // allow caller to specify a max object count to avoid very slow load times on large documents if (s_nMaxObjects != std::numeric_limits::max() && m_nNumObjects > s_nMaxObjects) PODOFO_RAISE_ERROR_INFO( ePdfError_ValueOutOfRange, "m_nNumObjects is greater than m_nMaxObjects." ); if (m_nNumObjects > 0) m_offsets.resize(m_nNumObjects); if( m_pLinearization ) { try { ReadXRefContents( m_nXRefLinearizedOffset ); } catch( PdfError & e ) { e.AddToCallstack( __FILE__, __LINE__, "Unable to read linearized XRef section." ); throw e; } } try { ReadXRefContents( m_nXRefOffset ); } catch( PdfError & e ) { e.AddToCallstack( __FILE__, __LINE__, "Unable to load xref entries." ); throw e; } } bool PdfParser::IsPdfFile() { const char* szPdfMagicStart = "%PDF-"; int i; if( m_device.Device()->Read( m_buffer.GetBuffer(), PDF_MAGIC_LEN ) != PDF_MAGIC_LEN ) return false; if( strncmp( m_buffer.GetBuffer(), szPdfMagicStart, strlen( szPdfMagicStart ) ) != 0 ) return false; // try to determine the excact PDF version of the file for( i=0;i<=MAX_PDF_VERSION_STRING_INDEX;i++ ) { if( strncmp( m_buffer.GetBuffer(), s_szPdfVersions[i], PDF_MAGIC_LEN ) == 0 ) { m_ePdfVersion = static_cast(i); break; } } return true; } void PdfParser::HasLinearizationDict() { if (m_pLinearization) { PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "HasLinarizationDict() called twice on one object"); } m_device.Device()->Seek( 0 ); // The linearization dictionary must be in the first 1024 // bytes of the PDF, our buffer might be larger so. // Therefore read only the first 1024 byte. // Normally we should jump to the end of the file, to determine // it's filesize and read the min(1024, filesize) to not fail // on smaller files, but jumping to the end is against the idea // of linearized PDF. Therefore just check if we read anything. const std::streamoff MAX_READ = 1024; PdfRefCountedBuffer linearizeBuffer( MAX_READ ); std::streamoff size = m_device.Device()->Read( linearizeBuffer.GetBuffer(), linearizeBuffer.GetSize() ); // Only fail if we read nothing, to allow files smaller than MAX_READ if( static_cast(size) <= 0 ) { // Clear the error state from the bad read m_device.Device()->Clear(); return; // Ignore Error Code: ERROR_PDF_NO_TRAILER; } //begin L.K //char * pszObj = strstr( m_buffer.GetBuffer(), "obj" ); char * pszObj = strstr( linearizeBuffer.GetBuffer(), "obj" ); //end L.K if( !pszObj ) // strange that there is no obj in the first 1024 bytes, // but ignore it return; --pszObj; // *pszObj == 'o', so the while would fail without decrement while( *pszObj && (PdfTokenizer::IsWhitespace( *pszObj ) || (*pszObj >= '0' && *pszObj <= '9')) ) --pszObj; m_pLinearization = new PdfParserObject( m_vecObjects, m_device, linearizeBuffer, pszObj - linearizeBuffer.GetBuffer() + 2 ); try { // Do not care for encryption here, as the linearization dictionary does not contain strings or streams // ... hint streams do, but we do not load the hintstream. static_cast(m_pLinearization)->ParseFile( NULL ); if (! (m_pLinearization->IsDictionary() && m_pLinearization->GetDictionary().HasKey( "Linearized" ) ) ) { delete m_pLinearization; m_pLinearization = NULL; return; } } catch( PdfError & e ) { PdfError::LogMessage( eLogSeverity_Warning, e.ErrorName(e.GetError()) ); delete m_pLinearization; m_pLinearization = NULL; return; } pdf_int64 lXRef = -1; lXRef = m_pLinearization->GetDictionary().GetKeyAsLong( "T", lXRef ); if( lXRef == -1 ) { PODOFO_RAISE_ERROR( ePdfError_InvalidLinearization ); } // avoid moving to a negative file position here m_device.Device()->Seek( (static_cast(lXRef-PDF_XREF_BUF) > 0 ? static_cast(lXRef-PDF_XREF_BUF) : PDF_XREF_BUF) ); m_nXRefLinearizedOffset = m_device.Device()->Tell(); if( m_device.Device()->Read( m_buffer.GetBuffer(), PDF_XREF_BUF ) != PDF_XREF_BUF ) { PODOFO_RAISE_ERROR( ePdfError_InvalidLinearization ); } m_buffer.GetBuffer()[PDF_XREF_BUF] = '\0'; // search backwards in the buffer in case the buffer contains null bytes // because it is right after a stream (can't use strstr for this reason) const int XREF_LEN = 4; // strlen( "xref" ); int i = 0; char* pszStart = NULL; for( i = PDF_XREF_BUF - XREF_LEN; i >= 0; i-- ) if( strncmp( m_buffer.GetBuffer()+i, "xref", XREF_LEN ) == 0 ) { pszStart = m_buffer.GetBuffer()+i; break; } m_nXRefLinearizedOffset += i; if( !pszStart ) { if( m_ePdfVersion < ePdfVersion_1_5 ) { PdfError::LogMessage( eLogSeverity_Warning, "Linearization dictionaries are only supported with PDF version 1.5. This is 1.%i. Trying to continue.\n", static_cast(m_ePdfVersion) ); // PODOFO_RAISE_ERROR( ePdfError_InvalidLinearization ); } { m_nXRefLinearizedOffset = static_cast(lXRef); /* eCode = ReadXRefStreamContents(); i = 0; */ } } } void PdfParser::MergeTrailer( const PdfObject* pTrailer ) { PdfVariant cVar; if( !pTrailer || !m_pTrailer ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } // Only update keys, if not already present if( pTrailer->GetDictionary().HasKey( PdfName::KeySize ) && !m_pTrailer->GetDictionary().HasKey( PdfName::KeySize ) ) m_pTrailer->GetDictionary().AddKey( PdfName::KeySize, *(pTrailer->GetDictionary().GetKey( PdfName::KeySize )) ); if( pTrailer->GetDictionary().HasKey( "Root" ) && !m_pTrailer->GetDictionary().HasKey( "Root" )) m_pTrailer->GetDictionary().AddKey( "Root", *(pTrailer->GetDictionary().GetKey( "Root" )) ); if( pTrailer->GetDictionary().HasKey( "Encrypt" ) && !m_pTrailer->GetDictionary().HasKey( "Encrypt" ) ) m_pTrailer->GetDictionary().AddKey( "Encrypt", *(pTrailer->GetDictionary().GetKey( "Encrypt" )) ); if( pTrailer->GetDictionary().HasKey( "Info" ) && !m_pTrailer->GetDictionary().HasKey( "Info" ) ) m_pTrailer->GetDictionary().AddKey( "Info", *(pTrailer->GetDictionary().GetKey( "Info" )) ); if( pTrailer->GetDictionary().HasKey( "ID" ) && !m_pTrailer->GetDictionary().HasKey( "ID" ) ) m_pTrailer->GetDictionary().AddKey( "ID", *(pTrailer->GetDictionary().GetKey( "ID" )) ); } void PdfParser::ReadNextTrailer() { // be careful changing this limit - overflow limits depend on the OS, linker settings, and how much stack space compiler allocates // 500 limit prevents overflow on Win7 with VC++ 2005 with default linker stack size (1000 caused overflow with same compiler/OS) const int maxReadNextTrailerLevel = 500; ++m_nReadNextTrailerLevel; if ( m_nReadNextTrailerLevel > maxReadNextTrailerLevel ) { // avoid stack overflow on documents that have circular cross references in trailer PODOFO_RAISE_ERROR( ePdfError_InvalidXRef ); } // ReadXRefcontents has read the first 't' from "trailer" so just check for "railer" if( this->IsNextToken( "trailer" ) ) //if( strcmp( m_buffer.GetBuffer(), "railer" ) == 0 ) { PdfParserObject trailer( m_vecObjects, m_device, m_buffer ); try { // Ignore the encryption in the trailer as the trailer may not be encrypted trailer.ParseFile( NULL, true ); } catch( PdfError & e ) { e.AddToCallstack( __FILE__, __LINE__, "The linearized trailer was found in the file, but contains errors." ); throw e; } // now merge the information of this trailer with the main documents trailer MergeTrailer( &trailer ); if( trailer.GetDictionary().HasKey( "XRefStm" ) ) { // Whenever we read a XRefStm key, // we know that the file was updated. if( !trailer.GetDictionary().HasKey( "Prev" ) ) m_nIncrementalUpdates++; try { ReadXRefStreamContents( static_cast(trailer.GetDictionary().GetKeyAsLong( "XRefStm", 0 )), false ); } catch( PdfError & e ) { e.AddToCallstack( __FILE__, __LINE__, "Unable to load /XRefStm xref stream." ); throw e; } } if( trailer.GetDictionary().HasKey( "Prev" ) ) { // Whenever we read a Prev key, // we know that the file was updated. m_nIncrementalUpdates++; try { ReadXRefContents( static_cast(trailer.GetDictionary().GetKeyAsLong( "Prev", 0 )) ); } catch( PdfError & e ) { e.AddToCallstack( __FILE__, __LINE__, "Unable to load /Prev xref entries." ); throw e; } } } else // OC 13.08.2010 BugFix: else belongs to IsNextToken( "trailer" ) and not to HasKey( "Prev" ) { PODOFO_RAISE_ERROR( ePdfError_NoTrailer ); } --m_nReadNextTrailerLevel; } void PdfParser::ReadTrailer() { FindToken( "trailer", PDF_XREF_BUF ); if( !this->IsNextToken( "trailer" ) ) { // if( m_ePdfVersion < ePdfVersion_1_5 ) // Ulrich Arnold 19.10.2009, found linearized 1.3-pdf's with trailer-info in xref-stream if( m_ePdfVersion < ePdfVersion_1_3 ) { PODOFO_RAISE_ERROR( ePdfError_NoTrailer ); } else { // Since PDF 1.5 trailer information can also be found // in the crossreference stream object // and a trailer dictionary is not required m_device.Device()->Seek( m_nXRefOffset ); m_pTrailer = new PdfParserObject( m_vecObjects, m_device, m_buffer ); static_cast(m_pTrailer)->ParseFile( NULL, false ); return; } } else { m_pTrailer = new PdfParserObject( m_vecObjects, m_device, m_buffer ); try { // Ignore the encryption in the trailer as the trailer may not be encrypted static_cast(m_pTrailer)->ParseFile( NULL, true ); } catch( PdfError & e ) { e.AddToCallstack( __FILE__, __LINE__, "The trailer was found in the file, but contains errors." ); throw e; } #ifdef PODOFO_VERBOSE_DEBUG PdfError::DebugMessage("Size=%li\n", m_pTrailer->GetDictionary().GetKeyAsLong( PdfName::KeySize, 0 ) ); #endif // PODOFO_VERBOSE_DEBUG } } void PdfParser::ReadXRef( pdf_long* pXRefOffset ) { FindToken( "startxref", PDF_XREF_BUF ); if( !this->IsNextToken( "startxref" ) ) { // Could be non-standard startref if(!m_bStrictParsing) { FindToken( "startref", PDF_XREF_BUF ); if( !this->IsNextToken( "startref" ) ) { PODOFO_RAISE_ERROR( ePdfError_NoXRef ); } } else { PODOFO_RAISE_ERROR( ePdfError_NoXRef ); } } *pXRefOffset = this->GetNextNumber(); } void PdfParser::ReadXRefContents( pdf_long lOffset, bool bPositionAtEnd ) { pdf_int64 nFirstObject = 0; pdf_int64 nNumObjects = 0; size_t curPosition = m_device.Device()->Tell(); m_device.Device()->Seek(0,std::ios_base::end); std::streamoff fileSize = m_device.Device()->Tell(); m_device.Device()->Seek(curPosition,std::ios_base::beg); if (lOffset > fileSize) { // Invalid "startxref" Peter Petrov 23 December 2008 // ignore returned value and get offset from the device ReadXRef( &lOffset ); lOffset = m_device.Device()->Tell(); // TODO: hard coded value "4" m_buffer.Resize(PDF_XREF_BUF*4); FindToken2("xref", PDF_XREF_BUF*4,lOffset); m_buffer.Resize(PDF_XREF_BUF); lOffset = m_device.Device()->Tell(); m_nXRefOffset = lOffset; } else { m_device.Device()->Seek( lOffset ); } if( !this->IsNextToken( "xref" ) ) { // if( m_ePdfVersion < ePdfVersion_1_5 ) // Ulrich Arnold 19.10.2009, found linearized 1.3-pdf's with trailer-info in xref-stream if( m_ePdfVersion < ePdfVersion_1_3 ) { PODOFO_RAISE_ERROR( ePdfError_NoXRef ); } else { ReadXRefStreamContents( lOffset, bPositionAtEnd ); return; } } // read all xref subsections // OC 13.08.2010: Avoid exception to terminate endless loop for( int nXrefSection = 0; ; ++nXrefSection ) { try { // OC 13.08.2010: Avoid exception to terminate endless loop if ( nXrefSection > 0 ) { // something like PeekNextToken() EPdfTokenType eType; const char* pszRead; bool gotToken = this->GetNextToken( pszRead, &eType ); if( gotToken ) { this->QuequeToken( pszRead, eType ); if ( strcmp( "trailer", pszRead ) == 0 ) break; } } nFirstObject = this->GetNextNumber(); nNumObjects = this->GetNextNumber(); #ifdef PODOFO_VERBOSE_DEBUG PdfError::DebugMessage("Reading numbers: %" PDF_FORMAT_INT64 " %" PDF_FORMAT_INT64 "\n", nFirstObject, nNumObjects ); #endif // PODOFO_VERBOSE_DEBUG if( bPositionAtEnd ) { #ifdef _WIN32 m_device.Device()->Seek( static_cast(nNumObjects* PDF_XREF_ENTRY_SIZE), std::ios_base::cur ); #else m_device.Device()->Seek( nNumObjects* PDF_XREF_ENTRY_SIZE, std::ios_base::cur ); #endif // _WIN32 } else { ReadXRefSubsection( nFirstObject, nNumObjects ); } } catch( PdfError & e ) { if( e == ePdfError_NoNumber || e == ePdfError_InvalidXRef || e == ePdfError_UnexpectedEOF ) break; else { e.AddToCallstack( __FILE__, __LINE__ ); throw e; } } } try { ReadNextTrailer(); } catch( PdfError & e ) { if( e != ePdfError_NoTrailer ) { e.AddToCallstack( __FILE__, __LINE__ ); throw e; } } } void PdfParser::ReadXRefSubsection( pdf_int64 & nFirstObject, pdf_int64 & nNumObjects ) { int count = 0; #ifdef PODOFO_VERBOSE_DEBUG PdfError::DebugMessage("Reading XRef Section: %" PDF_FORMAT_INT64 " with %" PDF_FORMAT_INT64 " Objects.\n", nFirstObject, nNumObjects ); #endif // PODOFO_VERBOSE_DEBUG if ( nFirstObject + nNumObjects > m_nNumObjects ) { // Total number of xref entries to read is greater than the /Size // specified in the trailer if any. That's an error unless we're trying // to recover from a missing /Size entry. PdfError::LogMessage( eLogSeverity_Warning, "There are more objects (%" PDF_FORMAT_INT64 ") in this XRef table than " "specified in the size key of the trailer directory (%" PDF_FORMAT_INT64 ")!\n", nFirstObject + nNumObjects, m_nNumObjects ); #ifdef _WIN32 m_nNumObjects = static_cast(nFirstObject + nNumObjects); m_offsets.resize(static_cast(nFirstObject+nNumObjects)); #else m_nNumObjects = nFirstObject + nNumObjects; m_offsets.resize(nFirstObject+nNumObjects); #endif // _WIN32 } // consume all whitespaces int charcode; while( this->IsWhitespace((charcode = m_device.Device()->Look())) ) { m_device.Device()->GetChar(); } while( count < nNumObjects && m_device.Device()->Read( m_buffer.GetBuffer(), PDF_XREF_ENTRY_SIZE ) == PDF_XREF_ENTRY_SIZE ) { char empty1; char empty2; m_buffer.GetBuffer()[PDF_XREF_ENTRY_SIZE] = '\0'; #ifdef _WIN32 const int objID = static_cast(nFirstObject+count); #else const int objID = nFirstObject+count; #endif // _WIN32 if( static_cast(objID) < m_offsets.size() && !m_offsets[objID].bParsed ) { // don't scan directly into m_offsets since TXRefEntry structure member sizes change between platforms and compilers // // pdf_long lOffset; // pdf_long is ptrdiff_t: 64 bits on Mac64, Linux64, Win64; 32 bits on Mac32, Linux32, Win32 // long lGeneration; // 64 bits on Mac64, Linux64; 32 bits on Win64, Mac32, Linux32, Win32 // char cUsed; // always 8 bits // pdf_int64 llOffset = 0; pdf_int64 llGeneration = 0; char cUsed = 0; // XRefEntry is defined in PDF spec section 7.5.4 Cross-Reference Table as // nnnnnnnnnn ggggg n eol // nnnnnnnnnn is 10-digit offset number with max value 9999999999 (bigger than 2**32 = 4GB) // ggggg is a 5-digit generation number with max value 99999 (smaller than 2**17) int read = sscanf( m_buffer.GetBuffer(), "%10" PDF_FORMAT_INT64 " %5" PDF_FORMAT_INT64 " %c%c%c", &llOffset, &llGeneration, &cUsed, &empty1, &empty2 ); if ( read != 5 ) { // part of XrefEntry is missing, or i/o error PODOFO_RAISE_ERROR( ePdfError_InvalidXRef ); } if ( llOffset > PDF_LONG_MAX ) { // pdf_long max size is PTRDIFF_MAX, so throw error if llOffset too big PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } m_offsets[objID].lOffset = static_cast(llOffset); m_offsets[objID].lGeneration = static_cast(llGeneration); m_offsets[objID].cUsed = cUsed; m_offsets[objID].bParsed = true; } ++count; } if( count != nNumObjects ) { PdfError::LogMessage( eLogSeverity_Warning, "Count of readobject is %i. Expected %" PDF_FORMAT_INT64 ".\n", count, nNumObjects ); PODOFO_RAISE_ERROR( ePdfError_NoXRef ); } } void PdfParser::ReadXRefStreamContents( pdf_long lOffset, bool bReadOnlyTrailer ) { m_device.Device()->Seek( lOffset ); PdfXRefStreamParserObject xrefObject( m_vecObjects, m_device, m_buffer, &m_offsets ); xrefObject.Parse(); if( !m_pTrailer ) m_pTrailer = new PdfParserObject( m_vecObjects, m_device, m_buffer ); MergeTrailer( &xrefObject ); if( bReadOnlyTrailer ) return; xrefObject.ReadXRefTable(); // Check for a previous XRefStm or xref table if(xrefObject.HasPrevious()) { try { m_nIncrementalUpdates++; // PDFs that have been through multiple PDF tools may have a mix of xref tables (ISO 32000-1 7.5.4) // and XRefStm streams (ISO 32000-1 7.5.8.1) and in the Prev chain, // so call ReadXRefContents (which deals with both) instead of ReadXRefStreamContents ReadXRefContents( xrefObject.GetPreviousOffset(), bReadOnlyTrailer ); } catch(PdfError &e) { /* Be forgiving, the error happens when an entry in XRef stream points to a wrong place (offset) in the PDF file. */ if( e != ePdfError_NoNumber ) { e.AddToCallstack( __FILE__, __LINE__ ); throw e; } } } } bool PdfParser::QuickEncryptedCheck( const char* pszFilename ) { bool bEncryptStatus = false; bool bOldLoadOnDemand = m_bLoadOnDemand; Init(); Clear(); m_bLoadOnDemand = true; // maybe will be quicker if true? if( !pszFilename || !pszFilename[0] ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } m_device = PdfRefCountedInputDevice( pszFilename, "rb" ); if( !m_device.Device() ) { //PODOFO_RAISE_ERROR_INFO( ePdfError_FileNotFound, pszFilename ); // If we can not open PDF file // then file does not exist return false; } if( !IsPdfFile() ) { //PODOFO_RAISE_ERROR( ePdfError_NoPdfFile ); return false; } ReadDocumentStructure(); try { m_vecObjects->Reserve( m_nNumObjects ); // Check for encryption and make sure that the encryption object // is loaded before all other objects const PdfObject * encObj = m_pTrailer->GetDictionary().GetKey( PdfName("Encrypt") ); if( encObj && ! encObj->IsNull() ) { bEncryptStatus = true; } } catch( PdfError & e ) { m_bLoadOnDemand = bOldLoadOnDemand; // Restore load on demand behaviour e.AddToCallstack( __FILE__, __LINE__, "Unable to load objects from file." ); throw e; } m_bLoadOnDemand = bOldLoadOnDemand; // Restore load on demand behaviour return bEncryptStatus; } void PdfParser::ReadObjects() { int i = 0; PdfParserObject* pObject = NULL; m_vecObjects->Reserve( m_nNumObjects ); // Check for encryption and make sure that the encryption object // is loaded before all other objects PdfObject* pEncrypt = m_pTrailer->GetDictionary().GetKey( PdfName("Encrypt") ); if( pEncrypt && !pEncrypt->IsNull() ) { #ifdef PODOFO_VERBOSE_DEBUG PdfError::DebugMessage("The PDF file is encrypted.\n" ); #endif // PODOFO_VERBOSE_DEBUG if( pEncrypt->IsReference() ) { i = pEncrypt->GetReference().ObjectNumber(); pObject = new PdfParserObject( m_vecObjects, m_device, m_buffer, m_offsets[i].lOffset ); if( !pObject ) PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); pObject->SetLoadOnDemand( false ); // Never load this on demand, as we will use it immediately try { pObject->ParseFile( NULL ); // The encryption dictionary is not encrypted :) // Never add the encryption dictionary to m_vecObjects // we create a new one, if we need it for writing // m_vecObjects->push_back( pObject ); m_offsets[i].bParsed = false; m_pEncrypt = PdfEncrypt::CreatePdfEncrypt( pObject ); delete pObject; } catch( PdfError & e ) { std::ostringstream oss; oss << "Error while loading object " << pObject->Reference().ObjectNumber() << " " << pObject->Reference().GenerationNumber() << std::endl; delete pObject; e.AddToCallstack( __FILE__, __LINE__, oss.str().c_str() ); throw e; } } else if( pEncrypt->IsDictionary() ) { m_pEncrypt = PdfEncrypt::CreatePdfEncrypt( pEncrypt ); } else { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidEncryptionDict, "The encryption entry in the trailer is neither an object nor a reference." ); } // Generate encryption keys // Set user password, try first with an empty password bool bAuthenticate = m_pEncrypt->Authenticate( "", this->GetDocumentId() ); #ifdef PODOFO_VERBOSE_DEBUG PdfError::DebugMessage("Authentication with empty password: %i.\n", bAuthenticate ); #endif // PODOFO_VERBOSE_DEBUG if( !bAuthenticate ) { // authentication failed so we need a password from the user. // The user can set the password using PdfParser::SetPassword PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidPassword, "A password is required to read this PDF file."); } } ReadObjectsInternal(); } void PdfParser::ReadObjectsInternal() { int i = 0; int nLast = 0; PdfParserObject* pObject = NULL; // Read objects for( i=0; i < m_nNumObjects; i++ ) { #ifdef PODOFO_VERBOSE_DEBUG std::cerr << "ReadObjectsInteral\t" << i << " " << (m_offsets[i].bParsed ? "parsed" : "unparsed") << " " << m_offsets[i].cUsed << " " << m_offsets[i].lOffset << " " << m_offsets[i].lGeneration << std::endl; #endif if( m_offsets[i].bParsed && m_offsets[i].cUsed == 'n' && m_offsets[i].lOffset > 0 ) { //printf("Reading object %i 0 R from %li\n", i, m_offsets[i].lOffset ); pObject = new PdfParserObject( m_vecObjects, m_device, m_buffer, m_offsets[i].lOffset ); if( !pObject ) PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); pObject->SetLoadOnDemand( m_bLoadOnDemand ); try { pObject->ParseFile( m_pEncrypt ); if (m_pEncrypt && pObject->IsDictionary()) { PdfObject* pObjType = pObject->GetDictionary().GetKey( PdfName::KeyType ); if( pObjType && pObjType->IsName() && pObjType->GetName() == "XRef" ) { // XRef is never encrypted delete pObject; pObject = new PdfParserObject( m_vecObjects, m_device, m_buffer, m_offsets[i].lOffset ); pObject->SetLoadOnDemand( m_bLoadOnDemand ); pObject->ParseFile( NULL ); } } nLast = pObject->Reference().ObjectNumber(); /* if( i != pObject->Reference().ObjectNumber() ) { printf("Expected %i got %i\n", i, pObject->Reference().ObjectNumber()); } if( pObject->Reference().ObjectNumber() != i ) { printf("EXPECTED: %i got %i\n", i, pObject->Reference().ObjectNumber() ); abort(); } */ // final pdf should not contain a linerization dictionary as it contents are invalid // as we change some objects and the final xref table if( m_pLinearization && nLast == static_cast(m_pLinearization->Reference().ObjectNumber()) ) { m_vecObjects->AddFreeObject( pObject->Reference() ); delete pObject; } else m_vecObjects->push_back( pObject ); } catch( PdfError & e ) { std::ostringstream oss; oss << "Error while loading object " << pObject->Reference().ObjectNumber() << " " << pObject->Reference().GenerationNumber() << " Offset = " << m_offsets[i].lOffset << " Index = " << i << std::endl; delete pObject; if( m_bIgnoreBrokenObjects ) { PdfError::LogMessage( eLogSeverity_Error, oss.str().c_str() ); m_vecObjects->AddFreeObject( PdfReference( i, 0 ) ); } else { e.AddToCallstack( __FILE__, __LINE__, oss.str().c_str() ); throw e; } } } else if( m_offsets[i].bParsed && m_offsets[i].cUsed == 'n' && (m_offsets[i].lOffset == 0) ) { // There are broken PDFs which add objects with 'n' // and 0 offset and 0 generation number // to the xref table instead of using free objects // treating them as free objects if( m_bStrictParsing ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidXRef, "Found object with 0 offset which should be 'f' instead of 'n'." ); } else { PdfError::LogMessage( eLogSeverity_Warning, "Treating object %i 0 R as a free object." ); m_vecObjects->AddFreeObject( PdfReference( i, PODOFO_LL_LITERAL(1) ) ); } } // Ulrich Arnold 30.7.2009: the linked free list in the xref section is not always correct in pdf's // (especially Illustrator) but Acrobat still accepts them. I've seen XRefs // where some object-numbers are alltogether missing and multiple XRefs where // the link list is broken. // Because PdfVecObjects relies on a unbroken range, fill the free list more // robustly from all places which are either free or unparsed // else if( m_offsets[i].bParsed && m_offsets[i].cUsed == 'f' && m_offsets[i].lOffset ) // { // m_vecObjects->AddFreeObject( PdfReference( static_cast(m_offsets[i].lOffset), PODOFO_LL_LITERAL(1) ) ); // TODO: do not hard code // } else if( (!m_offsets[i].bParsed || m_offsets[i].cUsed == 'f') && i != 0 ) { m_vecObjects->AddFreeObject( PdfReference( static_cast(i), PODOFO_LL_LITERAL(1) ) ); // TODO: do not hard code generation number } } // all normal objects including object streams are available now, // we can parse the object streams safely now. // // Note that even if demand loading is enabled we still currently read all // objects from the stream into memory then free the stream. // for( i = 0; i < m_nNumObjects; i++ ) { if( m_offsets[i].bParsed && m_offsets[i].cUsed == 's' ) // we have an object stream { #if defined(PODOFO_VERBOSE_DEBUG) if (m_bLoadOnDemand) cerr << "Demand loading on, but can't demand-load from object stream." << endl; #endif ReadObjectFromStream( static_cast(m_offsets[i].lGeneration), static_cast(m_offsets[i].lOffset) ); } } if( !m_bLoadOnDemand ) { // Force loading of streams. We can't do this during the initial // run that populates m_vecObjects because a stream might have a /Length // key that references an object we haven't yet read. So we must do it here // in a second pass, or (if demand loading is enabled) defer it for later. for (TCIVecObjects itObjects = m_vecObjects->begin(); itObjects != m_vecObjects->end(); ++itObjects) { pObject = dynamic_cast(*itObjects); // only parse streams for objects that have not yet parsed // their streams if( pObject && pObject->HasStreamToParse() && !pObject->HasStream() ) pObject->GetStream(); } } // Now sort the list of objects m_vecObjects->Sort(); UpdateDocumentVersion(); } void PdfParser::SetPassword( const std::string & sPassword ) { if( !m_pEncrypt ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Cannot set password for unencrypted PDF." ); } bool bAuthenticate = m_pEncrypt->Authenticate( sPassword, this->GetDocumentId() ); if( !bAuthenticate ) { #ifdef PODOFO_VERBOSE_DEBUG PdfError::DebugMessage("Authentication with user password failed\n" ); #endif // PODOFO_VERBOSE_DEBUG PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidPassword, "Authentication with user specified password failed."); } ReadObjectsInternal(); } void PdfParser::ReadObjectFromStream( int nObjNo, int ) { // check if we already have read all objects // from this stream if( m_setObjectStreams.find( nObjNo ) != m_setObjectStreams.end() ) { return; } else m_setObjectStreams.insert( nObjNo ); // generation number of object streams is always 0 PdfParserObject* pStream = dynamic_cast(m_vecObjects->GetObject( PdfReference( nObjNo, 0 ) ) ); if( !pStream ) { std::ostringstream oss; oss << "Loading of object " << nObjNo << " 0 R failed!" << std::endl; PODOFO_RAISE_ERROR_INFO( ePdfError_NoObject, oss.str().c_str() ); } PdfObjectStreamParserObject::ObjectIdList list; for( int i = 0; i < m_nNumObjects; i++ ) { if( m_offsets[i].bParsed && m_offsets[i].cUsed == 's' && m_offsets[i].lGeneration == nObjNo) { list.push_back(static_cast(i)); } } PdfObjectStreamParserObject pParserObject( pStream, m_vecObjects, m_buffer, m_pEncrypt ); pParserObject.Parse( list ); } const char* PdfParser::GetPdfVersionString() const { return s_szPdfVersions[static_cast(m_ePdfVersion)]; } void PdfParser::FindToken( const char* pszToken, const long lRange ) { // James McGill 18.02.2011, offset read position to the EOF marker if it is not the last thing in the file m_device.Device()->Seek( -m_lLastEOFOffset, std::ios_base::end ); std::streamoff nFileSize = m_device.Device()->Tell(); if (nFileSize == -1) { PODOFO_RAISE_ERROR_INFO( ePdfError_NoXRef, "Failed to seek to EOF when looking for xref"); } pdf_long lXRefBuf = PDF_MIN( static_cast(nFileSize), static_cast(lRange) ); size_t nTokenLen = strlen( pszToken ); m_device.Device()->Seek( -lXRefBuf, std::ios_base::cur ); if( m_device.Device()->Read( m_buffer.GetBuffer(), lXRefBuf ) != lXRefBuf && !m_device.Device()->Eof() ) { PODOFO_RAISE_ERROR( ePdfError_NoXRef ); } m_buffer.GetBuffer()[lXRefBuf] = '\0'; int i; // Do not make this unsigned, this will cause infinte loops in files without trailer // search backwards in the buffer in case the buffer contains null bytes // because it is right after a stream (can't use strstr for this reason) for( i = lXRefBuf - nTokenLen; i >= 0; i-- ) { if( strncmp( m_buffer.GetBuffer()+i, pszToken, nTokenLen ) == 0 ) { break; } } if( !i ) { PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } // James McGill 18.02.2011, offset read position to the EOF marker if it is not the last thing in the file m_device.Device()->Seek( ((lXRefBuf-i)*-1)-m_lLastEOFOffset, std::ios_base::end ); } // Peter Petrov 23 December 2008 void PdfParser::FindToken2( const char* pszToken, const long lRange, size_t searchEnd ) { m_device.Device()->Seek( searchEnd, std::ios_base::beg ); std::streamoff nFileSize = m_device.Device()->Tell(); if (nFileSize == -1) { PODOFO_RAISE_ERROR_INFO( ePdfError_NoXRef, "Failed to seek to EOF when looking for xref"); } pdf_long lXRefBuf = PDF_MIN( static_cast(nFileSize), static_cast(lRange) ); size_t nTokenLen = strlen( pszToken ); m_device.Device()->Seek( -lXRefBuf, std::ios_base::cur ); if( m_device.Device()->Read( m_buffer.GetBuffer(), lXRefBuf ) != lXRefBuf && !m_device.Device()->Eof() ) { PODOFO_RAISE_ERROR( ePdfError_NoXRef ); } m_buffer.GetBuffer()[lXRefBuf] = '\0'; // search backwards in the buffer in case the buffer contains null bytes // because it is right after a stream (can't use strstr for this reason) int i; // Do not use an unsigned variable here for( i = lXRefBuf - nTokenLen; i >= 0; i-- ) if( strncmp( m_buffer.GetBuffer()+i, pszToken, nTokenLen ) == 0 ) { break; } if( !i ) { PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } m_device.Device()->Seek( searchEnd + (lXRefBuf-i)*-1, std::ios_base::beg ); } const PdfString & PdfParser::GetDocumentId() { if( !m_pTrailer->GetDictionary().HasKey( PdfName("ID") ) ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidEncryptionDict, "No document ID found in trailer."); } return m_pTrailer->GetDictionary().GetKey( PdfName("ID") )->GetArray()[0].GetString(); } void PdfParser::UpdateDocumentVersion() { if( m_pTrailer->IsDictionary() && m_pTrailer->GetDictionary().HasKey( PdfName("Root") ) ) { PdfObject* pCatalog = m_pTrailer->GetDictionary().GetKey( PdfName("Root") ); if( pCatalog->IsReference() ) { pCatalog = m_vecObjects->GetObject( pCatalog->GetReference() ); } if( pCatalog && pCatalog->IsDictionary() && pCatalog->GetDictionary().HasKey( PdfName("Version" ) ) ) { PdfObject* pVersion = pCatalog->GetDictionary().GetKey( PdfName( "Version" ) ); for(int i=0;i<=MAX_PDF_VERSION_STRING_INDEX;i++) { if( IsStrictParsing() && !pVersion->IsName()) { // Version must be of type name, according to PDF Specification PODOFO_RAISE_ERROR( ePdfError_InvalidName ); } if( pVersion->IsName() && pVersion->GetName().GetName() == s_szPdfVersionNums[i] ) { PdfError::LogMessage( eLogSeverity_Information, "Updating version from %s to %s\n", s_szPdfVersionNums[static_cast(m_ePdfVersion)], s_szPdfVersionNums[i] ); m_ePdfVersion = static_cast(i); break; } } } } } void PdfParser::CheckEOFMarker() { // Check for the existence of the EOF marker m_lLastEOFOffset = 0; const char* pszEOFToken = "%%EOF"; const size_t nEOFTokenLen = 5; char pszBuff[nEOFTokenLen+1]; m_device.Device()->Seek(-static_cast(nEOFTokenLen), std::ios_base::end ); if( IsStrictParsing() ) { // For strict mode EOF marker must be at the very end of the file if( static_cast(m_device.Device()->Read( pszBuff, nEOFTokenLen )) != nEOFTokenLen && !m_device.Device()->Eof() ) PODOFO_RAISE_ERROR( ePdfError_NoEOFToken ); if (strncmp( pszBuff, pszEOFToken, nEOFTokenLen) != 0) PODOFO_RAISE_ERROR( ePdfError_NoEOFToken ); } else { // Search for the Marker from the end of the file pdf_long lCurrentPos = m_device.Device()->Tell(); bool bFound = false; while (lCurrentPos>=0) { m_device.Device()->Seek( lCurrentPos, std::ios_base::beg ); if( static_cast(m_device.Device()->Read( pszBuff, nEOFTokenLen )) != nEOFTokenLen && !m_device.Device()->Eof() ) { PODOFO_RAISE_ERROR( ePdfError_NoEOFToken ); } if (strncmp( pszBuff, pszEOFToken, nEOFTokenLen) == 0) { bFound = true; break; } --lCurrentPos; } // Try and deal with garbage by offsetting the buffer reads in PdfParser from now on if (bFound) m_lLastEOFOffset = (m_nFileSize - (m_device.Device()->Tell()-1)) + nEOFTokenLen; else PODOFO_RAISE_ERROR( ePdfError_NoEOFToken ); } } bool PdfParser::HasXRefStream() { m_device.Device()->Tell(); m_device.Device()->Seek( m_nXRefOffset ); if( !this->IsNextToken( "xref" ) ) { // if( m_ePdfVersion < ePdfVersion_1_5 ) // Ulrich Arnold 19.10.2009, found linearized 1.3-pdf's with trailer-info in xref-stream if( m_ePdfVersion < ePdfVersion_1_3 ) { return false; } else { return true; } } return false; } }; podofo-0.9.5/src/base/PdfError.cpp0000664000175000017500000005433113023513022016610 0ustar dominikdominik/************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ // PdfError.h doesn't, and can't, include PdfDefines.h so we do so here. // PdfDefines.h will include PdfError.h for us. #include "PdfDefines.h" #include "PdfDefinesPrivate.h" #include #include namespace PoDoFo { bool PdfError::s_DgbEnabled = true; bool PdfError::s_LogEnabled = true; // OC 17.08.2010 New to optionally replace stderr output by a callback: PdfError::LogMessageCallback* PdfError::m_fLogMessageCallback = NULL; //static PdfError::LogMessageCallback* PdfError::SetLogMessageCallback(LogMessageCallback* fLogMessageCallback) { PdfError::LogMessageCallback* old_fLogMessageCallback = m_fLogMessageCallback; m_fLogMessageCallback = fLogMessageCallback; return old_fLogMessageCallback; } PdfErrorInfo::PdfErrorInfo() : m_nLine( -1 ) { } PdfErrorInfo::PdfErrorInfo( int line, const char* pszFile, const char* pszInfo ) : m_nLine( line ), m_sFile( pszFile ? pszFile : "" ), m_sInfo( pszInfo ? pszInfo : "" ) { } PdfErrorInfo::PdfErrorInfo( int line, const char* pszFile, const wchar_t* pszInfo ) : m_nLine( line ), m_sFile( pszFile ? pszFile : "" ), m_swInfo( pszInfo ? pszInfo : L"" ) { } PdfErrorInfo::PdfErrorInfo( const PdfErrorInfo & rhs ) { this->operator=( rhs ); } const PdfErrorInfo & PdfErrorInfo::operator=( const PdfErrorInfo & rhs ) { m_nLine = rhs.m_nLine; m_sFile = rhs.m_sFile; m_sInfo = rhs.m_sInfo; m_swInfo = rhs.m_swInfo; return *this; } // ----------------------------------------------------- // // ----------------------------------------------------- PdfError::PdfError() { m_error = ePdfError_ErrOk; } PdfError::PdfError( const EPdfError & eCode, const char* pszFile, int line, const char* pszInformation ) { this->SetError( eCode, pszFile, line, pszInformation ); } PdfError::PdfError( const PdfError & rhs ) { this->operator=( rhs ); } PdfError::~PdfError() throw() { } const PdfError & PdfError::operator=( const PdfError & rhs ) { m_error = rhs.m_error; m_callStack = rhs.m_callStack; return *this; } const PdfError & PdfError::operator=( const EPdfError & eCode ) { m_error = eCode; m_callStack.clear(); return *this; } bool PdfError::operator==( const PdfError & rhs ) { return this->operator==( rhs.m_error ); } bool PdfError::operator==( const EPdfError & eCode ) { return m_error == eCode; } bool PdfError::operator!=( const PdfError & rhs ) { return this->operator!=( rhs.m_error ); } bool PdfError::operator!=( const EPdfError & eCode ) { return !this->operator==( eCode ); } void PdfError::PrintErrorMsg() const { TCIDequeErrorInfo it = m_callStack.begin(); const char* pszMsg = PdfError::ErrorMessage( m_error ); const char* pszName = PdfError::ErrorName( m_error ); int i = 0; PdfError::LogErrorMessage( eLogSeverity_Error, "\n\nPoDoFo encountered an error. Error: %i %s\n", m_error, pszName ? pszName : "" ); if( pszMsg ) PdfError::LogErrorMessage( eLogSeverity_Error, "\tError Description: %s\n", pszMsg ); if( m_callStack.size() ) PdfError::LogErrorMessage( eLogSeverity_Error, "\tCallstack:\n" ); while( it != m_callStack.end() ) { if( !(*it).GetFilename().empty() ) PdfError::LogErrorMessage( eLogSeverity_Error, "\t#%i Error Source: %s:%i\n", i, (*it).GetFilename().c_str(), (*it).GetLine() ); if( !(*it).GetInformation().empty() ) PdfError::LogErrorMessage( eLogSeverity_Error, "\t\tInformation: %s\n", (*it).GetInformation().c_str() ); if( !(*it).GetInformationW().empty() ) PdfError::LogErrorMessage( eLogSeverity_Error, L"\t\tInformation: %s\n", (*it).GetInformationW().c_str() ); ++i; ++it; } PdfError::LogErrorMessage( eLogSeverity_Error, "\n\n" ); } const char* PdfError::what() const { return PdfError::ErrorName( m_error ); } const char* PdfError::ErrorName( EPdfError eCode ) { const char* pszMsg = NULL; switch( eCode ) { case ePdfError_ErrOk: pszMsg = "ePdfError_ErrOk"; break; case ePdfError_TestFailed: pszMsg = "ePdfError_TestFailed"; break; case ePdfError_InvalidHandle: pszMsg = "ePdfError_InvalidHandle"; break; case ePdfError_FileNotFound: pszMsg = "ePdfError_FileNotFound"; break; case ePdfError_InvalidDeviceOperation: pszMsg = "ePdfError_InvalidDeviceOperation"; break; case ePdfError_UnexpectedEOF: pszMsg = "ePdfError_UnexpectedEOF"; break; case ePdfError_OutOfMemory: pszMsg = "ePdfError_OutOfMemory"; break; case ePdfError_ValueOutOfRange: pszMsg = "ePdfError_ValueOutOfRange"; break; case ePdfError_InternalLogic: pszMsg = "ePdfError_InternalLogic"; break; case ePdfError_InvalidEnumValue: pszMsg = "ePdfError_InvalidEnumValue"; break; case ePdfError_PageNotFound: pszMsg = "ePdfError_PageNotFound"; break; case ePdfError_NoPdfFile: pszMsg = "ePdfError_NoPdfFile"; break; case ePdfError_NoXRef: pszMsg = "ePdfError_NoXRef"; break; case ePdfError_NoTrailer: pszMsg = "ePdfError_NoTrailer"; break; case ePdfError_NoNumber: pszMsg = "ePdfError_NoNumber"; break; case ePdfError_NoObject: pszMsg = "ePdfError_NoObject"; break; case ePdfError_NoEOFToken: pszMsg = "ePdfError_NoEOFToken"; break; case ePdfError_InvalidTrailerSize: pszMsg = "ePdfError_InvalidTrailerSize"; break; case ePdfError_InvalidLinearization: pszMsg = "ePdfError_InvalidLinearization"; break; case ePdfError_InvalidDataType: pszMsg = "ePdfError_InvalidDataType"; break; case ePdfError_InvalidXRef: pszMsg = "ePdfError_InvalidXRef"; break; case ePdfError_InvalidXRefStream: pszMsg = "ePdfError_InvalidXRefStream"; break; case ePdfError_InvalidXRefType: pszMsg = "ePdfError_InvalidXRefType"; break; case ePdfError_InvalidPredictor: pszMsg = "ePdfError_InvalidPredictor"; break; case ePdfError_InvalidStrokeStyle: pszMsg = "ePdfError_InvalidStrokeStyle"; break; case ePdfError_InvalidHexString: pszMsg = "ePdfError_InvalidHexString"; break; case ePdfError_InvalidStream: pszMsg = "ePdfError_InvalidStream"; break; case ePdfError_InvalidStreamLength: pszMsg = "ePdfError_InvalidStream"; break; case ePdfError_InvalidKey: pszMsg = "ePdfError_InvalidKey"; break; case ePdfError_InvalidName: pszMsg = "ePdfError_InvalidName"; break; case ePdfError_InvalidEncryptionDict: pszMsg = "ePdfError_InvalidEncryptionDict"; /**< The encryption dictionary is invalid or misses a required key */ break; case ePdfError_InvalidPassword: /**< The password used to open the PDF file was invalid */ pszMsg = "ePdfError_InvalidPassword"; break; case ePdfError_InvalidFontFile: pszMsg = "ePdfError_InvalidFontFile"; break; case ePdfError_InvalidContentStream: pszMsg = "ePdfError_InvalidContentStream"; break; case ePdfError_UnsupportedFilter: pszMsg = "ePdfError_UnsupportedFilter"; break; case ePdfError_UnsupportedFontFormat: /**< This font format is not supported by PoDoFO. */ pszMsg = "ePdfError_UnsupportedFontFormat"; break; case ePdfError_ActionAlreadyPresent: pszMsg = "ePdfError_ActionAlreadyPresent"; break; case ePdfError_WrongDestinationType: pszMsg = "ePdfError_WrongDestinationType"; break; case ePdfError_MissingEndStream: pszMsg = "ePdfError_MissingEndStream"; break; case ePdfError_Date: pszMsg = "ePdfError_Date"; break; case ePdfError_Flate: pszMsg = "ePdfError_Flate"; break; case ePdfError_FreeType: pszMsg = "ePdfError_FreeType"; break; case ePdfError_SignatureError: pszMsg = "ePdfError_SignatureError"; break; case ePdfError_MutexError: pszMsg = "ePdfError_MutexError"; break; case ePdfError_UnsupportedImageFormat: /**< This image format is not supported by PoDoFO. */ pszMsg = "ePdfError_UnsupportedImageFormat"; break; case ePdfError_CannotConvertColor: /**< This color format cannot be converted. */ pszMsg = "ePdfError_CannotConvertColor"; break; case ePdfError_NotImplemented: pszMsg = "ePdfError_NotImplemented"; break; case ePdfError_NotCompiled: pszMsg = "ePdfError_NotCompiled"; break; case ePdfError_DestinationAlreadyPresent: pszMsg = "ePdfError_DestinationAlreadyPresent"; break; case ePdfError_ChangeOnImmutable: pszMsg = "ePdfError_ChangeOnImmutable"; break; case ePdfError_OutlineItemAlreadyPresent: pszMsg = "ePdfError_OutlineItemAlreadyPresent"; break; case ePdfError_NotLoadedForUpdate: pszMsg = "ePdfError_NotLoadedForUpdate"; break; case ePdfError_CannotEncryptedForUpdate: pszMsg = "ePdfError_CannotEncryptedForUpdate"; break; case ePdfError_Unknown: pszMsg = "ePdfError_Unknown"; break; default: break; } return pszMsg; } const char* PdfError::ErrorMessage( EPdfError eCode ) { const char* pszMsg = NULL; switch( eCode ) { case ePdfError_ErrOk: pszMsg = "No error during execution."; break; case ePdfError_TestFailed: pszMsg = "An error curred in an automatic test included in PoDoFo."; break; case ePdfError_InvalidHandle: pszMsg = "A NULL handle was passed, but initialized data was expected."; break; case ePdfError_FileNotFound: pszMsg = "The specified file was not found."; break; case ePdfError_InvalidDeviceOperation: pszMsg = "Tried to do something unsupported to an I/O device like seek a non-seekable input device"; break; case ePdfError_UnexpectedEOF: pszMsg = "End of file was reached unxexpectedly."; break; case ePdfError_OutOfMemory: pszMsg = "PoDoFo is out of memory."; break; case ePdfError_ValueOutOfRange: pszMsg = "The passed value is out of range."; break; case ePdfError_InternalLogic: pszMsg = "An internal error occurred."; break; case ePdfError_InvalidEnumValue: pszMsg = "An invalid enum value was specified."; break; case ePdfError_PageNotFound: pszMsg = "The requested page could not be found in the PDF."; break; case ePdfError_NoPdfFile: pszMsg = "This is not a PDF file."; break; case ePdfError_NoXRef: pszMsg = "No XRef table was found in the PDF file."; break; case ePdfError_NoTrailer: pszMsg = "No trailer was found in the PDF file."; break; case ePdfError_NoNumber: pszMsg = "A number was expected but not found."; break; case ePdfError_NoObject: pszMsg = "A object was expected but not found."; break; case ePdfError_NoEOFToken: pszMsg = "No EOF Marker was found in the PDF file."; break; case ePdfError_InvalidTrailerSize: case ePdfError_InvalidLinearization: case ePdfError_InvalidDataType: case ePdfError_InvalidXRef: case ePdfError_InvalidXRefStream: case ePdfError_InvalidXRefType: case ePdfError_InvalidPredictor: case ePdfError_InvalidStrokeStyle: case ePdfError_InvalidHexString: case ePdfError_InvalidStream: case ePdfError_InvalidStreamLength: case ePdfError_InvalidKey: case ePdfError_InvalidName: break; case ePdfError_InvalidEncryptionDict: pszMsg = "The encryption dictionary is invalid or misses a required key."; break; case ePdfError_InvalidPassword: pszMsg = "The password used to open the PDF file was invalid."; break; case ePdfError_InvalidFontFile: pszMsg = "The font file is invalid."; break; case ePdfError_InvalidContentStream: pszMsg = "The content stream is invalid due to mismatched context pairing or other problems."; break; case ePdfError_UnsupportedFilter: break; case ePdfError_UnsupportedFontFormat: pszMsg = "This font format is not supported by PoDoFO."; break; case ePdfError_DestinationAlreadyPresent: case ePdfError_ActionAlreadyPresent: pszMsg = "Outlines can have either destinations or actions."; break; case ePdfError_WrongDestinationType: pszMsg = "The requested field is not available for the given destination type"; break; case ePdfError_MissingEndStream: case ePdfError_Date: break; case ePdfError_Flate: pszMsg = "ZLib returned an error."; break; case ePdfError_FreeType: pszMsg = "FreeType returned an error."; break; case ePdfError_SignatureError: pszMsg = "The signature contains an error."; break; case ePdfError_MutexError: pszMsg = "Error during a mutex operation."; break; case ePdfError_UnsupportedImageFormat: pszMsg = "This image format is not supported by PoDoFO."; break; case ePdfError_CannotConvertColor: pszMsg = "This color format cannot be converted."; break; case ePdfError_ChangeOnImmutable: pszMsg = "Changing values on immutable objects is not allowed."; break; case ePdfError_NotImplemented: pszMsg = "This feature is currently not implemented."; break; case ePdfError_NotCompiled: pszMsg = "This feature was disabled during compile time."; break; case ePdfError_OutlineItemAlreadyPresent: pszMsg = "Given OutlineItem already present in destination tree."; break; case ePdfError_NotLoadedForUpdate: pszMsg = "The document had not been loaded for update."; break; case ePdfError_CannotEncryptedForUpdate: pszMsg = "Cannot load encrypted documents for update."; break; case ePdfError_Unknown: pszMsg = "Error code unknown."; break; default: break; } return pszMsg; } void PdfError::LogMessage( ELogSeverity eLogSeverity, const char* pszMsg, ... ) { if(!PdfError::LoggingEnabled()) return; #ifdef DEBUG const ELogSeverity eMinSeverity = eLogSeverity_Debug; #else const ELogSeverity eMinSeverity = eLogSeverity_Information; #endif // DEBUG // OC 17.08.2010 BugFix: Higher level is lower value // if( eLogSeverity < eMinSeverity ) if( eLogSeverity > eMinSeverity ) return; va_list args; va_start( args, pszMsg ); LogMessageInternal( eLogSeverity, pszMsg, args ); va_end( args ); } void PdfError::LogErrorMessage( ELogSeverity eLogSeverity, const char* pszMsg, ... ) { va_list args; va_start( args, pszMsg ); LogMessageInternal( eLogSeverity, pszMsg, args ); va_end( args ); } void PdfError::LogMessageInternal( ELogSeverity eLogSeverity, const char* pszMsg, va_list & args ) { const char* pszPrefix = NULL; switch( eLogSeverity ) { case eLogSeverity_Error: break; case eLogSeverity_Critical: pszPrefix = "CRITICAL: "; break; case eLogSeverity_Warning: pszPrefix = "WARNING: "; break; case eLogSeverity_Information: break; case eLogSeverity_Debug: pszPrefix = "DEBUG: "; break; case eLogSeverity_None: case eLogSeverity_Unknown: default: break; } // OC 17.08.2010 New to optionally replace stderr output by a callback: if ( m_fLogMessageCallback != NULL ) { m_fLogMessageCallback->LogMessage(eLogSeverity, pszPrefix, pszMsg, args); return; } if( pszPrefix ) fprintf( stderr, "%s", pszPrefix ); vfprintf( stderr, pszMsg, args ); } void PdfError::LogMessage( ELogSeverity eLogSeverity, const wchar_t* pszMsg, ... ) { if(!PdfError::LoggingEnabled()) return; #ifdef DEBUG const ELogSeverity eMinSeverity = eLogSeverity_Debug; #else const ELogSeverity eMinSeverity = eLogSeverity_Information; #endif // DEBUG // OC 17.08.2010 BugFix: Higher level is lower value // if( eLogSeverity < eMinSeverity ) if( eLogSeverity > eMinSeverity ) return; va_list args; va_start( args, pszMsg ); LogMessageInternal( eLogSeverity, pszMsg, args ); va_end( args ); } void PdfError::EnableLogging( bool bEnable ) { PdfError::s_LogEnabled = bEnable; } bool PdfError::LoggingEnabled() { return PdfError::s_LogEnabled; } void PdfError::LogErrorMessage( ELogSeverity eLogSeverity, const wchar_t* pszMsg, ... ) { va_list args; va_start( args, pszMsg ); LogMessageInternal( eLogSeverity, pszMsg, args ); va_end( args ); } void PdfError::LogMessageInternal( ELogSeverity eLogSeverity, const wchar_t* pszMsg, va_list & args ) { const wchar_t* pszPrefix = NULL; switch( eLogSeverity ) { case eLogSeverity_Error: break; case eLogSeverity_Critical: pszPrefix = L"CRITICAL: "; break; case eLogSeverity_Warning: pszPrefix = L"WARNING: "; break; case eLogSeverity_Information: break; case eLogSeverity_Debug: pszPrefix = L"DEBUG: "; break; case eLogSeverity_None: case eLogSeverity_Unknown: default: break; } // OC 17.08.2010 New to optionally replace stderr output by a callback: if ( m_fLogMessageCallback != NULL ) { m_fLogMessageCallback->LogMessage(eLogSeverity, pszPrefix, pszMsg, args); return; } if( pszPrefix ) fwprintf( stderr, pszPrefix ); vfwprintf( stderr, pszMsg, args ); } void PdfError::DebugMessage( const char* pszMsg, ... ) { if ( !PdfError::DebugEnabled() ) return; const char* pszPrefix = "DEBUG: "; va_list args; va_start( args, pszMsg ); // OC 17.08.2010 New to optionally replace stderr output by a callback: if ( m_fLogMessageCallback != NULL ) { m_fLogMessageCallback->LogMessage(eLogSeverity_Debug, pszPrefix, pszMsg, args); } else { if( pszPrefix ) fprintf( stderr, "%s", pszPrefix ); vfprintf( stderr, pszMsg, args ); } // must call va_end after calling va_start (which allocates memory on some platforms) va_end( args ); } void PdfError::EnableDebug( bool bEnable ) { PdfError::s_DgbEnabled = bEnable; } bool PdfError::DebugEnabled() { return PdfError::s_DgbEnabled; } }; podofo-0.9.5/src/base/PdfObjectStreamParserObject.cpp0000664000175000017500000001405713013650710022413 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfObjectStreamParserObject.h" #include "PdfDictionary.h" #include "PdfEncrypt.h" #include "PdfInputDevice.h" #include "PdfParserObject.h" #include "PdfStream.h" #include "PdfVecObjects.h" #include #if defined(PODOFO_VERBOSE_DEBUG) #include #endif namespace PoDoFo { PdfObjectStreamParserObject::PdfObjectStreamParserObject(PdfParserObject* pParser, PdfVecObjects* pVecObjects, const PdfRefCountedBuffer & rBuffer, PdfEncrypt* pEncrypt ) : m_pParser( pParser ), m_vecObjects( pVecObjects ), m_buffer( rBuffer ), m_pEncrypt( pEncrypt ) { } PdfObjectStreamParserObject::~PdfObjectStreamParserObject() { } void PdfObjectStreamParserObject::Parse(ObjectIdList const & list) { pdf_int64 lNum = m_pParser->GetDictionary().GetKeyAsLong( "N", 0 ); pdf_int64 lFirst = m_pParser->GetDictionary().GetKeyAsLong( "First", 0 ); char* pBuffer; pdf_long lBufferLen; m_pParser->GetStream()->GetFilteredCopy( &pBuffer, &lBufferLen ); try { this->ReadObjectsFromStream( pBuffer, lBufferLen, lNum, lFirst, list ); podofo_free( pBuffer ); // the object stream is not needed anymore in the final PDF delete m_vecObjects->RemoveObject( m_pParser->Reference() ); m_pParser = NULL; } catch( PdfError & rError ) { podofo_free( pBuffer ); throw rError; } } void PdfObjectStreamParserObject::ReadObjectsFromStream( char* pBuffer, pdf_long lBufferLen, pdf_int64 lNum, pdf_int64 lFirst, ObjectIdList const & list) { PdfRefCountedInputDevice device( pBuffer, lBufferLen ); PdfTokenizer tokenizer( device, m_buffer ); PdfVariant var; int i = 0; while( static_cast(i) < lNum ) { const pdf_int64 lObj = tokenizer.GetNextNumber(); const pdf_int64 lOff = tokenizer.GetNextNumber(); const std::streamoff pos = device.Device()->Tell(); // move to the position of the object in the stream device.Device()->Seek( static_cast(lFirst + lOff) ); // use a second tokenizer here so that anything that gets dequeued isn't left in the tokenizer that reads the offsets and lengths PdfTokenizer variantTokenizer( device, m_buffer ); if( m_pEncrypt && (m_pEncrypt->GetEncryptAlgorithm() == PdfEncrypt::ePdfEncryptAlgorithm_AESV2 #ifndef OPENSSL_NO_RC4 || m_pEncrypt->GetEncryptAlgorithm() == PdfEncrypt::ePdfEncryptAlgorithm_RC4V2 #endif // OPENSSL_NO_RC4 ) ) variantTokenizer.GetNextVariant( var, 0 ); // Stream is already decrypted else variantTokenizer.GetNextVariant( var, m_pEncrypt ); bool should_read = std::find(list.begin(), list.end(), lObj) != list.end(); #if defined(PODOFO_VERBOSE_DEBUG) std::cerr << "ReadObjectsFromStream STREAM=" << m_pParser->Reference().ToString() << ", OBJ=" << lObj << ", " << (should_read ? "read" : "skipped") << std::endl; #endif if (should_read) { if(m_vecObjects->GetObject(PdfReference( static_cast(lObj), PODOFO_LL_LITERAL(0) ))) { PdfError::LogMessage( eLogSeverity_Warning, "Object: %li 0 R will be deleted and loaded again.\n", lObj ); delete m_vecObjects->RemoveObject(PdfReference( static_cast(lObj), PODOFO_LL_LITERAL(0) ),false); } m_vecObjects->insert_sorted( new PdfObject( PdfReference( static_cast(lObj), PODOFO_LL_LITERAL(0) ), var ) ); } // move back to the position inside of the table of contents device.Device()->Clear(); device.Device()->Seek( pos ); ++i; } } }; podofo-0.9.5/src/base/PdfContentsTokenizer.h0000664000175000017500000001432312344436402020664 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_CONTENTS_TOKENIZER_H_ #define _PDF_CONTENTS_TOKENIZER_H_ #include "PdfDefines.h" #include "PdfTokenizer.h" #include "PdfVariant.h" #include namespace PoDoFo { class PdfDocument; class PdfCanvas; class PdfObject; /** An enum describing the type of a read token */ enum EPdfContentsType { ePdfContentsType_Keyword, /**< The token is a PDF keyword. */ ePdfContentsType_Variant, /**< The token is a PDF variant. A variant is usually a parameter to a keyword */ ePdfContentsType_ImageData /**< The "token" is raw inline image data found between ID and EI tags (see PDF ref section 4.8.6) */ }; /** This class is a parser for content streams in PDF documents. * * The parsed content stream can be used and modified in various ways. * * This class is currently work in progress and subject to change! */ class PODOFO_API PdfContentsTokenizer : public PdfTokenizer { public: /** Construct a PdfContentsTokenizer from an existing buffer. * Usually a stream from a PdfPage. * * \param pBuffer pointer to a buffer * \param lLen length of the buffer */ PdfContentsTokenizer( const char* pBuffer, long lLen ) : PoDoFo::PdfTokenizer( pBuffer, lLen ), m_readingInlineImgData(false) { } /** Construct a PdfContentsTokenizer from a PdfCanvas * (i.e. PdfPage or a PdfXObject). * * This is more convinient as you do not have * to care about buffers yourself. * * \param pCanvas an object that hold a PDF contents stream */ PdfContentsTokenizer( PdfCanvas* pCanvas ); virtual ~PdfContentsTokenizer() { } /** Read the next keyword or variant, returning true and setting reType if something was read. * Either rpszKeyword or rVariant, but never both, have defined and usable values on * true return, with which being controlled by the value of eType. * * If EOF is encountered, returns false and leaves eType, pszKeyword and * rVariant undefined. * * As a special case, reType may be set to ePdfContentsType_ImageData. In * this case rpszzKeyword is undefined, and rVariant contains a PdfData * variant containing the byte sequence between the ID and BI keywords * sans the one byte of leading- and trailing- white space. No filter * decoding is performed. * * \param[out] reType will be set to either keyword or variant if true is returned. Undefined * if false is returned. * * \param[out] rpszKeyword if pType is set to ePdfContentsType_Keyword this will point to the keyword, * otherwise the value is undefined. If set, the value points to memory owned by the * PdfContentsTokenizer and must not be freed. The value is invalidated when ReadNext * is next called or when the PdfContentsTokenizer is destroyed. * * \param[out] rVariant if pType is set to ePdfContentsType_Variant or ePdfContentsType_ImageData * this will be set to the read variant, otherwise the value is undefined. * */ bool ReadNext( EPdfContentsType& reType, const char*& rpszKeyword, PoDoFo::PdfVariant & rVariant ); bool GetNextToken( const char *& pszToken, EPdfTokenType* peType = NULL); private: /** Set another objects stream as the current stream for parsing * * \param pObject use the stream of this object for parsing */ void SetCurrentContentsStream( PdfObject* pObject ); bool ReadInlineImgData(EPdfContentsType& reType, const char*& rpszKeyword, PoDoFo::PdfVariant & rVariant); private: std::list m_lstContents; ///< A list containing pointers to all contents objects bool m_readingInlineImgData; ///< A state of reading inline image data }; }; #endif // _PDF_CONTENTS_TOKENIZER_H_ podofo-0.9.5/src/base/PdfVersion.h0000664000175000017500000000036411460071654016623 0ustar dominikdominik#ifndef PODOFO_PDFVERSION_H #define PODOFO_PDFVERSION_H #define PODOFO_MAJOR PODOFO_VERSION_MAJOR #define PODOFO_MINOR PODOFO_VERSION_MINOR #define PODOFO_REVISION PODOFO_VERSION_PATCH #define PODOFO_VERSION_STRING PODOFO_VERSION_STR #endif podofo-0.9.5/src/base/PdfDictionary.h0000664000175000017500000002621412571356626017316 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_DICTIONARY_H_ #define _PDF_DICTIONARY_H_ #include "PdfDefines.h" #include "PdfDataType.h" #include "PdfName.h" #include "PdfObject.h" /** * PODOFO_USE_UNORDERED_MAP * * If you set this define, PoDoFo * will use std::tr1::unordered_map instead * of std::map for PdfDictionary. * * Some benchmarking tests using callgrind have shown * that unordered_map is a little faster for writing and AddKey * but of course slower for GetKey and HasKey. As PdfDictionaries * are usually very small the difference for GetKey and HasKey is * not very large and should therefore be rarely noticeable. * * By default this define is not set and std::map will be used. */ #ifdef PODOFO_USE_UNORDERED_MAP #include #endif // PODOFO_USE_ORDERED_MAP namespace PoDoFo { #ifdef PODOFO_USE_UNORDERED_MAP class PdfNameHash : public std::unary_function { public: size_t operator()( const PdfName& v ) const { std::tr1::hash hasher; return hasher( v.GetName() ); } }; typedef std::tr1::unordered_map TKeyMap; #else typedef std::map TKeyMap; #endif // PODOFO_USE_UNORDERED_MAP typedef TKeyMap::iterator TIKeyMap; typedef TKeyMap::const_iterator TCIKeyMap; class PdfOutputDevice; /** The PDF dictionary data type of PoDoFo (inherits from PdfDataType, * the base class for such representations) */ class PODOFO_API PdfDictionary : public PdfDataType { public: /** Create a new, empty dictionary */ PdfDictionary(); /** Deep copy a dictionary * \param rhs the PdfDictionary to copy */ PdfDictionary( const PdfDictionary & rhs ); /** Destructor */ virtual ~PdfDictionary(); /** Asignment operator. * Asign another PdfDictionary to this dictionary. This is a deep copy; * all elements of the source dictionary are duplicated. * * \param rhs the PdfDictionary to copy. * * \return this PdfDictionary * * This will set the dirty flag of this object. * \see IsDirty */ const PdfDictionary & operator=( const PdfDictionary & rhs ); /** * Comparison operator. If this dictionary contains all the same keys * as the other dictionary, and for each key the values compare equal, * the dictionaries are considered equal. */ bool operator==( const PdfDictionary& rhs ) const; /** * \see operator== */ inline bool operator!=( const PdfDictionary& rhs ) const; /** Removes all keys from the dictionary */ void Clear(); /** Add a key to the dictionary. If an existing key of this name exists, its * value is replaced and the old value object will be deleted. The passed * object is copied. * * \param identifier the key is identified by this name in the dictionary * \param rObject a variant object containing the data. The object is copied. * * This will set the dirty flag of this object. * \see IsDirty */ void AddKey( const PdfName & identifier, const PdfObject & rObject ); /** Add a key to the dictionary. If an existing key of this name exists, * its value is replaced and the old value object will be deleted. The * passed object is copied. * * This is an overloaded member function. * * \param identifier the key is identified by this name in the dictionary * \param rObject a variant object containing the data. The object is copied. * * This will set the dirty flag of this object. * \see IsDirty */ void AddKey( const PdfName & identifier, const PdfObject* pObject ); /** Get the keys value out of the dictionary. * * The returned value is a pointer to the internal object in the dictionary * so it MUST not be deleted. * * \param key look for the key names pszKey in the dictionary * * \returns pointer to the found value or 0 if the key was not found. */ const PdfObject* GetKey( const PdfName & key ) const; /** Get the keys value out of the dictionary. This is an overloaded member * function. * * The returned value is a pointer to the internal object in the dictionary. * It may be modified but is still owned by the dictionary so it MUST not * be deleted. * * \param key look for the key named key in the dictionary * * \returns the found value or 0 if the key was not found. */ PdfObject* GetKey( const PdfName & key ); pdf_int64 GetKeyAsLong( const PdfName & key, pdf_int64 lDefault = 0 ) const; double GetKeyAsReal( const PdfName & key, double dDefault = 0.0 ) const; bool GetKeyAsBool( const PdfName & key, bool bDefault = false ) const; PdfName GetKeyAsName( const PdfName & key ) const; /** Allows to check if a dictionary contains a certain key. \param key * look for the key named key.Name() in the dictionary * * \returns true if the key is part of the dictionary, otherwise false. */ bool HasKey( const PdfName & key ) const; /** Remove a key from this dictionary. If the key does not exists, this * function does nothing. * * \param identifier the name of the key to delete * * \returns true if the key was found in the object and was removed if * there was is no key with this name, false is returned. * * This will set the dirty flag of this object. * \see IsDirty */ bool RemoveKey( const PdfName & identifier ); /** Write the complete dictionary to a file. * * \param pDevice write the object to this device * \param eWriteMode additional options for writing this object * \param pEncrypt an encryption object which is used to encrypt this object * or NULL to not encrypt this object */ inline void Write( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, const PdfEncrypt* pEncrypt = NULL ) const; /** Write the complete dictionary to a file. * * \param pDevice write the object to this device * \param eWriteMode additional options for writing this object * \param pEncrypt an encryption object which is used to encrypt this object * or NULL to not encrypt this object * \param keyStop if not KeyNull and a key == keyStop is found * writing will stop right before this key! */ void Write( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, const PdfEncrypt* pEncrypt, const PdfName & keyStop = PdfName::KeyNull ) const; /** Get access to the internal map of keys. * * \returns all keys of this dictionary */ inline const TKeyMap & GetKeys() const; /** Get access to the internal map of keys. \returns all keys of this * dictionary */ inline TKeyMap & GetKeys(); /** The dirty flag is set if this variant * has been modified after construction. * * Usually the dirty flag is also set * if you call any non-const member function * as we cannot determine if you actually changed * something or not. * * \returns true if the value is dirty and has been * modified since construction */ virtual bool IsDirty() const; /** Sets the dirty flag of this PdfVariant * * \param bDirty true if this PdfVariant has been * modified from the outside * * \see IsDirty */ virtual void SetDirty( bool bDirty ); private: TKeyMap m_mapKeys; bool m_bDirty; ///< Indicates if this object was modified after construction }; typedef std::vector TVecDictionaries; typedef TVecDictionaries::iterator TIVecDictionaries; typedef TVecDictionaries::const_iterator TCIVecDictionaries; // ----------------------------------------------------- // // ----------------------------------------------------- const TKeyMap & PdfDictionary::GetKeys() const { return m_mapKeys; } // ----------------------------------------------------- // // ----------------------------------------------------- TKeyMap & PdfDictionary::GetKeys() { return m_mapKeys; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfDictionary::Write( PdfOutputDevice* pDevice, EPdfWriteMode eWriteMode, const PdfEncrypt* pEncrypt ) const { this->Write( pDevice, eWriteMode, pEncrypt, PdfName::KeyNull ); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfDictionary::operator!=( const PdfDictionary& rhs ) const { return !(*this == rhs); } }; #endif // _PDF_DICTIONARY_H_ podofo-0.9.5/src/base/PdfRefCountedInputDevice.cpp0000664000175000017500000001130113013650710021710 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfRefCountedInputDevice.h" #include "PdfInputDevice.h" #include "PdfDefinesPrivate.h" namespace PoDoFo { PdfRefCountedInputDevice::PdfRefCountedInputDevice() : m_pDevice( NULL ) { } PdfRefCountedInputDevice::PdfRefCountedInputDevice( const char* pszFilename, const char* ) : m_pDevice( NULL ) { m_pDevice = new TRefCountedInputDevice(); m_pDevice->m_lRefCount = 1; try { m_pDevice->m_pDevice = new PdfInputDevice( pszFilename ); } catch( PdfError & rError ) { delete m_pDevice; throw rError; } } #ifdef _WIN32 PdfRefCountedInputDevice::PdfRefCountedInputDevice( const wchar_t* pszFilename, const char* ) : m_pDevice( NULL ) { m_pDevice = new TRefCountedInputDevice(); m_pDevice->m_lRefCount = 1; try { m_pDevice->m_pDevice = new PdfInputDevice( pszFilename ); } catch( PdfError & rError ) { delete m_pDevice; throw rError; } } #endif // _WIN32 PdfRefCountedInputDevice::PdfRefCountedInputDevice( const char* pBuffer, size_t lLen ) : m_pDevice( NULL ) { m_pDevice = new TRefCountedInputDevice(); m_pDevice->m_lRefCount = 1; try { m_pDevice->m_pDevice = new PdfInputDevice( pBuffer, lLen ); } catch( PdfError & rError ) { delete m_pDevice; throw rError; } } PdfRefCountedInputDevice::PdfRefCountedInputDevice( PdfInputDevice* pDevice ) : m_pDevice( NULL ) { m_pDevice = new TRefCountedInputDevice(); m_pDevice->m_lRefCount = 1; m_pDevice->m_pDevice = pDevice; } PdfRefCountedInputDevice::PdfRefCountedInputDevice( const PdfRefCountedInputDevice & rhs ) : m_pDevice( NULL ) { this->operator=( rhs ); } PdfRefCountedInputDevice::~PdfRefCountedInputDevice() { Detach(); } void PdfRefCountedInputDevice::Detach() { if( m_pDevice && !--m_pDevice->m_lRefCount ) { // last owner of the file! m_pDevice->m_pDevice->Close(); delete m_pDevice->m_pDevice; delete m_pDevice; m_pDevice = NULL; } } const PdfRefCountedInputDevice & PdfRefCountedInputDevice::operator=( const PdfRefCountedInputDevice & rhs ) { Detach(); m_pDevice = rhs.m_pDevice; if( m_pDevice ) m_pDevice->m_lRefCount++; return *this; } }; podofo-0.9.5/src/base/PdfMemoryManagement.h0000664000175000017500000000714613013650710020440 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2009 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_MEMORY_MANAGEMENT_H_ #define _PDF_MEMORY_MANAGEMENT_H_ // PdfMemoryManagement.h should not include PdfDefines.h, since it is included by it. // It should avoid depending on anything defined in PdfDefines.h . #include "podofoapi.h" #include namespace PoDoFo { /** * Wrapper around malloc of the c-library used by PoDoFo. * * Is used to allocate buffers inside of PoDoFo. */ PODOFO_API void* podofo_malloc( size_t size ); /** * Wrapper around calloc of the c-library used by PoDoFo. * * Is used to allocate buffers inside of PoDoFo, guarding against count*size size_t overflow. */ PODOFO_API void* podofo_calloc( size_t count, size_t size ); /** * Wrapper around realloc of the c-library used by PoDoFo. */ PODOFO_API void* podofo_realloc( void* buffer, size_t size ); /** * Wrapper around free of the c-library used by PoDoFo. * * Use this to free memory allocated inside of PoDoFo * with podofo_malloc. */ PODOFO_API void podofo_free( void* buffer ); /** * Check during runtime if the current architecture is big- or little-endian. * \returns true if the architecture is little-endian */ PODOFO_API bool podofo_is_little_endian(); }; #endif // _PDF_MEMORY_MANAGEMENT_H_ podofo-0.9.5/src/podofo-base.h0000664000175000017500000000760113013116642016022 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PODOFO_BASE_H_ #define _PODOFO_BASE_H_ // Include files from PoDoFo-base #include "base/PdfVersion.h" #include "base/PdfDefines.h" #include "base/Pdf3rdPtyForwardDecl.h" #include "base/PdfArray.h" #include "base/PdfCanvas.h" #include "base/PdfColor.h" #include "base/PdfContentsTokenizer.h" #include "base/PdfData.h" #include "base/PdfDataType.h" #include "base/PdfDate.h" #include "base/PdfDictionary.h" #include "base/PdfEncodingFactory.h" #include "base/PdfEncoding.h" #include "base/PdfEncrypt.h" #include "base/PdfError.h" #include "base/PdfExtension.h" #include "base/PdfFileStream.h" #include "base/PdfFilter.h" #include "base/PdfImmediateWriter.h" #include "base/PdfInputDevice.h" #include "base/PdfInputStream.h" #include "base/PdfLocale.h" #include "base/PdfMemoryManagement.h" #include "base/PdfMemStream.h" #include "base/PdfName.h" #include "base/PdfObject.h" #include "base/PdfObjectStreamParserObject.h" #include "base/PdfOutputDevice.h" #include "base/PdfOutputStream.h" #include "base/PdfParser.h" #include "base/PdfParserObject.h" #include "base/PdfRect.h" #include "base/PdfRefCountedBuffer.h" #include "base/PdfRefCountedInputDevice.h" #include "base/PdfReference.h" #include "base/PdfStream.h" #include "base/PdfString.h" #include "base/PdfTokenizer.h" #include "base/PdfVariant.h" #include "base/PdfVecObjects.h" #include "base/PdfWriter.h" #include "base/PdfXRef.h" #include "base/PdfXRefStream.h" #include "base/PdfXRefStreamParserObject.h" #endif // _PODOFO_BASE_H_ podofo-0.9.5/src/podofo.h0000664000175000017500000001101313013116642015102 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PODOFO_H_ #define _PODOFO_H_ /** * This file can be used in client applications to include * all files required by PoDoFo at once. * * Some symbols may be declared in the PoDoFo::NonPublic namespace. * Client applications must never rely on or use these symbols directly. * On supporting platforms they will be excluded from the DLL interface, * and they are not guaranteed to continue to exist. */ #include "podofo-base.h" // Include files from PoDoFo-doc #include "doc/PdfAcroForm.h" #include "doc/PdfAction.h" #include "doc/PdfAnnotation.h" #include "doc/PdfCMapEncoding.h" #include "doc/PdfContents.h" #include "doc/PdfDestination.h" #include "doc/PdfDifferenceEncoding.h" #include "doc/PdfDocument.h" #include "doc/PdfElement.h" #include "doc/PdfEncodingObjectFactory.h" #include "doc/PdfExtGState.h" #include "doc/PdfField.h" #include "doc/PdfFileSpec.h" #include "doc/PdfFontCache.h" #include "doc/PdfFontCID.h" #include "doc/PdfFontConfigWrapper.h" #include "doc/PdfFontFactoryBase14Data.h" #include "doc/PdfFontFactory.h" #include "doc/PdfFont.h" #include "doc/PdfFontMetricsBase14.h" #include "doc/PdfFontMetricsFreetype.h" #include "doc/PdfFontMetrics.h" #include "doc/PdfFontMetricsObject.h" #include "doc/PdfFontSimple.h" #include "doc/PdfFontTrueType.h" #include "doc/PdfFontTTFSubset.h" #include "doc/PdfFontType1Base14.h" #include "doc/PdfFontType1.h" #include "doc/PdfFontType3.h" #include "doc/PdfFunction.h" #include "doc/PdfHintStream.h" #include "doc/PdfIdentityEncoding.h" #include "doc/PdfImage.h" #include "doc/PdfInfo.h" #include "doc/PdfMemDocument.h" #include "doc/PdfNamesTree.h" #include "doc/PdfOutlines.h" #include "doc/PdfPage.h" #include "doc/PdfPagesTreeCache.h" #include "doc/PdfPagesTree.h" #include "doc/PdfPainter.h" #include "doc/PdfPainterMM.h" #include "doc/PdfShadingPattern.h" #include "doc/PdfSignatureField.h" #include "doc/PdfSignOutputDevice.h" #include "doc/PdfStreamedDocument.h" #include "doc/PdfTable.h" #include "doc/PdfTilingPattern.h" #include "doc/PdfXObject.h" #ifdef _PODOFO_NO_NAMESPACE_ using namespace PoDoFo; #endif /* _PODOFO_NO_NAMESPACE_ */ #endif /* _PODOFO_H_ */ podofo-0.9.5/src/doc/0000775000175000017500000000000013044451160014215 5ustar dominikdominikpodofo-0.9.5/src/doc/PdfTable.h0000664000175000017500000007121412344436402016060 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_TABLE_H_ #define _PDF_TABLE_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfColor.h" #include "podofo/base/PdfRect.h" #include "podofo/base/PdfString.h" #include namespace PoDoFo { class PdfCanvas; class PdfFont; class PdfImage; class PdfPainter; class PdfPage; /** * This is an abstract interface of a model that can provide * data and formatting informations to a PdfTable. * * You can implement your own PdfTableModel to supply data * to a PdfTable. * PdfSimpleTableModel is an example of a simple model. * * * \see PdfTable * \see PdfSimpleTableModel */ class PODOFO_DOC_API PdfTableModel { public: virtual ~PdfTableModel() {}; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns the contents string of this table cell */ virtual PdfString GetText ( int col, int row ) const = 0; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns the horizontal alignment of the contents in the cell */ virtual EPdfAlignment GetAlignment ( int col, int row ) const = 0; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns the vertical alignment of the contents in the cell */ virtual EPdfVerticalAlignment GetVerticalAlignment ( int col, int row ) const = 0; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns the font of this table cell or NULL to use the default font */ virtual PdfFont* GetFont ( int col, int row ) const = 0; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns true if this cell has a background color */ virtual bool HasBackgroundColor( int col, int row ) const = 0; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns the background color of the specified cell */ virtual PdfColor GetBackgroundColor( int col, int row ) const = 0; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns the foreground (text) color of the specified cell */ virtual PdfColor GetForegroundColor( int col, int row ) const = 0; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns true if the specified cell should use wordwrapping */ virtual bool HasWordWrap( int col, int row ) const = 0; /** * \returns true if the table should have * a border around all cells. * \returns false if no cell border should be visible * * Cell borders are always drawn using the current PdfPainter * settings. */ virtual bool HasBorders() const = 0; /** * \returns the stroke witdth of the border line */ virtual double GetBorderWidth() const = 0; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns the border color */ virtual PdfColor GetBorderColor( int col, int row ) const = 0; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns true if the table cell contains an image */ virtual bool HasImage( int col, int row ) const = 0; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns the image for the specified cell or NULL if the cell has no image */ virtual PdfImage* GetImage( int col, int row ) const = 0; }; /** * An implementation of a simple PdfTableModel. * */ class PODOFO_DOC_API PdfSimpleTableModel : public PdfTableModel { public: /** Creates an empty PdfSimpleTableModel * that does not contain any data. * * Using this model will result in drawing an empty table! */ PdfSimpleTableModel(); /** Creates an empty PdfSimpleTableModel * that does not contain any data. * * Using this model will result in drawing an empty table! * * \param nCols number of columns of the data in this table model (must match the PdfTable object) * \param nRows number of rows of the data in this table model (must match the PdfTable object) * * You can set the tables data using SetText. * \see SetText */ PdfSimpleTableModel( int nCols, int nRows ); virtual ~PdfSimpleTableModel(); /** Set the font that will be used to draw all table contents. * * \param pFont the font for the table contents */ inline void SetFont( PdfFont* pFont ); /** Set the horizontal alignment of the contents in all table cells * * \param eAlignment the horizontal alignment of text in a table cell */ inline void SetAlignment( EPdfAlignment eAlignment ); /** Set the vertical alignment of the contents in all table cells * * \param eAlignment the vertiical alignment of text in a table cell */ inline void SetAlignment( EPdfVerticalAlignment eAlignment ); /** Set the background color of the table cells * * \param rColor the background color */ inline void SetBackgroundColor( const PdfColor & rColor ); /** Set the foreground color of the table cells * * \param rColor the foreground color */ inline void SetForegroundColor( const PdfColor & rColor ); /** Sets wether all cells have a background color or not * * \param bEnable if true all cells have a background color */ inline void SetBackgroundEnabled( bool bEnable ); /** Sets wether all cells have wordwrapping or not * * \param bEnable if true all cells have wordwrapping */ inline void SetWordWrapEnabled( bool bEnable ); /** Sets wether all cells have a border or not. * * \param bEnable if true a border will be drawn * using the current PdfPainter settings */ inline void SetBorderEnabled( bool bEnable ); /** Sets the stroke width of the border around * the table. * * \param dWidth the stroke width of the border */ inline void SetBorderWidth( double dWidth ); /** Sets the contents of a specific cell * * \param col the column of the table cell * \param row the row of the table cell * \param rsString the contents of this cell */ inline void SetText( int col, int row, const PdfString & rsString ); /** * \param col the column of the table cell * \param row the row of the table cell * * \returns the contents string of this table cell */ inline virtual PdfString GetText ( int col, int row ) const; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns the horizontal alignment of the contents in the cell */ inline virtual EPdfAlignment GetAlignment ( int col, int row ) const; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns the vertical alignment of the contents in the cell */ inline virtual EPdfVerticalAlignment GetVerticalAlignment ( int col, int row ) const; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns the font of this table cell or NULL to use the default font */ inline virtual PdfFont* GetFont ( int col, int row ) const; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns true if this cell has a background color */ inline virtual bool HasBackgroundColor( int col, int row ) const; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns the background color of the specified cell */ inline virtual PdfColor GetBackgroundColor( int col, int row ) const; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns the foreground (text) color of the specified cell */ inline virtual PdfColor GetForegroundColor( int col, int row ) const; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns true if the specified cell should use wordwrapping */ inline virtual bool HasWordWrap( int col, int row ) const; /** * \returns true if the table should have * a border around all cells. * \returns false if no cell border should be visible * * Cell borders are always drawn using the current PdfPainter * settings. */ inline virtual bool HasBorders() const; /** * \returns the stroke witdth of the border line */ inline virtual double GetBorderWidth() const; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns the border color */ inline virtual PdfColor GetBorderColor( int col, int row ) const; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns true if the table cell contains an image */ inline virtual bool HasImage( int col, int row ) const; /** * \param col the column of the table cell * \param row the row of the table cell * * \returns the image for the specified cell or NULL if the cell has no image */ inline virtual PdfImage* GetImage( int col, int row ) const; private: PdfFont* m_pFont; EPdfAlignment m_eAlignment; EPdfVerticalAlignment m_eVerticalAlignment; bool m_bWordWrap; PdfColor m_clForeground; bool m_bBackground; PdfColor m_clBackground; PdfString** m_ppData; int m_nCols; int m_nRows; bool m_bBorder; double m_dBorder; }; // ----------------------------------------------------- // // ----------------------------------------------------- void PdfSimpleTableModel::SetFont( PdfFont* pFont ) { m_pFont = pFont; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfSimpleTableModel::SetAlignment( EPdfAlignment eAlignment ) { m_eAlignment = eAlignment; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfSimpleTableModel::SetAlignment( EPdfVerticalAlignment eAlignment ) { m_eVerticalAlignment = eAlignment; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfSimpleTableModel::SetBackgroundEnabled( bool bEnable ) { m_bBackground = bEnable; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfSimpleTableModel::SetWordWrapEnabled( bool bEnable ) { m_bWordWrap = bEnable; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfSimpleTableModel::SetBorderEnabled( bool bEnable ) { m_bBorder = bEnable; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfSimpleTableModel::SetBorderWidth( double dWidth ) { m_dBorder = dWidth; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfSimpleTableModel::SetBackgroundColor( const PdfColor & rColor ) { m_clBackground = rColor; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfSimpleTableModel::SetForegroundColor( const PdfColor & rColor ) { m_clForeground = rColor; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfSimpleTableModel::SetText( int col, int row, const PdfString & rsString ) { if( !m_ppData || row >= m_nRows || col >= m_nCols ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } m_ppData[row][col] = rsString; } // ----------------------------------------------------- // // ----------------------------------------------------- PdfString PdfSimpleTableModel::GetText ( int col, int row ) const { if( !m_ppData || row >= m_nRows || col >= m_nCols ) return PdfString(); else return m_ppData[row][col].IsValid() ? m_ppData[row][col] : PdfString(""); } // ----------------------------------------------------- // // ----------------------------------------------------- EPdfAlignment PdfSimpleTableModel::GetAlignment ( int, int ) const { return m_eAlignment; } // ----------------------------------------------------- // // ----------------------------------------------------- EPdfVerticalAlignment PdfSimpleTableModel::GetVerticalAlignment ( int, int ) const { return m_eVerticalAlignment; } // ----------------------------------------------------- // // ----------------------------------------------------- PdfFont* PdfSimpleTableModel::GetFont ( int, int ) const { return m_pFont; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfSimpleTableModel::HasBackgroundColor ( int, int ) const { return m_bBackground; } // ----------------------------------------------------- // // ----------------------------------------------------- PdfColor PdfSimpleTableModel::GetBackgroundColor ( int, int ) const { return m_clBackground; } // ----------------------------------------------------- // // ----------------------------------------------------- PdfColor PdfSimpleTableModel::GetForegroundColor( int, int ) const { return m_clForeground; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfSimpleTableModel::HasWordWrap( int, int ) const { return m_bWordWrap; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfSimpleTableModel::HasBorders() const { return m_bBorder; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfSimpleTableModel::GetBorderWidth() const { return m_dBorder; } // ----------------------------------------------------- // // ----------------------------------------------------- PdfColor PdfSimpleTableModel::GetBorderColor( int, int ) const { // always return black return PdfColor( 0.0, 0.0, 0.0 ); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfSimpleTableModel::HasImage( int, int ) const { return false; } // ----------------------------------------------------- // // ----------------------------------------------------- PdfImage* PdfSimpleTableModel::GetImage( int, int ) const { return NULL; } /** * This is a high level class of a table which can be drawn to a PdfPainter. * * Use this class if you have to include data into your PDF as an table. * */ class PODOFO_DOC_API PdfTable { public: /** Callback to create a new page for PdfTable. * * \see SetAutoPageBreak * * \param rClipRect this is an output parameter which has * to be set to the clipping rectangle * of the new page. If the new page has * no clipping rectangle set it to * PdfRect( 0, 0, PdfPage::GetPageSize().GetWidth(), PdfPage::GetPageSize().GetHeight() ) * \param pCustom pointer to user defined data */ typedef PdfPage* (*CreatePageCallback)( PdfRect & rClipRect, void* pCustom ); /** Create a new PdfTable object. * * \param nCols number of columns in the table. * \param nRows number of rows in the table. */ PdfTable( int nCols, int nRows ); virtual ~PdfTable(); /** Draw the table with its current settings * on a PdfPainter. * * \param dX x coordinate of top left of the table * \param dY y coordinate of top left of the table * \param pPainter the painter to draw on. The painter has to have a page set currently. * \param rClipRect the clipping rectangle on the current page * \param pdLastX the last used X position by the table on the current page will be written to this value (usually bottom right) * \param pdLastY the last used Y positon by the table on the current page will be written to this value (usually bottom right) */ virtual void Draw( double dX, double dY, PdfPainter* pPainter, const PdfRect & rClipRect = PdfRect(), double* pdLastX = NULL, double* pdLastY = NULL ); /** Get the width of the table when drawn with the current settings at a certain position. * \param dX x coordinate of top left of the table * \param dY y coordinate of top left of the table * \param pPage the page on which the table will be drawn * * \returns the width of the table */ virtual double GetWidth( double dX, double dY, PdfCanvas* pPage ) const; /** Get the width of the table when drawn with the current settings at a certain position. * \param dX x coordinate of top left of the table * \param dY y coordinate of top left of the table * \param pPage the page on which the table will be drawn * * \returns the width of the table */ virtual double GetHeight( double dX, double dY, PdfCanvas* pPage ) const; /** Set the PdfTableModel that will supply all * contents and formatting informations to the table. * * \param pModel a PdfTableModel * * The model will not be owned by the PdfTable and has to be deleted * by the caller. * * \see GetModel */ inline void SetModel( PdfTableModel* pModel ); /** Get the current PdfTableModel * * \returns the currently set PdfTableModel or NULL if none was set */ inline const PdfTableModel* GetModel() const; /** Set the width of all columns. * * \param pdWidths a pointer to an array of GetCols() doubles * which are the individual width of a column. * * \see GetCols() */ void SetColumnWidths( double* pdWidths ); /** Set the height of all rows. * * \param pdHeights a pointer to an array of GetRows() doubles * which are the individual heights of a row. * * \see GetRows() */ void SetRowHeights( double* pdHeights ); /** Set all columns to have the same width. * * \param dWidth the width of every column * * By default the column with is calculated automatically * from either the table width or if no table width is set * from the width of the page on which the table is drawn. */ inline void SetColumnWidth( double dWidth ); /** Set all rows to have the same height. * * \param dHeight the height of every row * * By default the row height is calculated automatically * from either the table height or if no table height is set * from the height of the page on which the table is drawn. */ inline void SetRowHeight( double dHeight ); /** Set the width of the table. * * \param dWidth the width of the whole table. * * This width is used if no column width is set * to calculate the width of every column. * If this width is not set, the width of the page * on which this table is drawn is used. */ inline void SetTableWidth( double dWidth ); /** Set the height of the table. * * \param dHeight the height of the whole table. * * This height is used if no row height is set * to calculate the height of every row. * If this height is not set, the height of the page * on which this table is drawn is used. */ inline void SetTableHeight( double dHeight ); /** Automatically create a new page and continue * drawing the table on the new page, * if there is not enough space on the current page. * * The newly created page will be set as the current page * on the painter used to draw and will be created using the * same size as the old page. * * \param bPageBreak if true automatically create new pages * if required. * \param callback a callback function that is called to create * a new page. Please note: PdfTable cannot create new pages on its * own. You always have to implement a callback which does the new page * creation for the PdfTable. * \param pCustomData custom data that is passed to the callback * * By default this feature is turned off and contents are clipped * that do not fit on the current page. * * \see GetAutoPageBreak */ inline void SetAutoPageBreak( bool bPageBreak, CreatePageCallback callback, void* pCustomData = NULL); /** * \returns true if a new page is created automatically if more * space is required to draw the table. * * \see SetAutoPageBreak */ inline bool GetAutoPageBreak() const; /** * \returns the number of columns in the table. */ inline int GetCols() const; /** * \returns the number of rows in the table. */ inline int GetRows() const; protected: /** Internal functions that calculates the total table size * for a table with the current settings when drawn on a certain page. * * \param dX the X coordinate of top left at which is drawn * \param dY the Y coordinate of top left at which is drawn * \param pCanvas the canvas object (usually a page) on which the table will be drawn. * \param pdWidths pointer to an array with GetCols() doubles * where the width for each column will be stored * \param pdHeights pointer to an array with GetRows() doublesd * where the height for each row will be stored * * \param pdWidth pointer to a double where the total width of the table will be stored * \param pdHeight pointer to a double where the total height of the table will be stored */ void CalculateTableSize( const double dX, const double dY, const PdfCanvas* pCanvas, double* pdWidths, double* pdHeights, double* pdWidth, double* pdHeight ) const; /** Draw one row of horizontal cell borders using the correct color * for each cell. * * @param nRow the current row * @param dX left x coordinate * @param dY y coordinate * @param pPainter use this painter object * @param pdColWidths an array containing all colomun widths */ void DrawHorizontalBorders( int nRow, double dX, double dY, PdfPainter* pPainter, double* pdColWidths ); /** Checks if there is enough space on the current page * for one row! If necessary a new page is created. * * If GetAutoPageBreak is false, this method does nothing. * * \param pdY top of the table * \param pdCurY pointer to the current y position on the page. * Might be reset to a new y position. * \param dRowHeight height of the next row. * \param pPainter painter used for drawing * * \returns true if a new page was created, otherwise false */ bool CheckForNewPage( double* pdY, double* pdCurY, double dRowHeight, PdfPainter* pPainter ); protected: PdfTableModel* m_pModel; int m_nCols; int m_nRows; double m_dColWidth; double m_dRowHeight; double m_dTableWidth; double m_dTableHeight; double* m_pdColWidths; double* m_pdRowHeights; bool m_bAutoPageBreak; void* m_pCustomData; CreatePageCallback m_fpCallback; PdfRect m_curClipRect; }; // ----------------------------------------------------- // // ----------------------------------------------------- void PdfTable::SetModel( PdfTableModel* pModel ) { m_pModel = pModel; } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfTableModel* PdfTable::GetModel() const { return m_pModel; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfTable::SetColumnWidth( double dWidth ) { m_dColWidth = dWidth; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfTable::SetRowHeight( double dHeight ) { m_dRowHeight = dHeight; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfTable::SetTableWidth( double dWidth ) { m_dTableWidth = dWidth; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfTable::SetTableHeight( double dHeight ) { m_dTableHeight = dHeight; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfTable::SetAutoPageBreak( bool bPageBreak, CreatePageCallback callback, void* pCustomData ) { m_bAutoPageBreak = bPageBreak; m_fpCallback = callback; m_pCustomData = pCustomData; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfTable::GetAutoPageBreak() const { return m_bAutoPageBreak; } // ----------------------------------------------------- // // ----------------------------------------------------- int PdfTable::GetCols() const { return m_nCols; } // ----------------------------------------------------- // // ----------------------------------------------------- int PdfTable::GetRows() const { return m_nRows; } }; #endif // _PDF_TABLE_H_ podofo-0.9.5/src/doc/PdfTTFWriter.cpp0000664000175000017500000014531612715357362017234 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfTTFWriter.h" #include "PdfInputDevice.h" #include "PdfOutputDevice.h" #include "PdfRefCountedBuffer.h" #include "PdfString.h" #include "PdfDefinesPrivate.h" #include #include #include #include FT_FREETYPE_H #if defined(_MSC_VER) && _MSC_VER == 1500 // Ignore those warnings from MS-VS2008 #pragma warning(disable: 4018) #pragma warning(disable: 4244) #endif namespace { // MSVC++ does not provide the c99 exp2(..) and log2(..) in since they // are not required by C++ . Use the gcc ones if we're on gcc. #if defined(__GNUC__) inline double PdfLog2(double x) { return log2(x); } inline double PdfExp2(double x) { return exp2(x); } #else inline double PdfLog2(double x) { return log(x)/log(2.0f); } inline double PdfExp2(double x) { return pow(static_cast(2.0f),static_cast(x)); } #endif } namespace PoDoFo { extern bool podofo_is_little_endian(); #define READ_TTF_USHORT( value ) { pDevice->Read( reinterpret_cast(&(value)), sizeof(pdf_ttf_ushort) ); \ if( podofo_is_little_endian() ) \ this->SwapUShort( &(value) ); } #define READ_TTF_SHORT( value ) { pDevice->Read( reinterpret_cast(&(value)), sizeof(pdf_ttf_short) ); \ if( podofo_is_little_endian() ) \ this->SwapShort( &(value) ); } #define READ_TTF_ULONG( value ) { pDevice->Read( reinterpret_cast(&(value)), sizeof(pdf_ttf_ulong) ); \ if( podofo_is_little_endian() ) \ this->SwapULong( &(value) ); } #define WRITE_TTF_USHORT( value ) { { if( podofo_is_little_endian() ) \ this->SwapUShort( &(value) ); } \ pDevice->Write( reinterpret_cast(&(value)), sizeof(pdf_ttf_ushort) ); } #define WRITE_TTF_SHORT( value ) { { if( podofo_is_little_endian() ) \ this->SwapShort( &(value) ); } \ pDevice->Write( reinterpret_cast(&(value)), sizeof(pdf_ttf_short) ); } #define WRITE_TTF_ULONG( value ) { { if( podofo_is_little_endian() ) \ this->SwapULong( &(value) ); } \ pDevice->Write( reinterpret_cast(&(value)), sizeof(pdf_ttf_ulong) ); } namespace NonPublic { /** * The TTF format. * * - Big endian * * - Required tables: * cmap character to glyph mapping CHK * glyf glyph data CHK * head font header CHK * hhea horizontal header CHK * hmtx horizontal metrics CHK * loca index to location CHK * maxp maximum profile CHK * name naming table CHK * post PostScript information * OS/2 OS/2 and Windows specific metrics CHK * */ PdfTTFWriter::PdfTTFWriter() : m_lGlyphDataOffset( -1L ), m_lCMapOffset( -1L ), m_pRefBuffer( NULL ) { m_vecGlyphIndeces.push_back( static_cast('H') ); m_vecGlyphIndeces.push_back( static_cast('a') ); m_vecGlyphIndeces.push_back( static_cast('l') ); m_vecGlyphIndeces.push_back( static_cast('o') ); m_vecGlyphIndeces.push_back( static_cast(' ') ); m_vecGlyphIndeces.push_back( static_cast('W') ); m_vecGlyphIndeces.push_back( static_cast('r') ); m_vecGlyphIndeces.push_back( static_cast('d') ); m_vecGlyphIndeces.push_back( static_cast('!') ); // Composites do not work yet: m_vecGlyphIndeces.push_back( 0x00E4 ); // A dieresis std::sort( m_vecGlyphIndeces.begin(), m_vecGlyphIndeces.end() ); } PdfTTFWriter::PdfTTFWriter( const std::vector & rvecGlyphs ) : m_lGlyphDataOffset( -1L ), m_lCMapOffset( -1L ), m_pRefBuffer( NULL ) { m_vecGlyphIndeces = rvecGlyphs; std::sort( m_vecGlyphIndeces.begin(), m_vecGlyphIndeces.end() ); } PdfTTFWriter::~PdfTTFWriter() { delete m_pRefBuffer; } void PdfTTFWriter::Read( PdfInputDevice* pDevice ) { long lHead = -1; long lHHea = -1; long lLoca = -1; long lMaxp = -1; long lOs2 = -1; long lHmtx = -1; long lPost = -1; // Read the table directory this->ReadTableDirectory( pDevice ); // read the table of contents TVecTableDirectoryEntries vecTables; TTableDirectoryEntry entry; vecTables.reserve( m_tTableDirectory.numTables ); for( int i=0;iReadTableDirectoryEntry( pDevice, &entry ); if( entry.tag == this->CreateTag( 'l', 'o', 'c', 'a' ) ) lLoca = entry.offset; else if( entry.tag == this->CreateTag( 'g', 'l', 'y', 'f' ) ) m_lGlyphDataOffset = entry.offset; else if( entry.tag == this->CreateTag( 'm', 'a', 'x', 'p' ) ) lMaxp = entry.offset; else if( entry.tag == this->CreateTag( 'h', 'e', 'a', 'd' ) ) lHead = entry.offset; else if( entry.tag == this->CreateTag( 'c', 'm', 'a', 'p' ) ) m_lCMapOffset = entry.offset; else if( entry.tag == this->CreateTag( 'h', 'h', 'e', 'a' ) ) lHHea = entry.offset; else if( entry.tag == this->CreateTag( 'O', 'S', '/', '2' ) ) lOs2 = entry.offset; else if( entry.tag == this->CreateTag( 'h', 'm', 't', 'x' ) ) lHmtx = entry.offset; else if( entry.tag == this->CreateTag( 'p', 'o', 's', 't' ) ) lPost = entry.offset; vecTables.push_back( entry ); } // check if all required tables have been found if( lLoca == -1 ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidFontFile, "Table 'loca' not found." ); } else if( m_lGlyphDataOffset == -1 ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidFontFile, "Table 'glyf' not found." ); } else if( lMaxp == -1 ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidFontFile, "Table 'maxp' not found." ); } else if( lHead == -1 ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidFontFile, "Table 'head' not found." ); } else if( m_lCMapOffset == -1 ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidFontFile, "Table 'cmap' not found." ); } else if( lHHea == -1 ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidFontFile, "Table 'hhea' not found." ); } else if( lOs2 == -1 ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidFontFile, "Table 'OS/2' not found." ); } else if( lHmtx == -1 ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidFontFile, "Table 'hmtx' not found." ); } else if( lPost == -1 ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidFontFile, "Table 'post' not found." ); } // Read head table pDevice->Seek( lHead ); this->ReadHeadTable( pDevice ); // Read maxp table pDevice->Seek( lMaxp ); this->ReadMaxpTable( pDevice ); // Read loca table pDevice->Seek( lLoca ); this->ReadLocaTable( pDevice ); // Read hhea table pDevice->Seek( lHHea ); this->ReadHHeaTable( pDevice ); // Read cmap table pDevice->Seek( m_lCMapOffset ); this->ReadCmapTable( pDevice ); // Read glyf table pDevice->Seek( m_lGlyphDataOffset ); this->ReadGlyfTable( pDevice ); // Read OS/2 table pDevice->Seek( lOs2 ); this->ReadOs2Table( pDevice ); // Read hmtx table pDevice->Seek( lHmtx ); this->ReadHmtxTable( pDevice ); // Read post table pDevice->Seek( lPost ); this->ReadPostTable( pDevice ); // read the remaining data tables TIVecTableDirectoryEntries it = vecTables.begin(); while( it != vecTables.end() ) { // skip the 4 tables we have alread read if( (*it).tag != this->CreateTag( 'g', 'l', 'y', 'f' ) && (*it).tag != this->CreateTag( 'h', 'e', 'a', 'd' ) && (*it).tag != this->CreateTag( 'l', 'o', 'c', 'a' ) && (*it).tag != this->CreateTag( 'm', 'a', 'x', 'p' ) && (*it).tag != this->CreateTag( 'h', 'h', 'e', 'a' ) && (*it).tag != this->CreateTag( 'c', 'm', 'a', 'p' ) && (*it).tag != this->CreateTag( 'O', 'S', '/', '2' ) && (*it).tag != this->CreateTag( 'n', 'a', 'm', 'e' ) ) { TTable table; table.tag = (*it).tag; table.length = (*it).length; table.data = static_cast(podofo_calloc( (*it).length, sizeof(char) )); pDevice->Seek( (*it).offset ); pDevice->Read( table.data, (*it).length ); m_vecTableData.push_back( table ); } ++it; } } void PdfTTFWriter::ReadTableDirectory( PdfInputDevice* pDevice ) { pDevice->Read( reinterpret_cast(&m_tTableDirectory), sizeof(TTableDirectory) ); if( podofo_is_little_endian() ) { // Swap bytes SwapUShort( &m_tTableDirectory.numTables ); SwapUShort( &m_tTableDirectory.searchRange ); SwapUShort( &m_tTableDirectory.entrySelector ); SwapUShort( &m_tTableDirectory.rangeShift ); } } void PdfTTFWriter::WriteTableDirectory( PdfOutputDevice* pDevice ) { if( podofo_is_little_endian() ) { // Swap bytes SwapUShort( &m_tTableDirectory.numTables ); SwapUShort( &m_tTableDirectory.searchRange ); SwapUShort( &m_tTableDirectory.entrySelector ); SwapUShort( &m_tTableDirectory.rangeShift ); } pDevice->Write( reinterpret_cast(&m_tTableDirectory), sizeof(TTableDirectory) ); } void PdfTTFWriter::ReadTableDirectoryEntry( PdfInputDevice* pDevice, TTableDirectoryEntry* pEntry ) { pDevice->Read( reinterpret_cast(pEntry), sizeof(TTableDirectoryEntry) ); if( podofo_is_little_endian() ) { SwapULong( &pEntry->tag ); SwapULong( &pEntry->checkSum ); SwapULong( &pEntry->offset ); SwapULong( &pEntry->length ); } /* printf(" : Got table: %c%c%c%c length=%u\n", (pEntry->tag >> 24) & 0xff, (pEntry->tag >> 16) & 0xff, (pEntry->tag >> 8) & 0xff, (pEntry->tag ) & 0xff, pEntry->length ); */ } void PdfTTFWriter::ReadOs2Table( PdfInputDevice* pDevice ) { pDevice->Read( reinterpret_cast(&m_tOs2), sizeof(TOs2) ); if( podofo_is_little_endian() ) SwapOs2Table(); } void PdfTTFWriter::ReadHmtxTable( PdfInputDevice* pDevice ) { // read numOfHMetrics long values TLongHorMetric longValue; int n = m_tHHea.numberOfHMetrics; while( n-- ) { READ_TTF_USHORT( longValue.advanceWidth ); READ_TTF_SHORT ( longValue.leftSideBearing ); m_vecHmtx.push_back( longValue ); } // read numGlyphs - numOfHMetrics short values n = m_tHHea.numberOfHMetrics - m_tMaxp.numGlyphs; while( n-- ) { // advanceWidth stays the same as in the last read long value READ_TTF_SHORT ( longValue.leftSideBearing ); m_vecHmtx.push_back( longValue ); } } void PdfTTFWriter::SwapOs2Table() { SwapUShort ( &m_tOs2.version ); SwapShort ( &m_tOs2.xAvgCharWidth ); SwapUShort ( &m_tOs2.usWeightClass ); SwapUShort ( &m_tOs2.usWidthClass ); SwapShort ( &m_tOs2.fsType ); SwapShort ( &m_tOs2.ySubscriptXSize ); SwapShort ( &m_tOs2.ySubscriptYSize ); SwapShort ( &m_tOs2.ySubscriptXOffset ); SwapShort ( &m_tOs2.ySubscriptYOffset ); SwapShort ( &m_tOs2.ySuperscriptXSize ); SwapShort ( &m_tOs2.ySuperscriptYSize ); SwapShort ( &m_tOs2.ySuperscriptXOffset ); SwapShort ( &m_tOs2.ySuperscriptYOffset ); SwapShort ( &m_tOs2.yStrikeoutSize ); SwapShort ( &m_tOs2.yStrikeoutPosition ); SwapShort ( &m_tOs2.sFamilyClass ); SwapULong ( &m_tOs2.ulUnicodeRange1 ); SwapULong ( &m_tOs2.ulUnicodeRange2 ); SwapULong ( &m_tOs2.ulUnicodeRange3 ); SwapULong ( &m_tOs2.ulUnicodeRange4 ); SwapUShort ( &m_tOs2.fsSelection ); SwapUShort ( &m_tOs2.usFirstCharIndex ); SwapUShort ( &m_tOs2.usLastCharIndex ); SwapUShort ( &m_tOs2.sTypoAscender ); SwapUShort ( &m_tOs2.sTypoDescender ); SwapUShort ( &m_tOs2.sTypoLineGap ); SwapUShort ( &m_tOs2.usWinAscent ); SwapUShort ( &m_tOs2.usWinDescent ); SwapULong ( &m_tOs2.ulCodePageRange1 ); SwapULong ( &m_tOs2.ulCodePageRange2 ); } void PdfTTFWriter::ReadHeadTable( PdfInputDevice* pDevice ) { pDevice->Read( reinterpret_cast(&m_tHead), sizeof(THead) ); if( podofo_is_little_endian() ) SwapHeadTable(); } void PdfTTFWriter::SwapHeadTable() { // Swap bytes SwapULong ( &m_tHead.checkSumAdjustment ); SwapULong ( &m_tHead.magicNumber ); SwapUShort( &m_tHead.flags ); SwapUShort( &m_tHead.unitsPerEm ); SwapShort ( &m_tHead.fontDirectionHint ); SwapShort ( &m_tHead.indexToLocForm ); SwapShort ( &m_tHead.glyphDataFormat ); // Do not care for other values } void PdfTTFWriter::ReadMaxpTable( PdfInputDevice* pDevice ) { pDevice->Read( reinterpret_cast(&m_tMaxp), sizeof(TMaxP) ); if( podofo_is_little_endian() ) SwapMaxpTable(); } void PdfTTFWriter::SwapMaxpTable() { SwapUShort( &m_tMaxp.numGlyphs ); SwapUShort( &m_tMaxp.maxPoints ); SwapUShort( &m_tMaxp.maxContours ); SwapUShort( &m_tMaxp.maxCompositePoints ); SwapUShort( &m_tMaxp.maxCompositeContours ); SwapUShort( &m_tMaxp.maxZones ); SwapUShort( &m_tMaxp.maxTwilightPoints ); SwapUShort( &m_tMaxp.maxStorage ); SwapUShort( &m_tMaxp.maxFunctionsDefs ); SwapUShort( &m_tMaxp.maxInstructionDefs ); SwapUShort( &m_tMaxp.maxStackElements ); SwapUShort( &m_tMaxp.maxSizeOfInstruction ); SwapUShort( &m_tMaxp.maxComponentElements ); SwapUShort( &m_tMaxp.maxComponentDepth ); } void PdfTTFWriter::ReadHHeaTable( PdfInputDevice* pDevice ) { pDevice->Read( reinterpret_cast(&m_tHHea), sizeof(THHea) ); if( podofo_is_little_endian() ) SwapHHeaTable(); } void PdfTTFWriter::SwapHHeaTable() { SwapFWord ( &m_tHHea.advanceWidthMax ); SwapFWord ( &m_tHHea.minLeftSideBearing ); SwapFWord ( &m_tHHea.minRightSideBearing ); SwapFWord ( &m_tHHea.xMaxExtent ); SwapUShort ( &m_tHHea.numberOfHMetrics ); } void PdfTTFWriter::ReadPostTable( PdfInputDevice* pDevice ) { pDevice->Read( reinterpret_cast(&m_tPost), sizeof(TPost) ); if( podofo_is_little_endian() ) SwapPostTable(); } void PdfTTFWriter::SwapPostTable() { /* pdf_ttf_fixed format; pdf_ttf_fixed italicAngle; pdf_ttf_fword underlinePosition; pdf_ttf_fword underlineThickness; pdf_ttf_ulong isFixedPitch; pdf_ttf_ulong minMemType42; pdf_ttf_ulong maxMemType42; pdf_ttf_ulong minMemType1; pdf_ttf_ulong maxMemType1; */ } void PdfTTFWriter::ReadLocaTable( PdfInputDevice* pDevice ) { int n = m_tMaxp.numGlyphs + 1; pdf_ttf_ulong lValue; if( m_tHead.indexToLocForm == 0 ) { // short offsets pdf_ttf_ushort value; while( n-- ) { pDevice->Read( reinterpret_cast(&value), sizeof(pdf_ttf_ushort) ); this->SwapUShort( &value ); lValue = value; m_tLoca.push_back( lValue ); } } else if( m_tHead.indexToLocForm == 1 ) { // long offsets while( n-- ) { pDevice->Read( reinterpret_cast(&lValue), sizeof(pdf_ttf_ulong) ); this->SwapULong( &lValue ); m_tLoca.push_back( lValue ); } } else { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidFontFile, "Format of loca table not recognized." ); } } void PdfTTFWriter::ReadCmapTable( PdfInputDevice* pDevice ) { TCMapEntry entry; int nUnicodeIndex = -1; pdf_ttf_ushort tableVersion; pdf_ttf_ushort numberOfTables; std::vector cmap; READ_TTF_USHORT( tableVersion ); READ_TTF_USHORT( numberOfTables ); while( numberOfTables-- ) { READ_TTF_USHORT( entry.platformId ); READ_TTF_USHORT( entry.encodingId ); READ_TTF_ULONG ( entry.offset ); //printf("Got cmap table: %u %u at %u\n",entry.platformId, entry.encodingId, entry.offset ); cmap.push_back( entry ); if( entry.platformId == 3 && entry.encodingId == 1 ) nUnicodeIndex = cmap.size() - 1; } if( nUnicodeIndex == -1 ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidFontFile, "No unicode cmap table found." ); // TODO: Use other tables to build a unicode table. } m_lCMapOffset += cmap[nUnicodeIndex].offset; // Reset current cmap offset to actual cmap offset pDevice->Seek( m_lCMapOffset ); READ_TTF_USHORT( format4.format ); READ_TTF_USHORT( format4.length ); READ_TTF_USHORT( format4.version ); READ_TTF_USHORT( format4.segCountX2 ); READ_TTF_USHORT( format4.searchRange ); READ_TTF_USHORT( format4.entrySelector ); READ_TTF_USHORT( format4.rangeShift ); /* printf("Format: %i\n", format4.format ); printf("Length: %i\n", format4.length ); printf("SegCountX2: %i\n", format4.segCountX2 ); printf("Range Shift: %i\n", format4.rangeShift ); * */ int i; const int nSegCount = format4.segCountX2 >> 1; pdf_ttf_ushort nReservedPad; m_ranges.resize( nSegCount ); for( i=0;iTell(); READ_TTF_USHORT( m_ranges[i].nOffset ); /* if( m_ranges[i].nOffset ) { printf("BEFORE=%i\n", m_ranges[i].nOffset ); m_ranges[i].nOffset -= ((nSegCount - i) * 2); printf("AFTER =%i\n", static_cast(m_ranges[i].nOffset) ); } */ #if 0 if( m_ranges[i].nOffset ) { if( m_ranges[i].nStart == 160 ) { /* if(theLowByte >= firstCode && theLowByte < (firstCode + Int16FromMOTA(subHeader2s[k].entryCount))) { return *((&(subHeader2s[0].idRangeOffset)) + (Int16FromMOTA(subHeader2s[0].idRangeOffset)/2) + theLowByte - Int16FromMOTA(subHeader2s[0].firstCode) ); */ int c = 228; printf("OFFSET1 = %i\n", m_ranges[i].nOffset ); printf("OFFSET2 = %i\n", (c - m_ranges[i].nStart) ); printf("POS = %i\n", lPos ); //long lAddress = (m_ranges[i].nOffset/2 + (c - m_ranges[i].nStart) + lPos ); long lAddress = lPos + m_ranges[i].nOffset/2 + (c - m_ranges[i].nStart); printf("GOT ADDRESS: %x\n", lAddress - m_lCMapOffset ); pDevice->Seek( lAddress ); pdf_ttf_ushort u; READ_TTF_USHORT( u ); printf("Index=%u\n", u ); pDevice->Seek( lPos + sizeof(pdf_ttf_ushort) ); } } #endif // 0 } m_lCMapOffset = (pDevice->Tell() - m_lCMapOffset); long lGlyphIdArrayLen = (format4.length - m_lCMapOffset) / sizeof(pdf_ttf_ushort); pdf_ttf_ushort glyphId; m_vecGlyphIds.reserve( lGlyphIdArrayLen ); while( lGlyphIdArrayLen-- ) { READ_TTF_USHORT( glyphId ); m_vecGlyphIds.push_back( glyphId ); } // in case of broken TTF we have to sort this table std::sort( m_ranges.begin(), m_ranges.end() ); /* for( i=0;inumberOfContours ); SwapFWord ( &pHeader->xMin ); SwapFWord ( &pHeader->yMin ); SwapFWord ( &pHeader->xMax ); SwapFWord ( &pHeader->yMax ); } #define ARG_1_AND_2_ARE_WORDS 0x0001 #define ARGS_ARE_XY_VALUES 0x0002 #define ROUND_XY_TO_GRID 0x0004 #define WE_HAVE_A_SCALE 0x0008 #define RESERVED 0x0010 #define MORE_COMPONENTS 0x0020 #define WE_HAVE_AN_X_AND_Y_SCALE 0x0040 #define WE_HAVE_A_TWO_BY_TWO 0x0080 #define WE_HAVE_INSTRUCTIONS 0x0100 #define USE_MY_METRICS 0x0200 void PdfTTFWriter::ReadGlyfTable( PdfInputDevice* pDevice ) { std::vector::const_iterator it = m_vecGlyphIndeces.begin(); long lOffset; long lLength; while( it != m_vecGlyphIndeces.end() ) { lOffset = this->GetGlyphDataLocation( *it, &lLength, pDevice ); if( lOffset != -1 ) { PdfRefCountedBuffer buffer( lLength ); pDevice->Seek( lOffset ); pDevice->Read( buffer.GetBuffer(), lLength ); PdfTTFGlyph glyph( *it ); glyph.m_buffer = buffer; m_vecGlyphs.push_back( glyph ); //this->LoadGlyph( *it, lOffset, pDevice ); } else { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidFontFile, "Charnotfound" ); } ++it; } } void PdfTTFWriter::LoadGlyph( int nIndex, long lOffset, PdfInputDevice* pDevice ) { printf("!!!! Loading glyph %i\n", nIndex ); PdfTTFGlyph glyph( nIndex ); pDevice->Seek( lOffset ); pDevice->Read( reinterpret_cast(&glyph.m_tHeader), sizeof(TGlyphHeader) ); if( podofo_is_little_endian() ) SwapGlyfHeader( &glyph.m_tHeader ); glyph.SetComposite( glyph.m_tHeader.numberOfContours == -1 ); printf("Glyph with index %i is %s. (contours) = %i\n", nIndex, glyph.IsComposite() ? "composite" : "simple", glyph.m_tHeader.numberOfContours ); if( !glyph.IsComposite() ) { // Read the end points int nContours = glyph.m_tHeader.numberOfContours; pdf_ttf_ushort nEndPoint; glyph.vecEndPoints.reserve( nContours ); while( nContours-- ) { READ_TTF_USHORT( nEndPoint ); printf("Reading endpoint: %i\n", nEndPoint ); glyph.vecEndPoints.push_back( nEndPoint ); } // read instructions pDevice->Read( reinterpret_cast(&glyph.m_nInstructionLength), sizeof(pdf_ttf_ushort) ); if( podofo_is_little_endian() ) SwapUShort( &glyph.m_nInstructionLength ); printf("Reading instructions: %i\n", glyph.m_nInstructionLength ); if( glyph.m_nInstructionLength ) { glyph.m_pInstructions = static_cast(podofo_calloc( glyph.m_nInstructionLength, sizeof(char) )); if( !glyph.m_pInstructions ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } pDevice->Read( glyph.m_pInstructions, glyph.m_nInstructionLength ); } unsigned char flag; unsigned char repeat; int nPoints = glyph.vecEndPoints.back(); // read flags printf("Reading flags: %i\n", nPoints ); while( --nPoints >= 0 ) { pDevice->Read( reinterpret_cast(&flag), sizeof(char) ); glyph.vecFlagsOrig.push_back( flag ); if( (flag & 0x08) == 0x08 ) // i.e. the next byte tells us how often this flag is to be repeated { pDevice->Read( reinterpret_cast(&repeat), sizeof(char) ); glyph.vecFlagsOrig.push_back( repeat ); /* while( repeat-- ) glyph.vecFlags.push_back( flag ); */ } }; printf("!!!XXXXXXX\n"); ReadSimpleGlyfCoordinates( pDevice, glyph.vecFlags, glyph.vecXCoordinates, 0x02, 0x10 ); printf("!!!YYYYYYY\n"); ReadSimpleGlyfCoordinates( pDevice, glyph.vecFlags, glyph.vecYCoordinates, 0x04, 0x20 ); /* for( int z=0;zRead( reinterpret_cast(&flags), sizeof(pdf_ttf_ushort) ); pDevice->Read( reinterpret_cast(&glyphIndex), sizeof(pdf_ttf_ushort) ); if( podofo_is_little_endian() ) { this->SwapUShort( &flags ); this->SwapUShort( &glyphIndex ); } printf("glyphIndex=%i and should be %i\n", glyphIndex, nIndex ); if( glyphIndex != nIndex ) { PODOFO_RAISE_ERROR( ePdfError_InvalidFontFile ); } if( flags & ARG_1_AND_2_ARE_WORDS ) { pDevice->Read( reinterpret_cast(&glyph.arg1), sizeof(pdf_ttf_short) ); pDevice->Read( reinterpret_cast(&glyph.arg2), sizeof(pdf_ttf_short) ); if( podofo_is_little_endian() ) { this->SwapShort( &glyph.arg1 ); this->SwapShort( &glyph.arg2 ); } } else { char cArg1; char cArg2; pDevice->Read( &cArg1, sizeof(char) ); pDevice->Read( &cArg2, sizeof(char) ); glyph.arg1 = cArg1; glyph.arg2 = cArg2; } // glyph.xx = glyph.yy = 0x10000L; glyph.xx = glyph.yy = 0x00; if ( flags & WE_HAVE_A_SCALE ) { //F2Dot14 scale; /* Format 2.14 */ pDevice->Read( reinterpret_cast(&glyph.xx), sizeof(pdf_ttf_short) ); if( podofo_is_little_endian() ) this->SwapShort( &glyph.xx ); glyph.yy = glyph.xx; } else if ( flags & WE_HAVE_AN_X_AND_Y_SCALE ) { //F2Dot14 xscale; /* Format 2.14 */ //F2Dot14 yscale; /* Format 2.14 */ pDevice->Read( reinterpret_cast(&glyph.xx), sizeof(pdf_ttf_short) ); pDevice->Read( reinterpret_cast(&glyph.yy), sizeof(pdf_ttf_short) ); if( podofo_is_little_endian() ) { this->SwapShort( &glyph.xx ); this->SwapShort( &glyph.yy ); } } else if ( flags & WE_HAVE_A_TWO_BY_TWO ) { pDevice->Read( reinterpret_cast(&glyph.xx), sizeof(pdf_ttf_short) ); pDevice->Read( reinterpret_cast(&glyph.yx), sizeof(pdf_ttf_short) ); pDevice->Read( reinterpret_cast(&glyph.yy), sizeof(pdf_ttf_short) ); pDevice->Read( reinterpret_cast(&glyph.xy), sizeof(pdf_ttf_short) ); if( podofo_is_little_endian() ) { this->SwapShort( &glyph.xx ); this->SwapShort( &glyph.yx ); this->SwapShort( &glyph.yy ); this->SwapShort( &glyph.xy ); } //F2Dot14 xscale; /* Format 2.14 */ //F2Dot14 scale01; /* Format 2.14 */ //F2Dot14 scale10; /* Format 2.14 */ //F2Dot14 yscale; /* Format 2.14 */ } } while( flags & MORE_COMPONENTS ); if( flags & WE_HAVE_INSTRUCTIONS ) { pDevice->Read( reinterpret_cast(&glyph.m_nInstructionLength), sizeof(pdf_ttf_ushort) ); if( podofo_is_little_endian() ) this->SwapUShort( &glyph.m_nInstructionLength ); if( glyph.m_nInstructionLength ) { glyph.m_pInstructions = static_cast(podofo_calloc( glyph.m_nInstructionLength, sizeof(char) )); if( !glyph.m_pInstructions ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } pDevice->Read( glyph.m_pInstructions, glyph.m_nInstructionLength ); } } } m_vecGlyphs.push_back( glyph ); } void PdfTTFWriter::Subset() { } // ----------------------------------------------------- // Writing out a TTF file from memory // ----------------------------------------------------- void PdfTTFWriter::Write( PdfOutputDevice* pDevice ) { m_tTableDirectory.numTables = 9; // DS TMP TTableDirectoryEntry entry; TVecTableDirectoryEntries vecToc; const long lTableOffset = sizeof(TTableDirectory); const long lNumTables = m_tTableDirectory.numTables; this->WriteTableDirectory( pDevice ); // write dummy table of contents memset( &entry, 0, sizeof(TTableDirectoryEntry) ); for( unsigned int i=0; i(lNumTables); i++ ) pDevice->Write( reinterpret_cast(&entry), sizeof(TTableDirectoryEntry) ); // write contents this->WriteTable( pDevice, vecToc, this->CreateTag( 'm', 'a', 'x', 'p' ), &PdfTTFWriter::WriteMaxpTable ); this->WriteTable( pDevice, vecToc, this->CreateTag( 'h', 'e', 'a', 'd' ), &PdfTTFWriter::WriteHeadTable ); this->WriteTable( pDevice, vecToc, this->CreateTag( 'g', 'l', 'y', 'f' ), &PdfTTFWriter::WriteGlyfTable ); this->WriteTable( pDevice, vecToc, this->CreateTag( 'c', 'm', 'a', 'p' ), &PdfTTFWriter::WriteCMapTable ); this->WriteTable( pDevice, vecToc, this->CreateTag( 'l', 'o', 'c', 'a' ), &PdfTTFWriter::WriteLocaTable ); this->WriteTable( pDevice, vecToc, this->CreateTag( 'h', 'h', 'e', 'a' ), &PdfTTFWriter::WriteHHeaTable ); this->WriteTable( pDevice, vecToc, this->CreateTag( 'O', 'S', '/', '2' ), &PdfTTFWriter::WriteOs2Table ); this->WriteTable( pDevice, vecToc, this->CreateTag( 'n', 'a', 'm', 'e' ), &PdfTTFWriter::WriteNameTable ); this->WriteTable( pDevice, vecToc, this->CreateTag( 'h', 'm', 't', 'x' ), &PdfTTFWriter::WriteHmtxTable ); this->WriteTable( pDevice, vecToc, this->CreateTag( 'p', 'o', 's', 't' ), &PdfTTFWriter::WritePostTable ); // TODO:Check why this is commented. Without this code, we will have a memory leak because (*it).data is never podofo_free'ed /* TCIVecTable it = m_vecTableData.begin(); while( it != m_vecTableData.end() ) { TTableDirectoryEntry entry; entry.tag = (*it).tag; entry.checkSum = this->CalculateChecksum( reinterpret_cast(&(*it).data), (*it).length ); entry.offset = pDevice->GetLength(); entry.length = (*it).length; vecToc.push_back( entry ); pDevice->Write( (*it).data, (*it).length ); podofo_free( (*it).data ); ++it; } */ // write actual table of contents pDevice->Seek( lTableOffset ); TIVecTableDirectoryEntries itToc = vecToc.begin(); while( itToc != vecToc.end() ) { this->WriteTableDirectoryEntry( pDevice, &(*itToc) ); ++itToc; } } void PdfTTFWriter::WriteTableDirectoryEntry( PdfOutputDevice* pDevice, TTableDirectoryEntry* pEntry ) { if( podofo_is_little_endian() ) { SwapULong( &pEntry->tag ); SwapULong( &pEntry->checkSum ); SwapULong( &pEntry->offset ); SwapULong( &pEntry->length ); } pDevice->Write( reinterpret_cast(pEntry), sizeof(TTableDirectoryEntry) ); } void PdfTTFWriter::WriteGlyfTable( PdfOutputDevice* pDevice ) { TIVecGlyphs it = m_vecGlyphs.begin(); int nPosition = 0; while( it != m_vecGlyphs.end() ) { // set the position of the glyph so that a cmap can be generated (*it).SetPosition( nPosition++ ); pDevice->Write( (*it).m_buffer.GetBuffer(), (*it).m_buffer.GetSize() ); // add value to new loca table so that it can be created correctly m_vecLoca.push_back( pDevice->Tell() ); #if 0 if( podofo_is_little_endian() ) SwapGlyfHeader( &(*it).m_tHeader ); pDevice->Write( reinterpret_cast(&(*it).m_tHeader), sizeof(TGlyphHeader) ); if( (*it).IsComposite() ) { // TODO: Write a composite glyph } else { // Write a simple glyph std::vector::iterator itEndPoints = (*it).vecEndPoints.begin(); while( itEndPoints != (*it).vecEndPoints.end() ) { WRITE_TTF_USHORT( *itEndPoints ); ++itEndPoints; } pdf_ttf_ushort nLength = (*it).GetInstrunctionLength(); WRITE_TTF_USHORT( nLength ); pDevice->Write( (*it).GetInstrunctions(), (*it).GetInstrunctionLength() ); printf("?????= Glyph flags size=%i\n", (*it).vecFlagsOrig.size() ); pDevice->Write( reinterpret_cast(&(*it).vecFlagsOrig[0]), sizeof(char) * (*it).vecFlagsOrig.size() ); WriteSimpleGlyfCoordinates( pDevice, (*it).vecFlags, (*it).vecXCoordinates, 0x02, 0x10 ); WriteSimpleGlyfCoordinates( pDevice, (*it).vecFlags, (*it).vecYCoordinates, 0x04, 0x20 ); } #endif // 0 ++it; } // add an additional entry to loca so that the length of the last character can be determined m_vecLoca.push_back( pDevice->Tell() ); } void PdfTTFWriter::WriteCMapTable( PdfOutputDevice* pDevice ) { pdf_ttf_ushort nValue = 0; pdf_ttf_ulong lValue = 12; WRITE_TTF_USHORT( nValue ); // table version nValue = 1; WRITE_TTF_USHORT( nValue ); // number of tables nValue = 3; WRITE_TTF_USHORT( nValue ); // platform id (microsoft) nValue = 1; WRITE_TTF_USHORT( nValue ); // encoding id (unicode) WRITE_TTF_ULONG ( lValue ); // offset // create a cmap table in ram std::vector vecRanges; TCMapRange current; TCIVecGlyphs it = m_vecGlyphs.begin(); bool bReset = true; while( it != m_vecGlyphs.end() ) { if( bReset ) { if( it != m_vecGlyphs.begin() ) vecRanges.push_back( current ); current.nStart = (*it).GetIndex(); current.nEnd = (*it).GetIndex(); current.nDelta = -((*it).GetIndex() - (*it).GetPosition()); current.nOffset = 0; bReset = false; ++it; } else { if( (*it).GetIndex() == current.nEnd + 1 ) { current.nEnd++; ++it; } else bReset = true; } } if( !bReset ) vecRanges.push_back( current ); // create the ending section current.nStart = 0xFFFF; current.nEnd = 0xFFFF; current.nDelta = 0; current.nOffset = 0; vecRanges.push_back( current ); int i; double dSearchRange = 2.0 * ( PdfExp2( floor( PdfLog2( vecRanges.size() ) ) ) ); pdf_ttf_ushort nSearchRange = static_cast(dSearchRange); // write the actual cmap table nValue = 4; WRITE_TTF_USHORT( nValue ); // format nValue = vecRanges.size() * sizeof(pdf_ttf_ushort) * 4 + 16; // 4 parallel array per segment + 16 bytes of header WRITE_TTF_USHORT( nValue ); // length nValue = 0; WRITE_TTF_USHORT( nValue ); // version nValue = vecRanges.size() * 2; WRITE_TTF_USHORT( nValue ); // seg count * 2 nValue = nSearchRange; WRITE_TTF_USHORT( nValue ); // search range nValue = static_cast(PdfLog2( vecRanges.size() >> 1 )); WRITE_TTF_USHORT( nValue ); // entry selector nValue = 2 * vecRanges.size() - nSearchRange; WRITE_TTF_USHORT( nValue ); // range shift for( i=0;i(vecRanges.size());i++ ) { WRITE_TTF_USHORT( vecRanges[i].nEnd ); } nValue = 0; WRITE_TTF_USHORT( nValue ); // reserve pad for( i=0;i(vecRanges.size());i++ ) { WRITE_TTF_USHORT( vecRanges[i].nStart ); } for( i=0;i(vecRanges.size());i++ ) { WRITE_TTF_SHORT( vecRanges[i].nDelta ); } for( i=0;i(vecRanges.size());i++ ) { WRITE_TTF_USHORT( vecRanges[i].nOffset ); } } void PdfTTFWriter::WriteHHeaTable( PdfOutputDevice* pDevice ) { // We always write the long loca format // numberOfHMetrics has to be equal to numGlyphs so // that we have only to write LongHorMetric values to Hmtx and no short values m_tHHea.numberOfHMetrics = m_vecGlyphs.size(); if( podofo_is_little_endian() ) SwapHHeaTable(); pDevice->Write( reinterpret_cast(&m_tHHea), sizeof(THHea) ); } void PdfTTFWriter::WriteHmtxTable( PdfOutputDevice* pDevice ) { TLongHorMetric entry; TCIVecGlyphs it = m_vecGlyphs.begin(); while( it != m_vecGlyphs.end() ) { entry = m_vecHmtx[(*it).GetIndex()]; WRITE_TTF_USHORT( entry.advanceWidth ); WRITE_TTF_SHORT ( entry.leftSideBearing ); ++it; } } void PdfTTFWriter::WriteLocaTable( PdfOutputDevice* pDevice ) { TCIVecLoca it = m_vecLoca.begin(); pdf_ttf_ulong lValue; // Write a 0 value for first glyph lValue = 0x00; this->SwapULong( &lValue ); pDevice->Write( reinterpret_cast(&lValue), sizeof(pdf_ttf_ulong) ); while( it != m_vecLoca.end() ) { lValue = (*it); this->SwapULong( &lValue ); pDevice->Write( reinterpret_cast(&lValue), sizeof(pdf_ttf_ulong) ); ++it; } } void PdfTTFWriter::WriteMaxpTable( PdfOutputDevice* pDevice ) { m_tMaxp.numGlyphs = m_vecGlyphs.size(); if( podofo_is_little_endian() ) SwapMaxpTable(); pDevice->Write( reinterpret_cast(&m_tMaxp), sizeof(TMaxP) ); } void PdfTTFWriter::WriteNameTable( PdfOutputDevice* pDevice ) { const char* pszFontName = "PoDoFo"; PdfString unicodeName = PdfString( pszFontName ).ToUnicode(); long lLen = unicodeName.GetLength(); // Create a custom nametable TNameTable tNameTable; tNameTable.format = 0; tNameTable.numRecords = 1; tNameTable.offset = 6; tNameTable.platformId = 0; tNameTable.encodingId = 3; tNameTable.languageId = 0x0809; tNameTable.nameId = 6; tNameTable.stringLength = static_cast(lLen); tNameTable.stringOffset = 12; SwapUShort( &tNameTable.format ); SwapUShort( &tNameTable.numRecords ); SwapUShort( &tNameTable.offset ); SwapUShort( &tNameTable.platformId ); SwapUShort( &tNameTable.encodingId ); SwapUShort( &tNameTable.languageId ); SwapUShort( &tNameTable.nameId ); SwapUShort( &tNameTable.stringLength ); SwapUShort( &tNameTable.stringOffset ); pDevice->Write( reinterpret_cast(&tNameTable), sizeof(TNameTable) ); pDevice->Write( unicodeName.GetString(), lLen ); } void PdfTTFWriter::WriteOs2Table( PdfOutputDevice* pDevice ) { // We always write the long loca format if( podofo_is_little_endian() ) SwapOs2Table(); pDevice->Write( reinterpret_cast(&m_tOs2), sizeof(TOs2) ); } void PdfTTFWriter::WriteHeadTable( PdfOutputDevice* pDevice ) { // We always write the long loca format m_tHead.indexToLocForm = 1; if( podofo_is_little_endian() ) SwapHeadTable(); pDevice->Write( reinterpret_cast(&m_tHead), sizeof(THead) ); } void PdfTTFWriter::WritePostTable( PdfOutputDevice* pDevice ) { m_tPost.format = 0x00020000; // write table header pDevice->Write( reinterpret_cast(&m_tPost), sizeof(TPost) ); // write format 2 post table int nNameIndexValue = 258; pdf_ttf_ushort nameIndex; pdf_ttf_ushort numberOfGlyphs = m_tMaxp.numGlyphs; // this value has already been swapped when writing the maxp-table pDevice->Write( reinterpret_cast(&numberOfGlyphs), sizeof(pdf_ttf_ushort) ); SwapUShort( &numberOfGlyphs ); // swap it to native format so that we can use it while( numberOfGlyphs-- ) { nameIndex = nNameIndexValue++; SwapUShort( &nameIndex ); pDevice->Write( reinterpret_cast(&nameIndex), sizeof(pdf_ttf_ushort) ); } // write names std::vector::const_iterator it = m_vecGlyphIndeces.begin(); while( it != m_vecGlyphIndeces.end() ) { const char* pszName = "Test"; unsigned char cLen = static_cast(strlen(pszName)); pDevice->Write( reinterpret_cast(&cLen), 1 ); pDevice->Write( pszName, cLen ); ++it; } } // ----------------------------------------------------- // Helper functions // ----------------------------------------------------- PdfTTFWriter::pdf_ttf_ulong PdfTTFWriter::CalculateChecksum( const pdf_ttf_ulong* pTable, pdf_ttf_ulong lLength ) const { // This code is taken from the TTF specification pdf_ttf_ulong lSum = 0L; const pdf_ttf_ulong* pEnd = pTable + ((lLength+3) & ~3) / sizeof(pdf_ttf_ulong); while( pTable < pEnd ) lSum += *pTable++; return lSum; } void PdfTTFWriter::WriteTable( PdfOutputDevice* pDevice, TVecTableDirectoryEntries & rToc, pdf_ttf_ulong tag, void (PdfTTFWriter::*WriteTableFunc)( PdfOutputDevice* ) ) { if( !m_pRefBuffer ) { // start with a 4MB buffer const long l4MB = 4 * 1024 * 1024; m_pRefBuffer = new PdfRefCountedBuffer( l4MB ); } PdfOutputDevice memDevice( m_pRefBuffer ); TTableDirectoryEntry entry; entry.tag = tag; entry.checkSum = 0; entry.length = 0; entry.offset = pDevice->Tell(); (this->*WriteTableFunc)( &memDevice ); // create toc entry entry.checkSum = this->CalculateChecksum( reinterpret_cast(m_pRefBuffer->GetBuffer()), memDevice.GetLength() );; entry.length = memDevice.GetLength(); rToc.push_back( entry ); // write data to the real device pDevice->Write( m_pRefBuffer->GetBuffer(), memDevice.GetLength() ); } void PdfTTFWriter::ReadSimpleGlyfCoordinates( PdfInputDevice* pDevice, const std::vector & rvecFlags, std::vector & rvecCoordinates, int nFlagShort, int nFlag ) { pdf_ttf_short longCoordinate; unsigned char shortCoordinate; printf("~~~~~~~~~~~\n"); printf("FLAGS: %i\n", rvecFlags.size() ); std::vector::const_iterator itFlags = rvecFlags.begin(); while( itFlags != rvecFlags.end() ) { if( (*itFlags & nFlagShort) == nFlagShort ) { // read a 1 byte long coordinate pDevice->Read( reinterpret_cast(&shortCoordinate), sizeof(char) ); printf("Got short: %i\n", shortCoordinate ); longCoordinate = static_cast(shortCoordinate); if( (*itFlags & nFlag) == nFlag ) longCoordinate = -longCoordinate; } else { // read a 2 byte long coordinate if( (*itFlags & nFlag) == nFlag ) { // DO NOTHING // the value of longCoordinate is the same as the last value // so simply reuse the old value } else { pdf_ttf_short coordinate; READ_TTF_SHORT( coordinate ); printf("Got long: %i\n", longCoordinate ); longCoordinate += coordinate; } } printf("Pushing: %i\n", longCoordinate ); rvecCoordinates.push_back( longCoordinate ); ++itFlags; } } void PdfTTFWriter::WriteSimpleGlyfCoordinates( PdfOutputDevice* pDevice, const std::vector & rvecFlags, std::vector & rvecCoordinates, int nFlagShort, int nFlag ) { pdf_ttf_short longCoordinate; pdf_ttf_short lastCoordinate; char shortCoordinate; std::vector::const_iterator itFlags = rvecFlags.begin(); std::vector::iterator itCoordinates = rvecCoordinates.begin(); while( itFlags != rvecFlags.end() ) { longCoordinate = (*itCoordinates)++; if( (*itFlags & nFlagShort) == nFlagShort ) { // read a 1 byte long coordinate if( (*itFlags & nFlag) == nFlag ) longCoordinate = -longCoordinate; shortCoordinate = static_cast(longCoordinate); pDevice->Write( &shortCoordinate, sizeof(char) ); lastCoordinate = longCoordinate; // TODO: check if it is ok to assign a negative value here } else { // read a 2 byte long coordinate if( (*itFlags & nFlag) == nFlag ) { // DO NOTHING // the value of longCoordinate is the same as the last value // so simply reuse the old value longCoordinate = lastCoordinate; } else { longCoordinate = longCoordinate - lastCoordinate; lastCoordinate = longCoordinate + lastCoordinate; } if( podofo_is_little_endian() ) this->SwapShort( &longCoordinate ); pDevice->Write( reinterpret_cast(&longCoordinate), sizeof(pdf_ttf_short) ); } ++itFlags; } } long PdfTTFWriter::GetGlyphDataLocation( unsigned int nIndex, long* plLength, PdfInputDevice* pDevice ) const { // find the correct cmap range std::vector::const_iterator it = m_ranges.begin(); // TODO: binary search!!! while( it != m_ranges.end() ) { if( (*it).nStart <= nIndex && (*it).nEnd > nIndex ) { // we got a position!! printf("Found Range for %u: %6u - %6u Delta: %6i Offset: %6u\n", nIndex, (*it).nStart, (*it).nEnd, (*it).nDelta, (*it).nOffset ); if( (*it).nOffset ) { const int nSegCount = format4.segCountX2 >> 1; int j = (*it).nOffset - (nSegCount - (it-m_ranges.begin())*2); printf("j1 = %i\n", j ); j = (nIndex - (*it).nStart) + j/2; printf("j2 = %i\n", j ); nIndex = m_vecGlyphIds[j]; printf("nIndex=%i\n", nIndex ); // 81 ??? // 1314 /* long lAddress = (*it).nOffset/2 + (nIndex - (*it).nStart) + (*it).nOffset; pDevice->Seek( lAddress + m_lCMapOffset ); pdf_ttf_ushort glyph; READ_TTF_USHORT( glyph ); printf("lAddress alone=%lx %li\n", lAddress, lAddress ); printf("lAddress=%lx\n", lAddress + m_lCMapOffset ); nIndex = glyph; printf("glyph=%u\n", glyph ); */ //nIndex = 108; //lAddress = 0x858a; //nIndex = *lAddress nach Seek } nIndex = static_cast( (nIndex + (*it).nDelta & 0xFFFFU ) ); break; } ++it; } if( it == m_ranges.end() ) // go to "missing glyph" if no glyph was found nIndex = 0; printf("INDEX: %i RANGE(0 - %i)\n", nIndex, m_tLoca.size() ); // check if the glyph index is in our current range if( nIndex < 0 || nIndex > m_tLoca.size() ) return -1; if( nIndex + 1 < m_tLoca.size() ) *plLength = m_tLoca[nIndex+1] - m_tLoca[nIndex]; else *plLength = 0; printf("Reading from index: %i (max: %i) len=%i\n", nIndex, m_tLoca.size(), *plLength ); return m_lGlyphDataOffset + m_tLoca[nIndex]; } }; }; podofo-0.9.5/src/doc/PdfStreamedDocument.cpp0000664000175000017500000001005012344436402020616 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfStreamedDocument.h" #include "base/PdfDefinesPrivate.h" namespace PoDoFo { PdfStreamedDocument::PdfStreamedDocument( PdfOutputDevice* pDevice, EPdfVersion eVersion, PdfEncrypt* pEncrypt, EPdfWriteMode eWriteMode ) : m_pWriter( NULL ), m_pDevice( NULL ), m_pEncrypt( pEncrypt ), m_bOwnDevice( false ) { Init( pDevice, eVersion, pEncrypt, eWriteMode ); } PdfStreamedDocument::PdfStreamedDocument( const char* pszFilename, EPdfVersion eVersion, PdfEncrypt* pEncrypt, EPdfWriteMode eWriteMode ) : m_pWriter( NULL ), m_pEncrypt( pEncrypt ), m_bOwnDevice( true ) { m_pDevice = new PdfOutputDevice( pszFilename ); Init( m_pDevice, eVersion, pEncrypt, eWriteMode ); } #ifdef _WIN32 PdfStreamedDocument::PdfStreamedDocument( const wchar_t* pszFilename, EPdfVersion eVersion, PdfEncrypt* pEncrypt, EPdfWriteMode eWriteMode ) : m_pWriter( NULL ), m_pEncrypt( pEncrypt ), m_bOwnDevice( true ) { m_pDevice = new PdfOutputDevice( pszFilename ); Init( m_pDevice, eVersion, pEncrypt, eWriteMode ); } #endif // _WIN32 PdfStreamedDocument::~PdfStreamedDocument() { delete m_pWriter; if( m_bOwnDevice ) delete m_pDevice; } void PdfStreamedDocument::Init( PdfOutputDevice* pDevice, EPdfVersion eVersion, PdfEncrypt* pEncrypt, EPdfWriteMode eWriteMode ) { m_pWriter = new PdfImmediateWriter( pDevice, this->GetObjects(), this->GetTrailer(), eVersion, pEncrypt, eWriteMode ); } void PdfStreamedDocument::Close() { // TODO: Check if this works correctly // makes sure pending subset-fonts are embedded m_fontCache.EmbedSubsetFonts(); this->GetObjects()->Finish(); } }; podofo-0.9.5/src/doc/PdfTilingPattern.h0000664000175000017500000001276012347301431017612 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _PDF_TILING_PATTERN_H_ #define _PDF_TILING_PATTERN_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfName.h" #include "PdfElement.h" namespace PoDoFo { class PdfImage; class PdfObject; class PdfPage; class PdfWriter; /** * This class defined a tiling pattern which can be used * to fill abitrary shapes with a pattern using PdfPainter. */ class PODOFO_DOC_API PdfTilingPattern : public PdfElement { public: virtual ~PdfTilingPattern(); /** Returns the identifier of this TilingPattern how it is known * in the pages resource dictionary. * \returns PdfName containing the identifier (e.g. /PtrnXXXXX) */ inline const PdfName & GetIdentifier() const; /** Create a new PdfTilingPattern object, which will introduce itself * automatically to every page object it is used on. * * \param eTilingType the type of this tiling pattern * \param strokeR strok color red component * \param strokeG strok color green component * \param strokeB strok color blue component * \param doFill whether tile fills content first, with fill color * \param fillR fill color red component * \param fillG fill color green component * \param fillB fill color blue component * \param offsetX tile offset on X axis * \param offsetY tile offset on Y axis * \param pImage image to use - can be set only if eTilingType is ePdfTilingPatternType_Image * \param pParent parent vector of objects * * \note stroke and fill colors are ignored if eTilingType is ePdfTilingPatternType_Image * \note fill color is ignored if doFill is false * \note pImage is ignored for all but ePdfTilingPatternType_Image eTilingType types, where it cannot be NULL * */ PdfTilingPattern( EPdfTilingPatternType eTilingType, double strokeR, double strokeG, double strokeB, bool doFill, double fillR, double fillG, double fillB, double offsetX, double offsetY, PdfImage *pImage, PdfVecObjects* pParent); /** Create a new PdfTilingPattern object, which will introduce itself * automatically to every page object it is used on. * * \param eTilingType the type of this tiling pattern * \param strokeR strok color red component * \param strokeG strok color green component * \param strokeB strok color blue component * \param doFill whether tile fills content first, with fill color * \param fillR fill color red component * \param fillG fill color green component * \param fillB fill color blue component * \param offsetX tile offset on X axis * \param offsetY tile offset on Y axis * \param pImage image to use - can be set only if eTilingType is ePdfTilingPatternType_Image * \param pParent parent document * * \note stroke and fill colors are ignored if eTilingType is ePdfTilingPatternType_Image * \note fill color is ignored if doFill is false * \note pImage is ignored for all but ePdfTilingPatternType_Image eTilingType types, where it cannot be NULL * */ PdfTilingPattern( EPdfTilingPatternType eTilingType, double strokeR, double strokeG, double strokeB, bool doFill, double fillR, double fillG, double fillB, double offsetX, double offsetY, PdfImage *pImage, PdfDocument* pParent); private: /** Initialize the object */ void Init( EPdfTilingPatternType eTilingType, double strokeR, double strokeG, double strokeB, bool doFill, double fillR, double fillG, double fillB, double offsetX, double offsetY, PdfImage *pImage); void AddToResources(const PdfName &rIdentifier, const PdfReference &rRef, const PdfName &rName); private: PdfName m_Identifier; }; // ----------------------------------------------------- // // ----------------------------------------------------- const PdfName & PdfTilingPattern::GetIdentifier() const { return m_Identifier; } } // end namespace #endif // _PDF_TILING_PATTERN_H_ podofo-0.9.5/src/doc/PdfFontType1.cpp0000664000175000017500000005532413021053735017216 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfFontType1.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfDictionary.h" #include "base/PdfName.h" #include "base/PdfStream.h" #include "PdfDifferenceEncoding.h" #include namespace PoDoFo { PdfFontType1::PdfFontType1( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfVecObjects* pParent, bool bEmbed, bool bSubsetting ) : PdfFontSimple( pMetrics, pEncoding, pParent ) { memset( m_bUsed, 0, sizeof( m_bUsed ) ); m_bIsSubsetting = bSubsetting; this->Init( bEmbed, PdfName("Type1") ); } PdfFontType1::PdfFontType1( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfObject* pObject ) : PdfFontSimple( pMetrics, pEncoding, pObject ) { memset( m_bUsed, 0, sizeof( m_bUsed ) ); } PdfFontType1::PdfFontType1( PdfFontType1* pFont, PdfFontMetrics* pMetrics, const char *pszSuffix, PdfVecObjects* pParent ) : PdfFontSimple( pMetrics, pFont->m_pEncoding, pParent ) { memset( m_bUsed, 0, sizeof( m_bUsed ) ); // don't embedd font Init( false, PdfName("Type1") ); // Use identical subset-names if ( pFont->IsSubsetting() ) GetObject()->GetDictionary().AddKey( "BaseFont", pFont->GetObject()->GetDictionary().GetKey( "BaseFont" ) ); // set identifier std::string id = pFont->GetIdentifier().GetName(); id += pszSuffix; m_Identifier = id; // remove new FontDescriptor and use FontDescriptor of source font instead PdfObject* pObj = pParent->RemoveObject( GetObject()->GetIndirectKey( "FontDescriptor" )->Reference() ); delete pObj; GetObject()->GetDictionary().AddKey( "FontDescriptor", pFont->GetObject()->GetDictionary().GetKey( "FontDescriptor" ) ); } void PdfFontType1::AddUsedSubsettingGlyphs( const PdfString & sText, long lStringLen ) { if ( m_bIsSubsetting ) { // TODO: Unicode and Hex not yet supported PODOFO_ASSERT( sText.IsUnicode() == false ); PODOFO_ASSERT( sText.IsHex() == false ); const unsigned char* strp = reinterpret_cast(sText.GetString()); // must be unsigned for access to m_bUsed-array for ( int i = 0; i < lStringLen; i++ ) { m_bUsed[strp[i] / 32] |= 1 << (strp[i] % 32 ); } } } void PdfFontType1::AddUsedGlyphname( const char * sGlyphName ) { if ( m_bIsSubsetting ) { m_sUsedGlyph.insert( sGlyphName ); } } void PdfFontType1::EmbedSubsetFont() { if ( !m_bIsSubsetting || m_bWasEmbedded == true ) return; pdf_long lSize = 0; pdf_int64 lLength1 = 0L; pdf_int64 lLength2 = 0L; pdf_int64 lLength3 = 0L; PdfObject* pContents; const char* pBuffer; char* pAllocated = NULL; int i; m_bWasEmbedded = true; pContents = this->GetObject()->GetOwner()->CreateObject(); if( !pContents ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } m_pDescriptor->GetDictionary().AddKey( "FontFile", pContents->Reference() ); // if the data was loaded from memory - use it from there // otherwise, load from disk if ( m_pMetrics->GetFontDataLen() && m_pMetrics->GetFontData() ) { pBuffer = m_pMetrics->GetFontData(); lSize = m_pMetrics->GetFontDataLen(); } else { FILE* hFile = fopen( m_pMetrics->GetFilename(), "rb" ); if( !hFile ) { PODOFO_RAISE_ERROR_INFO( ePdfError_FileNotFound, m_pMetrics->GetFilename() ); } if( fseeko( hFile, 0L, SEEK_END ) == -1 ) { fclose( hFile ); PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to seek to the end of the file" ); } lSize = ftello( hFile ); if( lSize == -1 ) { fclose( hFile ); PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to read size of the file" ); } if( fseeko( hFile, 0L, SEEK_SET ) == -1 ) { fclose( hFile ); PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to seek to the beginning of the file" ); } pAllocated = static_cast(podofo_calloc( lSize, sizeof(char) )); if( !pAllocated ) { fclose( hFile ); PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } if( static_cast( fread( pAllocated, sizeof( char ), lSize, hFile ) ) != lSize ) { podofo_free( pAllocated ); fclose( hFile ); PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to read whole file into the memory" ); } fclose( hFile ); pBuffer = pAllocated; } // Allocate buffer for subsetted font, worst case size is input size unsigned char * outBuff = new unsigned char[lSize]; int outIndex = 0; // unsigned to make comparisons work unsigned const char * inBuff = reinterpret_cast(pBuffer); int inIndex = 0; // 6-Byte binary header for leading ascii-part PODOFO_ASSERT( inBuff[inIndex + 0] == 0x80 ); PODOFO_ASSERT( inBuff[inIndex + 1] == 0x01 ); int length = inBuff[inIndex + 2] + (inBuff[inIndex + 3] << 8) + (inBuff[inIndex + 4] << 16) + (inBuff[inIndex + 5] << 24); // little endian inIndex += 6; PODOFO_ASSERT( memcmp( &inBuff[inIndex], "%!PS-AdobeFont-1.", 17 ) == 0 ); // transfer ascii-part, modify encoding dictionary (dup ...), if present std::string line; bool dupFound = false; for ( i = 0; i < length; i++ ) { line += static_cast( inBuff[inIndex+i] ); if ( inBuff[inIndex+i] == '\r' ) { if ( line.find( "dup " ) != 0 ) { memcpy( &outBuff[outIndex], line.c_str(), line.length() ); outIndex += line.length(); } else { if ( dupFound == false ) { // if first found, replace with new dictionary according to used glyphs // ignore further dup's for ( int i = 0; i < 256; i++ ) { if ( (m_bUsed[i / 32] & (1 << (i % 32 ))) != 0 ) { outIndex += sprintf( reinterpret_cast( &outBuff[outIndex] ), "dup %d /%s put\r", i, PdfDifferenceEncoding::UnicodeIDToName( GetEncoding()->GetCharCode(i) ).GetName().c_str() ); } } dupFound = true; } } #if defined(_MSC_VER) && _MSC_VER <= 1200 // Visual Studio 6 line.erase(); #else line.clear(); #endif } } inIndex += length; lLength1 = outIndex; // 6-Byte binary header for binary-part PODOFO_ASSERT( inBuff[inIndex + 0] == 0x80 ); PODOFO_ASSERT( inBuff[inIndex + 1] == 0x02 ); length = inBuff[inIndex + 2] + (inBuff[inIndex + 3] << 8) + (inBuff[inIndex + 4] << 16) + (inBuff[inIndex + 5] << 24); // little endian inIndex += 6; // copy binary using encrpytion int outIndexStart = outIndex; bool foundSeacGlyph; // if glyph contains seac-command, add the used base-glyphs and loop again do { PdfType1EncryptEexec inCrypt; outIndex = outIndexStart; #if defined(_MSC_VER) && _MSC_VER <= 1200 // Visual Studio 6 line.erase(); #else line.clear(); #endif foundSeacGlyph = false; bool inCharString = false; for ( int i = 0; i < length; ) { unsigned char plain = inCrypt.Decrypt( inBuff[inIndex+i] ); i++; line += static_cast(plain); // output is ssssbuild uncrypted, as parts might be skipped and cipher-engine must be unchanged if ( inCharString && line.find( "/" ) == 0 ) { // we are now inside a glyph, copy anything until RD or -| to output, // in case this glyph will be skipped we go back to saveOutIndex int outIndexSave = outIndex; outBuff[outIndex++] = plain; while ( line.find( "RD " ) == static_cast(-1) && line.find( "-| " ) == static_cast(-1) ) { plain = inCrypt.Decrypt( inBuff[inIndex+i] ); outBuff[outIndex++] = plain; line += static_cast(plain); i++; } // parse line for name and length of glyph char *glyphName = new char[line.length()]; int glyphLen; int result; if ( line.find( "RD " ) != static_cast(-1) ) { result = sscanf( line.c_str(), "%s %d RD ", glyphName, &glyphLen ); } else { result = sscanf( line.c_str(), "%s %d -| ", glyphName, &glyphLen ); } PODOFO_ASSERT( result == 2); bool useGlyph = false; // determine if this glyph is used in normal chars for ( int code = 0; code <= 255; code++ ) { if ( (m_bUsed[code / 32] & (1 << (code % 32 ))) != 0 && strcmp( glyphName+1, PdfDifferenceEncoding::UnicodeIDToName( GetEncoding()->GetCharCode(code) ).GetName().c_str() ) == 0 ) { useGlyph = true; break; } } // determine if this glyph is used in special chars if ( m_sUsedGlyph.find( glyphName+1 ) != m_sUsedGlyph.end() ) useGlyph = true; // always use .notdef if ( strcmp( glyphName, "/.notdef" ) == 0 ) useGlyph = true; // transfer glyph to output for ( int j = 0; j < glyphLen; j++, i++ ) outBuff[outIndex++] = inCrypt.Decrypt( inBuff[inIndex+i] ); // check used glyph for seac-command if ( useGlyph && FindSeac( &outBuff[outIndex - glyphLen], glyphLen ) ) foundSeacGlyph = true; delete[] glyphName; // transfer rest until end of line to output do { plain = inCrypt.Decrypt( inBuff[inIndex+i] ); outBuff[outIndex++] = plain; line += static_cast(plain); i++; } while ( plain != '\r' && plain != '\n' ); if ( useGlyph == false ) { // glyph is not used, go back to saved position outIndex = outIndexSave; } } else { // copy anything outside glyph to output outBuff[outIndex++] = plain; } if ( plain == '\r' || plain == '\n' ) { // parse for /CharStrings = begin of glyphs if ( line.find( "/CharStrings" ) != static_cast(-1) ) inCharString = true; #if defined(_MSC_VER) && _MSC_VER <= 1200 // Visual Studio 6 line.erase(); #else line.clear(); #endif } } } while ( foundSeacGlyph ); // now encrypt resulting output-buffer PdfType1EncryptEexec outCrypt; for ( i = outIndexStart; i < outIndex; i++ ) outBuff[i] = outCrypt.Encrypt( outBuff[i] ); lLength2 = outIndex - outIndexStart; inIndex += length; // 6-Byte binary header for ascii-part PODOFO_ASSERT( inBuff[inIndex + 0] == 0x80 ); PODOFO_ASSERT( inBuff[inIndex + 1] == 0x01 ); length = inBuff[inIndex + 2] + (inBuff[inIndex + 3] << 8) + (inBuff[inIndex + 4] << 16) + (inBuff[inIndex + 5] << 24); // little endian inIndex += 6; // copy ascii memcpy( &outBuff[outIndex], &inBuff[inIndex], length ); lLength3 = length; inIndex += length; outIndex += length; // now embed pContents->GetStream()->Set( reinterpret_cast(outBuff), outIndex ); // cleanup memory if( pAllocated ) podofo_free( pAllocated ); delete[] outBuff; // enter length in dictionary pContents->GetDictionary().AddKey( "Length1", PdfVariant( lLength1 ) ); pContents->GetDictionary().AddKey( "Length2", PdfVariant( lLength2 ) ); pContents->GetDictionary().AddKey( "Length3", PdfVariant( lLength3 ) ); } void PdfFontType1::EmbedFontFile( PdfObject* pDescriptor ) { pdf_long lSize = 0; pdf_int64 lLength1 = 0L; pdf_int64 lLength2 = 0L; pdf_int64 lLength3 = 0L; PdfObject* pContents; const char* pBuffer; char* pAllocated = NULL; if (m_isBase14) { m_bWasEmbedded = false; return; } m_bWasEmbedded = true; pContents = this->GetObject()->GetOwner()->CreateObject(); if( !pContents ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } pDescriptor->GetDictionary().AddKey( "FontFile", pContents->Reference() ); // if the data was loaded from memory - use it from there // otherwise, load from disk if ( m_pMetrics->GetFontDataLen() && m_pMetrics->GetFontData() ) { pBuffer = m_pMetrics->GetFontData(); lSize = m_pMetrics->GetFontDataLen(); } else { FILE* hFile = fopen( m_pMetrics->GetFilename(), "rb" ); if( !hFile ) { PODOFO_RAISE_ERROR_INFO( ePdfError_FileNotFound, m_pMetrics->GetFilename() ); } if( fseeko( hFile, 0L, SEEK_END ) == -1 ) { fclose( hFile ); PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to seek to the end of the file" ); } lSize = ftello( hFile ); if( lSize == -1 ) { fclose( hFile ); PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to read size of the file" ); } if( fseeko( hFile, 0L, SEEK_SET ) == -1 ) { fclose( hFile ); PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to seek to the beginning of the file" ); } pAllocated = static_cast(podofo_calloc( lSize, sizeof(char) )); if( !pAllocated ) { fclose( hFile ); PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } if( static_cast( fread( pAllocated, sizeof( char ), lSize, hFile ) ) != lSize ) { podofo_free( pAllocated ); fclose( hFile ); PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to read whole file into the memory" ); } fclose( hFile ); pBuffer = pAllocated; } // Remove binary segment headers from pfb unsigned char *pBinary = reinterpret_cast(const_cast(pBuffer)); while( *pBinary == 0x80 ) // binary segment header { const int cHeaderLength = 6; int iSegmentType = pBinary[1]; // binary segment type long lSegmentLength = 0L; long lSegmentDelta = static_cast(&pBuffer[lSize] - reinterpret_cast(pBinary) ); switch( iSegmentType ) { case 1: // ASCII text lSegmentLength = pBinary[2] + // little endian pBinary[3] * 256L + pBinary[4] * 65536L + pBinary[5] * 16777216L; if( lLength1 == 0L ) lLength1 = lSegmentLength; else lLength3 = lSegmentLength; lSize -= cHeaderLength; memmove( pBinary, &pBinary[cHeaderLength], lSegmentDelta - cHeaderLength ); pBinary = &pBinary[lSegmentLength]; break; case 2: // binary data lSegmentLength = pBinary[2] + // little endian pBinary[3] * 256L + pBinary[4] * 65536L + pBinary[5] * 16777216L; lLength2 = lSegmentLength; lSize -= cHeaderLength; memmove( pBinary, &pBinary[cHeaderLength], lSegmentDelta - cHeaderLength ); pBinary = &pBinary[lSegmentLength]; break; case 3: // end-of-file // First set pContents keys before writing stream, so that PdfTFontType1 works with streamed document pContents->GetDictionary().AddKey( "Length1", PdfVariant( lLength1 ) ); pContents->GetDictionary().AddKey( "Length2", PdfVariant( lLength2 ) ); pContents->GetDictionary().AddKey( "Length3", PdfVariant( lLength3 ) ); pContents->GetStream()->Set( pBuffer, lSize - 2L ); if( pAllocated ) podofo_free( pAllocated ); return; default: break; } } // Parse the font data buffer to get the values for length1, length2 and length3 lLength1 = FindInBuffer( "eexec", pBuffer, lSize ); if( lLength1 > 0 ) lLength1 += 6; // 6 == eexec + lf else lLength1 = 0; if( lLength1 ) { lLength2 = FindInBuffer( "cleartomark", pBuffer, lSize ); if( lLength2 > 0 ) lLength2 = lSize - lLength1 - 520; // 520 == 512 + strlen(cleartomark) else lLength1 = 0; } lLength3 = lSize - lLength2 - lLength1; // TODO: Pdf Supports only Type1 fonts with binary encrypted sections and not the hex format pContents->GetStream()->Set( pBuffer, lSize ); if( pAllocated ) podofo_free( pAllocated ); pContents->GetDictionary().AddKey( "Length1", PdfVariant( lLength1 ) ); pContents->GetDictionary().AddKey( "Length2", PdfVariant( lLength2 ) ); pContents->GetDictionary().AddKey( "Length3", PdfVariant( lLength3 ) ); } bool PdfFontType1::FindSeac( const unsigned char * buffer, int length ) { PdfType1EncryptCharstring crypt; const PdfEncoding * stdEncoding = PdfEncodingFactory::GlobalStandardEncodingInstance(); bool foundNewGlyph = false; int code1 = 0; int code2 = 0; for ( int j = 0; j < length; ) { unsigned char plain = crypt.Decrypt( buffer[j++] ); if ( j <= 4 ) { // skip first 4 bytes } else if ( plain < 32 ) { // decode commands switch ( plain ) { case 1: // hstem case 3: // vstem case 4: // rmoveto case 5: // rlineto case 6: // hlineto case 7: // vlineto case 8: // rrcurveto case 9: // closepath case 10: // callsubr case 11: // return break; case 12: // escape { plain = crypt.Decrypt( buffer[j++] ); switch ( plain ) { case 0: // dotsection case 1: // vstem3 case 2: // hstem3 break; case 6: // seac { // found seac command, use acquired code1 and code2 to get glyphname in standard-encoding std::string name; name = PdfDifferenceEncoding::UnicodeIDToName( stdEncoding->GetCharCode(code1) ).GetName().c_str(); if ( m_sUsedGlyph.find( name ) == m_sUsedGlyph.end() ) { // add new glyph m_sUsedGlyph.insert( name ); foundNewGlyph = true; } name = PdfDifferenceEncoding::UnicodeIDToName( stdEncoding->GetCharCode(code2) ).GetName().c_str(); if ( m_sUsedGlyph.find( name ) == m_sUsedGlyph.end() ) { // add new glyph m_sUsedGlyph.insert( name ); foundNewGlyph = true; } } break; case 7: // sbw case 12: // div case 16: // callothersubr case 17: // pop case 33: // setcurrentpoint break; default: // ??? break; } } break; case 13: // hsbw case 14: // endchar case 21: // rmoveto case 22: // hmoveto case 30: // vhcurveto case 31: // hcurveto break; default: // ??? break; } } else if ( plain >= 32 ) // && plain <= 255 ) { // this is a number int number = 0; if ( plain >= 32 && plain <= 246 ) { number = static_cast(plain-139); } else if ( plain >= 247 && plain <= 250 ) { unsigned char next = crypt.Decrypt( buffer[j++] ); number = (static_cast(plain)-247)*256 + next + 108; } else if ( plain >= 251 && plain <= 254 ) { unsigned char next = crypt.Decrypt( buffer[j++] ); number = -((static_cast(plain)-251)*256) - next - 108; } else if ( plain == 255 ) { unsigned char next1 = crypt.Decrypt( buffer[j++] ); unsigned char next2 = crypt.Decrypt( buffer[j++] ); unsigned char next3 = crypt.Decrypt( buffer[j++] ); unsigned char next4 = crypt.Decrypt( buffer[j++] ); number = (static_cast(next1) << 24) + (static_cast(next2) << 16) + (static_cast(next3) << 8) + next4 ; } char num[32]; sprintf( num, "%d ", number ); code1 = code2; code2 = number; } } return foundNewGlyph; } pdf_long PdfFontType1::FindInBuffer( const char* pszNeedle, const char* pszHaystack, pdf_long lLen ) const { // if lNeedleLen is 0 the while loop will not be executed and we return -1 pdf_long lNeedleLen = pszNeedle ? strlen( pszNeedle ) : 0; const char* pszEnd = pszHaystack + lLen - lNeedleLen; const char* pszStart = pszHaystack; if ( pszNeedle ) { while( pszHaystack < pszEnd ) { if( strncmp( pszHaystack, pszNeedle, lNeedleLen ) == 0 ) return pszHaystack - pszStart; ++pszHaystack; } } return -1; } PdfType1EncryptEexec::PdfType1EncryptEexec() : PdfType1Encrypt() { m_r = 55665; } PdfType1EncryptCharstring::PdfType1EncryptCharstring() : PdfType1Encrypt() { m_r = 4330; } PdfType1Encrypt::PdfType1Encrypt() : m_r( -1 ) // will be initialized in subclasses with real value { m_c1 = 52845; m_c2 = 22719; } unsigned char PdfType1Encrypt::Encrypt( unsigned char plain ) { unsigned char cipher; cipher = (plain ^ (m_r >> 8)); m_r = ((cipher + m_r) * m_c1 + m_c2) & ((1<<16) -1); return cipher; } unsigned char PdfType1Encrypt::Decrypt( unsigned char cipher ) { unsigned char plain; plain = (cipher ^ (m_r >> 8)); m_r = (cipher + m_r) * m_c1 + m_c2; return plain; } }; podofo-0.9.5/src/doc/PdfAnnotation.cpp0000664000175000017500000003404513016622723017477 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfAnnotation.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfDictionary.h" #include "base/PdfDate.h" #include "PdfAction.h" #include "PdfFileSpec.h" #include "PdfPage.h" #include "base/PdfRect.h" #include "base/PdfVariant.h" #include "PdfXObject.h" namespace PoDoFo { const long PdfAnnotation::s_lNumActions = 27; const char* PdfAnnotation::s_names[] = { "Text", // - supported "Link", "FreeText", // PDF 1.3 // - supported "Line", // PDF 1.3 // - supported "Square", // PDF 1.3 "Circle", // PDF 1.3 "Polygon", // PDF 1.5 "PolyLine", // PDF 1.5 "Highlight", // PDF 1.3 "Underline", // PDF 1.3 "Squiggly", // PDF 1.4 "StrikeOut", // PDF 1.3 "Stamp", // PDF 1.3 "Caret", // PDF 1.5 "Ink", // PDF 1.3 "Popup", // PDF 1.3 "FileAttachment", // PDF 1.3 "Sound", // PDF 1.2 "Movie", // PDF 1.2 "Widget", // PDF 1.2 // - supported "Screen", // PDF 1.5 "PrinterMark", // PDF 1.4 "TrapNet", // PDF 1.3 "Watermark", // PDF 1.6 "3D", // PDF 1.6 "RichMedia", // PDF 1.7 ADBE ExtensionLevel 3 ALX: Petr P. Petrov "WebMedia", // PDF 1.7 IPDF ExtensionLevel 1 NULL }; PdfAnnotation::PdfAnnotation( PdfPage* pPage, EPdfAnnotation eAnnot, const PdfRect & rRect, PdfVecObjects* pParent ) : PdfElement( "Annot", pParent ), m_eAnnotation( eAnnot ), m_pAction( NULL ), m_pFileSpec( NULL ), m_pPage( pPage ) { PdfVariant rect; PdfDate date; PdfString sDate; const PdfName name( TypeNameForIndex( eAnnot, s_names, s_lNumActions ) ); if( !name.GetLength() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } rRect.ToVariant( rect ); this->GetObject()->GetDictionary().AddKey( PdfName::KeyRect, rect ); rRect.ToVariant( rect ); date.ToString( sDate ); this->GetObject()->GetDictionary().AddKey( PdfName::KeySubtype, name ); this->GetObject()->GetDictionary().AddKey( PdfName::KeyRect, rect ); this->GetObject()->GetDictionary().AddKey( "P", pPage->GetObject()->Reference() ); this->GetObject()->GetDictionary().AddKey( "M", sDate ); } PdfAnnotation::PdfAnnotation( PdfObject* pObject, PdfPage* pPage ) : PdfElement( "Annot", pObject ), m_eAnnotation( ePdfAnnotation_Unknown ), m_pAction( NULL ), m_pFileSpec( NULL ), m_pPage( pPage ) { m_eAnnotation = static_cast(TypeNameToIndex( this->GetObject()->GetDictionary().GetKeyAsName( PdfName::KeySubtype ).GetName().c_str(), s_names, s_lNumActions, ePdfAnnotation_Unknown )); } PdfAnnotation::~PdfAnnotation() { delete m_pAction; delete m_pFileSpec; } PdfRect PdfAnnotation::GetRect() const { if( this->GetObject()->GetDictionary().HasKey( PdfName::KeyRect ) ) return PdfRect( this->GetObject()->GetDictionary().GetKey( PdfName::KeyRect )->GetArray() ); return PdfRect(); } void SetAppearanceStreamForObject( PdfObject* pForObject, PdfXObject* pObject, EPdfAnnotationAppearance eAppearance, const PdfName & state ) { PdfDictionary dict; PdfDictionary internal; PdfName name; if( !pForObject || !pObject ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if( eAppearance == ePdfAnnotationAppearance_Rollover ) { name = "R"; } else if( eAppearance == ePdfAnnotationAppearance_Down ) { name = "D"; } else // ePdfAnnotationAppearance_Normal { name = "N"; } if( pForObject->GetDictionary().HasKey( "AP" ) ) { PdfObject* objAP = pForObject->GetDictionary().GetKey( "AP" ); if( objAP->GetDataType() == ePdfDataType_Reference ) { if( !objAP->GetOwner() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } objAP = objAP->GetOwner()->GetObject( objAP->GetReference() ); if( !objAP ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } } if( objAP->GetDataType() != ePdfDataType_Dictionary ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } if( !state.GetLength() ) { // allow overwrite only reference by a reference if( objAP->GetDictionary().HasKey( name ) && objAP->GetDictionary().GetKey( name )->GetDataType() != ePdfDataType_Reference ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } objAP->GetDictionary().AddKey( name, pObject->GetObject()->Reference() ); } else { // when the state is defined, then the appearance is expected to be a dictionary if( objAP->GetDictionary().HasKey( name ) && objAP->GetDictionary().GetKey( name )->GetDataType() != ePdfDataType_Dictionary ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } if( objAP->GetDictionary().HasKey( name ) ) { objAP->GetDictionary().GetKey( name )->GetDictionary().AddKey( state, pObject->GetObject()->Reference() ); } else { internal.AddKey( state, pObject->GetObject()->Reference() ); objAP->GetDictionary().AddKey( name, internal ); } } } else { if( !state.GetLength() ) { dict.AddKey( name, pObject->GetObject()->Reference() ); pForObject->GetDictionary().AddKey( "AP", dict ); } else { internal.AddKey( state, pObject->GetObject()->Reference() ); dict.AddKey( name, internal ); pForObject->GetDictionary().AddKey( "AP", dict ); } } if( state.GetLength() ) { if( !pForObject->GetDictionary().HasKey( "AS" ) ) { pForObject->GetDictionary().AddKey( "AS", state ); } } } void PdfAnnotation::SetAppearanceStream( PdfXObject* pObject, EPdfAnnotationAppearance eAppearance, const PdfName & state ) { SetAppearanceStreamForObject( this->GetObject(), pObject, eAppearance, state ); } bool PdfAnnotation::HasAppearanceStream() const { return this->GetObject()->GetDictionary().HasKey( "AP" ); } void PdfAnnotation::SetFlags( pdf_uint32 uiFlags ) { this->GetObject()->GetDictionary().AddKey( "F", PdfVariant( static_cast(uiFlags) ) ); } pdf_uint32 PdfAnnotation::GetFlags() const { if( this->GetObject()->GetDictionary().HasKey( "F" ) ) return static_cast(this->GetObject()->GetDictionary().GetKey( "F" )->GetNumber()); return static_cast(0); } void PdfAnnotation::SetBorderStyle( double dHCorner, double dVCorner, double dWidth ) { this->SetBorderStyle( dHCorner, dVCorner, dWidth, PdfArray() ); } void PdfAnnotation::SetBorderStyle( double dHCorner, double dVCorner, double dWidth, const PdfArray & rStrokeStyle ) { // TODO : Support for Border style for PDF Vers > 1.0 PdfArray aValues; aValues.push_back(dHCorner); aValues.push_back(dVCorner); aValues.push_back(dWidth); if( rStrokeStyle.size() ) aValues.push_back(rStrokeStyle); this->GetObject()->GetDictionary().AddKey( "Border", aValues ); } void PdfAnnotation::SetTitle( const PdfString & sTitle ) { this->GetObject()->GetDictionary().AddKey( "T", sTitle ); } PdfString PdfAnnotation::GetTitle() const { if( this->GetObject()->GetDictionary().HasKey( "T" ) ) return this->GetObject()->GetDictionary().GetKey( "T" )->GetString(); return PdfString(); } void PdfAnnotation::SetContents( const PdfString & sContents ) { this->GetObject()->GetDictionary().AddKey( "Contents", sContents ); } PdfString PdfAnnotation::GetContents() const { if( this->GetObject()->GetDictionary().HasKey( "Contents" ) ) return this->GetObject()->GetDictionary().GetKey( "Contents" )->GetString(); return PdfString(); } void PdfAnnotation::SetDestination( const PdfDestination & rDestination ) { rDestination.AddToDictionary( this->GetObject()->GetDictionary() ); } PdfDestination PdfAnnotation::GetDestination( PdfDocument* pDoc ) const { return PdfDestination( this->GetNonConstObject()->GetDictionary().GetKey( "Dest" ), pDoc ); } bool PdfAnnotation::HasDestination() const { return this->GetObject()->GetDictionary().HasKey( "Dest" ); } void PdfAnnotation::SetAction( const PdfAction & rAction ) { if( m_pAction ) delete m_pAction; m_pAction = new PdfAction( rAction ); this->GetObject()->GetDictionary().AddKey( "A", m_pAction->GetObject()->Reference() ); } PdfAction* PdfAnnotation::GetAction() const { if( !m_pAction && HasAction() ) const_cast(this)->m_pAction = new PdfAction( this->GetObject()->GetIndirectKey( "A" ) ); return m_pAction; } bool PdfAnnotation::HasAction() const { return this->GetObject()->GetDictionary().HasKey( "A" ); } void PdfAnnotation::SetOpen( bool b ) { this->GetObject()->GetDictionary().AddKey( "Open", b ); } bool PdfAnnotation::GetOpen() const { if( this->GetObject()->GetDictionary().HasKey( "Open" ) ) return this->GetObject()->GetDictionary().GetKey( "Open" )->GetBool(); return false; } bool PdfAnnotation::HasFileAttachement() const { return this->GetObject()->GetDictionary().HasKey( "FS" ); } void PdfAnnotation::SetFileAttachement( const PdfFileSpec & rFileSpec ) { if( m_pFileSpec ) delete m_pFileSpec; m_pFileSpec = new PdfFileSpec( rFileSpec ); this->GetObject()->GetDictionary().AddKey( "FS", m_pFileSpec->GetObject()->Reference() ); } PdfFileSpec* PdfAnnotation::GetFileAttachement() const { if( !m_pFileSpec && HasFileAttachement() ) const_cast(this)->m_pFileSpec = new PdfFileSpec( this->GetObject()->GetIndirectKey( "FS" ) ); return m_pFileSpec; } PdfArray PdfAnnotation::GetQuadPoints() const { if( this->GetObject()->GetDictionary().HasKey( "QuadPoints" ) ) return PdfArray( this->GetObject()->GetDictionary().GetKey( "QuadPoints" )->GetArray() ); return PdfArray(); } void PdfAnnotation::SetQuadPoints( const PdfArray & rQuadPoints ) { if ( m_eAnnotation != ePdfAnnotation_Highlight && m_eAnnotation != ePdfAnnotation_Underline && m_eAnnotation != ePdfAnnotation_Squiggly && m_eAnnotation != ePdfAnnotation_StrikeOut ) PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Must be a text markup annotation (hilight, underline, squiggly or strikeout) to set quad points" ); this->GetObject()->GetDictionary().AddKey( "QuadPoints", rQuadPoints ); } PdfArray PdfAnnotation::GetColor() const { if( this->GetObject()->GetDictionary().HasKey( "C" ) ) return PdfArray( this->GetObject()->GetDictionary().GetKey( "C" )->GetArray() ); return PdfArray(); } void PdfAnnotation::SetColor( double r, double g, double b ) { PdfArray c; c.push_back( PdfVariant( r ) ); c.push_back( PdfVariant( g ) ); c.push_back( PdfVariant( b ) ); this->GetObject()->GetDictionary().AddKey( "C", c ); } void PdfAnnotation::SetColor( double C, double M, double Y, double K ) { PdfArray c; c.push_back( PdfVariant( C ) ); c.push_back( PdfVariant( M ) ); c.push_back( PdfVariant( Y ) ); c.push_back( PdfVariant( K ) ); this->GetObject()->GetDictionary().AddKey( "C", c ); } void PdfAnnotation::SetColor( double gray ) { PdfArray c; c.push_back( PdfVariant( gray ) ); this->GetObject()->GetDictionary().AddKey( "C", c ); } void PdfAnnotation::SetColor() { PdfArray c; this->GetObject()->GetDictionary().AddKey( "C", c ); } }; podofo-0.9.5/src/doc/PdfContents.cpp0000664000175000017500000001141112344436402017152 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfContents.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfDictionary.h" #include "base/PdfName.h" #include "base/PdfOutputDevice.h" #include "PdfDocument.h" #include "PdfPage.h" #include namespace PoDoFo { PdfContents::PdfContents( PdfDocument* pParent ) : PdfElement( NULL, pParent ) { mContObj = this->GetObject(); } PdfContents::PdfContents( PdfVecObjects* pParent ) : PdfElement( NULL, pParent ) { mContObj = this->GetObject(); } PdfContents::PdfContents( PdfObject* inObj ) // A PdfElement expects normally a dictionary // But we may get here, a reference, a dictionary // or an array. Therefore, tell PdfElement // that we also want to accept the datatype of // the object we send in. : PdfElement( inObj->GetDataType(), inObj ) { if ( this->GetObject()->GetDataType() == ePdfDataType_Reference ) mContObj = inObj->GetOwner()->GetObject( this->GetObject()->GetReference() ); else mContObj = this->GetObject(); } PdfContents::PdfContents( PdfPage* pParent ) : PdfElement( NULL, pParent->GetObject()->GetOwner() ) { // TODO: Maybe create this only on demand pParent->GetObject()->GetDictionary().AddKey( "Contents", this->GetObject()->Reference() ); mContObj = this->GetObject(); } PdfObject* PdfContents::GetContentsForAppending() const { // if ( mContObj->GetDataType() == ePdfDataType_Stream || // mContObj->GetDataType() == ePdfDataType_Dictionary ) { // Use PdfObject::HasStream() instead of the datatype ePdfDataType_Stream // as large parts of the code rely on all PdfObjects having the datatype // ePdfDataType_Dictionary wether they have a stream or not if( mContObj->GetDataType() == ePdfDataType_Dictionary ) { return mContObj; // just return the stream itself } else if ( mContObj->GetDataType() == ePdfDataType_Array ) { /* Create a new stream, add it to the array, return it */ PdfObject* newStm = mContObj->GetOwner()->CreateObject(); newStm->GetStream(); PdfReference pdfr( newStm->Reference().ObjectNumber(), newStm->Reference().GenerationNumber() ); PdfArray& cArr = mContObj->GetArray(); cArr.push_back( pdfr ); return newStm; } else { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } } }; podofo-0.9.5/src/doc/PdfTilingPattern.cpp0000664000175000017500000002267112365216543020160 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "PdfTilingPattern.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfColor.h" #include "base/PdfDictionary.h" #include "base/PdfLocale.h" #include "base/PdfRect.h" #include "base/PdfStream.h" #include "base/PdfWriter.h" #include "PdfFunction.h" #include "PdfImage.h" #include #include #include namespace PoDoFo { PdfTilingPattern::PdfTilingPattern( EPdfTilingPatternType eTilingType, double strokeR, double strokeG, double strokeB, bool doFill, double fillR, double fillG, double fillB, double offsetX, double offsetY, PdfImage *pImage, PdfVecObjects* pParent) : PdfElement( "Pattern", pParent ) { std::ostringstream out; // We probably aren't doing anything locale sensitive here, but it's // best to be sure. PdfLocaleImbue(out); // Implementation note: the identifier is always // Prefix+ObjectNo. Prefix is /Ft for fonts. out << "Ptrn" << this->GetObject()->Reference().ObjectNumber(); m_Identifier = PdfName( out.str().c_str() ); this->Init( eTilingType, strokeR, strokeG, strokeB, doFill, fillR, fillG, fillB, offsetX, offsetY, pImage); } PdfTilingPattern::PdfTilingPattern( EPdfTilingPatternType eTilingType, double strokeR, double strokeG, double strokeB, bool doFill, double fillR, double fillG, double fillB, double offsetX, double offsetY, PdfImage *pImage, PdfDocument* pParent) : PdfElement( "Pattern", pParent ) { std::ostringstream out; // We probably aren't doing anything locale sensitive here, but it's // best to be sure. PdfLocaleImbue(out); // Implementation note: the identifier is always // Prefix+ObjectNo. Prefix is /Ft for fonts. out << "Ptrn" << this->GetObject()->Reference().ObjectNumber(); m_Identifier = PdfName( out.str().c_str() ); this->Init( eTilingType, strokeR, strokeG, strokeB, doFill, fillR, fillG, fillB, offsetX, offsetY, pImage); } PdfTilingPattern::~PdfTilingPattern() { } void PdfTilingPattern::AddToResources(const PdfName &rIdentifier, const PdfReference &rRef, const PdfName &rName) { PdfObject* pResource = GetObject()->GetDictionary().GetKey( "Resources" ); if( !pResource ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if( !pResource->GetDictionary().HasKey( rName ) ) { pResource->GetDictionary().AddKey( rName, PdfDictionary() ); } if (ePdfDataType_Reference == pResource->GetDictionary().GetKey( rName )->GetDataType()) { PdfObject *directObject = pResource->GetOwner()->GetObject(pResource->GetDictionary().GetKey( rName )->GetReference()); if (0 == directObject) { PODOFO_RAISE_ERROR( ePdfError_NoObject ); } if( !directObject->GetDictionary().HasKey( rIdentifier ) ) directObject->GetDictionary().AddKey( rIdentifier, rRef ); }else { if( !pResource->GetDictionary().GetKey( rName )->GetDictionary().HasKey( rIdentifier ) ) pResource->GetDictionary().GetKey( rName )->GetDictionary().AddKey( rIdentifier, rRef ); } } void PdfTilingPattern::Init( EPdfTilingPatternType eTilingType, double strokeR, double strokeG, double strokeB, bool doFill, double fillR, double fillG, double fillB, double offsetX, double offsetY, PdfImage *pImage) { if (eTilingType == ePdfTilingPatternType_Image && pImage == NULL) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if (eTilingType != ePdfTilingPatternType_Image && pImage != NULL) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } PdfRect rRect; rRect.SetLeft(0); rRect.SetBottom(0); if (pImage) { rRect.SetWidth(pImage->GetWidth()); rRect.SetHeight(-pImage->GetHeight()); } else { rRect.SetWidth(8); rRect.SetHeight(8); } PdfVariant var; rRect.ToVariant( var ); this->GetObject()->GetDictionary().AddKey( PdfName("PatternType"), static_cast(1L) ); // Tiling pattern this->GetObject()->GetDictionary().AddKey( PdfName("PaintType"), static_cast(1L) ); // Colored this->GetObject()->GetDictionary().AddKey( PdfName("TilingType"), static_cast(1L) ); // Constant spacing this->GetObject()->GetDictionary().AddKey( PdfName("BBox"), var ); this->GetObject()->GetDictionary().AddKey( PdfName("XStep"), static_cast(rRect.GetWidth()) ); this->GetObject()->GetDictionary().AddKey( PdfName("YStep"), static_cast(rRect.GetHeight()) ); this->GetObject()->GetDictionary().AddKey( PdfName("Resources"), PdfObject( PdfDictionary() ) ); if (offsetX < -1e-9 || offsetX > 1e-9 || offsetY < -1e-9 || offsetY > 1e-9) { PdfArray array; array.push_back (static_cast(1)); array.push_back (static_cast(0)); array.push_back (static_cast(0)); array.push_back (static_cast(1)); array.push_back (offsetX); array.push_back (offsetY); this->GetObject()->GetDictionary().AddKey( PdfName("Matrix"), array ); } std::ostringstream out; out.flags( std::ios_base::fixed ); out.precision( 1L /* clPainterDefaultPrecision */ ); PdfLocaleImbue(out); if (pImage) { AddToResources(pImage->GetIdentifier(), pImage->GetObjectReference(), PdfName("XObject")); out << rRect.GetWidth() << " 0 0 " << rRect.GetHeight() << " " << rRect.GetLeft() << " " << rRect.GetBottom() << " cm" << std::endl; out << "/" << pImage->GetIdentifier().GetName() << " Do" << std::endl; } else { if (doFill) { out << fillR << " " << fillG << " " << fillB << " rg" << " "; out << rRect.GetLeft() << " " << rRect.GetBottom() << " " << rRect.GetWidth() << " " << rRect.GetHeight() << " re" << " "; out << "f" << " "; //fill rect } out << strokeR << " " << strokeG << " " << strokeB << " RG" << " "; out << "2 J" << " "; // line capability style out << "0.5 w" << " "; //line width double left, bottom, right, top, whalf, hhalf; left = rRect.GetLeft(); bottom = rRect.GetBottom(); right = left + rRect.GetWidth(); top = bottom + rRect.GetHeight(); whalf = rRect.GetWidth() / 2; hhalf = rRect.GetHeight() / 2; switch (eTilingType) { case ePdfTilingPatternType_BDiagonal: out << left << " " << bottom << " m " << right << " " << top << " l "; out << left - whalf << " " << top - hhalf << " m " << left + whalf << " " << top + hhalf << " l "; out << right - whalf << " " << bottom - hhalf << " m " << right + whalf << " " << bottom + hhalf << " l" << std::endl; break; case ePdfTilingPatternType_Cross: out << left << " " << bottom + hhalf << " m " << right << " " << bottom + hhalf << " l "; out << left + whalf << " " << bottom << " m " << left + whalf << " " << top << " l" << std::endl; break; case ePdfTilingPatternType_DiagCross: out << left << " " << bottom << " m " << right << " " << top << " l "; out << left << " " << top << " m " << right << " " << bottom << " l" << std::endl; break; case ePdfTilingPatternType_FDiagonal: out << left << " " << top << " m " << right << " " << bottom << " l "; out << left - whalf << " " << bottom + hhalf << " m " << left + whalf << " " << bottom - hhalf << " l "; out << right - whalf << " " << top + hhalf << " m " << right + whalf << " " << top - hhalf << " l" << std::endl; break; case ePdfTilingPatternType_Horizontal: out << left << " " << bottom + hhalf << " m " << right << " " << bottom + hhalf << " l "; break; case ePdfTilingPatternType_Vertical: out << left + whalf << " " << bottom << " m " << left + whalf << " " << top << " l" << std::endl; break; case ePdfTilingPatternType_Image: /* This is handled above, based on the 'pImage' variable */ default: PODOFO_RAISE_ERROR (ePdfError_InvalidEnumValue); break; } out << "S"; //stroke path } TVecFilters vecFlate; vecFlate.push_back( ePdfFilter_FlateDecode ); std::string str = out.str(); PdfMemoryInputStream stream(str.c_str(), str.length()); this->GetObject()->GetStream()->Set(&stream, vecFlate); } } // end namespace podofo-0.9.5/src/doc/PdfSignatureField.h0000664000175000017500000001376213035003404017730 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2011 by Dominik Seichter * * domseichter@web.de * * by Petr Pytelka * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_SIGNATURE_FIELD_H_ #define _PDF_SIGNATURE_FIELD_H_ #include "PdfAnnotation.h" #include "PdfField.h" #include "podofo/base/PdfDate.h" namespace PoDoFo { /** Signature field */ class PODOFO_DOC_API PdfSignatureField :public PdfField { protected: PdfObject* m_pSignatureObj; void Init(); public: typedef enum { ePdfCertPermission_NoPerms = 1, ePdfCertPermission_FormFill = 2, ePdfCertPermission_Annotations = 3, } EPdfCertPermission; /** Create a new PdfSignatureField */ PdfSignatureField( PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc ); /** Create a new PdfSignatureField * \param bInit creates a signature field with/without a /V key */ PdfSignatureField( PdfAnnotation* pWidget, PdfAcroForm* pParent, PdfDocument* pDoc, bool bInit = true); /** Creates a PdfSignatureField from an existing PdfAnnotation, which should * be an annotation with a field type Sig. * \param pWidget the annotation to create from */ PdfSignatureField( PdfAnnotation* pWidget ); /** Set an appearance stream for this signature field * to specify its visual appearance * \param pObject an XObject * \param eAppearance an appearance type to set * \param state the state for which set it the pObject; states depend on the annotation type */ void SetAppearanceStream(PdfXObject *pObject, EPdfAnnotationAppearance eAppearance = ePdfAnnotationAppearance_Normal, const PdfName & state = "" ); /** Create space for signature * * \param signatureData String used to locate reserved space for signature. * This string will be replaiced with signature. * * Structure of the PDF file - before signing: * < * Have to be replaiced with the following structure: * < */ void SetSignature(const PdfData &signatureData); /** Set reason of the signature * * \param rsText the reason of signature */ void SetSignatureReason(const PdfString & rsText); /** Set location of the signature * * \param rsText the location of signature */ void SetSignatureLocation(const PdfString & rsText); /** Set the creator of the signature * * \param creator the creator of the signature */ void SetSignatureCreator( const PdfName & creator ); /** Date of signature */ void SetSignatureDate(const PdfDate &sigDate); /** Add certification dictionaries and references to document catalog. * * \param pDocumentCatalog the catalog of current document * \param perm document modification permission */ void AddCertificationReference(PdfObject *pDocumentCatalog, EPdfCertPermission perm = ePdfCertPermission_NoPerms); /** Returns signature object for this signature field. * It can be NULL, when the signature field was created * from an existing annotation and it didn't have set it. * * \returns associated signature object, or NULL */ PdfObject* GetSignatureObject( void ) const; /** Ensures that the signature field has set a signature object. * The function does nothing, if the signature object is already * set. This is useful for cases when the signature field had been * created from an existing annotation, which didn't have it set. */ void EnsureSignatureObject( void ); }; } #endif podofo-0.9.5/src/doc/PdfInfo.cpp0000664000175000017500000001246412347314126016262 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfInfo.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfDate.h" #include "base/PdfDictionary.h" #include "base/PdfString.h" #define PRODUCER_STRING "PoDoFo - http:/" "/podofo.sf.net" namespace PoDoFo { PdfInfo::PdfInfo( PdfVecObjects* pParent, int eInitial ) : PdfElement( NULL, pParent ) { Init( eInitial ); } PdfInfo::PdfInfo( PdfObject* pObject, int eInitial ) : PdfElement( NULL, pObject ) { Init( eInitial ); } PdfInfo::~PdfInfo() { } void PdfInfo::Init( int eInitial ) { PdfDate date; PdfString str; date.ToString( str ); if( (eInitial & ePdfInfoInitial_WriteCreationTime) == ePdfInfoInitial_WriteCreationTime ) { this->GetObject()->GetDictionary().AddKey( "CreationDate", str ); } if( (eInitial & ePdfInfoInitial_WriteModificationTime) == ePdfInfoInitial_WriteModificationTime ) { this->GetObject()->GetDictionary().AddKey( "ModDate", str ); } if( (eInitial & ePdfInfoInitial_WriteProducer) == ePdfInfoInitial_WriteProducer ) { this->GetObject()->GetDictionary().AddKey( "Producer", PdfString(PRODUCER_STRING) ); } } const PdfString & PdfInfo::GetStringFromInfoDict( const PdfName & rName ) const { const PdfObject* pObj = this->GetObject()->GetDictionary().GetKey( rName ); return pObj && (pObj->IsString() || pObj->IsHexString()) ? pObj->GetString() : PdfString::StringNull; } const PdfName & PdfInfo::GetNameFromInfoDict(const PdfName & rName) const { const PdfObject* pObj = this->GetObject()->GetDictionary().GetKey( rName ); return pObj && pObj->IsName() ? pObj->GetName() : PdfName::KeyNull; } void PdfInfo::SetCustomKey(const PdfName &sName, const PdfString &sValue) { this->GetObject()->GetDictionary().AddKey( sName, sValue ); } void PdfInfo::SetAuthor( const PdfString & sAuthor ) { this->GetObject()->GetDictionary().AddKey( "Author", sAuthor ); } void PdfInfo::SetCreator( const PdfString & sCreator ) { this->GetObject()->GetDictionary().AddKey( "Creator", sCreator ); } void PdfInfo::SetKeywords( const PdfString & sKeywords ) { this->GetObject()->GetDictionary().AddKey( "Keywords", sKeywords ); } void PdfInfo::SetSubject( const PdfString & sSubject ) { this->GetObject()->GetDictionary().AddKey( "Subject", sSubject ); } void PdfInfo::SetTitle( const PdfString & sTitle ) { this->GetObject()->GetDictionary().AddKey( "Title", sTitle ); } // Peter Petrov 27 April 2008 // We have added a SetProducer() method in PdfInfo void PdfInfo::SetProducer( const PdfString & sProducer ) { this->GetObject()->GetDictionary().AddKey( "Producer", sProducer ); } void PdfInfo::SetTrapped(const PdfName & sTrapped) { if((sTrapped.GetEscapedName() == "True" ) || (sTrapped.GetEscapedName() == "False" )) this->GetObject()->GetDictionary().AddKey( "Trapped", sTrapped ); else this->GetObject()->GetDictionary().AddKey( "Trapped", PdfName( "Unknown" ) ); } }; podofo-0.9.5/src/doc/PdfOutlines.h0000664000175000017500000002725012742477611016645 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_OUTLINE_H_ #define _PDF_OUTLINE_H_ #include "podofo/base/PdfDefines.h" #include "PdfElement.h" namespace PoDoFo { class PdfDestination; class PdfAction; class PdfObject; class PdfOutlineItem; class PdfString; class PdfVecObjects; /** * The title of an outline item can be displayed * in different formating styles since PDF 1.4. */ enum EPdfOutlineFormat { ePdfOutlineFormat_Default = 0x00, /**< Default format */ ePdfOutlineFormat_Italic = 0x01, /**< Italic */ ePdfOutlineFormat_Bold = 0x02, /**< Bold */ ePdfOutlineFormat_BoldItalic = 0x03, /**< Bold Italic */ ePdfOutlineFormat_Unknown = 0xFF }; /** * A PDF outline item has an title and a destination. * It is an element in the documents outline which shows * its hierarchical structure. * * \see PdfDocument * \see PdfOutlines * \see PdfDestination */ class PODOFO_DOC_API PdfOutlineItem : public PdfElement { public: virtual ~PdfOutlineItem(); /** Create a PdfOutlineItem that is a child of this item * \param sTitle title of this item * \param rDest destination of this item */ PdfOutlineItem* CreateChild( const PdfString & sTitle, const PdfDestination & rDest ); /** Create a PdfOutlineItem that is on the same level and follows the current item. * \param sTitle title of this item * \param rDest destination of this item */ PdfOutlineItem* CreateNext ( const PdfString & sTitle, const PdfDestination & rDest ); /** Create a PdfOutlineItem that is on the same level and follows the current item. * \param sTitle title of this item * \param rAction action of this item */ PdfOutlineItem* CreateNext ( const PdfString & sTitle, const PdfAction & rAction ); /** Inserts a new PdfOutlineItem as a child of this outline item. * The former can't be in the same tree as this one, as the tree property * would be broken. If this prerequisite is violated, a PdfError * exception (code ePdfError_OutlineItemAlreadyPresent) is thrown and * nothing is changed. * The item inserted is not copied, i.e. Erase() calls affect the original! * Therefore also shared ownership is in effect, i.e. deletion by where it * comes from damages the data structure it's inserted into. * * \param pItem an existing outline item */ void InsertChild( PdfOutlineItem* pItem ); /** * \returns the previous item or NULL if this is the first on the current level */ inline PdfOutlineItem* Prev() const; /** * \returns the next item or NULL if this is the last on the current level */ inline PdfOutlineItem* Next() const; /** * \returns the first outline item that is a child of this item */ inline PdfOutlineItem* First() const; /** * \returns the last outline item that is a child of this item */ inline PdfOutlineItem* Last() const; /** * \returns the parent item of this item or NULL if it is * the top level outlines dictionary */ inline PdfOutlineItem* GetParentOutline() const; /** Deletes this outline item and all its children from * the outline hierarchy and removes all objects from * the list of PdfObjects * All pointers to this item will be invalid after this function * call. */ void Erase(); /** Set the destination of this outline. * \param rDest the destination */ void SetDestination( const PdfDestination & rDest ); /** Get the destination of this outline. * \param pDoc a PdfDocument owning this annotation. * This is required to resolve names and pages. * \returns the destination, if there is one, or NULL */ PdfDestination* GetDestination( PdfDocument* pDoc ); /** Set the action of this outline. * \param rAction the action */ void SetAction( const PdfAction & rAction ); /** Get the action of this outline. * \returns the action, if there is one, or NULL */ PdfAction* GetAction( void ); /** Set the title of this outline item * \param sTitle the title to use */ void SetTitle( const PdfString & sTitle ); /** Get the title of this item * \returns the title as PdfString */ const PdfString & GetTitle() const; /** Set the text format of the title. * Supported since PDF 1.4. * * \param eFormat the formatting options * for the title */ void SetTextFormat( EPdfOutlineFormat eFormat ); /** Get the text format of the title * \returns the text format of the title */ EPdfOutlineFormat GetTextFormat() const; /** Set the color of the title of this item. * This property is supported since PDF 1.4. * \param r red color component * \param g green color component * \param b blue color component */ void SetTextColor( double r, double g, double b ); /** Get the color of the title of this item. * Supported since PDF 1.4. * \returns the red color component * * \see SetTextColor */ double GetTextColorRed() const; /** Get the color of the title of this item. * Supported since PDF 1.4. * \returns the red color component * * \see SetTextColor */ double GetTextColorBlue() const; /** Get the color of the title of this item. * Supported since PDF 1.4. * \returns the red color component * * \see SetTextColor */ double GetTextColorGreen() const; private: void SetPrevious( PdfOutlineItem* pItem ); void SetNext ( PdfOutlineItem* pItem ); void SetLast ( PdfOutlineItem* pItem ); void SetFirst ( PdfOutlineItem* pItem ); protected: /** Create a new PdfOutlineItem dictionary * \param pParent parent vector of objects */ PdfOutlineItem( PdfVecObjects* pParent ); /** Create a new PdfOutlineItem from scratch * \param sTitle title of this item * \param rDest destination of this item * \param pParentOutline parent of this outline item * in the outline item hierarchie * \param pParent parent vector of objects which is required * to create new objects */ PdfOutlineItem( const PdfString & sTitle, const PdfDestination & rDest, PdfOutlineItem* pParentOutline, PdfVecObjects* pParent ); /** Create a new PdfOutlineItem from scratch * \param sTitle title of this item * \param rAction action of this item * \param pParentOutline parent of this outline item * in the outline item hierarchie * \param pParent parent vector of objects which is required * to create new objects */ PdfOutlineItem( const PdfString & sTitle, const PdfAction & rAction, PdfOutlineItem* pParentOutline, PdfVecObjects* pParent ); /** Create a PdfOutlineItem from an existing PdfObject * \param pObject an existing outline item * \param pParentOutline parent of this outline item * in the outline item hierarchie * \param pPrevious previous item of this item */ PdfOutlineItem( PdfObject* pObject, PdfOutlineItem* pParentOutline, PdfOutlineItem* pPrevious ); private: PdfOutlineItem* m_pParentOutline; PdfOutlineItem* m_pPrev; PdfOutlineItem* m_pNext; PdfOutlineItem* m_pFirst; PdfOutlineItem* m_pLast; PdfDestination* m_pDestination; PdfAction* m_pAction; }; // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfOutlineItem* PdfOutlineItem::GetParentOutline() const { return m_pParentOutline; } // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfOutlineItem* PdfOutlineItem::First() const { return m_pFirst; } // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfOutlineItem* PdfOutlineItem::Last() const { return m_pLast; } // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfOutlineItem* PdfOutlineItem::Prev() const { return m_pPrev; } // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfOutlineItem* PdfOutlineItem::Next() const { return m_pNext; } /** The main PDF outlines dictionary. * * Do not create it by yourself but * use PdfDocument::GetOutlines() instead. * * \see PdfDocument */ class PODOFO_DOC_API PdfOutlines : public PdfOutlineItem { public: /** Create a new PDF outlines dictionary * \param pParent parent vector of objects */ PdfOutlines( PdfVecObjects* pParent ); /** Create a PDF outlines object from an existing dictionary * \param pObject an existing outlines dictionary */ PdfOutlines( PdfObject* pObject ); virtual ~PdfOutlines() { } /** Create the root node of the * outline item tree. * * \param sTitle the title of the root node */ PdfOutlineItem* CreateRoot( const PdfString & sTitle ); }; }; #endif // _PDF_OUTLINE_H_ podofo-0.9.5/src/doc/PdfFontFactory.cpp0000664000175000017500000003733312717070657017640 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfFontFactory.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfDictionary.h" #include "base/PdfEncoding.h" #include "base/PdfEncodingFactory.h" #include "PdfEncodingObjectFactory.h" #include "PdfFont.h" #include "PdfFontCID.h" #include "PdfFontMetrics.h" #include "PdfFontMetricsBase14.h" #include "PdfFontMetricsObject.h" #include "PdfFontType1.h" #include "PdfFontType3.h" #include "PdfFontType1Base14.h" #include "PdfFontTrueType.h" #include "PdfFontFactoryBase14Data.h" namespace PoDoFo { PdfFontFactory::PdfFontFactory() { } PdfFont* PdfFontFactory::CreateFontObject( PdfFontMetrics* pMetrics, int nFlags, const PdfEncoding* pEncoding, PdfVecObjects* pParent ) { PdfFont* pFont = NULL; EPdfFontType eType = pMetrics->GetFontType(); bool bEmbed = nFlags & ePdfFont_Embedded; bool bSubsetting = (nFlags & ePdfFont_Subsetting) != 0; try { pFont = PdfFontFactory::CreateFontForType( eType, pMetrics, pEncoding, bEmbed, bSubsetting, pParent ); if( pFont ) { pFont->SetBold( nFlags & ePdfFont_Bold ? true : false ); pFont->SetItalic( nFlags & ePdfFont_Italic ? true : false ); } else { // something went wrong, so we have to delete // the font metrics delete pMetrics; pMetrics = NULL; // make sure this will be done before the catch block // as the encoding might be deleted already // afterwars, but we cannot set the pointer to NULL if( pEncoding && pEncoding->IsAutoDelete() ) { delete pEncoding; pEncoding = NULL; } } } catch( PdfError & e ) { // we have to delete the pMetrics object in case of error if( pFont ) { // The font will delete encoding and metrics delete pFont; pFont = NULL; } else { // something went wrong, so we have to delete // the font metrics (and if auto-delete, also the encoding) delete pMetrics; pMetrics = NULL; if( pEncoding && pEncoding->IsAutoDelete() ) delete pEncoding; } e.AddToCallstack( __FILE__, __LINE__, "Font creation failed." ); throw e; } return pFont; } PdfFont* PdfFontFactory::CreateFontForType( EPdfFontType eType, PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, bool bEmbed, bool bSubsetting, PdfVecObjects* pParent ) { PdfFont* pFont = NULL; if( pEncoding->IsSingleByteEncoding() ) { switch( eType ) { case ePdfFontType_TrueType: // Peter Petrov 30 April 2008 - added bEmbed parameter if (bSubsetting) { pFont = new PdfFontCID( pMetrics, pEncoding, pParent, bEmbed, true ); } else { pFont = new PdfFontTrueType( pMetrics, pEncoding, pParent, bEmbed ); } break; case ePdfFontType_Type1Pfa: case ePdfFontType_Type1Pfb: if ( bSubsetting ) { // don't embed yet for subsetting pFont = new PdfFontType1( pMetrics, pEncoding, pParent, false, true ); } else pFont = new PdfFontType1( pMetrics, pEncoding, pParent, bEmbed ); break; case ePdfFontType_Type3: pFont = new PdfFontType3( pMetrics, pEncoding, pParent, bEmbed ); break; case ePdfFontType_Unknown: case ePdfFontType_Type1Base14: default: PdfError::LogMessage( eLogSeverity_Error, "The font format is unknown. Fontname: %s Filename: %s\n", (pMetrics->GetFontname() ? pMetrics->GetFontname() : ""), (pMetrics->GetFilename() ? pMetrics->GetFilename() : "") ); } } else { switch( eType ) { case ePdfFontType_TrueType: // Peter Petrov 30 April 2008 - added bEmbed parameter pFont = new PdfFontCID( pMetrics, pEncoding, pParent, bEmbed, bSubsetting ); break; case ePdfFontType_Type1Pfa: case ePdfFontType_Type1Pfb: case ePdfFontType_Type1Base14: case ePdfFontType_Type3: case ePdfFontType_Unknown: default: PdfError::LogMessage( eLogSeverity_Error, "The font format is unknown or no multibyte encoding defined. Fontname: %s Filename: %s\n", (pMetrics->GetFontname() ? pMetrics->GetFontname() : ""), (pMetrics->GetFilename() ? pMetrics->GetFilename() : "") ); } } return pFont; } PdfFont* PdfFontFactory::CreateFont( FT_Library*, PdfObject* pObject ) { PdfFontMetrics* pMetrics = NULL; PdfFont* pFont = NULL; PdfObject* pDescriptor = NULL; PdfObject* pEncoding = NULL; if( pObject->GetDictionary().GetKey( PdfName::KeyType )->GetName() != PdfName("Font") ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } const PdfName & rSubType = pObject->GetDictionary().GetKey( PdfName::KeySubtype )->GetName(); if( rSubType == PdfName("Type0") ) { // The PDF reference states that DescendantFonts must be an array, // some applications (e.g. MS Word) put the array into an indirect object though. const PdfArray & descendant = pObject->GetIndirectKey( "DescendantFonts" )->GetArray(); PdfObject* pFontObject = NULL; if (descendant.size() && descendant[0].IsReference()) { pFontObject = pObject->GetOwner()->GetObject( descendant[0].GetReference() ); pDescriptor = pFontObject->GetIndirectKey( "FontDescriptor" ); } pEncoding = pObject->GetIndirectKey( "Encoding" ); if ( pEncoding && pDescriptor ) // OC 18.08.2010: Avoid sigsegv { // TODO: If /ToUnicode is absent, use the CID font's predefined character collection // (/CIDSystemInfo<>) const PdfEncoding* const pPdfEncoding = PdfEncodingObjectFactory::CreateEncoding( pEncoding, pObject->GetIndirectKey("ToUnicode") ); // OC 15.08.2010 BugFix: Parameter pFontObject added: TODO: untested pMetrics = new PdfFontMetricsObject( pFontObject, pDescriptor, pPdfEncoding ); pFont = new PdfFontCID( pMetrics, pPdfEncoding, pObject, false ); } } else if( rSubType == PdfName("Type1") ) { // TODO: Old documents do not have a FontDescriptor for // the 14 standard fonts. This suggestions is // deprecated now, but give us problems with old documents. pDescriptor = pObject->GetIndirectKey( "FontDescriptor" ); pEncoding = pObject->GetIndirectKey( "Encoding" ); // OC 13.08.2010: Handle missing FontDescriptor for the 14 standard fonts: if( !pDescriptor ) { // Check if its a PdfFontType1Base14 PdfObject* pBaseFont = NULL; pBaseFont = pObject->GetIndirectKey( "BaseFont" ); const char* pszBaseFontName = pBaseFont->GetName().GetName().c_str(); PdfFontMetricsBase14* pMetrics = PODOFO_Base14FontDef_FindBuiltinData(pszBaseFontName); if ( pMetrics != NULL ) { // pEncoding may be undefined, found a valid pdf with // 20 0 obj // << // /Type /Font // /BaseFont /ZapfDingbats // /Subtype /Type1 // >> // endobj // If pEncoding is null then // use StandardEncoding for Courier, Times, Helvetica font families // and special encodings for Symbol and ZapfDingbats const PdfEncoding* pPdfEncoding = NULL; if ( pEncoding!= NULL ) pPdfEncoding = PdfEncodingObjectFactory::CreateEncoding( pEncoding ); else if ( !pMetrics->IsSymbol() ) pPdfEncoding = PdfEncodingFactory::GlobalStandardEncodingInstance(); else if ( strcmp(pszBaseFontName, "Symbol") == 0 ) pPdfEncoding = PdfEncodingFactory::GlobalSymbolEncodingInstance(); else if ( strcmp(pszBaseFontName, "ZapfDingbats") == 0 ) pPdfEncoding = PdfEncodingFactory::GlobalZapfDingbatsEncodingInstance(); return new PdfFontType1Base14(pMetrics, pPdfEncoding, pObject); } } const PdfEncoding* pPdfEncoding = NULL; if ( pEncoding != NULL ) pPdfEncoding = PdfEncodingObjectFactory::CreateEncoding( pEncoding ); else if ( pDescriptor ) { // OC 18.08.2010 TODO: Encoding has to be taken from the font's built-in encoding // Its extremely complicated to interpret the type1 font programs // so i try to determine if its a symbolic font by reading the FontDescriptor Flags // Flags & 4 --> Symbolic, Flags & 32 --> Nonsymbolic pdf_int32 lFlags = static_cast(pDescriptor->GetDictionary().GetKeyAsLong( "Flags", 0L )); if ( lFlags & 32 ) // Nonsymbolic, otherwise pEncoding remains NULL pPdfEncoding = PdfEncodingFactory::GlobalStandardEncodingInstance(); } if ( pPdfEncoding && pDescriptor ) // OC 18.08.2010: Avoid sigsegv { // OC 15.08.2010 BugFix: Parameter pObject added: pMetrics = new PdfFontMetricsObject( pObject, pDescriptor, pPdfEncoding ); pFont = new PdfFontType1( pMetrics, pPdfEncoding, pObject ); } } else if( rSubType == PdfName("Type3") ) { pDescriptor = pObject->GetIndirectKey( "FontDescriptor" ); pEncoding = pObject->GetIndirectKey( "Encoding" ); if ( pEncoding ) // FontDescriptor may only be present in PDF 1.5+ { const PdfEncoding* const pPdfEncoding = PdfEncodingObjectFactory::CreateEncoding( pEncoding, NULL, true ); pMetrics = new PdfFontMetricsObject( pObject, pDescriptor, pPdfEncoding ); pFont = new PdfFontType3( pMetrics, pPdfEncoding, pObject ); } } else if( rSubType == PdfName("TrueType") ) { pDescriptor = pObject->GetIndirectKey( "FontDescriptor" ); pEncoding = pObject->GetIndirectKey( "Encoding" ); if (!pEncoding) pEncoding = pObject->GetIndirectKey( "ToUnicode" ); if ( pEncoding && pDescriptor ) // OC 18.08.2010: Avoid sigsegv { const PdfEncoding* const pPdfEncoding = PdfEncodingObjectFactory::CreateEncoding( pEncoding, pObject->GetIndirectKey( "ToUnicode" ) ); // OC 15.08.2010 BugFix: Parameter pObject added: pMetrics = new PdfFontMetricsObject( pObject, pDescriptor, pPdfEncoding ); pFont = new PdfFontTrueType( pMetrics, pPdfEncoding, pObject ); } } return pFont; } EPdfFontType PdfFontFactory::GetFontType( const char* pszFilename ) { EPdfFontType eFontType = ePdfFontType_Unknown; // We check by file extension right now // which is not quite correct, but still better than before if( pszFilename && strlen( pszFilename ) > 3 ) { const char* pszExtension = pszFilename + strlen( pszFilename ) - 3; if( PoDoFo::compat::strncasecmp( pszExtension, "ttf", 3 ) == 0 ) eFontType = ePdfFontType_TrueType; else if( PoDoFo::compat::strncasecmp( pszExtension, "otf", 3 ) == 0 ) eFontType = ePdfFontType_TrueType; else if( PoDoFo::compat::strncasecmp( pszExtension, "ttc", 3 ) == 0 ) eFontType = ePdfFontType_TrueType; else if( PoDoFo::compat::strncasecmp( pszExtension, "pfa", 3 ) == 0 ) eFontType = ePdfFontType_Type1Pfa; else if( PoDoFo::compat::strncasecmp( pszExtension, "pfb", 3 ) == 0 ) eFontType = ePdfFontType_Type1Pfb; } return eFontType; } PdfFontMetricsBase14* PODOFO_Base14FontDef_FindBuiltinData(const char *font_name) { unsigned int i = 0; bool found = false; while (PODOFO_BUILTIN_FONTS[i].font_name) { if (strcmp(PODOFO_BUILTIN_FONTS[i].font_name, font_name) == 0) // kaushik : HPDFStrcmp changed to strcmp { found = true; break; } i++; } return found ? &PODOFO_BUILTIN_FONTS[i] : NULL; } PdfFont *PdfFontFactory::CreateBase14Font(const char* pszFontName, EPdfFontFlags eFlags, const PdfEncoding * const pEncoding, PdfVecObjects *pParent) { PdfFont *pFont = new PdfFontType1Base14( PODOFO_Base14FontDef_FindBuiltinData(pszFontName), pEncoding, pParent); if (pFont) { pFont->SetBold( eFlags & ePdfFont_Bold ? true : false ); pFont->SetItalic( eFlags & ePdfFont_Italic ? true : false ); } return pFont; } }; podofo-0.9.5/src/doc/PdfFontMetricsObject.h0000664000175000017500000002240712714722103020412 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FONT_METRICS_OBJECT_H_ #define _PDF_FONT_METRICS_OBJECT_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfArray.h" #include "podofo/base/PdfName.h" #include "podofo/base/PdfString.h" #include "PdfFontMetrics.h" namespace PoDoFo { class PdfArray; class PdfObject; class PdfVariant; class PODOFO_DOC_API PdfFontMetricsObject : public PdfFontMetrics { public: /** Create a font metrics object based on an existing PdfObject * * \param pObject an existing font descriptor object * \param pEncoding a PdfEncoding which will NOT be owned by PdfFontMetricsObject */ PdfFontMetricsObject( PdfObject* pFont, PdfObject* pDescriptor, const PdfEncoding* const pEncoding ); virtual ~PdfFontMetricsObject(); /** Create a width array for this font which is a required part * of every font dictionary. * \param var the final width array is written to this PdfVariant * \param nFirst first character to be in the array * \param nLast last character code to be in the array * \param pEncoding encoding for correct character widths. If not passed default (latin1) encoding is used */ virtual void GetWidthArray( PdfVariant & var, unsigned int nFirst, unsigned int nLast, const PdfEncoding* pEncoding = NULL ) const; /** Get the width of a single glyph id * * \returns the width of a single glyph id */ virtual double GetGlyphWidth( int nGlyphId ) const; /** Get the width of a single named glyph * * \param pszGlyphname name of the glyph * \returns the width of a single named glyph */ virtual double GetGlyphWidth( const char* pszGlyphname ) const; /** Create the bounding box array as required by the PDF reference * so that it can be written directly to a PDF file. * * \param array write the bounding box to this array. */ virtual void GetBoundingBox( PdfArray & array ) const; /** Retrieve the width of the given character in PDF units in the current font * \param c character * \returns the width in PDF units */ virtual double CharWidth( unsigned char c ) const; // Peter Petrov 20 March 2009 /** Retrieve the width of the given character in PDF units in the current font * \param c character * \returns the width in PDF units */ virtual double UnicodeCharWidth( unsigned short c ) const; /** Retrieve the line spacing for this font * \returns the linespacing in PDF units */ virtual double GetLineSpacing() const; /** Get the width of the underline for the current * font size in PDF units * \returns the thickness of the underline in PDF units */ virtual double GetUnderlineThickness() const; /** Return the position of the underline for the current font * size in PDF units * \returns the underline position in PDF units */ virtual double GetUnderlinePosition() const; /** Return the position of the strikeout for the current font * size in PDF units * \returns the underline position in PDF units */ virtual double GetStrikeOutPosition() const; /** Get the width of the strikeout for the current * font size in PDF units * \returns the thickness of the strikeout in PDF units */ virtual double GetStrikeoutThickness() const; /** Get a string with the postscript name of the font. * \returns the postscript name of the font or NULL string if no postscript name is available. */ virtual const char* GetFontname() const; /** Get the weight of this font. * Used to build the font dictionay * \returns the weight of this font (500 is normal). */ virtual unsigned int GetWeight() const; /** Get the ascent of this font in PDF * units for the current font size. * * \returns the ascender for this font * * \see GetPdfAscent */ virtual double GetAscent() const; /** Get the ascent of this font * Used to build the font dictionay * \returns the ascender for this font * * \see GetAscent */ virtual double GetPdfAscent() const; /** Get the descent of this font in PDF * units for the current font size. * This value is usually negative! * * \returns the descender for this font * * \see GetPdfDescent */ virtual double GetDescent() const; /** Get the descent of this font * Used to build the font dictionay * \returns the descender for this font * * \see GetDescent */ virtual double GetPdfDescent() const; /** Get the italic angle of this font. * Used to build the font dictionay * \returns the italic angle of this font. */ virtual int GetItalicAngle() const; /** Get the glyph id for a unicode character * in the current font. * * \param lUnicode the unicode character value * \returns the glyhph id for the character or 0 if the glyph was not found. */ virtual long GetGlyphId( long lUnicode ) const; /** Symbol fonts do need special treatment in a few cases. * Use this method to check if the current font is a symbol * font. Symbold fonts are detected by checking * if they use FT_ENCODING_MS_SYMBOL as internal encoding. * * \returns true if this is a symbol font */ virtual bool IsSymbol() const; /** Get a pointer to the actual font data - if it was loaded from memory. * \returns a binary buffer of data containing the font data */ virtual const char* GetFontData() const; /** Get the length of the actual font data - if it was loaded from memory. * \returns a the length of the font data */ virtual pdf_long GetFontDataLen() const; private: /** default constructor, not implemented */ PdfFontMetricsObject(void); /** copy constructor, not implemented */ PdfFontMetricsObject(const PdfFontMetricsObject& rhs); /** assignment operator, not implemented */ PdfFontMetricsObject& operator=(const PdfFontMetricsObject& rhs); //Private members: const PdfEncoding* const m_pEncoding; PdfName m_sName; PdfArray m_bbox; PdfArray m_matrix; PdfArray m_width; PdfObject *m_missingWidth; int m_nFirst; int m_nLast; unsigned int m_nWeight; int m_nItalicAngle; double m_dPdfAscent; double m_dPdfDescent; double m_dAscent; double m_dDescent; double m_dLineSpacing; double m_dUnderlineThickness; double m_dUnderlinePosition; double m_dStrikeOutThickness; double m_dStrikeOutPosition; bool m_bSymbol; ///< Internal member to singnal a symbol font double m_dDefWidth; ///< default width }; }; #endif // _PDF_FONT_METRICS_OBJECT_H_ podofo-0.9.5/src/doc/PdfShadingPattern.h0000664000175000017500000003051512347301431017737 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_SHADING_PATTERN_H_ #define _PDF_SHADING_PATTERN_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfName.h" #include "PdfElement.h" namespace PoDoFo { class PdfColor; class PdfObject; class PdfPage; class PdfWriter; enum EPdfShadingPatternType { ePdfShadingPatternType_FunctionBase = 1, ePdfShadingPatternType_Axial = 2, ePdfShadingPatternType_Radial = 3, ePdfShadingPatternType_FreeForm = 4, ePdfShadingPatternType_LatticeForm = 5, ePdfShadingPatternType_CoonsPatch = 6, ePdfShadingPatternType_TensorProduct = 7 }; /** * This class defined a shading pattern which can be used * to fill abitrary shapes with a pattern using PdfPainter. */ class PODOFO_DOC_API PdfShadingPattern : public PdfElement { public: virtual ~PdfShadingPattern(); /** Returns the identifier of this ShadingPattern how it is known * in the pages resource dictionary. * \returns PdfName containing the identifier (e.g. /Sh13) */ inline const PdfName & GetIdentifier() const; protected: /** Create a new PdfShadingPattern object which will introduce itself * automatically to every page object it is used on. * * \param pParent parent vector of objects * \param eShadingType the type of this shading pattern * */ PdfShadingPattern( EPdfShadingPatternType eShadingType, PdfVecObjects* pParent ); /** Create a new PdfShadingPattern object which will introduce itself * automatically to every page object it is used on. * * \param pParent parent document * \param eShadingType the type of this shading pattern * */ PdfShadingPattern( EPdfShadingPatternType eShadingType, PdfDocument* pParent ); private: /** Initialize the object * * \param eShadingType the type of this shading pattern */ void Init( EPdfShadingPatternType eShadingType ); private: PdfName m_Identifier; }; // ----------------------------------------------------- // // ----------------------------------------------------- const PdfName & PdfShadingPattern::GetIdentifier() const { return m_Identifier; } /** A shading pattern that is a simple axial * shading between two colors. */ class PODOFO_DOC_API PdfAxialShadingPattern : public PdfShadingPattern { public: /** Create an axial shading pattern * * \param dX0 the starting x coordinate * \param dY0 the starting y coordinate * \param dX1 the ending x coordinate * \param dY1 the ending y coordinate * \param rStart the starting color * \param rEnd the ending color * \param pParent the parent */ PdfAxialShadingPattern( double dX0, double dY0, double dX1, double dY1, const PdfColor & rStart, const PdfColor & rEnd, PdfVecObjects* pParent ); /** Create an axial shading pattern * * \param dX0 the starting x coordinate * \param dY0 the starting y coordinate * \param dX1 the ending x coordinate * \param dY1 the ending y coordinate * \param rStart the starting color * \param rEnd the ending color * \param pParent the parent */ PdfAxialShadingPattern( double dX0, double dY0, double dX1, double dY1, const PdfColor & rStart, const PdfColor & rEnd, PdfDocument* pParent ); private: /** Initialize an axial shading pattern * * \param dX0 the starting x coordinate * \param dY0 the starting y coordinate * \param dX1 the ending x coordinate * \param dY1 the ending y coordinate * \param rStart the starting color * \param rEnd the ending color */ void Init( double dX0, double dY0, double dX1, double dY1, const PdfColor & rStart, const PdfColor & rEnd ); }; /** A shading pattern that is an 2D * shading between four colors. */ class PODOFO_DOC_API PdfFunctionBaseShadingPattern : public PdfShadingPattern { public: /** Create an 2D shading pattern * * \param rLL the color on lower left corner * \param rUL the color on upper left corner * \param rLR the color on lower right corner * \param rUR the color on upper right corner * \param rMatrix the transformation matrix mapping the coordinate space * specified by the Domain entry into the shadings target coordinate space * \param pParent the parent */ PdfFunctionBaseShadingPattern( const PdfColor & rLL, const PdfColor & rUL, const PdfColor & rLR, const PdfColor & rUR, const PdfArray & rMatrix, PdfVecObjects* pParent ); /** Create an 2D shading pattern * * \param rLL the color on lower left corner * \param rUL the color on upper left corner * \param rLR the color on lower right corner * \param rUR the color on upper right corner * \param rMatrix the transformation matrix mapping the coordinate space * specified by the Domain entry into the shading's target coordinate space * \param pParent the parent */ PdfFunctionBaseShadingPattern( const PdfColor & rLL, const PdfColor & rUL, const PdfColor & rLR, const PdfColor & rUR, const PdfArray & rMatrix, PdfDocument* pParent ); private: /** Initialize an 2D shading pattern * * \param rLL the color on lower left corner * \param rUL the color on upper left corner * \param rLR the color on lower right corner * \param rUR the color on upper right corner * \param rMatrix the transformation matrix mapping the coordinate space * specified by the Domain entry into the shading's target coordinate space */ void Init( const PdfColor & rLL, const PdfColor & rUL, const PdfColor & rLR, const PdfColor & rUR, const PdfArray & rMatrix ); }; /** A shading pattern that is a simple radial * shading between two colors. */ class PODOFO_DOC_API PdfRadialShadingPattern : public PdfShadingPattern { public: /** Create an radial shading pattern * * \param dX0 the inner circles x coordinate * \param dY0 the inner circles y coordinate * \param dR0 the inner circles radius * \param dX1 the outer circles x coordinate * \param dY1 the outer circles y coordinate * \param dR1 the outer circles radius * \param rStart the starting color * \param rEnd the ending color * \param pParent the parent */ PdfRadialShadingPattern( double dX0, double dY0, double dR0, double dX1, double dY1, double dR1, const PdfColor & rStart, const PdfColor & rEnd, PdfVecObjects* pParent ); /** Create an radial shading pattern * * \param dX0 the inner circles x coordinate * \param dY0 the inner circles y coordinate * \param dR0 the inner circles radius * \param dX1 the outer circles x coordinate * \param dY1 the outer circles y coordinate * \param dR1 the outer circles radius * \param rStart the starting color * \param rEnd the ending color * \param pParent the parent */ PdfRadialShadingPattern( double dX0, double dY0, double dR0, double dX1, double dY1, double dR1, const PdfColor & rStart, const PdfColor & rEnd, PdfDocument* pParent ); private: /** Initialize an radial shading pattern * * \param dX0 the inner circles x coordinate * \param dY0 the inner circles y coordinate * \param dR0 the inner circles radius * \param dX1 the outer circles x coordinate * \param dY1 the outer circles y coordinate * \param dR1 the outer circles radius * \param rStart the starting color * \param rEnd the ending color */ void Init( double dX0, double dY0, double dR0, double dX1, double dY1, double dR1, const PdfColor & rStart, const PdfColor & rEnd ); }; /** A shading pattern that is a simple triangle * shading between three colors. It's a single-triangle * simplified variation of a FreeForm shadding pattern. */ class PODOFO_DOC_API PdfTriangleShadingPattern : public PdfShadingPattern { public: /** Create a triangle shading pattern * * \param dX0 triangle x coordinate of point 0 * \param dY0 triangle y coordinate of point 0 * \param color0 color of point 0 * \param dX1 triangle x coordinate of point 1 * \param dY1 triangle y coordinate of point 1 * \param color1 color of point 1 * \param dX2 triangle x coordinate of point 2 * \param dY2 triangle y coordinate of point 2 * \param color2 color of point 2 * \param pParent the parent */ PdfTriangleShadingPattern( double dX0, double dY0, const PdfColor &color0, double dX1, double dY1, const PdfColor &color1, double dX2, double dY2, const PdfColor &color2, PdfVecObjects* pParent ); /** Create a triangle shading pattern * * \param dX0 triangle x coordinate of point 0 * \param dY0 triangle y coordinate of point 0 * \param color0 color of point 0 * \param dX1 triangle x coordinate of point 1 * \param dY1 triangle y coordinate of point 1 * \param color1 color of point 1 * \param dX2 triangle x coordinate of point 2 * \param dY2 triangle y coordinate of point 2 * \param color2 color of point 2 * \param pParent the parent */ PdfTriangleShadingPattern( double dX0, double dY0, const PdfColor &color0, double dX1, double dY1, const PdfColor &color1, double dX2, double dY2, const PdfColor &color2, PdfDocument* pParent ); private: /** Initialize a triangle shading pattern * * \param dX0 triangle x coordinate of point 0 * \param dY0 triangle y coordinate of point 0 * \param color0 color of point 0 * \param dX1 triangle x coordinate of point 1 * \param dY1 triangle y coordinate of point 1 * \param color1 color of point 1 * \param dX2 triangle x coordinate of point 2 * \param dY2 triangle y coordinate of point 2 * \param color2 color of point 2 */ void Init( double dX0, double dY0, const PdfColor &color0, double dX1, double dY1, const PdfColor &color1, double dX2, double dY2, const PdfColor &color2 ); }; }; #endif // _PDF_SHADING_PATTERN_H_ podofo-0.9.5/src/doc/PdfFontType3.cpp0000664000175000017500000000626012347347566017235 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfFontType3.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfDictionary.h" #include "base/PdfName.h" #include "base/PdfStream.h" namespace PoDoFo { PdfFontType3::PdfFontType3( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfVecObjects* pParent, bool bEmbed ) : PdfFontSimple( pMetrics, pEncoding, pParent ) { this->Init( bEmbed, PdfName("Type3") ); } PdfFontType3::PdfFontType3( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfObject* pObject ) : PdfFontSimple( pMetrics, pEncoding, pObject ) { } void PdfFontType3::EmbedFontFile( PdfObject* /*pDescriptor*/ ) { PODOFO_RAISE_ERROR( ePdfError_UnsupportedFontFormat ); } }; podofo-0.9.5/src/doc/PdfDestination.cpp0000664000175000017500000002154312717043242017645 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfDestination.h" #include "base/PdfDictionary.h" #include "base/PdfDefinesPrivate.h" #include "PdfAction.h" #include "PdfMemDocument.h" #include "PdfNamesTree.h" #include "PdfPage.h" #include "PdfPagesTree.h" namespace PoDoFo { const long PdfDestination::s_lNumDestinations = 19; const char* PdfDestination::s_names[] = { "Fit", "FitH", "FitV", "FitB", "FitBH", "FitBV", NULL }; PdfDestination::PdfDestination( PdfVecObjects* pParent ) { m_pObject = pParent->CreateObject( m_array ); } PdfDestination::PdfDestination( PdfObject* pObject, PdfDocument* pDocument ) { Init( pObject, pDocument ); } PdfDestination::PdfDestination( PdfObject* pObject, PdfVecObjects* pVecObjects ) { PdfDocument* pDocument = pVecObjects->GetParentDocument(); if( !pDocument ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } Init( pObject, pDocument ); } PdfDestination::PdfDestination( const PdfPage* pPage, EPdfDestinationFit eFit ) { PdfName type = PdfName("Fit"); if( eFit == ePdfDestinationFit_Fit ) type = PdfName("Fit"); else if( eFit == ePdfDestinationFit_FitB ) type = PdfName("FitB"); else { // Peter Petrov 6 June 2008 // silent mode //PODOFO_RAISE_ERROR( ePdfError_InvalidKey ); } m_array.push_back( pPage->GetObject()->Reference() ); m_array.push_back( type ); m_pObject = pPage->GetObject()->GetOwner()->CreateObject( m_array ); } PdfDestination::PdfDestination( const PdfPage* pPage, const PdfRect & rRect ) { PdfVariant var; rRect.ToVariant( var ); m_array.push_back( pPage->GetObject()->Reference() ); m_array.push_back( PdfName("FitR") ); m_array.insert( m_array.end(), var.GetArray().begin(), var.GetArray().end() ); m_pObject = pPage->GetObject()->GetOwner()->CreateObject( m_array ); } PdfDestination::PdfDestination( const PdfPage* pPage, double dLeft, double dTop, double dZoom ) { m_array.push_back( pPage->GetObject()->Reference() ); m_array.push_back( PdfName("XYZ") ); m_array.push_back( dLeft ); m_array.push_back( dTop ); m_array.push_back( dZoom ); m_pObject = pPage->GetObject()->GetOwner()->CreateObject( m_array ); } PdfDestination::PdfDestination( const PdfPage* pPage, EPdfDestinationFit eFit, double dValue ) { PdfName type; if( eFit == ePdfDestinationFit_FitH ) type = PdfName("FitH"); else if( eFit == ePdfDestinationFit_FitV ) type = PdfName("FitV"); else if( eFit == ePdfDestinationFit_FitBH ) type = PdfName("FitBH"); else if( eFit == ePdfDestinationFit_FitBV ) type = PdfName("FitBV"); else { PODOFO_RAISE_ERROR( ePdfError_InvalidKey ); } m_array.push_back( pPage->GetObject()->Reference() ); m_array.push_back( type ); m_array.push_back( dValue ); m_pObject = pPage->GetObject()->GetOwner()->CreateObject( m_array ); } PdfDestination::PdfDestination( const PdfDestination & rhs ) { this->operator=( rhs ); } const PdfDestination & PdfDestination::operator=( const PdfDestination & rhs ) { m_array = rhs.m_array; m_pObject = rhs.m_pObject; return *this; } void PdfDestination::Init( PdfObject* pObject, PdfDocument* pDocument ) { bool bValueExpected = false; PdfObject* pValue = NULL; if ( pObject->GetDataType() == ePdfDataType_Array ) { m_array = pObject->GetArray(); m_pObject = pObject; } else if( pObject->GetDataType() == ePdfDataType_String ) { PdfNamesTree* pNames = pDocument->GetNamesTree( ePdfDontCreateObject ); if( !pNames ) { PODOFO_RAISE_ERROR( ePdfError_NoObject ); } pValue = pNames->GetValue( "Dests", pObject->GetString() ); bValueExpected = true; } else if( pObject->GetDataType() == ePdfDataType_Name ) { PdfMemDocument* pMemDoc = dynamic_cast(pDocument); if ( !pMemDoc ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "For reading from a document, only use PdfMemDocument." ); } PdfObject* pCatalog = pMemDoc->GetCatalog(); if ( !pCatalog ) { PODOFO_RAISE_ERROR( ePdfError_NoObject ); } PdfObject* pDests = pCatalog->GetIndirectKey( PdfName( "Dests" ) ); if( !pDests ) { // The error code has been chosen for its distinguishability. PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidKey, "No PDF-1.1-compatible destination dictionary found." ); } pValue = pDests->GetIndirectKey( pObject->GetName() ); bValueExpected = true; } else { PdfError::LogMessage( eLogSeverity_Error, "Unsupported object given to" " PdfDestination::Init of type %s", pObject->GetDataTypeString() ); m_array = PdfArray(); // needed to prevent crash on method calls // needed for GetObject() use w/o checking its return value for NULL m_pObject = pDocument->GetObjects()->CreateObject( m_array ); } if ( bValueExpected ) { if( !pValue ) { PODOFO_RAISE_ERROR( ePdfError_InvalidName ); } if( pValue->IsArray() ) m_array = pValue->GetArray(); else if( pValue->IsDictionary() ) m_array = pValue->GetDictionary().GetKey( "D" )->GetArray(); m_pObject = pValue; } } void PdfDestination::AddToDictionary( PdfDictionary & dictionary ) const { // Do not add empty destinations if( !m_array.size() ) return; // since we can only have EITHER a Dest OR an Action // we check for an Action, and if already present, we throw if ( dictionary.HasKey( PdfName( "A" ) ) ) PODOFO_RAISE_ERROR( ePdfError_ActionAlreadyPresent ); dictionary.RemoveKey( "Dest" ); dictionary.AddKey( "Dest", m_pObject ); } PdfPage* PdfDestination::GetPage( PdfDocument* pDoc ) { if( !m_array.size() ) return NULL; // first entry in the array is the page - so just make a new page from it! return pDoc->GetPagesTree()->GetPage( m_array[0].GetReference() ); } PdfPage* PdfDestination::GetPage( PdfVecObjects* pVecObjects ) { PdfDocument* pDoc = pVecObjects->GetParentDocument(); if( !pDoc ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "PdfVecObjects needs a parent PdfDocument to resolve pages." ); } return this->GetPage( pDoc ); } }; podofo-0.9.5/src/doc/PdfPainter.cpp0000664000175000017500000017231013040147616016765 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #if defined(_MSC_VER) && _MSC_VER <= 1200 #pragma warning(disable: 4786) #endif #include #include #include #include "PdfPainter.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfColor.h" #include "base/PdfDictionary.h" #include "base/PdfFilter.h" #include "base/PdfName.h" #include "base/PdfRect.h" #include "base/PdfStream.h" #include "base/PdfString.h" #include "base/PdfLocale.h" #include "PdfContents.h" #include "PdfExtGState.h" #include "PdfFont.h" #include "PdfFontMetrics.h" #include "PdfImage.h" #include "PdfMemDocument.h" #include "PdfShadingPattern.h" #include "PdfTilingPattern.h" #include "PdfXObject.h" #include #define BEZIER_POINTS 13 /* 4/3 * (1-cos 45,A0(B)/sin 45,A0(B = 4/3 * sqrt(2) - 1 */ #define ARC_MAGIC 0.552284749f #define PI 3.141592654f namespace PoDoFo { static const long clPainterHighPrecision = 15L; static const long clPainterDefaultPrecision = 3L; static inline void CheckDoubleRange( double val, double min, double max ) { if( val < min || val > max ) { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } } static inline unsigned short SwapBytes(unsigned short val) { return ((val & 0x00FF) << 8) | ((val & 0xFF00) >> 8); } static inline unsigned short SwapCharBytesIfRequired(pdf_utf16be ch) { #ifdef PODOFO_IS_LITTLE_ENDIAN return SwapBytes(ch); #else return ch; #endif } static inline bool IsNewLineChar(pdf_utf16be ch) { return SwapCharBytesIfRequired(ch) == '\n'; } static inline bool IsSpaceChar(pdf_utf16be ch) { return isspace( SwapCharBytesIfRequired(ch) & 0x00FF ) != 0; } PdfPainter::PdfPainter() : m_pCanvas( NULL ), m_pPage( NULL ), m_pFont( NULL ), m_nTabWidth( 4 ), m_curColor( PdfColor( 0.0, 0.0, 0.0 ) ), m_isTextOpen( false ), m_oss(), m_curPath() { m_oss.flags( std::ios_base::fixed ); m_oss.precision( clPainterDefaultPrecision ); PdfLocaleImbue(m_oss); m_curPath.flags( std::ios_base::fixed ); m_curPath.precision( clPainterDefaultPrecision ); PdfLocaleImbue(m_curPath); lpx = lpy = lpx2 = lpy2 = lpx3 = lpy3 = lcx = lcy = lrx = lry = 0.0; currentTextRenderingMode = ePdfTextRenderingMode_Fill; } PdfPainter::~PdfPainter() { // Throwing exceptions in C++ destructors is not allowed. // Just log the error. // PODOFO_RAISE_LOGIC_IF( m_pCanvas, "FinishPage() has to be called after a page is completed!" ); // Note that we can't do this for the user, since FinishPage() might // throw and we can't safely have that in a dtor. That also means // we can't throw here, but must abort. if( m_pCanvas ) PdfError::LogMessage( eLogSeverity_Error, "PdfPainter::~PdfPainter(): FinishPage() has to be called after a page is completed!" ); PODOFO_ASSERT( !m_pCanvas ); } void PdfPainter::SetPage( PdfCanvas* pPage ) { // Ignore setting the same page twice if( m_pPage == pPage ) return; if( m_pCanvas ) m_pCanvas->EndAppend(); m_pPage = pPage; m_pCanvas = pPage ? pPage->GetContentsForAppending()->GetStream() : NULL; if ( m_pCanvas ) { // GetLength() must be called before BeginAppend() if ( m_pCanvas->GetLength() ) { m_pCanvas->BeginAppend( false ); // there is already content here - so let's assume we are appending // as such, we MUST put in a "space" to separate whatever we do. m_pCanvas->Append( " " ); } else m_pCanvas->BeginAppend( false ); currentTextRenderingMode = ePdfTextRenderingMode_Fill; } else { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } } void PdfPainter::FinishPage() { try { if( m_pCanvas ) m_pCanvas->EndAppend(); } catch( PdfError & e ) { // clean up, even in case of error m_pCanvas = NULL; m_pPage = NULL; throw e; } m_pCanvas = NULL; m_pPage = NULL; currentTextRenderingMode = ePdfTextRenderingMode_Fill; } void PdfPainter::SetStrokingGray( double g ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); CheckDoubleRange( g, 0.0, 1.0 ); this->SetStrokingColor( PdfColor( g ) ); } void PdfPainter::SetGray( double g ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); CheckDoubleRange( g, 0.0, 1.0 ); this->SetColor( PdfColor( g ) ); } void PdfPainter::SetStrokingColor( double r, double g, double b ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); CheckDoubleRange( r, 0.0, 1.0 ); CheckDoubleRange( g, 0.0, 1.0 ); CheckDoubleRange( b, 0.0, 1.0 ); this->SetStrokingColor( PdfColor( r, g, b ) ); } void PdfPainter::SetColor( double r, double g, double b ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); CheckDoubleRange( r, 0.0, 1.0 ); CheckDoubleRange( g, 0.0, 1.0 ); CheckDoubleRange( b, 0.0, 1.0 ); this->SetColor( PdfColor( r, g, b ) ); } void PdfPainter::SetStrokingColorCMYK( double c, double m, double y, double k ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); CheckDoubleRange( c, 0.0, 1.0 ); CheckDoubleRange( m, 0.0, 1.0 ); CheckDoubleRange( y, 0.0, 1.0 ); CheckDoubleRange( k, 0.0, 1.0 ); this->SetStrokingColor( PdfColor( c, m, y, k ) ); } void PdfPainter::SetColorCMYK( double c, double m, double y, double k ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); CheckDoubleRange( c, 0.0, 1.0 ); CheckDoubleRange( m, 0.0, 1.0 ); CheckDoubleRange( y, 0.0, 1.0 ); CheckDoubleRange( k, 0.0, 1.0 ); this->SetColor( PdfColor( c, m, y, k ) ); } void PdfPainter::SetStrokingShadingPattern( const PdfShadingPattern & rPattern ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); this->AddToPageResources( rPattern.GetIdentifier(), rPattern.GetObject()->Reference(), PdfName("Pattern") ); m_oss.str(""); m_oss << "/Pattern CS /" << rPattern.GetIdentifier().GetName() << " SCN" << std::endl; m_pCanvas->Append( m_oss.str() ); } void PdfPainter::SetShadingPattern( const PdfShadingPattern & rPattern ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); this->AddToPageResources( rPattern.GetIdentifier(), rPattern.GetObject()->Reference(), PdfName("Pattern") ); m_oss.str(""); m_oss << "/Pattern cs /" << rPattern.GetIdentifier().GetName() << " scn" << std::endl; m_pCanvas->Append( m_oss.str() ); } void PdfPainter::SetStrokingTilingPattern( const PdfTilingPattern & rPattern ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); this->AddToPageResources( rPattern.GetIdentifier(), rPattern.GetObject()->Reference(), PdfName("Pattern") ); m_oss.str(""); m_oss << "/Pattern CS /" << rPattern.GetIdentifier().GetName() << " SCN" << std::endl; m_pCanvas->Append( m_oss.str() ); } void PdfPainter::SetStrokingTilingPattern( const std::string &rPatternName ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_oss.str(""); m_oss << "/Pattern CS /" << rPatternName << " SCN" << std::endl; m_pCanvas->Append( m_oss.str() ); } void PdfPainter::SetTilingPattern( const PdfTilingPattern & rPattern ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); this->AddToPageResources( rPattern.GetIdentifier(), rPattern.GetObject()->Reference(), PdfName("Pattern") ); m_oss.str(""); m_oss << "/Pattern cs /" << rPattern.GetIdentifier().GetName() << " scn" << std::endl; m_pCanvas->Append( m_oss.str() ); } void PdfPainter::SetTilingPattern( const std::string &rPatternName ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_oss.str(""); m_oss << "/Pattern cs /" << rPatternName << " scn" << std::endl; m_pCanvas->Append( m_oss.str() ); } void PdfPainter::SetStrokingColor( const PdfColor & rColor ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_oss.str(""); switch( rColor.GetColorSpace() ) { default: case ePdfColorSpace_DeviceRGB: m_oss << rColor.GetRed() << " " << rColor.GetGreen() << " " << rColor.GetBlue() << " RG" << std::endl; break; case ePdfColorSpace_DeviceCMYK: m_oss << rColor.GetCyan() << " " << rColor.GetMagenta() << " " << rColor.GetYellow() << " " << rColor.GetBlack() << " K" << std::endl; break; case ePdfColorSpace_DeviceGray: m_oss << rColor.GetGrayScale() << " G" << std::endl; break; case ePdfColorSpace_Separation: m_pPage->AddColorResource( rColor ); m_oss << "/ColorSpace" << PdfName( rColor.GetName() ).GetEscapedName() << " CS " << rColor.GetDensity() << " SCN" << std::endl; break; case ePdfColorSpace_CieLab: m_pPage->AddColorResource( rColor ); m_oss << "/ColorSpaceCieLab" << " CS " << rColor.GetCieL() << " " << rColor.GetCieA() << " " << rColor.GetCieB() << " SCN" << std::endl; break; case ePdfColorSpace_Unknown: case ePdfColorSpace_Indexed: { PODOFO_RAISE_ERROR( ePdfError_CannotConvertColor ); } } m_pCanvas->Append( m_oss.str() ); } void PdfPainter::SetColor( const PdfColor & rColor ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_oss.str(""); m_curColor = rColor; switch( rColor.GetColorSpace() ) { default: case ePdfColorSpace_DeviceRGB: m_oss << rColor.GetRed() << " " << rColor.GetGreen() << " " << rColor.GetBlue() << " rg" << std::endl; break; case ePdfColorSpace_DeviceCMYK: m_oss << rColor.GetCyan() << " " << rColor.GetMagenta() << " " << rColor.GetYellow() << " " << rColor.GetBlack() << " k" << std::endl; break; case ePdfColorSpace_DeviceGray: m_oss << rColor.GetGrayScale() << " g" << std::endl; break; case ePdfColorSpace_Separation: m_pPage->AddColorResource( rColor ); m_oss << "/ColorSpace" << PdfName( rColor.GetName() ).GetEscapedName() << " cs " << rColor.GetDensity() << " scn" << std::endl; break; case ePdfColorSpace_CieLab: m_pPage->AddColorResource( rColor ); m_oss << "/ColorSpaceCieLab" << " cs " << rColor.GetCieL() << " " << rColor.GetCieA() << " " << rColor.GetCieB() << " scn" << std::endl; break; case ePdfColorSpace_Unknown: case ePdfColorSpace_Indexed: { PODOFO_RAISE_ERROR( ePdfError_CannotConvertColor ); } } m_pCanvas->Append( m_oss.str() ); } void PdfPainter::SetStrokeWidth( double dWidth ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_oss.str(""); m_oss << dWidth << " w" << std::endl; m_pCanvas->Append( m_oss.str() ); } void PdfPainter::SetStrokeStyle( EPdfStrokeStyle eStyle, const char* pszCustom, bool inverted, double scale, bool subtractJoinCap) { bool have = false; PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_oss.str(""); if (eStyle != ePdfStrokeStyle_Custom) { m_oss << "["; } if (inverted && eStyle != ePdfStrokeStyle_Solid && eStyle != ePdfStrokeStyle_Custom) { m_oss << "0 "; } switch( eStyle ) { case ePdfStrokeStyle_Solid: have = true; break; case ePdfStrokeStyle_Dash: have = true; if (scale >= 1.0 - 1e-5 && scale <= 1.0 + 1e-5) { m_oss << "6 2"; } else { if (subtractJoinCap) { m_oss << scale * 2.0 << " " << scale * 2.0; } else { m_oss << scale * 3.0 << " " << scale * 1.0; } } break; case ePdfStrokeStyle_Dot: have = true; if (scale >= 1.0 - 1e-5 && scale <= 1.0 + 1e-5) { m_oss << "2 2"; } else { if (subtractJoinCap) { // zero length segments are drawn anyway here m_oss << 0.001 << " " << 2.0 * scale << " " << 0 << " " << 2.0 * scale; } else { m_oss << scale * 1.0 << " " << scale * 1.0; } } break; case ePdfStrokeStyle_DashDot: have = true; if (scale >= 1.0 - 1e-5 && scale <= 1.0 + 1e-5) { m_oss << "3 2 1 2"; } else { if (subtractJoinCap) { // zero length segments are drawn anyway here m_oss << scale * 2.0 << " " << scale * 2.0 << " " << 0 << " " << scale * 2.0; } else { m_oss << scale * 3.0 << " " << scale * 1.0 << " " << scale * 1.0 << " " << scale * 1.0; } } break; case ePdfStrokeStyle_DashDotDot: have = true; if (scale >= 1.0 - 1e-5 && scale <= 1.0 + 1e-5) { m_oss << "3 1 1 1 1 1"; } else { if (subtractJoinCap) { // zero length segments are drawn anyway here m_oss << scale * 2.0 << " " << scale * 2.0 << " " << 0 << " " << scale * 2.0 << " " << 0 << " " << scale * 2.0; } else { m_oss << scale * 3.0 << " " << scale * 1.0 << " " << scale * 1.0 << " " << scale * 1.0 << " " << scale * 1.0 << " " << scale * 1.0; } } break; case ePdfStrokeStyle_Custom: have = pszCustom != NULL; if (have) m_oss << pszCustom; break; default: { PODOFO_RAISE_ERROR( ePdfError_InvalidStrokeStyle ); } } if( !have ) { PODOFO_RAISE_ERROR( ePdfError_InvalidStrokeStyle ); } if (inverted && eStyle != ePdfStrokeStyle_Solid && eStyle != ePdfStrokeStyle_Custom) { m_oss << " 0"; } if (eStyle != ePdfStrokeStyle_Custom) { m_oss << "] 0"; } m_oss << " d" << std::endl; m_pCanvas->Append( m_oss.str() ); } void PdfPainter::SetLineCapStyle( EPdfLineCapStyle eCapStyle ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_oss.str(""); m_oss << static_cast(eCapStyle) << " J" << std::endl; m_pCanvas->Append( m_oss.str() ); } void PdfPainter::SetLineJoinStyle( EPdfLineJoinStyle eJoinStyle ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_oss.str(""); m_oss << static_cast(eJoinStyle) << " j" << std::endl; m_pCanvas->Append( m_oss.str() ); } void PdfPainter::SetFont( PdfFont* pFont ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); if( !pFont ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } m_pFont = pFont; } void PdfPainter::SetTextRenderingMode( EPdfTextRenderingMode mode ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); if (mode == currentTextRenderingMode) { return; } currentTextRenderingMode = mode; if (m_isTextOpen) SetCurrentTextRenderingMode(); } void PdfPainter::SetCurrentTextRenderingMode( void ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_oss << (int) currentTextRenderingMode << " Tr" << std::endl; } void PdfPainter::SetClipRect( double dX, double dY, double dWidth, double dHeight ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_oss.str(""); m_oss << dX << " " << dY << " " << dWidth << " " << dHeight << " re W n" << std::endl; m_pCanvas->Append( m_oss.str() ); m_curPath << dX << " " << dY << " " << dWidth << " " << dHeight << " re W n" << std::endl; } void PdfPainter::SetMiterLimit(double value) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_oss.str(""); m_oss << value << " M" << std::endl; m_pCanvas->Append( m_oss.str() ); } void PdfPainter::DrawLine( double dStartX, double dStartY, double dEndX, double dEndY ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_curPath.str(""); m_curPath << dStartX << " " << dStartY << " m " << dEndX << " " << dEndY << " l" << std::endl; m_oss.str(""); m_oss << dStartX << " " << dStartY << " m " << dEndX << " " << dEndY << " l S" << std::endl; m_pCanvas->Append( m_oss.str() ); } void PdfPainter::Rectangle( double dX, double dY, double dWidth, double dHeight, double dRoundX, double dRoundY ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); if ( static_cast(dRoundX) || static_cast(dRoundY) ) { double x = dX, y = dY, w = dWidth, h = dHeight, rx= dRoundX, ry = dRoundY; double b = 0.4477f; MoveTo(x + rx, y); LineTo(x + w - rx, y); CubicBezierTo(x + w - rx * b, y, x + w, y + ry * b, x + w, y + ry); LineTo(x + w, y + h - ry); CubicBezierTo(x + w, y + h - ry * b, x + w - rx * b, y + h, x + w - rx, y + h); LineTo(x + rx, y + h); CubicBezierTo(x + rx * b, y + h, x, y + h - ry * b, x, y + h - ry); LineTo(x, y + ry); CubicBezierTo(x, y + ry * b, x + rx * b, y, x + rx, y); } else { m_curPath << dX << " " << dY << " " << dWidth << " " << dHeight << " re" << std::endl; m_oss.str(""); m_oss << dX << " " << dY << " " << dWidth << " " << dHeight << " re" << std::endl; m_pCanvas->Append( m_oss.str() ); } } void PdfPainter::Ellipse( double dX, double dY, double dWidth, double dHeight ) { double dPointX[BEZIER_POINTS]; double dPointY[BEZIER_POINTS]; int i; PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); ConvertRectToBezier( dX, dY, dWidth, dHeight, dPointX, dPointY ); m_curPath << dPointX[0] << " " << dPointY[0] << " m" << std::endl; m_oss.str(""); m_oss << dPointX[0] << " " << dPointY[0] << " m" << std::endl; for( i=1;iAppend( m_oss.str() ); } void PdfPainter::Circle( double dX, double dY, double dRadius ) { if( !m_pCanvas ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } /* draw four Bezier curves to approximate a circle */ MoveTo( dX + dRadius, dY ); CubicBezierTo( dX + dRadius, dY + dRadius*ARC_MAGIC, dX + dRadius*ARC_MAGIC, dY + dRadius, dX, dY + dRadius ); CubicBezierTo( dX - dRadius*ARC_MAGIC, dY + dRadius, dX - dRadius, dY + dRadius*ARC_MAGIC, dX - dRadius, dY ); CubicBezierTo( dX - dRadius, dY - dRadius*ARC_MAGIC, dX - dRadius*ARC_MAGIC, dY - dRadius, dX, dY - dRadius ); CubicBezierTo( dX + dRadius*ARC_MAGIC, dY - dRadius, dX + dRadius, dY - dRadius*ARC_MAGIC, dX + dRadius, dY ); Close(); } void PdfPainter::DrawText( double dX, double dY, const PdfString & sText ) { this->DrawText( dX, dY, sText, static_cast(sText.GetCharacterLength()) ); } void PdfPainter::DrawText( double dX, double dY, const PdfString & sText, long lStringLen ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); if( !m_pFont || !m_pPage || !sText.IsValid() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } // Peter Petrov 25 September 2008 //m_pFont->EmbedFont(); PdfString sString = this->ExpandTabs( sText, lStringLen ); this->AddToPageResources( m_pFont->GetIdentifier(), m_pFont->GetObject()->Reference(), PdfName("Font") ); if( m_pFont->IsSubsetting() ) { m_pFont->AddUsedSubsettingGlyphs( sText, lStringLen ); } if( m_pFont->IsUnderlined() || m_pFont->IsStrikeOut()) { this->Save(); this->SetCurrentStrokingColor(); // Draw underline this->SetStrokeWidth( m_pFont->GetFontMetrics()->GetUnderlineThickness() ); if( m_pFont->IsUnderlined() ) { if (sString.IsUnicode()) this->DrawLine( dX, dY + m_pFont->GetFontMetrics()->GetUnderlinePosition(), dX + m_pFont->GetFontMetrics()->StringWidth( sString.GetUnicode() ), dY + m_pFont->GetFontMetrics()->GetUnderlinePosition() ); else this->DrawLine( dX, dY + m_pFont->GetFontMetrics()->GetUnderlinePosition(), dX + m_pFont->GetFontMetrics()->StringWidth( sString.GetString() ), dY + m_pFont->GetFontMetrics()->GetUnderlinePosition() ); } // Draw strikeout this->SetStrokeWidth( m_pFont->GetFontMetrics()->GetStrikeoutThickness() ); if( m_pFont->IsStrikeOut() ) { if (sString.IsUnicode()) this->DrawLine( dX, dY + m_pFont->GetFontMetrics()->GetStrikeOutPosition(), dX + m_pFont->GetFontMetrics()->StringWidth( sString.GetUnicode() ), dY + m_pFont->GetFontMetrics()->GetStrikeOutPosition() ); else this->DrawLine( dX, dY + m_pFont->GetFontMetrics()->GetStrikeOutPosition(), dX + m_pFont->GetFontMetrics()->StringWidth( sString.GetString() ), dY + m_pFont->GetFontMetrics()->GetStrikeOutPosition() ); } this->Restore(); } m_oss.str(""); m_oss << "BT" << std::endl << "/" << m_pFont->GetIdentifier().GetName() << " " << m_pFont->GetFontSize() << " Tf" << std::endl; if (currentTextRenderingMode != ePdfTextRenderingMode_Fill) { SetCurrentTextRenderingMode(); } //if( m_pFont->GetFontScale() != 100.0F ) - this value is kept between text blocks m_oss << m_pFont->GetFontScale() << " Tz" << std::endl; //if( m_pFont->GetFontCharSpace() != 0.0F ) - this value is kept between text blocks m_oss << m_pFont->GetFontCharSpace() * m_pFont->GetFontSize() / 100.0 << " Tc" << std::endl; m_oss << dX << std::endl << dY << std::endl << "Td "; m_pCanvas->Append( m_oss.str() ); m_pFont->WriteStringToStream( sString, m_pCanvas ); /* char* pBuffer; std::auto_ptr pFilter = PdfFilterFactory::Create( ePdfFilter_ASCIIHexDecode ); pFilter->Encode( sString.GetString(), sString.GetLength(), &pBuffer, &lLen ); m_pCanvas->Append( pBuffer, lLen ); podofo_free( pBuffer ); */ m_pCanvas->Append( " Tj\nET\n" ); } void PdfPainter::BeginText( double dX, double dY ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); if( !m_pFont || !m_pPage || m_isTextOpen) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } this->AddToPageResources( m_pFont->GetIdentifier(), m_pFont->GetObject()->Reference(), PdfName("Font") ); m_oss.str(""); m_oss << "BT" << std::endl << "/" << m_pFont->GetIdentifier().GetName() << " " << m_pFont->GetFontSize() << " Tf" << std::endl; if (currentTextRenderingMode != ePdfTextRenderingMode_Fill) { SetCurrentTextRenderingMode(); } //if( m_pFont->GetFontScale() != 100.0F ) - this value is kept between text blocks m_oss << m_pFont->GetFontScale() << " Tz" << std::endl; //if( m_pFont->GetFontCharSpace() != 0.0F ) - this value is kept between text blocks m_oss << m_pFont->GetFontCharSpace() * m_pFont->GetFontSize() / 100.0 << " Tc" << std::endl; m_oss << dX << " " << dY << " Td" << std::endl ; m_pCanvas->Append( m_oss.str() ); m_isTextOpen = true; } void PdfPainter::MoveTextPos( double dX, double dY ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); if( !m_pFont || !m_pPage || !m_isTextOpen ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } m_oss.str(""); m_oss << dX << " " << dY << " Td" << std::endl ; m_pCanvas->Append( m_oss.str() ); } void PdfPainter::AddText( const PdfString & sText ) { AddText( sText, sText.GetCharacterLength() ); } void PdfPainter::AddText( const PdfString & sText, pdf_long lStringLen ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); if( !m_pFont || !m_pPage || !sText.IsValid() || !m_isTextOpen ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } PdfString sString = this->ExpandTabs( sText, lStringLen ); if( m_pFont->IsSubsetting() ) { m_pFont->AddUsedSubsettingGlyphs( sText, lStringLen ); } // TODO: Underline and Strikeout not yet supported m_pFont->WriteStringToStream( sString, m_pCanvas ); m_pCanvas->Append( " Tj\n" ); } void PdfPainter::EndText() { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); if( !m_pFont || !m_pPage || !m_isTextOpen ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } m_pCanvas->Append( "ET\n" ); m_isTextOpen = false; } void PdfPainter::DrawMultiLineText( double dX, double dY, double dWidth, double dHeight, const PdfString & rsText, EPdfAlignment eAlignment, EPdfVerticalAlignment eVertical, bool bClip ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); if( !m_pFont || !m_pPage || !rsText.IsValid() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } // Peter Petrov 25 September 2008 //m_pFont->EmbedFont(); if( dWidth <= 0.0 || dHeight <= 0.0 ) // nonsense arguments return; this->Save(); if( bClip ) { this->SetClipRect( dX, dY, dWidth, dHeight ); } PdfString sString = this->ExpandTabs( rsText, rsText.GetCharacterLength() ); std::vector vecLines = GetMultiLineTextAsLines(dWidth, sString); double dLineGap = m_pFont->GetFontMetrics()->GetLineSpacing() - m_pFont->GetFontMetrics()->GetAscent() + m_pFont->GetFontMetrics()->GetDescent(); // Do vertical alignment switch( eVertical ) { default: case ePdfVerticalAlignment_Top: dY += dHeight; break; case ePdfVerticalAlignment_Bottom: dY += m_pFont->GetFontMetrics()->GetLineSpacing() * vecLines.size(); break; case ePdfVerticalAlignment_Center: dY += (dHeight - ((dHeight - (m_pFont->GetFontMetrics()->GetLineSpacing() * vecLines.size()))/2.0)); break; } dY -= (m_pFont->GetFontMetrics()->GetAscent() + dLineGap / (2.0)); std::vector::const_iterator it = vecLines.begin(); while( it != vecLines.end() ) { if( (*it).GetCharacterLength() ) this->DrawTextAligned( dX, dY, dWidth, *it, eAlignment ); dY -= m_pFont->GetFontMetrics()->GetLineSpacing(); ++it; } this->Restore(); } std::vector PdfPainter::GetMultiLineTextAsLines( double dWidth, const PdfString & rsText) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); if( !m_pFont || !m_pPage || !rsText.IsValid() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if( dWidth <= 0.0 ) // nonsense arguments return std::vector(); if( rsText.GetCharacterLength() == 0 ) // empty string return std::vector(1, rsText); // We will work with utf16 encoded string because it allows us // fast and easy individual characters access const std::string& stringUtf8 = rsText.GetStringUtf8(); std::vector stringUtf16(stringUtf8.length() + 1, 0); PODOFO_ASSERT( stringUtf16.size() > 0 ); const pdf_long converted = PdfString::ConvertUTF8toUTF16( reinterpret_cast(stringUtf8.c_str()), &stringUtf16[0], stringUtf16.size()); //const pdf_long len = rsText.GetCharacterLength(); PODOFO_ASSERT( converted == (rsText.GetCharacterLength() + 1) ); const pdf_utf16be* const stringUtf16Begin = &stringUtf16[0]; const pdf_utf16be* pszLineBegin = stringUtf16Begin; const pdf_utf16be* pszCurrentCharacter = stringUtf16Begin; const pdf_utf16be* pszStartOfCurrentWord = stringUtf16Begin; bool startOfWord = true; double dCurWidthOfLine = 0.0; std::vector vecLines; // do simple word wrapping while( *pszCurrentCharacter ) { if( IsNewLineChar( *pszCurrentCharacter ) ) // hard-break! { vecLines.push_back( PdfString( pszLineBegin, pszCurrentCharacter - pszLineBegin ) ); pszLineBegin = pszCurrentCharacter + 1;// skip the line feed startOfWord = true; dCurWidthOfLine = 0.0; } else if( IsSpaceChar( *pszCurrentCharacter ) ) { if( dCurWidthOfLine > dWidth ) { // The previous word does not fit in the current line. // -> Move it to the next one. if( pszStartOfCurrentWord > pszLineBegin ) { vecLines.push_back( PdfString( pszLineBegin, pszStartOfCurrentWord - pszLineBegin ) ); } else { vecLines.push_back( PdfString( pszLineBegin, pszCurrentCharacter - pszLineBegin ) ); // Skip all spaces at the end of the line while (IsSpaceChar(*(pszCurrentCharacter + 1))) pszCurrentCharacter++; pszStartOfCurrentWord = pszCurrentCharacter + 1; startOfWord=true; } pszLineBegin = pszStartOfCurrentWord; if (!startOfWord) { dCurWidthOfLine = m_pFont->GetFontMetrics()->StringWidth( pszStartOfCurrentWord, pszCurrentCharacter - pszStartOfCurrentWord ); } else { dCurWidthOfLine = 0.0; } } else { dCurWidthOfLine += m_pFont->GetFontMetrics()->UnicodeCharWidth( SwapCharBytesIfRequired( *pszCurrentCharacter ) ); } startOfWord = true; } else { if (startOfWord) { pszStartOfCurrentWord = pszCurrentCharacter; startOfWord = false; } //else do nothing if ((dCurWidthOfLine + m_pFont->GetFontMetrics()->UnicodeCharWidth( SwapCharBytesIfRequired( *pszCurrentCharacter ))) > dWidth) { if ( pszLineBegin == pszStartOfCurrentWord ) { // This word takes up the whole line. // Put as much as possible on this line. if (pszLineBegin == pszCurrentCharacter) { vecLines.push_back( PdfString( pszCurrentCharacter, 1 ) ); pszLineBegin = pszCurrentCharacter + 1; pszStartOfCurrentWord = pszCurrentCharacter + 1; dCurWidthOfLine = 0; } else { vecLines.push_back(PdfString(pszLineBegin, pszCurrentCharacter - pszLineBegin)); pszLineBegin = pszCurrentCharacter; pszStartOfCurrentWord = pszCurrentCharacter; dCurWidthOfLine = m_pFont->GetFontMetrics()->UnicodeCharWidth( SwapCharBytesIfRequired( *pszCurrentCharacter ) ); } } else { // The current word does not fit in the current line. // -> Move it to the next one. vecLines.push_back( PdfString( pszLineBegin, pszStartOfCurrentWord - pszLineBegin ) ); pszLineBegin = pszStartOfCurrentWord; dCurWidthOfLine = m_pFont->GetFontMetrics()->StringWidth( pszStartOfCurrentWord, (pszCurrentCharacter - pszStartOfCurrentWord) + 1); } } else { dCurWidthOfLine += m_pFont->GetFontMetrics()->UnicodeCharWidth( SwapCharBytesIfRequired( *pszCurrentCharacter ) ); } } ++pszCurrentCharacter; } if( (pszCurrentCharacter - pszLineBegin) > 0 ) { if( dCurWidthOfLine > dWidth && pszStartOfCurrentWord > pszLineBegin ) { // The previous word does not fit in the current line. // -> Move it to the next one. vecLines.push_back( PdfString( pszLineBegin, pszStartOfCurrentWord - pszLineBegin) ); pszLineBegin = pszStartOfCurrentWord; } //else do nothing if( pszCurrentCharacter - pszLineBegin > 0 ) { vecLines.push_back( PdfString( pszLineBegin, pszCurrentCharacter - pszLineBegin) ); } //else do nothing } return vecLines; } void PdfPainter::DrawTextAligned( double dX, double dY, double dWidth, const PdfString & rsText, EPdfAlignment eAlignment ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); if( !m_pFont || !m_pPage || !rsText.IsValid() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } // Peter Petrov 25 Septemer 2008 //m_pFont->EmbedFont(); if( dWidth <= 0.0 ) // nonsense arguments return; switch( eAlignment ) { default: case ePdfAlignment_Left: break; case ePdfAlignment_Center: dX += (dWidth - m_pFont->GetFontMetrics()->StringWidth( rsText ) ) / 2.0; break; case ePdfAlignment_Right: dX += (dWidth - m_pFont->GetFontMetrics()->StringWidth( rsText ) ); break; } this->DrawText( dX, dY, rsText ); } void PdfPainter::DrawGlyph( PdfMemDocument* pDocument, double dX, double dY, const char* pszGlyphname) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); if( !m_pFont || !m_pPage || !pszGlyphname ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } PdfFont* pGlyphFont = NULL; int code = 32; for ( int num = 1; num <= 999; num++ ) { // search for a copy of this font to enter difference-encoding, create a new one if not found char suffix[256]; sprintf( suffix, "Glyph%i", num ); pGlyphFont = pDocument->CreateDuplicateFontType1( m_pFont, suffix ); PdfObject* pGlyphFontObj = pGlyphFont->GetObject(); PdfObject* pEncoding = pGlyphFontObj->GetDictionary().GetKey( "Encoding" ); // first time: create difference-encoding as reference, enter glyph if ( pEncoding == NULL || pEncoding->IsReference() == false ) { // get width of glyph to enter in difference-encoding int width = static_cast(pGlyphFont->GetFontMetrics()->GetGlyphWidth( pszGlyphname ) ); pEncoding = pDocument->GetObjects().CreateObject( "Encoding" ); code++; PdfArray diffs; diffs.push_back( PdfVariant( static_cast( code ) ) ); diffs.push_back( PdfName( pszGlyphname ) ); pEncoding->GetDictionary().AddKey( "Differences", diffs ); pGlyphFontObj->GetDictionary().AddKey("Encoding", pEncoding->Reference() ); // clear Widths-array and enter width of this glyph PdfObject* pWidthObj = pGlyphFontObj->GetIndirectKey( "Widths" ); PdfArray & rWidthArr = pWidthObj->GetArray(); for ( unsigned int i = 0; i < rWidthArr.size(); i++ ) { rWidthArr[i] = PdfVariant( static_cast( 0 ) ); } rWidthArr[code] = PdfVariant( static_cast( width ) ); break; } // Existing font, search for glyph in existing difference-encoding { pEncoding = pDocument->GetObjects().GetObject( pEncoding->GetReference() ); PODOFO_ASSERT( pEncoding != NULL ); // paranoia PdfArray diffs; diffs = pEncoding->GetDictionary().GetKey( "Differences" )->GetArray(); bool foundIt = false; TCIVariantList it = diffs.begin(); while( it != diffs.end() ) { if( (*it).GetDataType() == ePdfDataType_Name ) { code++; if ( (*it).GetName().GetName() == pszGlyphname ) { foundIt = true; break; } } ++it; } if ( foundIt ) // glyph fount, use it break; } // limit to codes <= 127, make new duplicate font if more if ( code+1 >= 127 ) { code = 32; continue; } // add glyph to existing difference-encoding { // get width of glyph to enter in difference-encoding int width = static_cast(pGlyphFont->GetFontMetrics()->GetGlyphWidth( pszGlyphname ) ); code++; PdfArray diffs; diffs = pEncoding->GetDictionary().GetKey( "Differences" )->GetArray(); diffs.push_back( PdfName( pszGlyphname ) ); pEncoding->GetDictionary().AddKey( "Differences", diffs ); // enter width of glyph PdfObject* pWidthObj = pGlyphFontObj->GetIndirectKey( "Widths" ); PdfArray & rWidthArr = pWidthObj->GetArray(); rWidthArr[code] = PdfVariant( static_cast( width ) ); break; } } // select identical sizes pGlyphFont->SetFontSize( m_pFont->GetFontSize() ); pGlyphFont->SetFontCharSpace( m_pFont->GetFontCharSpace() ); pGlyphFont->SetFontScale( m_pFont->GetFontScale() ); PODOFO_ASSERT( code > 32 && code <= 127 ); if( m_pFont->IsSubsetting() ) { // mark glyph as used in basefont (needed for subsetting) m_pFont->AddUsedGlyphname( pszGlyphname ); } // output SetFont( pGlyphFont ); char temp[2]; temp[0] = code; temp[1] = '\0'; DrawText( dX, dY, PdfString( temp ) ); SetFont( m_pFont ); } void PdfPainter::DrawImage( double dX, double dY, PdfImage* pObject, double dScaleX, double dScaleY ) { this->DrawXObject( dX, dY, reinterpret_cast(pObject), dScaleX * pObject->GetPageSize().GetWidth(), dScaleY * pObject->GetPageSize().GetHeight() ); } void PdfPainter::DrawXObject( double dX, double dY, PdfXObject* pObject, double dScaleX, double dScaleY ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); if( !pObject ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } // use OriginalReference() as the XObject might have been written to disk // already and is not in memory anymore in this case. this->AddToPageResources( pObject->GetIdentifier(), pObject->GetObjectReference(), "XObject" ); std::streamsize oldPrecision = m_oss.precision(clPainterHighPrecision); m_oss.str(""); m_oss << "q" << std::endl << dScaleX << " 0 0 " << dScaleY << " " << dX << " " << dY << " cm" << std::endl << "/" << pObject->GetIdentifier().GetName() << " Do" << std::endl << "Q" << std::endl; m_oss.precision(oldPrecision); m_pCanvas->Append( m_oss.str() ); } void PdfPainter::ClosePath() { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_curPath << "h" << std::endl; m_pCanvas->Append( "h\n" ); } void PdfPainter::LineTo( double dX, double dY ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_curPath << dX << " " << dY << " l" << std::endl; m_oss.str(""); m_oss << dX << " " << dY << " l" << std::endl; m_pCanvas->Append( m_oss.str() ); } void PdfPainter::MoveTo( double dX, double dY ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_curPath << dX << " " << dY << " m" << std::endl; m_oss.str(""); m_oss << dX << " " << dY << " m" << std::endl; m_pCanvas->Append( m_oss.str() ); } void PdfPainter::CubicBezierTo( double dX1, double dY1, double dX2, double dY2, double dX3, double dY3 ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_curPath << dX1 << " " << dY1 << " " << dX2 << " " << dY2 << " " << dX3 << " " << dY3 << " c" << std::endl; m_oss.str(""); m_oss << dX1 << " " << dY1 << " " << dX2 << " " << dY2 << " " << dX3 << " " << dY3 << " c" << std::endl; m_pCanvas->Append( m_oss.str() ); } void PdfPainter::HorizontalLineTo( double inX ) { LineTo( inX, lpy3 ); } void PdfPainter::VerticalLineTo( double inY ) { LineTo( lpx3, inY ); } void PdfPainter::SmoothCurveTo( double inX2, double inY2, double inX3, double inY3 ) { double px, py, px2 = inX2, py2 = inY2, px3 = inX3, py3 = inY3; // compute the reflective points (thanks Raph!) px = 2 * lcx - lrx; py = 2 * lcy - lry; lpx = px; lpy = py; lpx2 = px2; lpy2 = py2; lpx3 = px3; lpy3 = py3; lcx = px3; lcy = py3; lrx = px2; lry = py2; // thanks Raph! CubicBezierTo( px, py, px2, py2, px3, py3 ); } void PdfPainter::QuadCurveTo( double inX1, double inY1, double inX3, double inY3 ) { double px = inX1, py = inY1, px2, py2, px3 = inX3, py3 = inY3; /* raise quadratic bezier to cubic - thanks Raph! http://www.icce.rug.nl/erikjan/bluefuzz/beziers/beziers/beziers.html */ px = (lcx + 2 * px) * (1.0 / 3.0); py = (lcy + 2 * py) * (1.0 / 3.0); px2 = (px3 + 2 * px) * (1.0 / 3.0); py2 = (py3 + 2 * py) * (1.0 / 3.0); lpx = px; lpy = py; lpx2 = px2; lpy2 = py2; lpx3 = px3; lpy3 = py3; lcx = px3; lcy = py3; lrx = px2; lry = py2; // thanks Raph! CubicBezierTo( px, py, px2, py2, px3, py3 ); } void PdfPainter::SmoothQuadCurveTo( double inX3, double inY3 ) { double px, py, px2, py2, px3 = inX3, py3 = inY3; double xc, yc; /* quadratic control point */ xc = 2 * lcx - lrx; yc = 2 * lcy - lry; /* generate a quadratic bezier with control point = xc, yc */ px = (lcx + 2 * xc) * (1.0 / 3.0); py = (lcy + 2 * yc) * (1.0 / 3.0); px2 = (px3 + 2 * xc) * (1.0 / 3.0); py2 = (py3 + 2 * yc) * (1.0 / 3.0); lpx = px; lpy = py; lpx2 = px2; lpy2 = py2; lpx3 = px3; lpy3 = py3; lcx = px3; lcy = py3; lrx = xc; lry = yc; // thanks Raph! CubicBezierTo( px, py, px2, py2, px3, py3 ); } void PdfPainter::ArcTo( double inX, double inY, double inRadiusX, double inRadiusY, double inRotation, bool inLarge, bool inSweep) { double px = inX, py = inY; double rx = inRadiusX, ry = inRadiusY, rot = inRotation; int large = ( inLarge ? 1 : 0 ), sweep = ( inSweep ? 1 : 0 ); double sin_th, cos_th; double a00, a01, a10, a11; double x0, y0, x1, y1, xc, yc; double d, sfactor, sfactor_sq; double th0, th1, th_arc; int i, n_segs; sin_th = sin (rot * (PI / 180.0)); cos_th = cos (rot * (PI / 180.0)); a00 = cos_th / rx; a01 = sin_th / rx; a10 = -sin_th / ry; a11 = cos_th / ry; x0 = a00 * lcx + a01 * lcy; y0 = a10 * lcx + a11 * lcy; x1 = a00 * px + a01 * py; y1 = a10 * px + a11 * py; /* (x0, y0) is current point in transformed coordinate space. (x1, y1) is new point in transformed coordinate space. The arc fits a unit-radius circle in this space. */ d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0); sfactor_sq = 1.0 / d - 0.25; if (sfactor_sq < 0) sfactor_sq = 0; sfactor = sqrt (sfactor_sq); if (sweep == large) sfactor = -sfactor; xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0); yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0); /* (xc, yc) is center of the circle. */ th0 = atan2 (y0 - yc, x0 - xc); th1 = atan2 (y1 - yc, x1 - xc); th_arc = th1 - th0; if (th_arc < 0 && sweep) th_arc += 2 * PI; else if (th_arc > 0 && !sweep) th_arc -= 2 * PI; n_segs = static_cast(ceil (fabs (th_arc / (PI * 0.5 + 0.001)))); for (i = 0; i < n_segs; i++) { double nth0 = th0 + static_cast(i) * th_arc / n_segs, nth1 = th0 + static_cast(i + 1) * th_arc / n_segs; double nsin_th = 0.0, ncos_th = 0.0; double na00 = 0.0, na01 = 0.0, na10 = 0.0, na11 = 0.0; double nx1 = 0.0, ny1 = 0.0, nx2 = 0.0, ny2 = 0.0, nx3 = 0.0, ny3 = 0.0; double t = 0.0; double th_half = 0.0; nsin_th = sin (rot * (PI / 180.0)); ncos_th = cos (rot * (PI / 180.0)); /* inverse transform compared with rsvg_path_arc */ na00 = ncos_th * rx; na01 = -nsin_th * ry; na10 = nsin_th * rx; na11 = ncos_th * ry; th_half = 0.5 * (nth1 - nth0); t = (8.0 / 3.0) * sin (th_half * 0.5) * sin (th_half * 0.5) / sin (th_half); nx1 = xc + cos (nth0) - t * sin (nth0); ny1 = yc + sin (nth0) + t * cos (nth0); nx3 = xc + cos (nth1); ny3 = yc + sin (nth1); nx2 = nx3 + t * sin (nth1); ny2 = ny3 - t * cos (nth1); nx1 = na00 * nx1 + na01 * ny1; ny1 = na10 * nx1 + na11 * ny1; nx2 = na00 * nx2 + na01 * ny2; ny2 = na10 * nx2 + na11 * ny2; nx3 = na00 * nx3 + na01 * ny3; ny3 = na10 * nx3 + na11 * ny3; CubicBezierTo( nx1, ny1, nx2, ny2, nx3, ny3 ); } lpx = lpx2 = lpx3 = px; lpy = lpy2 = lpy3 = py; lcx = px; lcy = py; lrx = px; lry = py; // thanks Raph! } // Peter Petrov 5 January 2009 was delivered from libHaru bool PdfPainter::Arc(double dX, double dY, double dRadius, double dAngle1, double dAngle2) { bool cont_flg = false; bool ret = true; if (dAngle1 >= dAngle2 || (dAngle2 - dAngle1) >= 360.0f) return false; while (dAngle1 < 0.0f || dAngle2 < 0.0f) { dAngle1 = dAngle1 + 360.0f; dAngle2 = dAngle2 + 360.0f; } for (;;) { if (dAngle2 - dAngle1 <= 90.0f) return InternalArc (dX, dY, dRadius, dAngle1, dAngle2, cont_flg); else { double tmp_ang = dAngle1 + 90.0f; ret = InternalArc (dX, dY, dRadius, dAngle1, tmp_ang, cont_flg); if (!ret) return ret; dAngle1 = tmp_ang; } if (dAngle1 >= dAngle2) break; cont_flg = true; } return true; } bool PdfPainter::InternalArc( double x, double y, double ray, double ang1, double ang2, bool cont_flg) { bool ret = true; double rx0, ry0, rx1, ry1, rx2, ry2, rx3, ry3; double x0, y0, x1, y1, x2, y2, x3, y3; double delta_angle = (90.0f - static_cast(ang1 + ang2) / 2.0f) / 180.0f * PI; double new_angle = static_cast(ang2 - ang1) / 2.0f / 180.0f * PI; rx0 = ray * cos (new_angle); ry0 = ray * sin (new_angle); rx2 = (ray * 4.0f - rx0) / 3.0f; ry2 = ((ray * 1.0f - rx0) * (rx0 - ray * 3.0f)) / (3.0 * ry0); rx1 = rx2; ry1 = -ry2; rx3 = rx0; ry3 = -ry0; x0 = rx0 * cos (delta_angle) - ry0 * sin (delta_angle) + x; y0 = rx0 * sin (delta_angle) + ry0 * cos (delta_angle) + y; x1 = rx1 * cos (delta_angle) - ry1 * sin (delta_angle) + x; y1 = rx1 * sin (delta_angle) + ry1 * cos (delta_angle) + y; x2 = rx2 * cos (delta_angle) - ry2 * sin (delta_angle) + x; y2 = rx2 * sin (delta_angle) + ry2 * cos (delta_angle) + y; x3 = rx3 * cos (delta_angle) - ry3 * sin (delta_angle) + x; y3 = rx3 * sin (delta_angle) + ry3 * cos (delta_angle) + y; if (!cont_flg) { MoveTo(x0,y0); } CubicBezierTo( x1, y1, x2, y2, x3, y3 ); //attr->cur_pos.x = (HPDF_REAL)x3; //attr->cur_pos.y = (HPDF_REAL)y3; lcx = x3; lcy = y3; lpx = lpx2 = lpx3 = x3; lpy = lpy2 = lpy3 = y3; lcx = x3; lcy = y3; lrx = x3; lry = y3; return ret; } void PdfPainter::Close() { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_curPath << "h" << std::endl; m_pCanvas->Append( "h\n" ); } void PdfPainter::Stroke() { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_curPath.str(""); m_pCanvas->Append( "S\n" ); } void PdfPainter::Fill(bool useEvenOddRule) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_curPath.str(""); if (useEvenOddRule) m_pCanvas->Append( "f*\n" ); else m_pCanvas->Append( "f\n" ); } void PdfPainter::FillAndStroke(bool useEvenOddRule) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_curPath.str(""); if (useEvenOddRule) m_pCanvas->Append( "B*\n" ); else m_pCanvas->Append( "B\n" ); } void PdfPainter::Clip( bool useEvenOddRule ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); if ( useEvenOddRule ) m_pCanvas->Append( "W* n\n" ); else m_pCanvas->Append( "W n\n" ); } void PdfPainter::EndPath(void) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_curPath << "n" << std::endl; m_pCanvas->Append( "n\n" ); } void PdfPainter::Save() { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_pCanvas->Append( "q\n" ); } void PdfPainter::Restore() { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_pCanvas->Append( "Q\n" ); } void PdfPainter::AddToPageResources( const PdfName & rIdentifier, const PdfReference & rRef, const PdfName & rName ) { if( !m_pPage ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } m_pPage->AddResource( rIdentifier, rRef, rName ); } void PdfPainter::ConvertRectToBezier( double dX, double dY, double dWidth, double dHeight, double pdPointX[], double pdPointY[] ) { // this function is based on code from: // http://www.codeguru.com/Cpp/G-M/gdi/article.php/c131/ // (Llew Goodstadt) // MAGICAL CONSTANT to map ellipse to beziers // 2/3*(sqrt(2)-1) const double dConvert = 0.2761423749154; double dOffX = dWidth * dConvert; double dOffY = dHeight * dConvert; double dCenterX = dX + (dWidth / 2.0); double dCenterY = dY + (dHeight / 2.0); pdPointX[0] = //------------------------// pdPointX[1] = // // pdPointX[11] = // 2___3___4 // pdPointX[12] = dX; // 1 5 // pdPointX[5] = // | | // pdPointX[6] = // | | // pdPointX[7] = dX + dWidth; // 0,12 6 // pdPointX[2] = // | | // pdPointX[10] = dCenterX - dOffX; // | | // pdPointX[4] = // 11 7 // pdPointX[8] = dCenterX + dOffX; // 10___9___8 // pdPointX[3] = // // pdPointX[9] = dCenterX; //------------------------// pdPointY[2] = pdPointY[3] = pdPointY[4] = dY; pdPointY[8] = pdPointY[9] = pdPointY[10] = dY + dHeight; pdPointY[7] = pdPointY[11] = dCenterY + dOffY; pdPointY[1] = pdPointY[5] = dCenterY - dOffY; pdPointY[0] = pdPointY[12] = pdPointY[6] = dCenterY; } void PdfPainter::SetCurrentStrokingColor() { SetStrokingColor( m_curColor ); } void PdfPainter::SetTransformationMatrix( double a, double b, double c, double d, double e, double f ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); // Need more precision for transformation-matrix !! std::streamsize oldPrecision = m_oss.precision(clPainterHighPrecision); m_oss.str(""); m_oss << a << " " << b << " " << c << " " << d << " " << e << " " << f << " cm" << std::endl; m_oss.precision(oldPrecision); m_pCanvas->Append( m_oss.str() ); } void PdfPainter::SetExtGState( PdfExtGState* inGState ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); this->AddToPageResources( inGState->GetIdentifier(), inGState->GetObject()->Reference(), PdfName("ExtGState") ); m_oss.str(""); m_oss << "/" << inGState->GetIdentifier().GetName() << " gs" << std::endl; m_pCanvas->Append( m_oss.str() ); } void PdfPainter::SetRenderingIntent( char* intent ) { PODOFO_RAISE_LOGIC_IF( !m_pCanvas, "Call SetPage() first before doing drawing operations." ); m_oss.str(""); m_oss << "/" << intent << " ri" << std::endl; m_pCanvas->Append( m_oss.str() ); } #if defined(_MSC_VER) && _MSC_VER <= 1200 // MSC 6.0 has a template-bug PdfString PdfPainter::ExpandTabs_char( const char* pszText, long lStringLen, int nTabCnt, const char cTab, const char cSpace ) const { long lLen = lStringLen + nTabCnt*(m_nTabWidth-1) + sizeof(char); char* pszTab = static_cast(podofo_calloc( lLen, sizeof(char) )); if( !pszTab ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } int i = 0; while( lStringLen-- ) { if( *pszText == cTab ) { for( int z=0;z(podofo_calloc( lLen, sizeof(pdf_utf16be) )); if( !pszTab ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } int i = 0; while( lStringLen-- ) { if( *pszText == cTab ) { for( int z=0;z PdfString PdfPainter::ExpandTabsPrivate( const C* pszText, pdf_long lStringLen, int nTabCnt, const C cTab, const C cSpace ) const { pdf_long lLen = lStringLen + nTabCnt*(m_nTabWidth-1) + sizeof(C); C* pszTab = static_cast(podofo_calloc( lLen, sizeof(C) )); if( !pszTab ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } int i = 0; while( lStringLen-- ) { if( *pszText == cTab ) { for( int z=0;z( rsString.GetUnicode(), lStringLen, nTabCnt, cTab, cSpace ); else return ExpandTabsPrivate( rsString.GetString(), lStringLen, nTabCnt, '\t', ' ' ); #endif } } /* namespace PoDoFo */ podofo-0.9.5/src/doc/PdfFontTTFSubset.cpp0000664000175000017500000007635313013650710020041 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfFontTTFSubset.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfInputDevice.h" #include "base/PdfOutputDevice.h" #include #include FT_FREETYPE_H #include FT_TRUETYPE_TABLES_H #include FT_TRUETYPE_TAGS_H #include #include #include namespace PoDoFo { static const unsigned int __LENGTH_HEADER12 = 12; static const unsigned int __LENGTH_OFFSETTABLE16 = 16; static const unsigned int __LENGTH_DWORD = 4; static const unsigned int __LENGTH_WORD = 2; //Big-endian to little-endian or little-endian to big endian. #ifdef PODOFO_IS_LITTLE_ENDIAN inline unsigned long Big2Little(unsigned long big) { return ((big << 24) & 0xFF000000) | ((big << 8) & 0x00FF0000) | ((big >> 8) & 0x0000FF00) | ((big >> 24) & 0x000000FF) ; } inline unsigned short Big2Little(unsigned short big) { return ((big << 8) & 0xFF00) | ((big >> 8) & 0x00FF); } inline short Big2Little(short big) { return ((big << 8) & 0xFF00) | ((big >> 8) & 0x00FF); } #else #define Big2Little( x ) x #endif // PODOFO_IS_LITTLE_ENDIAN inline void TTFWriteUInt32(char *bufp, unsigned long value) { bufp[0] = static_cast(value >> 24); bufp[1] = static_cast(value >> 16); bufp[2] = static_cast(value >> 8); bufp[3] = static_cast(value); } inline void TTFWriteUInt16(char *bufp, unsigned short value) { bufp[0] = static_cast(value >> 8); bufp[1] = static_cast(value); } //Get the number of bytes to pad the ul, because of 4-byte-alignment. #if UNUSED_CODE static unsigned int GetPadding(unsigned long ul); #endif static unsigned long TableCheksum(const char* bufp, unsigned long size); static unsigned short xln2(unsigned short v); static unsigned long TableCheksum(const char* bufp, unsigned long size) { unsigned long chksum = 0; unsigned long v = 0; for(unsigned long offset = 0; offset < size; offset += 4) { v = ((static_cast(bufp[offset + 0]) << 24) & 0xff000000) | ((static_cast(bufp[offset + 1]) << 16) & 0x00ff0000) | ((static_cast(bufp[offset + 2]) << 8) & 0x0000ff00) | ((static_cast(bufp[offset + 3]) ) & 0x000000ff); chksum += v; } return chksum; } PdfFontTTFSubset::PdfFontTTFSubset( const char* pszFontFileName, PdfFontMetrics* pMetrics, unsigned short nFaceIndex ) : m_pMetrics( pMetrics ), m_bIsLongLoca( false ), m_numTables( 0 ), m_numGlyphs( 0 ), m_numHMetrics( 0 ), m_faceIndex( nFaceIndex ), m_ulStartOfTTFOffsets( 0 ), m_bOwnDevice( true ) { //File type is now distinguished by ext, which might cause problems. const char* pname = pszFontFileName; const char* ext = pname + strlen(pname) - 3; if (PoDoFo::compat::strcasecmp(ext,"ttf") == 0) { m_eFontFileType = eFontFileType_TTF; } else if (PoDoFo::compat::strcasecmp(ext,"ttc") == 0) { m_eFontFileType = eFontFileType_TTC; } else if (PoDoFo::compat::strcasecmp(ext,"otf") == 0) { m_eFontFileType = eFontFileType_OTF; } else { m_eFontFileType = eFontFileType_Unknown; } m_pDevice = new PdfInputDevice( pszFontFileName ); } PdfFontTTFSubset::PdfFontTTFSubset( PdfInputDevice* pDevice, PdfFontMetrics* pMetrics, EFontFileType eType, unsigned short nFaceIndex ) : m_pMetrics( pMetrics ), m_eFontFileType( eType ), m_bIsLongLoca( false ), m_numTables( 0 ), m_numGlyphs( 0 ), m_numHMetrics( 0 ), m_faceIndex( nFaceIndex ), m_ulStartOfTTFOffsets( 0 ), m_pDevice( pDevice ), m_bOwnDevice( false ) { } PdfFontTTFSubset::~PdfFontTTFSubset() { if( m_bOwnDevice ) { delete m_pDevice; m_pDevice = NULL; } } void PdfFontTTFSubset::Init() { GetStartOfTTFOffsets(); GetNumberOfTables(); InitTables(); GetNumberOfGlyphs(); SeeIfLongLocaOrNot(); } unsigned long PdfFontTTFSubset::GetTableOffset( unsigned long tag ) { std::vector::const_iterator it = m_vTable.begin(); for (; it != m_vTable.end(); it++) { if (it->tag == tag) return it->offset; } PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "table missing" ); } void PdfFontTTFSubset::GetNumberOfGlyphs() { unsigned long ulOffset = GetTableOffset( TTAG_maxp ); GetData( ulOffset+__LENGTH_DWORD*1,&m_numGlyphs,__LENGTH_WORD); m_numGlyphs = Big2Little(m_numGlyphs); //std::cout << "numGlyphs: "<< m_numGlyphs << std::endl; ulOffset = GetTableOffset( TTAG_hhea ); GetData( ulOffset+__LENGTH_WORD*17, &m_numHMetrics, __LENGTH_WORD); m_numHMetrics = Big2Little(m_numHMetrics); //std::cout << "numHMetrics: "<< m_numHMetrics << std::endl; } #if UNUSED_CODE static void logTag(unsigned long tag) { std::cout << "ttfTable=" << static_cast(tag>>24) << static_cast(tag>>16) << static_cast(tag>>8) << static_cast(tag) << std::endl; } #endif void PdfFontTTFSubset::InitTables() { unsigned short tableMask = 0; TTrueTypeTable tbl; //std::cout << "ttfTables" << std::endl; for (unsigned short i = 0; i < m_numTables; i++) { //Name of each table: GetData( m_ulStartOfTTFOffsets+__LENGTH_HEADER12+__LENGTH_OFFSETTABLE16*i, &tbl.tag, __LENGTH_DWORD ); tbl.tag = Big2Little(tbl.tag); //Checksum of each table: GetData( m_ulStartOfTTFOffsets+__LENGTH_HEADER12+__LENGTH_OFFSETTABLE16*i+__LENGTH_DWORD*1,&tbl.checksum,__LENGTH_DWORD); tbl.checksum = Big2Little(tbl.checksum); //Offset of each table: GetData( m_ulStartOfTTFOffsets+__LENGTH_HEADER12+__LENGTH_OFFSETTABLE16*i+__LENGTH_DWORD*2,&tbl.offset,__LENGTH_DWORD); tbl.offset = Big2Little(tbl.offset); //Length of each table: GetData( m_ulStartOfTTFOffsets+__LENGTH_HEADER12+__LENGTH_OFFSETTABLE16*i+__LENGTH_DWORD*3,&tbl.length,__LENGTH_DWORD); tbl.length = Big2Little(tbl.length); //logTag(tbl.tag); //std::cout << " tableOffset=" << tbl.offset << " length=" << tbl.length << std::endl; switch(tbl.tag) { case TTAG_head: tableMask |= 0x0001; break; case TTAG_maxp: tableMask |= 0x0002; break; case TTAG_hhea: /* required to get numHMetrics */ tableMask |= 0x0004; break; case TTAG_glyf: tableMask |= 0x0008; break; case TTAG_loca: tableMask |= 0x0010; break; case TTAG_hmtx: /* advance width */ tableMask |= 0x0020; break; case TTAG_cmap: /* cmap table will be generated later */ tableMask |= 0x0100; break; case TTAG_post: if (tbl.length < 32) { tbl.tag = 0; } /* reduce table size, leter we will change format to 0x00030000 */ tbl.length = 32; break; case TTAG_cvt: case TTAG_fpgm: case TTAG_OS2: case TTAG_prep: //case TTAG_name: break; default: /* exclude all other tables */ tbl.tag = 0; break; } if (tbl.tag) { m_vTable.push_back(tbl); } } if ((tableMask & 0x3f )!= 0x3f) { //std::cout << "ttfTables=" << std::hex << tableMask << std::dec << std::endl; PODOFO_RAISE_ERROR_INFO( ePdfError_UnsupportedFontFormat, "Required TrueType table missing" ); } if ((tableMask & 0x0100 ) == 0x00) { tbl.tag = TTAG_cmap; tbl.checksum = 0; tbl.offset = 0; tbl.length = 0; m_vTable.push_back(tbl); } m_numTables = static_cast(m_vTable.size()); } void PdfFontTTFSubset::GetStartOfTTFOffsets() { switch (m_eFontFileType) { case eFontFileType_TTF: case eFontFileType_OTF: m_ulStartOfTTFOffsets = 0x0; break; case eFontFileType_TTC: { unsigned long ulnumFace; GetData( 8,&ulnumFace,4); ulnumFace = Big2Little(ulnumFace); GetData( (3+m_faceIndex)*__LENGTH_DWORD,&m_ulStartOfTTFOffsets,__LENGTH_DWORD); m_ulStartOfTTFOffsets = Big2Little(m_ulStartOfTTFOffsets); } break; case eFontFileType_Unknown: default: PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Invalid font type" ); } } void PdfFontTTFSubset::GetNumberOfTables() { GetData( m_ulStartOfTTFOffsets+1*__LENGTH_DWORD,&m_numTables,__LENGTH_WORD); m_numTables = Big2Little(m_numTables); } void PdfFontTTFSubset::SeeIfLongLocaOrNot() { unsigned short usIsLong; //1 for long unsigned long ulHeadOffset = GetTableOffset(TTAG_head); GetData( ulHeadOffset+50,&usIsLong,__LENGTH_WORD); usIsLong = Big2Little(usIsLong); m_bIsLongLoca = (usIsLong == 0 ? false : true); } static unsigned short xln2(unsigned short v) { unsigned short e = 0; while (v >>= 1) { ++e; } return e; } void PdfFontTTFSubset::BuildUsedCodes(CodePointToGid& usedCodes, const std::set& usedChars ) { CodePoint codePoint; GID gid; for (std::set::const_iterator it = usedChars.begin(); it != usedChars.end(); ++it) { codePoint = *it; gid = static_cast( m_pMetrics->GetGlyphId( codePoint ) ); usedCodes[codePoint] = gid; } } void PdfFontTTFSubset::LoadGlyphs(GlyphContext& ctx, const CodePointToGid& usedCodes) { // For any fonts, assume that glyph 0 is needed. LoadGID(ctx, 0); for (CodePointToGid::const_iterator cit = usedCodes.begin(); cit != usedCodes.end(); ++cit) { LoadGID(ctx, cit->second); } m_numGlyphs = 0; GlyphMap::reverse_iterator it = m_mGlyphMap.rbegin(); if (it != m_mGlyphMap.rend()) { m_numGlyphs = it->first; } ++m_numGlyphs; if (m_numHMetrics > m_numGlyphs) { m_numHMetrics = m_numGlyphs; } } void PdfFontTTFSubset::LoadGID(GlyphContext& ctx, GID gid) { if (gid < m_numGlyphs) { if (!m_mGlyphMap.count(gid)) { if (m_bIsLongLoca) { GetData( ctx.ulLocaTableOffset+__LENGTH_DWORD*gid, &ctx.glyphData.glyphAddress, __LENGTH_DWORD); ctx.glyphData.glyphAddress = Big2Little(ctx.glyphData.glyphAddress); GetData( ctx.ulLocaTableOffset+__LENGTH_DWORD*(gid+1), &ctx.glyphData.glyphLength, __LENGTH_DWORD); ctx.glyphData.glyphLength = Big2Little(ctx.glyphData.glyphLength); } else { GetData( ctx.ulLocaTableOffset+__LENGTH_WORD*gid, &ctx.shortOffset, __LENGTH_WORD); ctx.glyphData.glyphAddress = Big2Little(ctx.shortOffset); ctx.glyphData.glyphAddress <<= 1; GetData( ctx.ulLocaTableOffset+__LENGTH_WORD*(gid + 1), &ctx.shortOffset, __LENGTH_WORD); ctx.glyphData.glyphLength = Big2Little(ctx.shortOffset); ctx.glyphData.glyphLength <<= 1; } ctx.glyphData.glyphLength -= ctx.glyphData.glyphAddress; //std::cout << "gid=" << std::hex << gid << " len=" << std::dec << ctx.glyphData.glyphLength << std::endl; m_mGlyphMap[gid] = ctx.glyphData; GetData( ctx.ulGlyfTableOffset + ctx.glyphData.glyphAddress, &ctx.contourCount, __LENGTH_WORD); ctx.contourCount = Big2Little(ctx.contourCount); if (ctx.contourCount < 0) { /* skeep over numberOfContours, xMin, yMin, xMax and yMax */ LoadCompound(ctx, ctx.glyphData.glyphAddress + 5 * __LENGTH_WORD); } } return; } PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "GID out of range" ); } void PdfFontTTFSubset::LoadCompound(GlyphContext& ctx, unsigned long offset) { unsigned short flags; unsigned short glyphIndex; const int ARG_1_AND_2_ARE_WORDS = 0x01; const int WE_HAVE_A_SCALE = 0x08; const int MORE_COMPONENTS = 0x20; const int WE_HAVE_AN_X_AND_Y_SCALE = 0x40; const int WE_HAVE_TWO_BY_TWO = 0x80; while(true) { GetData( ctx.ulGlyfTableOffset + offset, &flags,__LENGTH_WORD); flags = Big2Little(flags); GetData( ctx.ulGlyfTableOffset + offset + __LENGTH_WORD, &glyphIndex, __LENGTH_WORD); glyphIndex = Big2Little( glyphIndex ); //std::cout << " comp gid=" << std::hex << glyphIndex << std::dec << std::endl; LoadGID(ctx, glyphIndex); if (!(flags & MORE_COMPONENTS)) { break; } offset += (flags & ARG_1_AND_2_ARE_WORDS) ? 4 * __LENGTH_WORD : 3 * __LENGTH_WORD; if (flags & WE_HAVE_A_SCALE) { offset += __LENGTH_WORD; } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) { offset += 2 * __LENGTH_WORD; } else if (flags & WE_HAVE_TWO_BY_TWO) { offset += 4 * __LENGTH_WORD; } } } unsigned long PdfFontTTFSubset::GetHmtxTableSize() { unsigned long tableLength = static_cast(m_numGlyphs + m_numHMetrics) << 1; //std::cout << "numGlyphs: "<< m_numGlyphs << " numHMetrics: " << m_numHMetrics << std::endl; return tableLength; } unsigned long PdfFontTTFSubset::GetCmapTableSize() { unsigned long tableSize = 0; //(m_sCMap.ranges.size() + 1) * 4 * __LENGTH_WORD; tableSize += m_sCMap.segCount * 4 * __LENGTH_WORD + __LENGTH_WORD; tableSize += m_sCMap.glyphArray.size() * __LENGTH_WORD; //std::cout << "cmapRanges: "<< m_sCMap.ranges.size() << " arraySize: " << m_sCMap.glyphArray.size() << std::endl; return 12ul + 14ul + tableSize; } void PdfFontTTFSubset::CreateCmapTable( const CodePointToGid& usedCodes ) { CMapRanges cmapRanges; CMapv4Range range; unsigned short arrayCount = 0; CodePointToGid::const_iterator cit = usedCodes.begin(); while (cit != usedCodes.end()) { range.endCode = range.startCode = static_cast(cit->first); range.delta = static_cast( cit->second - cit->first ); range.offset = 0; while (++cit != usedCodes.end()) { if ((range.endCode + 1u) != cit->first) { break; } ++range.endCode; if (!range.offset) { range.offset = range.endCode + range.delta - cit->second; } } if (range.offset) { //range.delta = 0; arrayCount += range.endCode - range.startCode + 1; } //std::cout << " sc=" << std::hex << range.startCode << " ec=" << range.endCode << " dc=" << range.startCode + range.delta << " of=" << range.offset << std::dec << std::endl; m_sCMap.ranges.push_back(range); } m_sCMap.segCount = static_cast(m_sCMap.ranges.size() + 1); /* fill glyphArray */ if (arrayCount) { m_sCMap.glyphArray.reserve(arrayCount); unsigned short arrayOffset = m_sCMap.segCount * __LENGTH_WORD; for (CMapRanges::iterator it = m_sCMap.ranges.begin(); it != m_sCMap.ranges.end(); ++it) { if (it->offset) { it->offset = arrayOffset; FillGlyphArray(usedCodes, it->startCode, it->endCode - it->startCode + 1); arrayOffset += (it->endCode - it->startCode + 1) * __LENGTH_WORD; } arrayOffset -= __LENGTH_WORD; //std::cout << " !sc=" << std::hex << it->startCode << " ec=" << it->endCode << " dc=" << it->startCode + it->delta << " of=" << it->offset << std::dec << std::endl; } } /* append final range */ range.endCode = range.startCode = static_cast(~0u); range.offset = range.delta = 0; m_sCMap.ranges.push_back(range); } void PdfFontTTFSubset::FillGlyphArray(const CodePointToGid& usedCodes, GID gid, unsigned short count) { CodePointToGid::const_iterator it = usedCodes.lower_bound(gid); do { if (it == usedCodes.end()) { PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Unexpected" ); } m_sCMap.glyphArray.push_back(it->second); ++it; } while(--count); } unsigned long PdfFontTTFSubset::WriteCmapTable(char* bufp) { unsigned short offset = 12; /* version and number of subtables */ TTFWriteUInt16(bufp + 0, 0); TTFWriteUInt16(bufp + 2, 1); /* platformID, platformSpecificID and offset */ TTFWriteUInt16(bufp + 4, 3); TTFWriteUInt16(bufp + 6, 1); TTFWriteUInt32(bufp + 8, offset); /* adjust bufp to begin of cmap format 4 table */ bufp += offset; /* format, length, language */ TTFWriteUInt16(bufp + 0, 4); TTFWriteUInt16(bufp + 2, 0); TTFWriteUInt16(bufp + 4, 0); /* segCountX2 */ TTFWriteUInt16(bufp + 6, m_sCMap.segCount << 1); unsigned short es = xln2(m_sCMap.segCount); unsigned short sr = 1 << (es + 1); /* searchRange */ TTFWriteUInt16(bufp + 8, sr); /* entrySelector */ TTFWriteUInt16(bufp + 10, es); /* rangeShift */ TTFWriteUInt16(bufp + 12, (m_sCMap.segCount << 1) - sr); /* adjust offset to first array */ offset = 14; CMapRanges::const_iterator it; /* write endCode array */ for (it = m_sCMap.ranges.begin(); it != m_sCMap.ranges.end(); ++it) { TTFWriteUInt16(bufp + offset, it->endCode); offset += __LENGTH_WORD; } /* write reservedPad */ TTFWriteUInt16(bufp + offset, 0); offset += __LENGTH_WORD; /* write startCode array */ for (it = m_sCMap.ranges.begin(); it != m_sCMap.ranges.end(); ++it) { TTFWriteUInt16(bufp + offset, it->startCode); offset += __LENGTH_WORD; } /* write idDelta array */ for (it = m_sCMap.ranges.begin(); it != m_sCMap.ranges.end(); ++it) { TTFWriteUInt16(bufp + offset, it->delta); offset += __LENGTH_WORD; } /* write idRangeOffset array */ for (it = m_sCMap.ranges.begin(); it != m_sCMap.ranges.end(); ++it) { TTFWriteUInt16(bufp + offset, it->offset); offset += __LENGTH_WORD; } std::vector::const_iterator uit; /* write glyphIndexArray */ for (uit = m_sCMap.glyphArray.begin(); uit != m_sCMap.glyphArray.end(); ++uit) { TTFWriteUInt16(bufp + offset, *uit); offset += __LENGTH_WORD; } /* update length of this table */ TTFWriteUInt16(bufp + 2, offset); /* return total length of cmap tables */ return offset + 12ul; } unsigned long PdfFontTTFSubset::GetGlyphTableSize() { unsigned long glyphTableSize = 0; for(GlyphMap::const_iterator it = m_mGlyphMap.begin(); it != m_mGlyphMap.end(); ++it) { glyphTableSize += it->second.glyphLength; } return glyphTableSize; } unsigned long PdfFontTTFSubset::WriteGlyphTable(char* bufp, unsigned long ulGlyphTableOffset) { unsigned long offset = 0; //std::cout << "glyfTable" << std::endl; for(GlyphMap::const_iterator it = m_mGlyphMap.begin(); it != m_mGlyphMap.end(); ++it) { //std::cout << " gid=" << std::hex << it->first << " len=" << it->second.glyphLength << std::dec << std::endl; if (it->second.glyphLength) { GetData( ulGlyphTableOffset + it->second.glyphAddress, bufp + offset, it->second.glyphLength); offset += it->second.glyphLength; } } return offset; } unsigned long PdfFontTTFSubset::GetLocaTableSize() { unsigned long offset = static_cast(m_numGlyphs + 1); return (m_bIsLongLoca) ? offset << 2 : offset << 1; } unsigned long PdfFontTTFSubset::WriteLocaTable(char* bufp) { GID glyphIndex = 0; unsigned long offset = 0; unsigned long glyphAddress = 0; //std::cout << "locaTable" << std::endl; if (m_bIsLongLoca) { for(GlyphMap::const_iterator it = m_mGlyphMap.begin(); it != m_mGlyphMap.end(); ++it) { while(glyphIndex < it->first) { /* set the glyph length to zero */ //std::cout << " gid=" << std::hex << glyphIndex << " offs=" << glyphAddress << std::dec << std::endl; TTFWriteUInt32(bufp + offset, glyphAddress); offset += 4; ++glyphIndex; } //std::cout << " gid=" << std::hex << glyphIndex << " offs=" << glyphAddress << " len=" << it->second.glyphLength << std::dec << std::endl; TTFWriteUInt32(bufp + offset, glyphAddress); glyphAddress += it->second.glyphLength; offset += 4; ++glyphIndex; //std::cout << " gid=" << glyphIndex << " address=" << ulNextAddress << " length=" << it->glyphLength << std::endl; } //std::cout << " gid=" << std::hex << glyphIndex << " offs=" << glyphAddress << std::dec << std::endl; TTFWriteUInt32(bufp + offset, glyphAddress); offset += 4; } else { for(GlyphMap::const_iterator it = m_mGlyphMap.begin(); it != m_mGlyphMap.end(); ++it) { while(glyphIndex < it->first) { //std::cout << " gid=" << std::hex << glyphIndex << " offs=" << glyphAddress << std::dec << std::endl; TTFWriteUInt16(bufp + offset, static_cast(glyphAddress >> 1)); offset += 2; ++glyphIndex; } //std::cout << " gid=" << std::hex << glyphIndex << " offs=" << glyphAddress << " len=" << it->second.glyphLength << std::dec << std::endl; TTFWriteUInt16(bufp + offset, static_cast(glyphAddress >> 1)); glyphAddress += it->second.glyphLength; offset += 2; ++glyphIndex; } //std::cout << " gid=" << std::hex << glyphIndex << " offs=" << glyphAddress << std::dec << std::endl; TTFWriteUInt16(bufp + offset, static_cast(glyphAddress >> 1)); offset += 2; } return offset; } unsigned long PdfFontTTFSubset::CalculateSubsetSize() { unsigned long subsetLength = __LENGTH_HEADER12 + m_numTables * __LENGTH_OFFSETTABLE16; unsigned long tableLength; //std::cout << "calcSubset" << std::endl; for (std::vector::iterator it = m_vTable.begin(); it != m_vTable.end(); it++) { switch(it->tag) { case TTAG_glyf: tableLength = GetGlyphTableSize(); break; case TTAG_loca: tableLength = GetLocaTableSize(); break; case TTAG_hmtx: tableLength = GetHmtxTableSize(); break; case TTAG_cmap: tableLength = GetCmapTableSize(); break; default: tableLength = it->length; break; } //logTag(it->tag); //std::cout << " calcSize=" << tableLength << " before=" << it->length << std::endl; it->length = tableLength; subsetLength += (tableLength + 3) & ~3; } //std::cout << "subsetSize=" << subsetLength << std::endl; return subsetLength; } void PdfFontTTFSubset::WriteTables(PdfRefCountedBuffer& fontData) { fontData.Resize( CalculateSubsetSize() ); char *bufp = fontData.GetBuffer(); /* write TFF Offset table */ { unsigned short es = xln2(m_numTables); unsigned short sr = es << 4; TTFWriteUInt32(bufp + 0, 0x00010000); TTFWriteUInt16(bufp + 4, m_numTables); TTFWriteUInt16(bufp + 6, sr); TTFWriteUInt16(bufp + 8, es); es = (m_numTables << 4) - sr; TTFWriteUInt16(bufp + 10, es); } unsigned long headOffset = 0; unsigned long dirOffset = __LENGTH_HEADER12; unsigned long tableOffset = dirOffset + m_numTables * __LENGTH_OFFSETTABLE16; unsigned long tableLength; unsigned long totalLength; for (std::vector::const_iterator it = m_vTable.begin(); it != m_vTable.end(); it++) { //logTag(it->tag); tableLength = 0; switch(it->tag) { case TTAG_head: headOffset = tableOffset; tableLength = it->length; GetData( it->offset, bufp + tableOffset, tableLength); TTFWriteUInt32(bufp + tableOffset + 8, 0); break; case TTAG_maxp: tableLength = it->length; GetData( it->offset, bufp + tableOffset, tableLength); TTFWriteUInt16(bufp + tableOffset + 4, m_numGlyphs); break; case TTAG_hhea: tableLength = it->length; GetData( it->offset, bufp + tableOffset, tableLength); TTFWriteUInt16(bufp + tableOffset + 34, m_numHMetrics); break; case TTAG_hmtx: tableLength = it->length; GetData( it->offset, bufp + tableOffset, tableLength); break; case TTAG_post: tableLength = it->length; GetData( it->offset, bufp + tableOffset, tableLength); TTFWriteUInt32(bufp + tableOffset, 0x00030000); memset(bufp + tableOffset + 16, 0, 16); break; case TTAG_glyf: //std::cout << " calcLen=" << it->length << std::endl; tableLength = WriteGlyphTable(bufp + tableOffset, it->offset); break; case TTAG_loca: //std::cout << " calcLen=" << it->length << std::endl; tableLength = WriteLocaTable(bufp + tableOffset); break; case TTAG_cmap: //std::cout << " calcLen=" << it->length << std::endl; tableLength = WriteCmapTable(bufp + tableOffset); break; default: tableLength = it->length; GetData( it->offset, bufp + tableOffset, tableLength); break; } //std::cout << " tableOffset=" << tableOffset << " length=" << tableLength << std::endl; if (tableLength) { /* write TFF Directory table entry */ totalLength = tableLength; while(totalLength & 3ul) { bufp[tableOffset + totalLength++] = '\0'; } TTFWriteUInt32(bufp + dirOffset, it->tag); TTFWriteUInt32(bufp + dirOffset + 4, TableCheksum(bufp + tableOffset, totalLength)); TTFWriteUInt32(bufp + dirOffset + 8, tableOffset); TTFWriteUInt32(bufp + dirOffset + 12, tableLength); tableOffset += totalLength; dirOffset += 16ul; } } //std::cout << " finalSize=" << tableOffset << " alloced=" << fontData.GetSize() << std::endl; /* head table */ if (!headOffset) { PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "'head' table missing" ); } TTFWriteUInt32(bufp + headOffset + 8, TableCheksum(bufp, tableLength) - 0xB1B0AFBA); } void PdfFontTTFSubset::BuildFont( PdfRefCountedBuffer& outputBuffer, const std::set& usedChars, std::vector& cidSet ) { Init(); #if UNUSED_CODE //Find the font offset table: unsigned long ulStartOfTTFOffsets = m_ulStartOfTTFOffsets; #endif GlyphContext context; context.ulGlyfTableOffset = GetTableOffset(TTAG_glyf); context.ulLocaTableOffset = GetTableOffset(TTAG_loca); { CodePointToGid usedCodes; BuildUsedCodes(usedCodes, usedChars); CreateCmapTable(usedCodes); LoadGlyphs(context, usedCodes); } //std::cout << "numGlyphs: "<< m_numGlyphs << " numHMetrics: " << m_numHMetrics << std::endl; if (m_numGlyphs) { cidSet.assign((m_numGlyphs + 7) >> 3, 0); GlyphMap::reverse_iterator rit = m_mGlyphMap.rbegin(); //std::cout << "createCIDSet n=" << gidToCodePoint.size() << std::endl; if (rit != m_mGlyphMap.rend()) { static const unsigned char bits[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; do { //std::cout << " cid=" << rit->first << std::endl; cidSet[rit->first >> 3] |= bits[rit->first & 7]; } while(++rit != m_mGlyphMap.rend()); } } WriteTables(outputBuffer); } void PdfFontTTFSubset::GetData(unsigned long offset, void* address, unsigned long sz) { m_pDevice->Seek( offset ); m_pDevice->Read( static_cast(address), sz ); } #if UNUSED_CODE // ----------------------------------------------------- // // ----------------------------------------------------- static unsigned int GetPadding(unsigned long ul) { ul &= 3; if (ul != 0) { ul = 4-ul; } return ul; } #endif }; /* PoDoFo */ podofo-0.9.5/src/doc/PdfFontType1Base14.cpp0000664000175000017500000001277613013650710020157 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfFontType1Base14.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfDictionary.h" #include "base/PdfEncoding.h" #include "PdfFontMetricsBase14.h" #include "base/PdfArray.h" namespace PoDoFo { PdfFontType1Base14::PdfFontType1Base14( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfVecObjects* pParent ) : PdfFontSimple( pMetrics, pEncoding, pParent ) { InitBase14Font( pMetrics ); } // OC 13.08.2010 New: PdfFontType1Base14::PdfFontType1Base14( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfObject* pObject ) : PdfFontSimple( pMetrics, pEncoding, pObject ) { InitBase14Font( pMetrics ); } PdfFontType1Base14::~PdfFontType1Base14() { // FontMetrics of base14 fonts may not be deleted m_pMetrics = NULL; } /* kausik : April 12th 2010 This is the font dictionary. It gets added to the page resources dictionary of the pdf. */ void PdfFontType1Base14::InitBase14Font( PdfFontMetrics* pMetrics ) { PdfVariant var; if( !m_pEncoding ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } this->GetObject()->GetDictionary().AddKey( PdfName::KeySubtype, PdfName("Type1")); this->GetObject()->GetDictionary().AddKey("BaseFont", PdfName( pMetrics->GetFontname() ) ); PdfObject *pWidth = this->GetObject()->GetOwner()->CreateObject(); if( !pWidth ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } m_pMetrics->GetWidthArray( *pWidth, m_pEncoding->GetFirstChar(), m_pEncoding->GetLastChar(), m_pEncoding ); this->GetObject()->GetDictionary().AddKey("Widths", pWidth->Reference() ); this->GetObject()->GetDictionary().AddKey("FirstChar", PdfVariant( static_cast(m_pEncoding->GetFirstChar()) ) ); this->GetObject()->GetDictionary().AddKey("LastChar", PdfVariant( static_cast(m_pEncoding->GetLastChar()) ) ); m_pEncoding->AddToDictionary( this->GetObject()->GetDictionary() ); // Add encoding key // pDescriptor->GetDictionary().AddKey( "FontName", this->GetBaseFont() ); //pDescriptor->GetDictionary().AddKey( "FontWeight", (long)m_pMetrics->Weight() ); // pDescriptor->GetDictionary().AddKey( PdfName::KeyFlags, PdfVariant( static_cast(32LL) ) ); // TODO: 0 ???? // pDescriptor->GetDictionary().AddKey( "FontBBox", array ); // pDescriptor->GetDictionary().AddKey( "ItalicAngle", PdfVariant( static_cast(m_pMetrics->GetItalicAngle()) ) ); // pDescriptor->GetDictionary().AddKey( "Ascent", m_pMetrics->GetPdfAscent() ); // pDescriptor->GetDictionary().AddKey( "Descent", m_pMetrics->GetPdfDescent() ); // pDescriptor->GetDictionary().AddKey( "CapHeight", m_pMetrics->GetPdfAscent() ); // m_pMetrics->CapHeight() ); // pDescriptor->GetDictionary().AddKey( "StemV", PdfVariant( static_cast(1LL) ) ); // m_pMetrics->StemV() ); // Peter Petrov 24 September 2008 // m_pDescriptor = pDescriptor; } void PdfFontType1Base14::EmbedFontFile( PdfObject* ) { // Do nothing, base 14 fonts do not need to be embedded } }; podofo-0.9.5/src/doc/PdfPage.cpp0000664000175000017500000004746712717041252016254 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfPage.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfDictionary.h" #include "base/PdfRect.h" #include "base/PdfVariant.h" #include "base/PdfWriter.h" #include "base/PdfStream.h" #include "PdfDocument.h" namespace PoDoFo { PdfPage::PdfPage( const PdfRect & rSize, PdfDocument* pParent ) : PdfElement( "Page", pParent ), PdfCanvas(), m_pContents( NULL ) { InitNewPage( rSize ); } PdfPage::PdfPage( const PdfRect & rSize, PdfVecObjects* pParent ) : PdfElement( "Page", pParent ), PdfCanvas(), m_pContents( NULL ) { InitNewPage( rSize ); } PdfPage::PdfPage( PdfObject* pObject, const std::deque & rListOfParents ) : PdfElement( "Page", pObject ), PdfCanvas() { m_pResources = this->GetObject()->GetIndirectKey( "Resources" ); if( !m_pResources ) { // Resources might be inherited std::deque::const_reverse_iterator it = rListOfParents.rbegin(); while( it != rListOfParents.rend() && !m_pResources ) { m_pResources = (*it)->GetIndirectKey( "Resources" ); ++it; } } PdfObject* pContents = this->GetObject()->GetIndirectKey( "Contents" ); if (pContents) { m_pContents = new PdfContents( pContents ); } else { // Create object on demand m_pContents = NULL; } } PdfPage::~PdfPage() { TIMapAnnotation it = m_mapAnnotations.begin(); while( it != m_mapAnnotations.end() ) { delete (*it).second; ++it; } delete m_pContents; // just clears the C++ object from memory, NOT the PdfObject } void PdfPage::InitNewPage( const PdfRect & rSize ) { PdfVariant mediabox; rSize.ToVariant( mediabox ); this->GetObject()->GetDictionary().AddKey( "MediaBox", mediabox ); // The PDF specification suggests that we send all available PDF Procedure sets this->GetObject()->GetDictionary().AddKey( "Resources", PdfObject( PdfDictionary() ) ); m_pResources = this->GetObject()->GetIndirectKey( "Resources" ); m_pResources->GetDictionary().AddKey( "ProcSet", PdfCanvas::GetProcSet() ); } void PdfPage::CreateContents() { if( !m_pContents ) { m_pContents = new PdfContents( this ); this->GetObject()->GetDictionary().AddKey( PdfName::KeyContents, m_pContents->GetContents()->Reference()); } } PdfObject* PdfPage::GetContents() const { if( !m_pContents ) { const_cast(this)->CreateContents(); } return m_pContents->GetContents(); } PdfObject* PdfPage::GetContentsForAppending() const { if( !m_pContents ) { const_cast(this)->CreateContents(); } return m_pContents->GetContentsForAppending(); } PdfRect PdfPage::CreateStandardPageSize( const EPdfPageSize ePageSize, bool bLandscape ) { PdfRect rect; switch( ePageSize ) { case ePdfPageSize_A0: rect.SetWidth( 2384.0 ); rect.SetHeight( 3370.0 ); break; case ePdfPageSize_A1: rect.SetWidth( 1684.0 ); rect.SetHeight( 2384.0 ); break; case ePdfPageSize_A2: rect.SetWidth( 1191.0 ); rect.SetHeight( 1684.0 ); break; case ePdfPageSize_A3: rect.SetWidth( 842.0 ); rect.SetHeight( 1190.0 ); break; case ePdfPageSize_A4: rect.SetWidth( 595.0 ); rect.SetHeight( 842.0 ); break; case ePdfPageSize_A5: rect.SetWidth( 420.0 ); rect.SetHeight( 595.0 ); break; case ePdfPageSize_A6: rect.SetWidth( 297.0 ); rect.SetHeight( 420.0 ); break; case ePdfPageSize_Letter: rect.SetWidth( 612.0 ); rect.SetHeight( 792.0 ); break; case ePdfPageSize_Legal: rect.SetWidth( 612.0 ); rect.SetHeight( 1008.0 ); break; case ePdfPageSize_Tabloid: rect.SetWidth( 792.0 ); rect.SetHeight( 1224.0 ); break; default: break; } if( bLandscape ) { double dTmp = rect.GetWidth(); rect.SetWidth ( rect.GetHeight() ); rect.SetHeight( dTmp ); } return rect; } const PdfObject* PdfPage::GetInheritedKeyFromObject( const char* inKey, const PdfObject* inObject ) const { const PdfObject* pObj = NULL; // check for it in the object itself if ( inObject->GetDictionary().HasKey( inKey ) ) { pObj = inObject->GetDictionary().GetKey( inKey ); if ( !pObj->IsNull() ) return pObj; } // if we get here, we need to go check the parent - if there is one! if( inObject->GetDictionary().HasKey( "Parent" ) ) { pObj = inObject->GetIndirectKey( "Parent" ); if( pObj ) pObj = GetInheritedKeyFromObject( inKey, pObj ); } return pObj; } const PdfRect PdfPage::GetPageBox( const char* inBox ) const { PdfRect pageBox; const PdfObject* pObj; // Take advantage of inherited values - walking up the tree if necessary pObj = GetInheritedKeyFromObject( inBox, this->GetObject() ); // Sometime page boxes are defined using reference objects while ( pObj && pObj->IsReference() ) { pObj = this->GetObject()->GetOwner()->GetObject( pObj->GetReference() ); } // assign the value of the box from the array if ( pObj && pObj->IsArray() ) { pageBox.FromArray( pObj->GetArray() ); } else if ( strcmp( inBox, "ArtBox" ) == 0 || strcmp( inBox, "BleedBox" ) == 0 || strcmp( inBox, "TrimBox" ) == 0 ) { // If those page boxes are not specified then // default to CropBox per PDF Spec (3.6.2) pageBox = GetPageBox( "CropBox" ); } else if ( strcmp( inBox, "CropBox" ) == 0 ) { // If crop box is not specified then // default to MediaBox per PDF Spec (3.6.2) pageBox = GetPageBox( "MediaBox" ); } return pageBox; } int PdfPage::GetRotation() const { int rot = 0; const PdfObject* pObj = GetInheritedKeyFromObject( "Rotate", this->GetObject() ); if ( pObj && pObj->IsNumber() ) rot = static_cast(pObj->GetNumber()); return rot; } void PdfPage::SetRotation(int nRotation) { if( nRotation != 0 && nRotation != 90 && nRotation != 180 && nRotation != 270 ) PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); this->GetObject()->GetDictionary().AddKey( "Rotate", PdfVariant(static_cast(nRotation)) ); } PdfObject* PdfPage::GetAnnotationsArray( bool bCreate ) const { PdfObject* pObj; // check for it in the object itself if ( this->GetObject()->GetDictionary().HasKey( "Annots" ) ) { pObj = this->GetObject()->GetIndirectKey( "Annots" ); if( pObj && pObj->IsArray() ) return pObj; } else if( bCreate ) { PdfArray array; this->GetNonConstObject()->GetDictionary().AddKey( "Annots", array ); return const_cast(this->GetObject()->GetDictionary().GetKey( "Annots" )); } return NULL; } int PdfPage::GetNumAnnots() const { PdfObject* pObj = this->GetAnnotationsArray(); return pObj ? static_cast(pObj->GetArray().size()) : 0; } PdfAnnotation* PdfPage::CreateAnnotation( EPdfAnnotation eType, const PdfRect & rRect ) { PdfAnnotation* pAnnot = new PdfAnnotation( this, eType, rRect, this->GetObject()->GetOwner() ); PdfObject* pObj = this->GetAnnotationsArray( true ); PdfReference ref = pAnnot->GetObject()->Reference(); pObj->GetArray().push_back( ref ); m_mapAnnotations[ref] = pAnnot; return pAnnot; } PdfAnnotation* PdfPage::GetAnnotation( int index ) { PdfAnnotation* pAnnot; PdfReference ref; PdfObject* pObj = this->GetAnnotationsArray( false ); if( !(pObj && pObj->IsArray()) ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } if( index < 0 && static_cast(index) >= pObj->GetArray().size() ) { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } ref = pObj->GetArray()[index].GetReference(); pAnnot = m_mapAnnotations[ref]; if( !pAnnot ) { pObj = this->GetObject()->GetOwner()->GetObject( ref ); if( !pObj ) { PdfError::DebugMessage( "Error looking up object %i %i R\n", ref.ObjectNumber(), ref.GenerationNumber() ); PODOFO_RAISE_ERROR( ePdfError_NoObject ); } pAnnot = new PdfAnnotation( pObj, this ); m_mapAnnotations[ref] = pAnnot; } return pAnnot; } void PdfPage::DeleteAnnotation( int index ) { PdfReference ref; PdfObject* pObj = this->GetAnnotationsArray( false ); if( !(pObj && pObj->IsArray()) ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } if( index < 0 && static_cast(index) >= pObj->GetArray().size() ) { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } ref = pObj->GetArray()[index].GetReference(); this->DeleteAnnotation( ref ); } void PdfPage::DeleteAnnotation( const PdfReference & ref ) { PdfAnnotation* pAnnot; PdfArray::iterator it; PdfObject* pObj = this->GetAnnotationsArray( false ); bool bFound = false; // delete the annotation from the array if( !(pObj && pObj->IsArray()) ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } it = pObj->GetArray().begin(); while( it != pObj->GetArray().end() ) { if( (*it).GetReference() == ref ) { pObj->GetArray().erase( it ); bFound = true; break; } ++it; } // if no such annotation was found // throw an error instead of deleting // another object with this reference if( !bFound ) { PODOFO_RAISE_ERROR( ePdfError_NoObject ); } // delete any cached PdfAnnotations pAnnot = m_mapAnnotations[ref]; if( pAnnot ) { delete pAnnot; m_mapAnnotations.erase( ref ); } // delete the PdfObject in the file delete this->GetObject()->GetOwner()->RemoveObject( ref ); } // added by Petr P. Petrov 21 Febrary 2010 bool PdfPage::SetPageWidth(int newWidth) { PdfObject* pObjMediaBox; // Take advantage of inherited values - walking up the tree if necessary pObjMediaBox = const_cast(GetInheritedKeyFromObject( "MediaBox", this->GetObject() )); // assign the value of the box from the array if ( pObjMediaBox && pObjMediaBox->IsArray() ) { // in PdfRect::FromArray(), the Left value is subtracted from Width double dLeftMediaBox = pObjMediaBox->GetArray()[0].GetReal(); pObjMediaBox->GetArray()[2].SetReal( newWidth + dLeftMediaBox ); PdfObject* pObjCropBox; // Take advantage of inherited values - walking up the tree if necessary pObjCropBox = const_cast(GetInheritedKeyFromObject( "CropBox", this->GetObject() )); if ( pObjCropBox && pObjCropBox->IsArray() ) { // in PdfRect::FromArray(), the Left value is subtracted from Width double dLeftCropBox = pObjCropBox->GetArray()[0].GetReal(); pObjCropBox->GetArray()[2].SetReal( newWidth + dLeftCropBox ); return true; } else { return false; } } else { return false; } } // added by Petr P. Petrov 21 Febrary 2010 bool PdfPage::SetPageHeight(int newHeight) { PdfObject* pObj; // Take advantage of inherited values - walking up the tree if necessary pObj = const_cast(GetInheritedKeyFromObject( "MediaBox", this->GetObject() )); // assign the value of the box from the array if ( pObj && pObj->IsArray() ) { // in PdfRect::FromArray(), the Bottom value is subtracted from Height double dBottom = pObj->GetArray()[1].GetReal(); pObj->GetArray()[3].SetReal( newHeight + dBottom ); PdfObject* pObjCropBox; // Take advantage of inherited values - walking up the tree if necessary pObjCropBox = const_cast(GetInheritedKeyFromObject( "CropBox", this->GetObject() )); if ( pObjCropBox && pObjCropBox->IsArray() ) { // in PdfRect::FromArray(), the Bottom value is subtracted from Height double dBottomCropBox = pObjCropBox->GetArray()[1].GetReal(); pObjCropBox->GetArray()[3].SetReal( newHeight + dBottomCropBox ); return true; } else { return false; } } else { return false; } } void PdfPage::SetTrimBox( const PdfRect & rSize ) { PdfVariant trimbox; rSize.ToVariant( trimbox ); this->GetObject()->GetDictionary().AddKey( "TrimBox", trimbox ); } unsigned int PdfPage::GetPageNumber() const { unsigned int nPageNumber = 0; PdfObject* pParent = this->GetObject()->GetIndirectKey( "Parent" ); PdfReference ref = this->GetObject()->Reference(); while( pParent ) { PdfObject* pKids = pParent->GetIndirectKey( "Kids" ); if ( pKids != NULL ) { const PdfArray& kids = pKids->GetArray(); PdfArray::const_iterator it = kids.begin(); while( it != kids.end() && (*it).GetReference() != ref ) { PdfObject* pNode = this->GetObject()->GetOwner()->GetObject( (*it).GetReference() ); if( pNode->GetDictionary().GetKey( PdfName::KeyType ) != NULL && pNode->GetDictionary().GetKey( PdfName::KeyType )->GetName() == PdfName( "Pages" ) ) { PdfObject* pCount = pNode->GetIndirectKey( "Count" ); if( pCount != NULL ) { nPageNumber += static_cast(pCount->GetNumber()); } } else { // if we do not have a page tree node, // we most likely have a page object: // so the page count is 1 ++nPageNumber; } ++it; } } ref = pParent->Reference(); pParent = pParent->GetIndirectKey( "Parent" ); } return ++nPageNumber; } int PdfPage::GetNumFields() const { int nCount = 0; int nAnnots = this->GetNumAnnots(); const PdfAnnotation* pAnnot = NULL; for( int i=0;i(this)->GetAnnotation( i ); // Count every widget annotation with a FieldType as PdfField if( pAnnot->GetType() == ePdfAnnotation_Widget ) ++nCount; } return nCount; } PdfField PdfPage::GetField( int index ) { int nCount = 0; int nAnnots = this->GetNumAnnots(); PdfAnnotation* pAnnot = NULL; for( int i=0;iGetAnnotation( i ); // Count every widget annotation with a FieldType as PdfField if( pAnnot->GetType() == ePdfAnnotation_Widget ) { if( nCount == index ) { return PdfField( pAnnot->GetObject(), pAnnot ); } else ++nCount; } } PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } const PdfField PdfPage::GetField( int index ) const { PdfField field = const_cast(this)->GetField( index ); return field; } PdfObject* PdfPage::GetFromResources( const PdfName & rType, const PdfName & rKey ) { if( m_pResources->GetDictionary().HasKey( rType ) ) { // OC 15.08.2010 BugFix: Ghostscript creates here sometimes an indirect reference to a directory // PdfObject* pType = m_pResources->GetDictionary().GetKey( rType ); PdfObject* pType = m_pResources->GetIndirectKey( rType ); if( pType->IsDictionary() && pType->GetDictionary().HasKey( rKey ) ) { const PdfReference & ref = pType->GetDictionary().GetKey( rKey )->GetReference(); return this->GetObject()->GetOwner()->GetObject( ref ); } } return NULL; } PdfObject* PdfPage::GetOwnAnnotationsArray( bool bCreate, PdfDocument *pDocument) { PdfObject* pObj; if ( this->GetObject()->GetDictionary().HasKey( "Annots" ) ) { pObj = this->GetObject()->GetIndirectKey( "Annots" ); if(!pObj) { pObj = this->GetObject()->GetDictionary().GetKey("Annots"); if( pObj->IsReference() ) { if( !pDocument ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "Object is a reference but does not have an owner!" ); } pObj = pDocument->GetObjects()->GetObject( pObj->GetReference() ); if(pObj) { pObj->SetOwner(this->GetObject()->GetOwner()); } } else pObj->SetOwner( this->GetObject()->GetOwner() );// even directs might want an owner... } if( pObj && pObj->IsArray() ) return pObj; } else if( bCreate ) { PdfArray array; this->GetNonConstObject()->GetDictionary().AddKey( "Annots", array ); return const_cast(this->GetObject()->GetDictionary().GetKey( "Annots" )); } return NULL; } }; podofo-0.9.5/src/doc/PdfShadingPattern.cpp0000664000175000017500000005631412355520733020306 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfShadingPattern.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfColor.h" #include "base/PdfDictionary.h" #include "base/PdfLocale.h" #include "base/PdfStream.h" #include "base/PdfWriter.h" #include "PdfFunction.h" #include namespace PoDoFo { PdfShadingPattern::PdfShadingPattern( EPdfShadingPatternType eShadingType, PdfVecObjects* pParent ) : PdfElement( "Pattern", pParent ) { std::ostringstream out; // We probably aren't doing anything locale sensitive here, but it's // best to be sure. PdfLocaleImbue(out); // Implementation note: the identifier is always // Prefix+ObjectNo. Prefix is /Ft for fonts. out << "Sh" << this->GetObject()->Reference().ObjectNumber(); m_Identifier = PdfName( out.str().c_str() ); this->Init( eShadingType ); } PdfShadingPattern::PdfShadingPattern( EPdfShadingPatternType eShadingType, PdfDocument* pParent ) : PdfElement( "Pattern", pParent ) { std::ostringstream out; // We probably aren't doing anything locale sensitive here, but it's // best to be sure. PdfLocaleImbue(out); // Implementation note: the identifier is always // Prefix+ObjectNo. Prefix is /Ft for fonts. out << "Sh" << this->GetObject()->Reference().ObjectNumber(); m_Identifier = PdfName( out.str().c_str() ); this->Init( eShadingType ); } PdfShadingPattern::~PdfShadingPattern() { } void PdfShadingPattern::Init( EPdfShadingPatternType eShadingType ) { /* switch( eShadingType ) { case ePdfShadingPatternType_FunctionBase: { PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } break; case ePdfShadingPatternType_Radial: { PdfArray coords; coords.push_back( 0.0 ); coords.push_back( 0.0 ); coords.push_back( 0.096 ); coords.push_back( 0.0 ); coords.push_back( 0.0 ); coords.push_back( 1.0 ); PdfArray domain; domain.push_back( 0.0 ); domain.push_back( 1.0 ); PdfArray c0; c0.push_back( 0.929 ); c0.push_back( 0.357 ); c0.push_back( 1.0 ); c0.push_back( 0.298 ); PdfArray c1a; c0.push_back( 0.631 ); c0.push_back( 0.278 ); c0.push_back( 1.0 ); c0.push_back( 0.027 ); PdfArray c1b; c0.push_back( 0.94 ); c0.push_back( 0.4 ); c0.push_back( 1.0 ); c0.push_back( 0.102 ); PdfExponentialFunction f1( domain, c0, c1a, 1.048, this->GetObject()->GetOwner() ); PdfExponentialFunction f2( domain, c0, c1b, 1.374, this->GetObject()->GetOwner() ); PdfFunction::List list; list.push_back( f1 ); list.push_back( f2 ); PdfArray bounds; bounds.push_back( 0.708 ); PdfArray encode; encode.push_back( 1.0 ); encode.push_back( 0.0 ); encode.push_back( 0.0 ); encode.push_back( 1.0 ); PdfStitchingFunction function( list, domain, bounds, encode, this->GetObject()->GetOwner() ); shading.AddKey( PdfName("Coords"), coords ); shading.AddKey( PdfName("Function"), function.GetObject()->Reference() ); break; } case ePdfShadingPatternType_FreeForm: { PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } break; case ePdfShadingPatternType_LatticeForm: { PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } break; case ePdfShadingPatternType_CoonsPatch: { PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } break; case ePdfShadingPatternType_TensorProduct: { PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } break; default: { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidEnumValue, "PdfShadingPattern::Init() failed because of an invalid shading pattern type." ); } }; */ // keys common to all shading directories PdfDictionary shading; shading.AddKey( PdfName("ShadingType"), static_cast(eShadingType) ); this->GetObject()->GetDictionary().AddKey( PdfName("PatternType"), static_cast(2L) ); // Shading pattern if (eShadingType < ePdfShadingPatternType_FreeForm) { this->GetObject()->GetDictionary().AddKey( PdfName("Shading"), shading ); } else { PdfObject *shadingObject = this->GetObject()->GetOwner()->CreateObject(shading); this->GetObject()->GetDictionary().AddKey(PdfName("Shading"), shadingObject->Reference()); this->GetObject()->GetDictionary().GetKey(PdfName("Shading"))->SetOwner(this->GetObject()->GetOwner()); } } PdfAxialShadingPattern::PdfAxialShadingPattern( double dX0, double dY0, double dX1, double dY1, const PdfColor & rStart, const PdfColor & rEnd, PdfVecObjects* pParent ) : PdfShadingPattern( ePdfShadingPatternType_Axial, pParent ) { Init( dX0, dY0, dX1, dY1, rStart, rEnd ); } PdfAxialShadingPattern::PdfAxialShadingPattern( double dX0, double dY0, double dX1, double dY1, const PdfColor & rStart, const PdfColor & rEnd, PdfDocument* pParent ) : PdfShadingPattern( ePdfShadingPatternType_Axial, pParent ) { Init( dX0, dY0, dX1, dY1, rStart, rEnd ); } void PdfAxialShadingPattern::Init( double dX0, double dY0, double dX1, double dY1, const PdfColor & rStart, const PdfColor & rEnd ) { PdfArray coords; coords.push_back( dX0 ); coords.push_back( dY0 ); coords.push_back( dX1 ); coords.push_back( dY1 ); if( rStart.GetColorSpace() != rEnd.GetColorSpace() ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Colorspace of start and end color in PdfAxialShadingPattern does not match." ); } PdfArray c0 = rStart.ToArray(); PdfArray c1 = rEnd.ToArray(); PdfArray extend; extend.push_back( true ); extend.push_back( true ); PdfArray domain; domain.push_back( 0.0 ); domain.push_back( 1.0 ); PdfExponentialFunction function( domain, c0, c1, 1.0, this->GetObject()->GetOwner() ); PdfDictionary & shading = this->GetObject()->GetDictionary().GetKey( PdfName("Shading") )->GetDictionary(); switch( rStart.GetColorSpace() ) { case ePdfColorSpace_DeviceRGB: shading.AddKey( PdfName("ColorSpace"), PdfName("DeviceRGB") ); break; case ePdfColorSpace_DeviceCMYK: shading.AddKey( PdfName("ColorSpace"), PdfName("DeviceCMYK") ); break; case ePdfColorSpace_DeviceGray: shading.AddKey( PdfName("ColorSpace"), PdfName("DeviceGray") ); break; case ePdfColorSpace_CieLab: { PdfObject * csp = rStart.BuildColorSpace( this->GetObject()->GetOwner() ); shading.AddKey( PdfName("ColorSpace"), csp->Reference() ); } break; case ePdfColorSpace_Separation: { PdfObject * csp = rStart.BuildColorSpace( this->GetObject()->GetOwner() ); shading.AddKey( PdfName("ColorSpace"), csp->Reference() ); } break; case ePdfColorSpace_Indexed: case ePdfColorSpace_Unknown: default: PODOFO_RAISE_ERROR_INFO( ePdfError_CannotConvertColor, "Colorspace not supported in PdfAxialShadingPattern." ); break; } shading.AddKey( PdfName("Coords"), coords ); shading.AddKey( PdfName("Function"), function.GetObject()->Reference() ); shading.AddKey( PdfName("Extend"), extend ); } PdfFunctionBaseShadingPattern::PdfFunctionBaseShadingPattern( const PdfColor & rLL, const PdfColor & rUL, const PdfColor & rLR, const PdfColor & rUR, const PdfArray & rMatrix, PdfVecObjects* pParent ) : PdfShadingPattern( ePdfShadingPatternType_FunctionBase, pParent ) { Init( rLL, rUL, rLR, rUR, rMatrix ); } PdfFunctionBaseShadingPattern::PdfFunctionBaseShadingPattern( const PdfColor & rLL, const PdfColor & rUL, const PdfColor & rLR, const PdfColor & rUR, const PdfArray & rMatrix, PdfDocument* pParent ) : PdfShadingPattern( ePdfShadingPatternType_FunctionBase, pParent ) { Init( rLL, rUL, rLR, rUR, rMatrix ); } void PdfFunctionBaseShadingPattern::Init( const PdfColor & rLL, const PdfColor & rUL, const PdfColor & rLR, const PdfColor & rUR, const PdfArray & rMatrix ) { if( rLL.GetColorSpace() != rUL.GetColorSpace() || rUL.GetColorSpace() != rLR.GetColorSpace() || rLR.GetColorSpace() != rUR.GetColorSpace() ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Colorspace of start and end color in PdfFunctionBaseShadingPattern does not match." ); } PdfArray domain; domain.push_back( 0.0 ); domain.push_back( 1.0 ); domain.push_back( 0.0 ); domain.push_back( 1.0 ); PdfDictionary & shading = this->GetObject()->GetDictionary().GetKey( PdfName("Shading") )->GetDictionary(); PdfArray range; PdfSampledFunction::Sample samples; switch ( rLL.GetColorSpace() ) { case ePdfColorSpace_DeviceRGB: { range.push_back( 0.0 ); range.push_back( 1.0 ); range.push_back( 0.0 ); range.push_back( 1.0 ); range.push_back( 0.0 ); range.push_back( 1.0 ); samples.insert( samples.end(), static_cast ( rLL.GetRed() *255.0 ) ); samples.insert( samples.end(), static_cast ( rLL.GetGreen() *255.0 ) ); samples.insert( samples.end(), static_cast ( rLL.GetBlue() *255.0 ) ); samples.insert( samples.end(), static_cast ( rLR.GetRed() *255.0 ) ); samples.insert( samples.end(), static_cast ( rLR.GetGreen() *255.0 ) ); samples.insert( samples.end(), static_cast ( rLR.GetBlue() *255.0 ) ); samples.insert( samples.end(), static_cast ( rUL.GetRed() *255.0 ) ); samples.insert( samples.end(), static_cast ( rUL.GetGreen() *255.0 ) ); samples.insert( samples.end(), static_cast ( rUL.GetBlue() *255.0 ) ); samples.insert( samples.end(), static_cast ( rUR.GetRed() *255.0 ) ); samples.insert( samples.end(), static_cast ( rUR.GetGreen() *255.0 ) ); samples.insert( samples.end(), static_cast ( rUR.GetBlue() *255.0 ) ); shading.AddKey( PdfName("ColorSpace"), PdfName("DeviceRGB") ); } break; case ePdfColorSpace_DeviceCMYK: { range.push_back( 0.0 ); range.push_back( 1.0 ); range.push_back( 0.0 ); range.push_back( 1.0 ); range.push_back( 0.0 ); range.push_back( 1.0 ); range.push_back( 0.0 ); range.push_back( 1.0 ); samples.insert( samples.end(), static_cast ( rLL.GetCyan() *255.0 ) ); samples.insert( samples.end(), static_cast ( rLL.GetMagenta() *255.0 ) ); samples.insert( samples.end(), static_cast ( rLL.GetYellow() *255.0 ) ); samples.insert( samples.end(), static_cast ( rLL.GetBlack() *255.0 ) ); samples.insert( samples.end(), static_cast ( rLR.GetCyan() *255.0 ) ); samples.insert( samples.end(), static_cast ( rLR.GetMagenta() *255.0 ) ); samples.insert( samples.end(), static_cast ( rLR.GetYellow() *255.0 ) ); samples.insert( samples.end(), static_cast ( rLR.GetBlack() *255.0 ) ); samples.insert( samples.end(), static_cast ( rUL.GetCyan() *255.0 ) ); samples.insert( samples.end(), static_cast ( rUL.GetMagenta() *255.0 ) ); samples.insert( samples.end(), static_cast ( rUL.GetYellow() *255.0 ) ); samples.insert( samples.end(), static_cast ( rUL.GetBlack() *255.0 ) ); samples.insert( samples.end(), static_cast ( rUR.GetCyan() *255.0 ) ); samples.insert( samples.end(), static_cast ( rUR.GetMagenta() *255.0 ) ); samples.insert( samples.end(), static_cast ( rUR.GetYellow() *255.0 ) ); samples.insert( samples.end(), static_cast ( rUR.GetBlack() *255.0 ) ); shading.AddKey( PdfName("ColorSpace"), PdfName("DeviceCMYK") ); } break; case ePdfColorSpace_DeviceGray: { range.push_back( 0.0 ); range.push_back( 1.0 ); samples.insert( samples.end(), static_cast ( rLL.GetGrayScale() *255.0 ) ); samples.insert( samples.end(), static_cast ( rLR.GetGrayScale() *255.0 ) ); samples.insert( samples.end(), static_cast ( rUL.GetGrayScale() *255.0 ) ); samples.insert( samples.end(), static_cast ( rUR.GetGrayScale() *255.0 ) ); shading.AddKey( PdfName("ColorSpace"), PdfName("DeviceGray") ); } break; case ePdfColorSpace_CieLab: { range.push_back( 0.0 ); range.push_back( 100.0 ); range.push_back( -128.0 ); range.push_back( 127.0 ); range.push_back( -128.0 ); range.push_back( 127.0 ); samples.insert( samples.end(), static_cast ( rLL.GetCieL() *2.55 ) ); samples.insert( samples.end(), static_cast ( rLL.GetCieA() +128 ) ); samples.insert( samples.end(), static_cast ( rLL.GetCieB() +128 ) ); samples.insert( samples.end(), static_cast ( rLR.GetCieL() *2.55 ) ); samples.insert( samples.end(), static_cast ( rLR.GetCieA() +128 ) ); samples.insert( samples.end(), static_cast ( rLR.GetCieB() +128 ) ); samples.insert( samples.end(), static_cast ( rUL.GetCieL() *2.55 ) ); samples.insert( samples.end(), static_cast ( rUL.GetCieA() +128 ) ); samples.insert( samples.end(), static_cast ( rUL.GetCieB() +128 ) ); samples.insert( samples.end(), static_cast ( rUR.GetCieL() *2.55 ) ); samples.insert( samples.end(), static_cast ( rUR.GetCieA() +128 ) ); samples.insert( samples.end(), static_cast ( rUR.GetCieB() +128 ) ); PdfObject * csp = rLL.BuildColorSpace( this->GetObject()->GetOwner() ); shading.AddKey( PdfName("ColorSpace"), csp->Reference() ); } break; case ePdfColorSpace_Separation: { range.push_back( 0.0 ); range.push_back( 1.0 ); samples.insert( samples.end(), static_cast ( rLL.GetDensity() *255.0 ) ); samples.insert( samples.end(), static_cast ( rLR.GetDensity() *255.0 ) ); samples.insert( samples.end(), static_cast ( rUL.GetDensity() *255.0 ) ); samples.insert( samples.end(), static_cast ( rUR.GetDensity() *255.0 ) ); PdfObject * csp = rLL.BuildColorSpace( this->GetObject()->GetOwner() ); shading.AddKey( PdfName("ColorSpace"), csp->Reference() ); } break; case ePdfColorSpace_Indexed: case ePdfColorSpace_Unknown: default: PODOFO_RAISE_ERROR_INFO( ePdfError_CannotConvertColor, "Colorspace not supported in PdfFunctionBaseShadingPattern." ); break; } PdfSampledFunction function( domain, range, samples, this->GetObject()->GetOwner() ); shading.AddKey( PdfName("Function"), function.GetObject()->Reference() ); shading.AddKey( PdfName("Domain"), domain ); shading.AddKey( PdfName("Matrix"), rMatrix ); } PdfRadialShadingPattern::PdfRadialShadingPattern( double dX0, double dY0, double dR0, double dX1, double dY1, double dR1, const PdfColor & rStart, const PdfColor & rEnd, PdfVecObjects* pParent ) : PdfShadingPattern( ePdfShadingPatternType_Radial, pParent ) { Init( dX0, dY0, dR0, dX1, dY1, dR1, rStart, rEnd ); } PdfRadialShadingPattern::PdfRadialShadingPattern( double dX0, double dY0, double dR0, double dX1, double dY1, double dR1, const PdfColor & rStart, const PdfColor & rEnd, PdfDocument* pParent ) : PdfShadingPattern( ePdfShadingPatternType_Radial, pParent ) { Init( dX0, dY0, dR0, dX1, dY1, dR1, rStart, rEnd ); } void PdfRadialShadingPattern::Init( double dX0, double dY0, double dR0, double dX1, double dY1, double dR1, const PdfColor & rStart, const PdfColor & rEnd ) { PdfArray coords; coords.push_back( dX0 ); coords.push_back( dY0 ); coords.push_back( dR0 ); coords.push_back( dX1 ); coords.push_back( dY1 ); coords.push_back( dR1 ); if( rStart.GetColorSpace() != rEnd.GetColorSpace() ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Colorspace of start and end color in PdfRadialShadingPattern does not match." ); } PdfArray c0 = rStart.ToArray(); PdfArray c1 = rEnd.ToArray(); PdfArray extend; extend.push_back( true ); extend.push_back( true ); PdfArray domain; domain.push_back( 0.0 ); domain.push_back( 1.0 ); PdfExponentialFunction function( domain, c0, c1, 1.0, this->GetObject()->GetOwner() ); PdfDictionary & shading = this->GetObject()->GetDictionary().GetKey( PdfName("Shading") )->GetDictionary(); switch( rStart.GetColorSpace() ) { case ePdfColorSpace_DeviceRGB: shading.AddKey( PdfName("ColorSpace"), PdfName("DeviceRGB") ); break; case ePdfColorSpace_DeviceCMYK: shading.AddKey( PdfName("ColorSpace"), PdfName("DeviceCMYK") ); break; case ePdfColorSpace_DeviceGray: shading.AddKey( PdfName("ColorSpace"), PdfName("DeviceGray") ); break; case ePdfColorSpace_CieLab: { PdfObject * csp = rStart.BuildColorSpace( this->GetObject()->GetOwner() ); shading.AddKey( PdfName("ColorSpace"), csp->Reference() ); } break; case ePdfColorSpace_Separation: { PdfObject * csp = rStart.BuildColorSpace( this->GetObject()->GetOwner() ); shading.AddKey( PdfName("ColorSpace"), csp->Reference() ); } break; case ePdfColorSpace_Indexed: case ePdfColorSpace_Unknown: default: PODOFO_RAISE_ERROR_INFO( ePdfError_CannotConvertColor, "Colorspace not supported in PdfRadialShadingPattern." ); break; } shading.AddKey( PdfName("Coords"), coords ); shading.AddKey( PdfName("Function"), function.GetObject()->Reference() ); shading.AddKey( PdfName("Extend"), extend ); } PdfTriangleShadingPattern::PdfTriangleShadingPattern( double dX0, double dY0, const PdfColor &color0, double dX1, double dY1, const PdfColor &color1, double dX2, double dY2, const PdfColor &color2, PdfVecObjects* pParent ) : PdfShadingPattern( ePdfShadingPatternType_FreeForm, pParent ) { Init(dX0, dY0, color0, dX1, dY1, color1, dX2, dY2, color2 ); } PdfTriangleShadingPattern::PdfTriangleShadingPattern( double dX0, double dY0, const PdfColor &color0, double dX1, double dY1, const PdfColor &color1, double dX2, double dY2, const PdfColor &color2, PdfDocument* pParent ) : PdfShadingPattern( ePdfShadingPatternType_FreeForm, pParent ) { Init(dX0, dY0, color0, dX1, dY1, color1, dX2, dY2, color2 ); } void PdfTriangleShadingPattern::Init( double dX0, double dY0, const PdfColor &color0, double dX1, double dY1, const PdfColor &color1, double dX2, double dY2, const PdfColor &color2 ) { if (color0.GetColorSpace() != color1.GetColorSpace() || color0.GetColorSpace() != color2.GetColorSpace()) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Colorspace of start and end color in PdfTriangleShadingPattern does not match." ); } PdfColor rgb0 = color0.ConvertToRGB(); PdfColor rgb1 = color1.ConvertToRGB(); PdfColor rgb2 = color2.ConvertToRGB(); PdfArray decode; double minx, maxx, miny, maxy; #define mMIN(a,b) ((a) < (b) ? (a) : (b)) #define mMAX(a,b) ((a) > (b) ? (a) : (b)) minx = mMIN(mMIN(dX0, dX1), dX2); maxx = mMAX(mMAX(dX0, dX1), dX2); miny = mMIN(mMIN(dY0, dY1), dY2); maxy = mMAX(mMAX(dY0, dY1), dY2); #undef mMIN #undef mMAX decode.push_back(minx); decode.push_back(maxx); decode.push_back(miny); decode.push_back(maxy); decode.push_back(static_cast(0)); decode.push_back(static_cast(1)); decode.push_back(static_cast(0)); decode.push_back(static_cast(1)); decode.push_back(static_cast(0)); decode.push_back(static_cast(1)); PdfObject *shadingObject = this->GetObject()->GetIndirectKey(PdfName("Shading")); PdfDictionary &shading = shadingObject->GetDictionary(); shading.AddKey( PdfName("ColorSpace"), PdfName("DeviceRGB") ); shading.AddKey( PdfName("BitsPerCoordinate"), static_cast(8)); shading.AddKey( PdfName("BitsPerComponent"), static_cast(8)); shading.AddKey( PdfName("BitsPerFlag"), static_cast(8)); shading.AddKey( PdfName("Decode"), decode); // f x y c1 c2 c3 int len = (1 + 1 + 1 + 1 + 1 + 1) * 3; char buff[18]; buff[ 0] = 0; // flag - start new triangle buff[ 1] = static_cast(255.0 * (dX0 - minx) / (maxx - minx)); buff[ 2] = static_cast(255.0 * (dY0 - miny) / (maxy - miny)); buff[ 3] = static_cast(255.0 * rgb0.GetRed()); buff[ 4] = static_cast(255.0 * rgb0.GetGreen()); buff[ 5] = static_cast(255.0 * rgb0.GetBlue()); buff[ 6] = 0; // flag - start new triangle buff[ 7] = static_cast(255.0 * (dX1 - minx) / (maxx - minx)); buff[ 8] = static_cast(255.0 * (dY1 - miny) / (maxy - miny)); buff[ 9] = static_cast(255.0 * rgb1.GetRed()); buff[10] = static_cast(255.0 * rgb1.GetGreen()); buff[11] = static_cast(255.0 * rgb1.GetBlue()); buff[12] = 0; // flag - start new triangle buff[13] = static_cast(255.0 * (dX2 - minx) / (maxx - minx)); buff[14] = static_cast(255.0 * (dY2 - miny) / (maxy - miny)); buff[15] = static_cast(255.0 * rgb2.GetRed()); buff[16] = static_cast(255.0 * rgb2.GetGreen()); buff[17] = static_cast(255.0 * rgb2.GetBlue()); shadingObject->GetStream()->Set(buff, len); } } // end namespace podofo-0.9.5/src/doc/PdfInfo.h0000664000175000017500000002212212347307436015725 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_INFO_H_ #define _PDF_INFO_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfName.h" #include "podofo/base/PdfDate.h" #include "PdfElement.h" namespace PoDoFo { class PdfString; /** This class provides access to the documents * info dictionary, which provides information * about the PDF document. */ class PODOFO_DOC_API PdfInfo : public PdfElement { public: /** * Enum to specifiy the initial information of the * info dictionary. */ enum EPdfInfoInitial { ePdfInfoInitial_WriteCreationTime = 0x01, ///< Write the creation time (current time). Default for new documents. ePdfInfoInitial_WriteModificationTime = 0x02, ///< Write the modification time (current time). Default for loaded documents. ePdfInfoInitial_WriteProducer = 0x04 ///< Write producer key. Default for new documents. }; /** Create a new PdfInfo object * \param pParent the parent of this object * \param eInitial which information should be * writting initially to the information dictionary */ PdfInfo( PdfVecObjects* pParent, int eInitial = ePdfInfoInitial_WriteCreationTime | ePdfInfoInitial_WriteProducer ); /** Create a PdfInfo object from an existing * object in the PDF file. * \param pObject must be an info dictionary. * \param eInitial which information should be * writting initially to the information */ PdfInfo( PdfObject* pObject, int eInitial = ePdfInfoInitial_WriteModificationTime ); /** Destructor */ ~PdfInfo(); /** Set the author of the document. * \param sAuthor author */ void SetAuthor( const PdfString & sAuthor ); /** Get the author of the document * \returns the author */ inline const PdfString & GetAuthor() const; /** Set the creator of the document. * Typically the name of the application using the library. * \param sCreator creator */ void SetCreator( const PdfString & sCreator ); /** Get the creator of the document * \returns the creator */ inline const PdfString & GetCreator() const; /** Set keywords for this document * \param sKeywords a list of keywords */ void SetKeywords( const PdfString & sKeywords ); /** Get the keywords of the document * \returns the keywords */ inline const PdfString & GetKeywords() const; /** Set the subject of the document. * \param sSubject subject */ void SetSubject( const PdfString & sSubject ); /** Get the subject of the document * \returns the subject */ inline const PdfString & GetSubject() const; /** Set the title of the document. * \param sTitle title */ void SetTitle( const PdfString & sTitle ); /** Get the title of the document * \returns the title */ inline const PdfString & GetTitle() const; // Peter Petrov 27 April 2008 /** Set the producer of the document. * \param sProducer producer */ void SetProducer( const PdfString & sProducer ); // Peter Petrov 27 April 2008 /** Get the producer of the document * \returns the producer */ inline const PdfString & GetProducer() const; /** Set the trapping state of the document. * \param sTrapped trapped */ void SetTrapped( const PdfName & sTrapped ); /** Get the trapping state of the document * \returns the title */ inline const PdfName & GetTrapped() const; /** Get creation date of document * \return creation date */ inline PdfDate GetCreationDate() const; /** Get modification date of document * \return modification date */ inline PdfDate GetModDate() const; /** Set custom info key. * \param sName Name of the key. * \param sValue Value of the key. */ void SetCustomKey(const PdfName &sName, const PdfString &sValue); private: /** Add the initial document information to the dictionary. * \param eInitial which information should be * writting initially to the information */ void Init( int eInitial ); /** Get a value from the info dictionary as name * \para rName the key to fetch from the info dictionary * \return a value from the info dictionary */ const PdfString & GetStringFromInfoDict( const PdfName & rName ) const; /** Get a value from the info dictionary as name * \para rName the key to fetch from the info dictionary * \return a value from the info dictionary */ const PdfName & GetNameFromInfoDict( const PdfName & rName ) const; }; // ----------------------------------------------------- // // ----------------------------------------------------- const PdfString & PdfInfo::GetAuthor() const { return this->GetStringFromInfoDict( PdfName("Author") ); } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfString & PdfInfo::GetCreator() const { return this->GetStringFromInfoDict( PdfName("Creator") ); } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfString & PdfInfo::GetKeywords() const { return this->GetStringFromInfoDict( PdfName("Keywords") ); } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfString & PdfInfo::GetSubject() const { return this->GetStringFromInfoDict( PdfName("Subject") ); } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfString & PdfInfo::GetTitle() const { return this->GetStringFromInfoDict( PdfName("Title") ); } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfString & PdfInfo::GetProducer() const { return this->GetStringFromInfoDict( PdfName("Producer") ); } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfName & PdfInfo::GetTrapped() const { return this->GetNameFromInfoDict( PdfName("Trapped") ); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfDate PdfInfo::GetCreationDate() const { return PdfDate(this->GetStringFromInfoDict(PdfName("CreationDate"))); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfDate PdfInfo::GetModDate() const { return PdfDate(this->GetStringFromInfoDict(PdfName("ModDate"))); } }; #endif // _PDF_INFO_H_ podofo-0.9.5/src/doc/PdfCMapEncoding.h0000664000175000017500000000756312602051620017316 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2011 by Dominik Seichter * * domseichter@web.de * * * * Pdf CMAP encoding by kalyan * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_CMAP_ENCODING_H #define _PDF_CMAP_ENCODING_H #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfEncoding.h" #include "PdfElement.h" namespace PoDoFo { class PODOFO_DOC_API PdfCMapEncoding: public PdfEncoding, private PdfElement{ public: enum EBaseEncoding { eBaseEncoding_Font, ///< Use The fonts encoding as base eBaseEncoding_WinAnsi, ///< Use WinAnsiEncoding as base encoding eBaseEncoding_MacRoman, ///< Use MacRomanEncoding as base encoding eBaseEncoding_MacExpert ///< Use MacExpertEncoding as base encoding }; PdfCMapEncoding(PdfObject* pObject, PdfObject* pToUnicode = NULL); virtual PdfString ConvertToUnicode(const PdfString& rEncodedString, const PdfFont* pFont) const; virtual void AddToDictionary(PdfDictionary & rDictionary ) const; virtual PdfRefCountedBuffer ConvertToEncoding(const PdfString& rString, const PdfFont* pFont) const; virtual bool IsAutoDelete() const; virtual bool IsSingleByteEncoding() const; virtual pdf_utf16be GetCharCode(int nIndex) const; virtual const PdfName & GetID() const; const PdfEncoding* GetBaseEncoding() const; private: EBaseEncoding m_baseEncoding; std::map m_cMap; }; }; /*PoDoFo namespace end*/ #endif // _PDF_CMAP_ENCODING_H podofo-0.9.5/src/doc/PdfNamesTree.h0000664000175000017500000001711112344436402016710 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_NAMES_TREE_H_ #define _PDF_NAMES_TREE_H_ #include "podofo/base/PdfDefines.h" #include "PdfElement.h" namespace PoDoFo { class PdfDictionary; class PdfName; class PdfObject; class PdfString; class PdfVecObjects; enum EPdfNameLimits { ePdfNameLimits_Before, ePdfNameLimits_Inside, ePdfNameLimits_After }; class PODOFO_DOC_API PdfNamesTree : public PdfElement { public: /** Create a new PdfNamesTree object * \param pParent parent of this action */ PdfNamesTree( PdfVecObjects* pParent ); /** Create a PdfNamesTree object from an existing PdfObject * \param pObject the object to create from * \param pCatalog the Catalog dictionary of the owning PDF */ PdfNamesTree( PdfObject* pObject, PdfObject* pCatalog ); virtual ~PdfNamesTree() { } /** Insert a key and value in one of the dictionaries of the name tree. * \param tree name of the tree to search for the key. * \param key the key to insert. If it exists, it will be overwritten. * \param rValue the value to insert. */ void AddValue( const PdfName & tree, const PdfString & key, const PdfObject & rValue ); /** Get the object referenced by a string key in one of the dictionaries * of the name tree. * \param tree name of the tree to search for the key. * \param key the key to search for * \returns the value of the key or NULL if the key was not found. * if the value is a reference, the object referenced by * this reference is returned. */ PdfObject* GetValue( const PdfName & tree, const PdfString & key ) const; /** Tests wether a certain nametree has a value. * * It is generally faster to use GetValue and check for NULL * as return value. * * \param tree name of the tree to search for the key. * \param key name of the key to look for * \returns true if the dictionary has such a key. */ bool HasValue( const PdfName & tree, const PdfString & key ) const; /** Tests wether a key is in the range of a limits entry of a name tree node * \returns ePdfNameLimits_Inside if the key is inside of the range * \returns ePdfNameLimits_After if the key is greater than the specified range * \returns ePdfNameLimits_Before if the key is smalelr than the specified range * * Internal use only. */ static EPdfNameLimits CheckLimits( const PdfObject* pObj, const PdfString & key ); /** * Adds all keys and values from a name tree to a dictionary. * Removes all keys that have been previously in the dictionary. * * \param tree the name of the tree to convert into a dictionary * \param rDict add all keys and values to this dictionary */ void ToDictionary( const PdfName & dictionary, PdfDictionary& rDict ); /** Peter Petrov: 23 May 2008 * I have made it for access to "JavaScript" dictonary. This is "document-level javascript storage" * \param bCreate if true the javascript node is created if it does not exists. */ inline PdfObject* GetJavaScriptNode(bool bCreate = false) const; /** Peter Petrov: 6 June 2008 * I have made it for access to "Dest" dictionary. This is "document-level named destination storage" * \param bCreate if true the dests node is created if it does not exists. */ inline PdfObject* GetDestsNode(bool bCreate = false) const; private: /** Get a PdfNameTrees root node for a certain name. * \param name that identifies a specific name tree. * Valid names are: * - Dests * - AP * - JavaScript * - Pages * - Templates * - IDS * - URLS * - EmbeddedFiles * - AlternatePresentations * - Renditions * * \param bCreate if true the root node is created if it does not exists. * \returns the root node of the tree or NULL if it does not exists */ PdfObject* GetRootNode( const PdfName & name, bool bCreate = false ) const; /** Recursively walk through the name tree and find the value for key. * \param pObj the name tree * \param key the key to find a value for * \return the value for the key or NULL if it was not found */ PdfObject* GetKeyValue( PdfObject* pObj, const PdfString & key ) const; /** * Add all keys and values from an object and its children to a dictionary. * \param pObj a pdf name tree node * \param rDict a dictionary */ void AddToDictionary( PdfObject* pObj, PdfDictionary & rDict ); private: PdfObject* m_pCatalog; }; // ----------------------------------------------------- // // ----------------------------------------------------- PdfObject* PdfNamesTree::GetJavaScriptNode(bool bCreate) const { return this->GetRootNode( PdfName("JavaScript"), bCreate ); } // ----------------------------------------------------- // // ----------------------------------------------------- PdfObject* PdfNamesTree::GetDestsNode(bool bCreate) const { return this->GetRootNode( PdfName("Dests"), bCreate ); } }; #endif // _PDF_NAMES_TREE_H_ podofo-0.9.5/src/doc/PdfFontCID.h0000664000175000017500000001300212347317314016251 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FONT_CID_H_ #define _PDF_FONT_CID_H_ #include "podofo/base/PdfDefines.h" #include "PdfFont.h" #include namespace PoDoFo { class PdfFontMetricsFreetype; /** A PdfFont that represents a CID font. */ class PdfFontCID : public PdfFont { public: /** Create a new CID font. * * \param pMetrics pointer to a font metrics object. The font in the PDF * file will match this fontmetrics object. The metrics object is * deleted along with the font. * \param pEncoding the encoding of this font. The font will take ownership of this object * depending on pEncoding->IsAutoDelete() * \param pParent parent of the font object * \param bEmbed specifies the embedding of font * \param bSubset specifies the subsetting of the font; forces bEmbed to false, if set * */ PdfFontCID( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfVecObjects* pParent, bool bEmbed, bool bSubset ); // Peter Petrov 30 April 2008 /** Create a PdfFont based on an existing PdfObject * \param pMetrics pointer to a font metrics object. The font in the PDF * file will match this fontmetrics object. The metrics object is * deleted along with the font. * \param pEncoding the encoding of this font. The font will take ownership of this object * depending on pEncoding->IsAutoDelete() * \param pObject an existing PdfObject * \param bEmbed specifies the embedding of font */ PdfFontCID( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfObject* pObject, bool bEmbed ); // Peter Petrov 24 September 2008 /** Embeds the font into PDF page * */ virtual void EmbedFont(); virtual void EmbedSubsetFont(); virtual void AddUsedSubsettingGlyphs (const PdfString &sText, long lStringLen); private: /** Create the DW and W entries which contain * all glyph width in the given font dictionary. * * \param pFontDict a CID font dictionary */ void CreateWidth( PdfObject* pFontDict ) const; /** Create a ToUnicode CMap and write it to the stream * of the given object. * * \param pUnicode the object which will contain the CMap */ void CreateCMap( PdfObject* pUnicode ) const; protected: /** Initialize this font object. * * \param bEmbed if true embed the font data into the PDF file. * \param bSubset specifies the subsetting of the font; forces bEmbed to false, if set */ void Init( bool bEmbed, bool bSubset ); /** Embed the font file directly into the PDF file. * * \param pDescriptor font descriptor object */ void EmbedFont( PdfObject* pDescriptor ); PdfObject *m_pDescendantFonts; protected: // Peter Petrov 24 September 2008 PdfObject* m_pDescriptor; std::set m_setUsed; void MaybeUpdateBaseFontKey(void); /* to update "BaseFont" key */ virtual void SetBold( bool bBold ); virtual void SetItalic( bool bItalic ); }; }; #endif // _PDF_FONT_CID_H_ podofo-0.9.5/src/doc/PdfAction.cpp0000664000175000017500000001247112344436402016601 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfAction.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfDictionary.h" namespace PoDoFo { const long PdfAction::s_lNumActions = 18; const char* PdfAction::s_names[] = { "GoTo", "GoToR", "GoToE", "Launch", "Thread", "URI", "Sound", "Movie", "Hide", "Named", "SubmitForm", "ResetForm", "ImportData", "JavaScript", "SetOCGState", "Rendition", "Trans", "GoTo3DView", NULL }; PdfAction::PdfAction( EPdfAction eAction, PdfVecObjects* pParent ) : PdfElement( "Action", pParent ), m_eType( eAction ) { const PdfName type = PdfName( TypeNameForIndex( eAction, s_names, s_lNumActions ) ); if( !type.GetLength() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } this->GetObject()->GetDictionary().AddKey( "S", type ); } PdfAction::PdfAction( EPdfAction eAction, PdfDocument* pParent ) : PdfElement( "Action", pParent ), m_eType( eAction ) { const PdfName type = PdfName( TypeNameForIndex( eAction, s_names, s_lNumActions ) ); if( !type.GetLength() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } this->GetObject()->GetDictionary().AddKey( "S", type ); } PdfAction::PdfAction( PdfObject* pObject ) // The typename /Action is optional for PdfActions : PdfElement( NULL, pObject ) { m_eType = static_cast(TypeNameToIndex( this->GetObject()->GetDictionary().GetKeyAsName( "S" ).GetName().c_str(), s_names, s_lNumActions, ePdfAction_Unknown )); } PdfAction::PdfAction( const PdfAction & rhs ) : PdfElement( "Action", rhs.GetNonConstObject() ) { m_eType = static_cast(TypeNameToIndex( this->GetObject()->GetDictionary().GetKeyAsName( "S" ).GetName().c_str(), s_names, s_lNumActions, ePdfAction_Unknown )); } void PdfAction::SetURI( const PdfString & sUri ) { this->GetObject()->GetDictionary().AddKey( "URI", sUri ); } PdfString PdfAction::GetURI() const { return this->GetObject()->GetIndirectKey( "URI" )->GetString(); } bool PdfAction::HasURI() const { return (this->GetObject()->GetIndirectKey( "URI" ) != NULL); } void PdfAction::SetScript( const PdfString & sScript ) { this->GetObject()->GetDictionary().AddKey( "JS", sScript ); } PdfString PdfAction::GetScript() const { return this->GetObject()->GetDictionary().GetKey( "JS" )->GetString(); } bool PdfAction::HasScript() const { return this->GetObject()->GetDictionary().HasKey( "JS" ); } void PdfAction::AddToDictionary( PdfDictionary & dictionary ) const { // Do not add empty destinations // if( !m_array.size() ) // return; // since we can only have EITHER a Dest OR an Action // we check for an Action, and if already present, we throw if ( dictionary.HasKey( PdfName( "Dest" ) ) ) PODOFO_RAISE_ERROR( ePdfError_ActionAlreadyPresent ); dictionary.RemoveKey( "A" ); dictionary.AddKey( "A", this->GetObject() ); } }; podofo-0.9.5/src/doc/PdfDestination.h0000664000175000017500000003301312344436402017305 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_DESTINATION_H_ #define _PDF_DESTINATION_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfArray.h" #include "podofo/base/PdfRect.h" #include "podofo/base/PdfReference.h" namespace PoDoFo { class PdfAction; class PdfPage; class PdfRect; enum EPdfDestinationFit { ePdfDestinationFit_Fit, ePdfDestinationFit_FitH, ePdfDestinationFit_FitV, ePdfDestinationFit_FitB, ePdfDestinationFit_FitBH, ePdfDestinationFit_FitBV, ePdfDestinationFit_Unknown = 0xFF }; /** Destination type, as per 12.3.2.2 of the Pdf spec. * * (see table 151 in the pdf spec) */ enum EPdfDestinationType { ePdfDestinationType_XYZ, ePdfDestinationType_Fit, ePdfDestinationType_FitH, ePdfDestinationType_FitV, ePdfDestinationType_FitR, ePdfDestinationType_FitB, ePdfDestinationType_FitBH, ePdfDestinationType_FitBV, ePdfDestinationType_Unknown = 0xFF }; /** A destination in a PDF file. * A destination can either be a page or an action. * * \see PdfOutlineItem \see PdfAnnotation \see PdfDocument */ class PODOFO_DOC_API PdfDestination { public: /** Create an empty destination - points to nowhere */ PdfDestination( PdfVecObjects* pParent ); /** Create a new PdfDestination from an existing PdfObject (such as loaded from a doc) * \param pObject the object to construct from * \param pDocument a PDF document owning this destination, needed to resolve pages */ PdfDestination( PdfObject* pObject, PdfDocument* pDocument ); /** Create a new PdfDestination from an existing PdfObject (such as loaded from a doc) * \param pObject the object to construct from * \param pVecObjects a PdfVecObjects owning this destination, needed to resolve pages */ PdfDestination( PdfObject* pObject, PdfVecObjects* pVecObjects ); /** Create a new PdfDestination with a page as destination * \param pPage a page which is the destination * \param eFit fit mode for the page. Must be ePdfDestinationFit_Fit or ePdfDestinationFit_FitB */ PdfDestination( const PdfPage* pPage, EPdfDestinationFit eFit = ePdfDestinationFit_Fit ); /** Create a destination to a page with its contents magnified to fit into the given rectangle * \param pPage a page which is the destination * \param rRect magnify the page so that the contents of the rectangle are visible */ PdfDestination( const PdfPage* pPage, const PdfRect & rRect ); /** Create a new destination to a page with specified left * and top coordinates and a zoom factor. * \param pPage a page which is the destination * \param dLeft left coordinate * \param dTop top coordinate * \param dZoom zoom factor in the viewer */ PdfDestination( const PdfPage* pPage, double dLeft, double dTop, double dZoom ); /** Create a new destination to a page. * \param pPage a page which is the destination * \param eFit fit mode for the Page. Allowed values are ePdfDestinationFit_FitH, * ePdfDestinationFit_FitV, ePdfDestinationFit_FitBH, ePdfDestinationFit_FitBV * \param dValue value which is a required argument for the selected fit mode */ PdfDestination( const PdfPage* pPage, EPdfDestinationFit eFit, double dValue ); /** Copy an existing PdfDestination * \param rhs copy this PdfDestination */ PdfDestination( const PdfDestination & rhs ); /** Copy an existing PdfDestination * \param rhs copy this PdfDestination * \returns this object */ const PdfDestination & operator=( const PdfDestination & rhs ); /** Get the page that this destination points to * Requires that this PdfDestination was somehow * created by or from a PdfDocument. Won't work otherwise. * \param pDoc a PDF document owning this destination, needed to resolve pages * * \returns the referenced PdfPage */ PdfPage* GetPage( PdfDocument* pDoc ); /** Get the page that this destination points to * Requires that this PdfDestination was somehow * created by or from a PdfDocument. Won't work otherwise. * \param pVecObjects a PdfVecObjects owning this destination, needed to resolve pages * * \returns the referenced PdfPage */ PdfPage* GetPage( PdfVecObjects* pVecObjects ); /** Get the destination fit type * * \returns the fit type */ inline EPdfDestinationType GetType() const; /** Get the destination zoom * Destination must be of type XYZ * otherwise exception is thrown. * * \returns the zoom */ inline double GetZoom() const; /** Get the destination rect * Destination must be of type FirR * otherwise exception is thrown * * \returns the destination rect */ inline PdfRect GetRect() const; /** Get the destination Top position * Destination must be of type XYZ, FitH, FitR, FitBH * otherwise exception is thrown. * * \returns the Top position */ inline double GetTop() const; /** Get the destination Left position * Destination must be of type XYZ, FitV or FitR * otherwise exception is thrown. * * \returns the Left position */ inline double GetLeft() const; /** Get the destination Value * Destination must be of type FitH, FitV * or FitBH, otherwise exception is thrown * * \returns the destination Value */ inline double GetDValue() const; /** Get access to the internal object * * \returns the internal PdfObject */ inline PdfObject* GetObject(); /** Get access to the internal object * This is an overloaded member function. * * \returns the internal PdfObject */ inline const PdfObject* GetObject() const; /** Get access to the internal array * \returns the internal PdfArray */ inline PdfArray &GetArray(); /** Get access to the internal array * This is an overloaded member function. * * \returns the internal PdfArray */ inline const PdfArray &GetArray() const; /** Adds this destination to an dictionary. * This method handles the all the complexities of making sure it's added correctly * * If this destination is empty. Nothing will be added. * * \param dictionary the destination will be added to this dictionary */ void AddToDictionary( PdfDictionary & dictionary ) const; private: /** Initialize a new PdfDestination from an existing PdfObject (such as loaded from a doc) * and a document. * * \param pObject the object to construct from * \param pDoc a PDF document owning this destination, needed to resolve pages */ void Init( PdfObject* pObject, PdfDocument* pDocument ); private: static const long s_lNumDestinations; static const char* s_names[]; PdfArray m_array; PdfObject* m_pObject; /** Create an empty destination - NOT ALLOWED */ PdfDestination(); }; // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfObject* PdfDestination::GetObject() { return m_pObject; } // ----------------------------------------------------- // // ----------------------------------------------------- inline const PdfObject* PdfDestination::GetObject() const { return m_pObject; } // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfArray &PdfDestination::GetArray() { return m_array; } // ----------------------------------------------------- // // ----------------------------------------------------- inline const PdfArray &PdfDestination::GetArray() const { return m_array; } // ----------------------------------------------------- // // ----------------------------------------------------- inline EPdfDestinationType PdfDestination::GetType() const { if ( !m_array.size() ) return ePdfDestinationType_Unknown; PdfName tp = m_array[1].GetName(); if ( tp == PdfName("XYZ") ) return ePdfDestinationType_XYZ; if ( tp == PdfName("Fit") ) return ePdfDestinationType_Fit; if ( tp == PdfName("FitH") ) return ePdfDestinationType_FitH; if ( tp == PdfName("FitV") ) return ePdfDestinationType_FitV; if ( tp == PdfName("FitR") ) return ePdfDestinationType_FitR; if ( tp == PdfName("FitB") ) return ePdfDestinationType_FitB; if ( tp == PdfName("FitBH") ) return ePdfDestinationType_FitBH; if ( tp == PdfName("FitBV") ) return ePdfDestinationType_FitBV; return ePdfDestinationType_Unknown; } // ----------------------------------------------------- // // ----------------------------------------------------- inline double PdfDestination::GetDValue() const { EPdfDestinationType tp = GetType(); if ( tp != ePdfDestinationType_FitH && tp != ePdfDestinationType_FitV && tp != ePdfDestinationType_FitBH ) { PODOFO_RAISE_ERROR( ePdfError_WrongDestinationType ); } return m_array[2].GetReal(); } // ----------------------------------------------------- // // ----------------------------------------------------- inline double PdfDestination::GetLeft() const { EPdfDestinationType tp = GetType(); if ( tp != ePdfDestinationType_FitV && tp != ePdfDestinationType_XYZ && tp != ePdfDestinationType_FitR ) { PODOFO_RAISE_ERROR( ePdfError_WrongDestinationType ); } return m_array[2].GetReal(); } // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfRect PdfDestination::GetRect() const { if ( GetType() != ePdfDestinationType_FitR ) { PODOFO_RAISE_ERROR( ePdfError_WrongDestinationType ); } return PdfRect(m_array[2].GetReal(), m_array[3].GetReal(), m_array[4].GetReal(), m_array[5].GetReal()); } // ----------------------------------------------------- // // ----------------------------------------------------- inline double PdfDestination::GetTop() const { EPdfDestinationType tp = GetType(); switch (tp) { case ePdfDestinationType_XYZ: return m_array[3].GetReal(); case ePdfDestinationType_FitH: case ePdfDestinationType_FitBH: return m_array[2].GetReal(); case ePdfDestinationType_FitR: return m_array[5].GetReal(); case ePdfDestinationType_Fit: case ePdfDestinationType_FitV: case ePdfDestinationType_FitB: case ePdfDestinationType_FitBV: case ePdfDestinationType_Unknown: default: { PODOFO_RAISE_ERROR( ePdfError_WrongDestinationType ); } }; } // ----------------------------------------------------- // // ----------------------------------------------------- inline double PdfDestination::GetZoom() const { if ( GetType() != ePdfDestinationType_XYZ ) { PODOFO_RAISE_ERROR( ePdfError_WrongDestinationType ); } return m_array[4].GetReal(); } }; #endif // _PDF_DESTINATION_H_ podofo-0.9.5/src/doc/PdfFontCID.cpp0000664000175000017500000010027013013650710016577 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfFontCID.h" #include "base/PdfDefines.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfDictionary.h" #include "base/PdfEncoding.h" #include "base/PdfLocale.h" #include "base/PdfName.h" #include "base/PdfStream.h" #include "PdfFontMetricsFreetype.h" #include "PdfFontTTFSubset.h" #include "base/PdfInputDevice.h" #include "base/PdfOutputDevice.h" #include #include FT_FREETYPE_H #include #include namespace PoDoFo { struct TBFRange { FT_UInt srcCode; std::vector vecDest; }; typedef std::map GlyphWidths; typedef std::map GidToCodePoint; static bool fillGidToCodePoint(GidToCodePoint& array, PdfFontMetrics* metrics); typedef std::map UnicodeToIndex; static UnicodeToIndex getUnicodeToIndexTable(const PdfEncoding* pEnconding); static GlyphWidths getGlyphWidths(PdfFontMetrics* metrics, const std::set& setUsed, const UnicodeToIndex& unicodeToIndex); static GlyphWidths getGlyphWidths(PdfFontMetrics* metrics, const std::set& setUsed); static void createWidths(PdfObject* pFontDict, PdfFontMetrics* metrics, const std::set& setUsed, const UnicodeToIndex& unicodeToIndex); static void createWidths(PdfObject* pFontDict, PdfFontMetrics* metrics, const std::set& setUsed); static GidToCodePoint getGidToCodePoint(const PdfEncoding* pEncoding, PdfFontMetrics* pMetrics, const std::set& setUsed, const UnicodeToIndex& unicodeToIndex); static GidToCodePoint getGidToCodePoint(const PdfEncoding* pEncoding, PdfFontMetrics* pMetrics, const std::set& setUsed); static void fillUnicodeStream( PdfStream* pStream , const GidToCodePoint& gidToCodePoint, int nFirstChar, int nLastChar, bool bSingleByteEncoding); #define SWAP_UTF16BE(x) static_cast(((x << 8) & 0xFF00) | ((x >> 8) & 0x00FF)) /** Build a reverse lookup table, determine a position/index of each unicode code */ UnicodeToIndex getUnicodeToIndexTable(const PdfEncoding* pEncoding) { UnicodeToIndex table; pdf_utf16be uc; int nLast = pEncoding->GetLastChar(); for (int nChar = pEncoding->GetFirstChar(); nChar <= nLast; ++nChar) { uc = pEncoding->GetCharCode(nChar); table[SWAP_UTF16BE(uc)] = nChar; } return table; } class WidthExporter { PdfArray& _output; PdfArray _widths; /* array of consecutive different widths */ long _start; /* glyphIndex of start range */ double _width; long _count; /* number of processed glyphIndex'es since start of range */ /* methods */ void reset(GlyphWidths::const_iterator& it); void emitSameWidth(); void emitArrayWidths(); public: WidthExporter(PdfArray& output, GlyphWidths::const_iterator& it); void update(GlyphWidths::const_iterator& it); void finish(); void updateSBE(GlyphWidths::const_iterator& it); void finishSBE(); }; PdfFontCID::PdfFontCID( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfObject* pObject, bool PODOFO_UNUSED_PARAM(bEmbed) ) : PdfFont( pMetrics, pEncoding, pObject ), m_pDescendantFonts( NULL ) { m_pDescriptor = NULL; /* this->Init( bEmbed, false ); No changes to dictionary */ m_bWasEmbedded = true; /* embedding on this path is not allowed at all, so pretend like it's already done */ } PdfFontCID::PdfFontCID( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfVecObjects* pParent, bool bEmbed, bool bSubset ) : PdfFont( pMetrics, pEncoding, pParent ), m_pDescendantFonts( NULL ) { m_pDescriptor = NULL; this->Init( bEmbed, bSubset ); } void PdfFontCID::Init( bool bEmbed, bool bSubset ) { PdfObject* pDescriptor; PdfVariant var; PdfArray array; if (m_pEncoding->IsSingleByteEncoding()) { pDescriptor = this->GetObject()->GetOwner()->CreateObject("FontDescriptor"); // Now setting each of the entries of the font this->GetObject()->GetDictionary().AddKey( PdfName::KeySubtype, PdfName("TrueType")); this->GetObject()->GetDictionary().AddKey( "BaseFont", this->GetBaseFont() ); this->GetObject()->GetDictionary().AddKey( "FontDescriptor", pDescriptor->Reference() ); // The encoding is here usually a (Predefined) CMap from PdfIdentityEncoding: m_pEncoding->AddToDictionary( this->GetObject()->GetDictionary() ); } else { pDescriptor = this->GetObject()->GetOwner()->CreateObject("FontDescriptor"); // Now setting each of the entries of the font this->GetObject()->GetDictionary().AddKey( PdfName::KeySubtype, PdfName("Type0") ); this->GetObject()->GetDictionary().AddKey( "BaseFont", this->GetBaseFont() ); // The encoding is here usually a (Predefined) CMap from PdfIdentityEncoding: m_pEncoding->AddToDictionary( this->GetObject()->GetDictionary() ); // The descendant font is a CIDFont: m_pDescendantFonts = this->GetObject()->GetOwner()->CreateObject("Font"); // The DecendantFonts, should be an indirect object: array.push_back( m_pDescendantFonts->Reference() ); this->GetObject()->GetDictionary().AddKey( "DescendantFonts", array ); // Setting the DescendantFonts paras // This is a type2 CIDFont, which is also known as TrueType: m_pDescendantFonts->GetDictionary().AddKey( PdfName::KeySubtype, PdfName("CIDFontType2") ); // Same base font as the owner font: m_pDescendantFonts->GetDictionary().AddKey( "BaseFont", this->GetBaseFont() ); // The CIDSystemInfo, should be an indirect object: PdfObject* pCIDSystemInfo = this->GetObject()->GetOwner()->CreateObject(); m_pDescendantFonts->GetDictionary().AddKey( "CIDSystemInfo", pCIDSystemInfo->Reference() ); // Setting the CIDSystemInfo paras: pCIDSystemInfo->GetDictionary().AddKey( "Registry", PdfString("Adobe") ); pCIDSystemInfo->GetDictionary().AddKey( "Ordering", PdfString("Identity") ); pCIDSystemInfo->GetDictionary().AddKey( "Supplement", PdfVariant(static_cast(PODOFO_LL_LITERAL(0))) ); // The FontDescriptor, should be an indirect object: m_pDescendantFonts->GetDictionary().AddKey( "FontDescriptor", pDescriptor->Reference() ); m_pDescendantFonts->GetDictionary().AddKey( "CIDToGIDMap", PdfName("Identity") ); } // Setting the FontDescriptor paras: array.Clear(); m_pMetrics->GetBoundingBox( array ); pDescriptor->GetDictionary().AddKey( "FontName", this->GetBaseFont() ); pDescriptor->GetDictionary().AddKey( PdfName::KeyFlags, PdfVariant( static_cast(PODOFO_LL_LITERAL(32)) ) ); // TODO: 0 ???? pDescriptor->GetDictionary().AddKey( "FontBBox", array ); pDescriptor->GetDictionary().AddKey( "ItalicAngle", PdfVariant( static_cast(m_pMetrics->GetItalicAngle()) ) ); pDescriptor->GetDictionary().AddKey( "Ascent", m_pMetrics->GetPdfAscent() ); pDescriptor->GetDictionary().AddKey( "Descent", m_pMetrics->GetPdfDescent() ); pDescriptor->GetDictionary().AddKey( "CapHeight", m_pMetrics->GetPdfAscent() ); // m_pMetrics->CapHeight() ); pDescriptor->GetDictionary().AddKey( "StemV", PdfVariant( static_cast(PODOFO_LL_LITERAL(1)) ) ); // m_pMetrics->StemV() ); // Peter Petrov 24 September 2008 m_pDescriptor = pDescriptor; m_bIsSubsetting = bSubset; if( bEmbed && !bSubset) { this->EmbedFont( pDescriptor ); m_bWasEmbedded = true; } else if (!bEmbed && !bSubset) { // it's not asked to be embedded, thus mark as embedded already, to not do that at PdfFontCID::EmbedFont() m_bWasEmbedded = true; } } void PdfFontCID::EmbedFont() { if (!m_bWasEmbedded) { this->EmbedFont( m_pDescriptor ); m_bWasEmbedded = true; } } void PdfFontCID::EmbedSubsetFont() { EmbedFont(); } void PdfFontCID::AddUsedSubsettingGlyphs (const PdfString &sText, long lStringLen) { if (IsSubsetting()) { PdfString uniText = sText.ToUnicode(); const pdf_utf16be *uniChars = uniText.GetUnicode(); for (long ii = 0; ii < lStringLen; ii++) { m_setUsed.insert(SWAP_UTF16BE(uniChars[ii])); } } } void PdfFontCID::EmbedFont( PdfObject* pDescriptor ) { bool fallback = true; if (IsSubsetting()) { if (m_setUsed.empty()) { /* Space at least should exist (as big endian) */ m_setUsed.insert(0x20); } PdfFontMetrics *pMetrics = GetFontMetrics2(); if (pMetrics && pMetrics->GetFontDataLen() && pMetrics->GetFontData()) { if (m_pEncoding->IsSingleByteEncoding()) { UnicodeToIndex unicodeToIndex = getUnicodeToIndexTable(m_pEncoding); createWidths(this->GetObject(), pMetrics, m_setUsed, unicodeToIndex); PdfObject* pUnicode = this->GetObject()->GetOwner()->CreateObject(); GidToCodePoint gidToCodePoint = getGidToCodePoint( m_pEncoding, pMetrics, m_setUsed, unicodeToIndex); fillUnicodeStream( pUnicode->GetStream(), gidToCodePoint, *m_setUsed.begin(), *m_setUsed.rbegin(), true); this->GetObject()->GetDictionary().AddKey( "ToUnicode", pUnicode->Reference() ); } else { createWidths(m_pDescendantFonts, pMetrics, m_setUsed); PdfObject* pUnicode = this->GetObject()->GetOwner()->CreateObject(); GidToCodePoint gidToCodePoint = getGidToCodePoint( m_pEncoding, pMetrics, m_setUsed); fillUnicodeStream( pUnicode->GetStream(), gidToCodePoint, *m_setUsed.begin(), *m_setUsed.rbegin(), false); this->GetObject()->GetDictionary().AddKey( "ToUnicode", pUnicode->Reference() ); } PdfInputDevice input(pMetrics->GetFontData(), pMetrics->GetFontDataLen()); PdfRefCountedBuffer buffer; PdfOutputDevice output(&buffer); PdfFontTTFSubset subset(&input, pMetrics, PdfFontTTFSubset::eFontFileType_TTF); std::vector array; subset.BuildFont(buffer, m_setUsed, array ); if (!m_pEncoding->IsSingleByteEncoding()) { if (!array.empty()) { PdfObject* cidSet = pDescriptor->GetOwner()->CreateObject(); TVecFilters vecFlate; vecFlate.push_back(ePdfFilter_FlateDecode); #if (defined(_MSC_VER) && _MSC_VER < 1700) || (defined(__BORLANDC__)) // MSC before VC11 has no data member, same as BorlandC PdfMemoryInputStream stream(reinterpret_cast(&array[0]), array.size()); #else PdfMemoryInputStream stream(reinterpret_cast(array.data()), array.size()); #endif cidSet->GetStream()->Set(&stream, vecFlate); pDescriptor->GetDictionary().AddKey("CIDSet", cidSet->Reference()); } } PdfObject *pContents = this->GetObject()->GetOwner()->CreateObject(); pDescriptor->GetDictionary().AddKey( "FontFile2", pContents->Reference() ); pdf_long lSize = buffer.GetSize(); pContents->GetDictionary().AddKey("Length1", PdfVariant(static_cast(lSize))); pContents->GetStream()->Set(buffer.GetBuffer(), lSize); fallback = false; } } if (fallback) { PdfObject* pContents; pdf_long lSize = 0; pContents = this->GetObject()->GetOwner()->CreateObject(); if( !pContents || !m_pMetrics ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } pDescriptor->GetDictionary().AddKey( "FontFile2", pContents->Reference() ); // if the data was loaded from memory - use it from there // otherwise, load from disk if ( m_pMetrics->GetFontDataLen() && m_pMetrics->GetFontData() ) { // FIXME const_cast is dangerous if string literals may ever be passed char* pBuffer = const_cast( m_pMetrics->GetFontData() ); lSize = m_pMetrics->GetFontDataLen(); // Set Length1 before creating the stream // as PdfStreamedDocument does not allow // adding keys to an object after a stream was written pContents->GetDictionary().AddKey( "Length1", PdfVariant( static_cast(lSize) ) ); pContents->GetStream()->Set( pBuffer, lSize ); } else { PdfFileInputStream stream( m_pMetrics->GetFilename() ); lSize = stream.GetFileLength(); // Set Length1 before creating the stream // as PdfStreamedDocument does not allow // adding keys to an object after a stream was written pContents->GetDictionary().AddKey( "Length1", PdfVariant( static_cast(lSize) ) ); pContents->GetStream()->Set( &stream ); } } } void PdfFontCID::CreateWidth( PdfObject* pFontDict ) const { const int cAbsoluteMax = 0xffff; int nFirstChar = m_pEncoding->GetFirstChar(); int nLastChar = m_pEncoding->GetLastChar(); int i; // Allocate an initialize an array, large enough to // hold a width value for every possible glyph index double* pdWidth = static_cast(podofo_calloc( cAbsoluteMax, sizeof(double) ) ); if( !pdWidth ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } for( i=0;iGetGlyphId( i ); if( lGlyph ) { nMin = PDF_MIN( static_cast(nMin), lGlyph ); nMax = PDF_MAX( static_cast(nMax), lGlyph ); nMax = PDF_MIN( nMax, cAbsoluteMax ); if( lGlyph < cAbsoluteMax ) pdWidth[lGlyph] = m_pMetrics->GetGlyphWidth( lGlyph ); } } if (nMax >= nMin) { // Now compact the array std::ostringstream oss; PdfArray array; array.reserve( nMax - nMin + 1 ); i = nMin; double dCurWidth = pdWidth[i]; pdf_int64 lCurIndex = i++; pdf_int64 lCurLength = 1L; for( ;i<=nMax;i++ ) { if( static_cast(pdWidth[i] - dCurWidth) == 0 ) ++lCurLength; else { if( lCurLength > 1 ) { array.push_back( lCurIndex ); pdf_int64 temp = lCurIndex + lCurLength - 1; array.push_back( temp ); array.push_back( dCurWidth ); } else { if( array.size() && array.back().IsArray() ) { array.back().GetArray().push_back( dCurWidth ); } else { PdfArray tmp; tmp.push_back( dCurWidth ); array.push_back( lCurIndex ); array.push_back( tmp ); } } lCurIndex = i; lCurLength = 1L; dCurWidth = pdWidth[i]; } } if (array.size() == 0) { array.push_back( lCurIndex = nMin ); array.push_back( lCurIndex = nMax ); array.push_back( dCurWidth ); } pFontDict->GetDictionary().AddKey( PdfName("W"), array ); } podofo_free( pdWidth ); } void PdfFontCID::CreateCMap( PdfObject* PODOFO_UNUSED_PARAM(pUnicode) ) const { GidToCodePoint gidToCodePoint; if (fillGidToCodePoint(gidToCodePoint, m_pMetrics)) { //createCMap(pUnicode, gidToCodePoint, m_pEncoding->GetFirstChar(), m_pEncoding->GetLastChar(), m_pEncoding->IsSingleByteEncoding() ); } } static std::vector createUnicodeRanges(const GidToCodePoint& gidToCodePoint, int nFirstChar, int nLastChar) { TBFRange curRange; curRange.srcCode = -1; std::vector vecRanges; FT_UInt gindex; FT_ULong charcode; // Only 255 sequent characters are allowed to be in one range! const unsigned int MAX_CHARS_IN_RANGE = 255; for(GidToCodePoint::const_iterator it = gidToCodePoint.begin(); it != gidToCodePoint.end(); ++it) { gindex = it->first; charcode = it->second; if( static_cast(charcode) > nLastChar ) { break; } if( static_cast(charcode) >= nFirstChar ) { if( curRange.vecDest.size() == 0 ) { curRange.srcCode = gindex; curRange.vecDest.push_back( charcode ); } else if( (curRange.srcCode + curRange.vecDest.size() == gindex) && ((gindex - curRange.srcCode + curRange.vecDest.size()) < MAX_CHARS_IN_RANGE) && ((gindex & 0xff00) == (curRange.srcCode & 0xff00)) ) { curRange.vecDest.push_back( charcode ); } else { // Create a new bfrange vecRanges.push_back( curRange ); curRange.srcCode = gindex; curRange.vecDest.clear(); curRange.vecDest.push_back( charcode ); } } } if( curRange.vecDest.size() ) vecRanges.push_back( curRange ); return vecRanges; } static void fillUnicodeStream( PdfStream* pStream , const GidToCodePoint& gidToCodePoint, int nFirstChar, int nLastChar, bool bSingleByteEncoding) { std::ostringstream oss; std::ostringstream range; std::vector vecRanges = createUnicodeRanges( gidToCodePoint, nFirstChar, nLastChar ); pStream->BeginAppend(); pStream->Append("/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"); if (bSingleByteEncoding) pStream->Append("<00> \n"); else pStream->Append("<0000> \n"); pStream->Append("endcodespacerange\n"); int numberOfEntries = 0; std::vector::const_iterator it = vecRanges.begin(); const int BUFFER_LEN = 5; char buffer[BUFFER_LEN]; // buffer of the format "XXXX\0" while( it != vecRanges.end() ) { if( numberOfEntries == 99 ) { oss << numberOfEntries << " beginbfrange" << std::endl; oss << range.str(); oss << "endbfrange" << std::endl; pStream->Append(oss.str()); oss.str(""); range.str(""); numberOfEntries = 0; } pdf_long iStart = (*it).srcCode; pdf_long iEnd = (*it).srcCode + (*it).vecDest.size() - 1; if (bSingleByteEncoding) { snprintf( buffer, BUFFER_LEN, "%02X", static_cast(iStart) ); range << "<" << buffer << "> <"; snprintf( buffer, BUFFER_LEN, "%02X", static_cast(iEnd) ); } else { snprintf( buffer, BUFFER_LEN, "%04X", static_cast(iStart) ); range << "<" << buffer << "> <"; snprintf( buffer, BUFFER_LEN, "%04X", static_cast(iEnd) ); } range << buffer << "> [ "; std::vector::const_iterator it2 = (*it).vecDest.begin(); while( it2 != (*it).vecDest.end() ) { snprintf( buffer, BUFFER_LEN, "%04X", *it2 ); range << "<" << buffer << "> "; ++it2; } range << "]" << std::endl; ++it; ++numberOfEntries; } if( numberOfEntries > 0 ) { oss << numberOfEntries << " beginbfrange" << std::endl; oss << range.str(); oss << "endbfrange" << std::endl; pStream->Append( oss.str().c_str() ); } pStream->Append("endcmap\n" "CMapName currentdict /CMap defineresource pop\n" "end\n" "end\n"); pStream->EndAppend(); } static GidToCodePoint getGidToCodePoint(const PdfEncoding* PODOFO_UNUSED_PARAM(pEncoding), PdfFontMetrics* pMetrics, const std::set& setUsed, const UnicodeToIndex& unicodeToIndex) { GidToCodePoint gidToCodePoint; pdf_utf16be codePoint; long lGlyph; long lRepl = pMetrics->GetGlyphId( 0xFFFD ); UnicodeToIndex::const_iterator indexLookup; for (std::set::const_iterator it = setUsed.begin(); it != setUsed.end(); ++it) { codePoint = *it; indexLookup = unicodeToIndex.find( codePoint ); if (indexLookup != unicodeToIndex.end()) { lGlyph = pMetrics->GetGlyphId( codePoint ); if( lGlyph ) { gidToCodePoint[indexLookup->second] = codePoint; } else if (lRepl) { gidToCodePoint[indexLookup->second] = 0xFFFD; } } } return gidToCodePoint; } static GidToCodePoint getGidToCodePoint(const PdfEncoding* PODOFO_UNUSED_PARAM(pEncoding), PdfFontMetrics* pMetrics, const std::set& setUsed) { GidToCodePoint gidToCodePoint; pdf_utf16be codePoint; long lGlyph; for (std::set::const_iterator it = setUsed.begin(); it != setUsed.end(); ++it) { codePoint = *it; lGlyph = pMetrics->GetGlyphId( codePoint ); if( lGlyph ) { gidToCodePoint[lGlyph] = codePoint; } } return gidToCodePoint; } void PdfFontCID::MaybeUpdateBaseFontKey(void) { /* FIXME: I believe that this is not required on Win32 platforms, but... */ if (!m_pDescendantFonts) { return; } const PdfFontMetricsFreetype *pFreetype = dynamic_cast(this->GetFontMetrics()); if (!pFreetype) { return; } std::string name = this->GetBaseFont().GetName(); if (this->IsBold() && this->IsItalic()) { if (pFreetype->IsBold() && pFreetype->IsItalic()) { return; } if (pFreetype->IsBold() && !pFreetype->IsItalic()) { name += ",Italic"; } else if (!pFreetype->IsBold() && pFreetype->IsItalic()) { name += ",Bold"; } else { name += ",BoldItalic"; } } else if (this->IsBold()) { if (pFreetype->IsBold()) { return; } name += ",Bold"; } else if (this->IsItalic()) { if (pFreetype->IsItalic()) { return; } name += ",Italic"; } else { return; } m_pDescendantFonts->GetDictionary().AddKey("BaseFont", PdfName( name ) ); } void PdfFontCID::SetBold( bool bBold ) { PdfFont::SetBold(bBold); MaybeUpdateBaseFontKey(); } void PdfFontCID::SetItalic( bool bItalic ) { PdfFont::SetItalic(bItalic); MaybeUpdateBaseFontKey(); } WidthExporter::WidthExporter(PdfArray& output, GlyphWidths::const_iterator& it) : _output(output), _widths() { reset(it); } void WidthExporter::reset(GlyphWidths::const_iterator& it) { _start = it->first; _width = it->second; _count = 1; } void WidthExporter::update(GlyphWidths::const_iterator& it) { if (it->first == (_start + _count)) { /* continous gid */ if (static_cast(it->second - _width) != 0) { /* different width, so emit if previous range was with same width */ if ((_count != 1) && _widths.empty()) { emitSameWidth(); reset(it); return; } _widths.push_back(static_cast(_width + 0.5)); _width = it->second; ++_count; return; } /* two or more gids with same width */ if (!_widths.empty()) { emitArrayWidths(); /* setup previous width as start position */ _start += _count - 1; _count = 2; return; } /* consecutive range of same widths */ ++_count; return; } /* gid gap (font subset) */ finish(); reset(it); } void WidthExporter::finish() { /* if there is a single glyph remaining, emit it as array */ if (!_widths.empty() || (_count == 1)) { _widths.push_back(static_cast(_width + 0.5)); emitArrayWidths(); return; } emitSameWidth(); } void WidthExporter::emitSameWidth() { _output.push_back(static_cast(_start)); _output.push_back(static_cast(_start + _count - 1)); _output.push_back(static_cast(_width + 0.5)); } void WidthExporter::emitArrayWidths() { _output.push_back(static_cast(_start)); _output.push_back(_widths); _widths.Clear(); } void WidthExporter::updateSBE(GlyphWidths::const_iterator& it) { _output.push_back(static_cast(_width + 0.5)); while(++_start < it->first) { _output.push_back(static_cast(0)); } reset(it); } void WidthExporter::finishSBE() { _output.push_back(static_cast(_width + 0.5)); } static bool fillGidToCodePoint(GidToCodePoint& array, PdfFontMetrics* metrics) { PdfFontMetricsFreetype* pFreetype = dynamic_cast(metrics); if (!pFreetype) return false; FT_Face face = pFreetype->GetFace(); FT_UInt gindex; FT_ULong charcode = FT_Get_First_Char( face, &gindex ); while ( gindex != 0 ) { array.insert(std::pair(gindex, charcode)); charcode = FT_Get_Next_Char( face, charcode, &gindex ); } return true; } static GlyphWidths getGlyphWidths(PdfFontMetrics* pMetrics, const std::set& setUsed) { GlyphWidths glyphWidths; const long cAbsoluteMax = 0xffff; long nMin = cAbsoluteMax; long nMax = 0; long lGlyph; double dCurWidth = 1000; // Load the width of all requested glyph indeces for (std::set::const_iterator it = setUsed.begin(); it != setUsed.end(); ++it) { /* If font does not contain a character code, then .notdef */ lGlyph = pMetrics->GetGlyphId( *it ); if( lGlyph ) { nMin = PDF_MIN( nMin, lGlyph ); nMax = PDF_MAX( nMax, lGlyph ); nMax = PDF_MIN( nMax, cAbsoluteMax ); if( lGlyph < cAbsoluteMax ) { dCurWidth = pMetrics->GetGlyphWidth( lGlyph ); glyphWidths[lGlyph] = dCurWidth; } } } return glyphWidths; } static GlyphWidths getGlyphWidths(PdfFontMetrics* metrics, const std::set& setUsed, const UnicodeToIndex& unicodeToIndex) { GlyphWidths glyphWidths; // Load the width of all requested glyph indeces const long cAbsoluteMax = 0xffff; long nMin = cAbsoluteMax; long nMax = 0; long lGlyph; double dCurWidth = 1000; pdf_utf16be codePoint; UnicodeToIndex::const_iterator indexLookup; for (std::set::const_iterator it = setUsed.begin(); it != setUsed.end(); ++it) { codePoint = *it; indexLookup = unicodeToIndex.find( codePoint ); if ( (indexLookup != unicodeToIndex.end()) && indexLookup->second ) { lGlyph = metrics->GetGlyphId( codePoint ); /* XXX: If character code is not found in font, then do nothing */ if( lGlyph ) { nMin = PDF_MIN( nMin, lGlyph ); nMax = PDF_MAX( nMax, lGlyph ); nMax = PDF_MIN( nMax, cAbsoluteMax ); if( lGlyph < cAbsoluteMax ) { dCurWidth = metrics->GetGlyphWidth( lGlyph ); glyphWidths[indexLookup->second] = dCurWidth; } } } } return glyphWidths; } static void createWidths(PdfObject* pFontDict, PdfFontMetrics* metrics, const std::set& setUsed, const UnicodeToIndex& unicodeToIndex) { PdfArray array; GlyphWidths glyphWidths = getGlyphWidths(metrics, setUsed, unicodeToIndex); if (!glyphWidths.empty()) { // Now compact the array array.reserve( glyphWidths.size() + 1 ); GlyphWidths::const_iterator it = glyphWidths.begin(); WidthExporter exporter(array, it); while(++it != glyphWidths.end()) { exporter.updateSBE(it); } exporter.finishSBE(); if (!array.empty()) { #if USE_INDIRECT_WIDTHS PdfObject* widthsObject = pFontDict->GetOwner()->CreateObject( array ); if (widthsObject) { pFontDict->GetDictionary().AddKey( PdfName("Widths"), widthsObject->Reference() ); } #else pFontDict->GetDictionary().AddKey( PdfName("Widths"), array ); #endif } pFontDict->GetDictionary().AddKey("FirstChar", PdfVariant( static_cast(glyphWidths.begin()->first) ) ); pFontDict->GetDictionary().AddKey("LastChar", PdfVariant( static_cast(glyphWidths.rbegin()->first) ) ); } } static void createWidths(PdfObject* pFontDict, PdfFontMetrics* metrics, const std::set& setUsed) { PdfArray array; GlyphWidths glyphWidths = getGlyphWidths(metrics, setUsed); if (!glyphWidths.empty()) { // Now compact the array array.reserve( glyphWidths.size() + 1 ); GlyphWidths::const_iterator it = glyphWidths.begin(); WidthExporter exporter(array, it); while(++it != glyphWidths.end()) { exporter.update(it); } exporter.finish(); if (!array.empty()) { #if USE_INDIRECT_WIDTHS PdfObject* widthsObject = pFontDict->GetOwner()->CreateObject( array ); if (widthsObject) { pFontDict->GetDictionary().AddKey( PdfName("W"), widthsObject->Reference() ); } #else pFontDict->GetDictionary().AddKey( PdfName("W"), array ); #endif } } } }; podofo-0.9.5/src/doc/PdfFunction.h0000664000175000017500000002514112344436402016614 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FUNCTION_H_ #define _PDF_FUNCTION_H_ #include "podofo/base/PdfDefines.h" #include "PdfElement.h" #include namespace PoDoFo { class PdfArray; /** * The function type of a mathematical function in a PDF file. */ enum EPdfFunctionType { ePdfFunctionType_Sampled = 0, ///< A sampled function (Type1) ePdfFunctionType_Exponential = 2, ///< An exponential interpolation function (Type2) ePdfFunctionType_Stitching = 3, ///< A stitching function (Type3) ePdfFunctionType_PostScript = 4 ///< A PostScript calculator function (Type4) }; /** * This class defines a PdfFunction. * A function can be used in various ways in a PDF file. * Examples are device dependent rasterization for high quality * printing or color transformation functions for certain colorspaces. */ class PODOFO_DOC_API PdfFunction : public PdfElement { public: typedef std::list List; typedef std::list Sample; virtual ~PdfFunction(); protected: /** Create a new PdfFunction object. * * \param eType the function type * \param rDomain this array describes the input parameters of this PdfFunction. If this * function has m input parameters, this array has to contain 2*m numbers * where each number describes either the lower or upper boundary of the input range. * \param pParent parent vector of objects * */ PdfFunction( EPdfFunctionType eType, const PdfArray & rDomain, PdfVecObjects* pParent ); /** Create a new PdfFunction object. * * \param eType the function type * \param rDomain this array describes the input parameters of this PdfFunction. If this * function has m input parameters, this array has to contain 2*m numbers * where each number describes either the lower or upper boundary of the input range. * \param pParent parent document * */ PdfFunction( EPdfFunctionType eType, const PdfArray & rDomain, PdfDocument* pParent ); private: /** Initialize this object. * * \param eType the function type * \param rDomain this array describes the input parameters of this PdfFunction. If this * function has m input parameters, this array has to contain 2*m numbers * where each number describes either the lower or upper boundary of the input range. */ void Init( EPdfFunctionType eType, const PdfArray & rDomain ); }; /** This class is a PdfSampledFunction. */ class PODOFO_DOC_API PdfSampledFunction : public PdfFunction { public: /** Create a new PdfSampledFunction object. * * \param rDomain this array describes the input parameters of this PdfFunction. If this * function has m input parameters, this array has to contain 2*m numbers * where each number describes either the lower or upper boundary of the input range. * \param rRange this array describes the output parameters of this PdfFunction. If this * function has n input parameters, this array has to contain 2*n numbers * where each number describes either the lower or upper boundary of the output range. * \param rlstSamples a list of bytes which are used to build up this function sample data * \param pParent parent vector of objects */ PdfSampledFunction( const PdfArray & rDomain, const PdfArray & rRange, const PdfFunction::Sample & rlstSamples, PdfVecObjects* pParent ); /** Create a new PdfSampledFunction object. * * \param rDomain this array describes the input parameters of this PdfFunction. If this * function has m input parameters, this array has to contain 2*m numbers * where each number describes either the lower or upper boundary of the input range. * \param rRange this array describes the output parameters of this PdfFunction. If this * function has n input parameters, this array has to contain 2*n numbers * where each number describes either the lower or upper boundary of the output range. * \param rlstSamples a list of bytes which are used to build up this function sample data * \param pParent parent document */ PdfSampledFunction( const PdfArray & rDomain, const PdfArray & rRange, const PdfFunction::Sample & rlstSamples, PdfDocument* pParent ); private: /** Initialize this object. */ void Init( const PdfArray & rDomain, const PdfArray & rRange, const PdfFunction::Sample & rlstSamples ); }; /** This class is a PdfExponentialFunction. */ class PODOFO_DOC_API PdfExponentialFunction : public PdfFunction { public: /** Create a new PdfExponentialFunction object. * * \param rDomain this array describes the input parameters of this PdfFunction. If this * function has m input parameters, this array has to contain 2*m numbers * where each number describes either the lower or upper boundary of the input range. * \param rC0 * \param rC1 * \param dExponent * \param pParent parent vector of objects */ PdfExponentialFunction( const PdfArray & rDomain, const PdfArray & rC0, const PdfArray & rC1, double dExponent, PdfVecObjects* pParent ); /** Create a new PdfExponentialFunction object. * * \param rDomain this array describes the input parameters of this PdfFunction. If this * function has m input parameters, this array has to contain 2*m numbers * where each number describes either the lower or upper boundary of the input range. * \param rC0 * \param rC1 * \param dExponent * \param pParent parent document */ PdfExponentialFunction( const PdfArray & rDomain, const PdfArray & rC0, const PdfArray & rC1, double dExponent, PdfDocument* pParent ); private: /** Initialize this object. */ void Init( const PdfArray & rC0, const PdfArray & rC1, double dExponent ); }; /** This class is a PdfStitchingFunction, i.e. a PdfFunction that combines * more than one PdfFunction into one. * * It combines several PdfFunctions that take 1 input parameter to * a new PdfFunction taking again only 1 input parameter. */ class PODOFO_DOC_API PdfStitchingFunction : public PdfFunction { public: /** Create a new PdfStitchingFunction object. * * \param rlstFunctions a list of functions which are used to built up this function object * \param rDomain this array describes the input parameters of this PdfFunction. If this * function has m input parameters, this array has to contain 2*m numbers * where each number describes either the lower or upper boundary of the input range. * \param rBounds the bounds array * \param rEncode the encode array * \param pParent parent vector of objects * */ PdfStitchingFunction( const PdfFunction::List & rlstFunctions, const PdfArray & rDomain, const PdfArray & rBounds, const PdfArray & rEncode, PdfVecObjects* pParent ); /** Create a new PdfStitchingFunction object. * * \param rlstFunctions a list of functions which are used to built up this function object * \param rDomain this array describes the input parameters of this PdfFunction. If this * function has m input parameters, this array has to contain 2*m numbers * where each number describes either the lower or upper boundary of the input range. * \param rBounds the bounds array * \param rEncode the encode array * \param pParent parent document * */ PdfStitchingFunction( const PdfFunction::List & rlstFunctions, const PdfArray & rDomain, const PdfArray & rBounds, const PdfArray & rEncode, PdfDocument* pParent ); private: /** Initialize this object. * * \param rlstFunctions a list of functions which are used to built up this function object * \param rBounds the bounds array * \param rEncode the encode array */ void Init( const PdfFunction::List & rlstFunctions, const PdfArray & rBounds, const PdfArray & rEncode ); }; }; #endif // _PDF_FUNCTION_H_ podofo-0.9.5/src/doc/PdfFontTTFSubset.h0000664000175000017500000002137012716141341017477 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FONT_TTF_SUBSET_H_ #define _PDF_FONT_TTF_SUBSET_H_ #include "podofo/base/PdfDefines.h" #include "PdfFontMetrics.h" #include #include namespace PoDoFo { class PdfInputDevice; class PdfOutputDevice; // This code is based heavily on code by ZhangYang // (å¼ æ¨.国际) // // (Do not put this into doxygen documentation blocks // as this will break latex documentation generation) /** * This class is able to build a new TTF font with only * certain glyphs from an existing font. * */ class PODOFO_DOC_API PdfFontTTFSubset { public: /** * Internal enum specifying the type of a fontfile. */ enum EFontFileType { eFontFileType_TTF, ///< TrueType Font eFontFileType_TTC, ///< TrueType Collection eFontFileType_OTF, ///< OpenType Font eFontFileType_Unknown ///< Unknown }; /** Create a new PdfFontTTFSubset from an existing * TTF font file. * * @param pszFontFileName path to a TTF file * @param pMetrics font metrics object for this font * @param nFaceIndex index of the face inside of the font */ PdfFontTTFSubset( const char* pszFontFileName, PdfFontMetrics* pMetrics, unsigned short nFaceIndex = 0 ); /** Create a new PdfFontTTFSubset from an existing * TTF font file using an input device. * * @param pDevice a PdfInputDevice * @param pMetrics font metrics object for this font * @param eType the type of the font * @param nFaceIndex index of the face inside of the font */ PdfFontTTFSubset( PdfInputDevice* pDevice, PdfFontMetrics* pMetrics, EFontFileType eType, unsigned short nFaceIndex = 0 ); ~PdfFontTTFSubset(); /** * Actually generate the subsetted font * * @param pOutputDevice write the font to this device */ void BuildFont( PdfRefCountedBuffer& outputBuffer, const std::set& usedChars, std::vector& cidSet ); private: /** Hide default constructor */ PdfFontTTFSubset() : m_bOwnDevice( false ) {} /** copy constructor, not implemented */ PdfFontTTFSubset(const PdfFontTTFSubset& rhs); /** assignment operator, not implemented */ PdfFontTTFSubset& operator=(const PdfFontTTFSubset& rhs); void Init(); /** Get the offset of a specified table. * @param pszTableName name of the table */ unsigned long GetTableOffset( unsigned long tag ); void GetNumberOfTables(); void GetNumberOfGlyphs(); void SeeIfLongLocaOrNot(); void InitTables(); void GetStartOfTTFOffsets(); /** Get sz bytes from the offset'th bytes of the input file * */ void GetData(unsigned long offset, void* address, unsigned long sz); /** Information of TrueType tables. */ class TTrueTypeTable { public: TTrueTypeTable() : tag( 0L ), checksum( 0L ), length( 0L ), offset( 0L ) { } unsigned long tag; unsigned long checksum; unsigned long length; unsigned long offset; }; /** GlyphData contains the glyph address relative * to the beginning of the glyf table. */ class TGlyphData { public: TGlyphData() : glyphLength( 0L ), glyphAddress( 0L ) { } unsigned long glyphLength; unsigned long glyphAddress; //In the original truetype file. }; typedef unsigned short GID; typedef unsigned long CodePoint; typedef std::map GlyphMap; typedef std::map CodePointToGid; class CMapv4Range { public: CMapv4Range() : endCode( 0 ), startCode( 0 ), delta( 0 ), offset( 0 ) { } unsigned short endCode; unsigned short startCode; short delta; unsigned short offset; }; typedef std::vector CMapRanges; class CMap { public: CMap() : segCount( 0 ) { } unsigned short segCount; CMapRanges ranges; std::vector glyphArray; }; class GlyphContext { public: GlyphContext() : ulGlyfTableOffset( 0 ), ulLocaTableOffset( 0 ), contourCount( 0 ) , shortOffset( 0 ) { } unsigned long ulGlyfTableOffset; unsigned long ulLocaTableOffset; /* Used internaly during recursive load */ TGlyphData glyphData; short contourCount; unsigned short shortOffset; }; void BuildUsedCodes(CodePointToGid& usedCodes, const std::set& usedChars ); void LoadGlyphs(GlyphContext& ctx, const CodePointToGid& usedCodes); void LoadGID(GlyphContext& ctx, GID gid); void LoadCompound(GlyphContext& ctx, unsigned long offset); void CreateCmapTable( const CodePointToGid& usedCodes ); void FillGlyphArray(const CodePointToGid& usedCodes, GID gid, unsigned short count); unsigned long GetCmapTableSize(); unsigned long WriteCmapTable(char*); unsigned long GetGlyphTableSize(); unsigned long WriteGlyphTable(char* bufp, unsigned long ulGlyphTableOffset); unsigned long GetLocaTableSize(); unsigned long WriteLocaTable(char* bufp); unsigned long GetHmtxTableSize(); unsigned long WriteHmtxTable(char* bufp, unsigned long ulHmtxTableOffset); unsigned long CalculateSubsetSize(); void WriteTables(PdfRefCountedBuffer& fontData); PdfFontMetrics* m_pMetrics; ///< FontMetrics object which is required to convert unicode character points to glyph ids EFontFileType m_eFontFileType; bool m_bIsLongLoca; unsigned short m_numTables; unsigned short m_numGlyphs; unsigned short m_numHMetrics; std::vector m_vTable; GlyphMap m_mGlyphMap; CMap m_sCMap; /* temp storage during load */ unsigned short m_faceIndex; unsigned long m_ulStartOfTTFOffsets; ///< Start address of the truetype offset tables, differs from ttf to ttc. PdfInputDevice* m_pDevice; ///< Read data from this input device const bool m_bOwnDevice; ///< If the input device is owned by this object }; // ----------------------------------------------------- // // ----------------------------------------------------- }; /* PoDoFo */ #endif /* _PDF_FONT_TRUE_TYPE_H_ */ podofo-0.9.5/src/doc/PdfNamesTree.cpp0000664000175000017500000004316612344436402017254 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfNamesTree.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfDictionary.h" #include "base/PdfOutputDevice.h" #include namespace PoDoFo { #define BALANCE_TREE_MAX 65 /* #define BALANCE_TREE_MAX 9 */ class PdfNameTreeNode { public: PdfNameTreeNode( PdfNameTreeNode* pParent, PdfObject* pObject ) : m_pParent( pParent ), m_pObject( pObject ) { m_bHasKids = m_pObject->GetDictionary().HasKey("Kids"); } bool AddValue( const PdfString & key, const PdfObject & value ); void SetLimits(); inline PdfObject* GetObject() { return m_pObject; } private: bool Rebalance(); private: PdfNameTreeNode* m_pParent; PdfObject* m_pObject; bool m_bHasKids; }; bool PdfNameTreeNode::AddValue( const PdfString & key, const PdfObject & rValue ) { if( m_bHasKids ) { const PdfArray & kids = this->GetObject()->GetDictionary().GetKey("Kids")->GetArray(); PdfArray::const_iterator it = kids.begin(); PdfObject* pChild = NULL; EPdfNameLimits eLimits = ePdfNameLimits_Before; // RG: TODO Compiler complains that this variable should be initialised while( it != kids.end() ) { pChild = this->GetObject()->GetOwner()->GetObject( (*it).GetReference() ); if( !pChild ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } eLimits = PdfNamesTree::CheckLimits( pChild, key ); if( (eLimits == ePdfNameLimits_Before) || (eLimits == ePdfNameLimits_Inside) ) { break; } ++it; } if( it == kids.end() ) { // not added, so add to last child pChild = this->GetObject()->GetOwner()->GetObject( kids.back().GetReference() ); if( !pChild ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } eLimits = ePdfNameLimits_After; } PdfNameTreeNode child( this, pChild ); if( child.AddValue( key, rValue ) ) { // if a child insert the key in a way that the limits // are changed, we have to change our limits as well! // our parent has to change his parents too! if( eLimits != ePdfNameLimits_Inside ) this->SetLimits(); this->Rebalance(); return true; } else return false; } else { bool bRebalance = false; PdfArray limits; if( this->GetObject()->GetDictionary().HasKey( "Names" ) ) { PdfArray& array = this->GetObject()->GetDictionary().GetKey("Names")->GetArray(); PdfArray::iterator it = array.begin(); while( it != array.end() ) { if( (*it).GetString() == key ) { // no need to write the key as it is anyways the same ++it; // write the value *it = rValue; break; } else if( (*it).GetString() > key ) { it = array.insert( it, rValue ); // array.insert invalidates the iterator it = array.insert( it, key ); break; } it += 2; } if( it == array.end() ) { array.push_back( key ); array.push_back( rValue ); } limits.push_back( (*array.begin()) ); limits.push_back( (*(array.end()-2)) ); bRebalance = true; } else { // we create a completely new node PdfArray array; array.push_back( key ); array.push_back( rValue ); limits.push_back( key ); limits.push_back( key ); // create a child object PdfObject* pChild = this->GetObject()->GetOwner()->CreateObject(); pChild->GetDictionary().AddKey( "Names", array ); pChild->GetDictionary().AddKey( "Limits", limits ); PdfArray kids( pChild->Reference() ); this->GetObject()->GetDictionary().AddKey( "Kids", kids ); m_bHasKids = true; } if( m_pParent ) { // Root node is not allowed to have a limits key! this->GetObject()->GetDictionary().AddKey( "Limits", limits ); } if( bRebalance ) this->Rebalance(); return true; } } void PdfNameTreeNode::SetLimits() { PdfArray limits; if( m_bHasKids ) { if( this->GetObject()->GetDictionary().HasKey( PdfName("Kids") ) && this->GetObject()->GetDictionary().GetKey( PdfName("Kids") )->IsArray() ) { const PdfReference & rRefFirst = (*this->GetObject()->GetDictionary().GetKey("Kids")->GetArray().begin()).GetReference(); PdfObject* pChild = this->GetObject()->GetOwner()->GetObject( rRefFirst ); if( pChild && pChild->GetDictionary().HasKey( PdfName("Limits") ) && pChild->GetDictionary().GetKey( PdfName("Limits") )->IsArray() ) limits.push_back( *(pChild->GetDictionary().GetKey("Limits")->GetArray().begin()) ); const PdfReference & rRefLast = this->GetObject()->GetDictionary().GetKey("Kids")->GetArray().back().GetReference(); pChild = this->GetObject()->GetOwner()->GetObject( rRefLast ); if( pChild && pChild->GetDictionary().HasKey( PdfName("Limits") ) && pChild->GetDictionary().GetKey( PdfName("Limits") )->IsArray() ) limits.push_back( pChild->GetDictionary().GetKey("Limits")->GetArray().back() ); } else PdfError::LogMessage( eLogSeverity_Error, "Object %i %si does not have Kids array.", this->GetObject()->Reference().ObjectNumber(), this->GetObject()->Reference().GenerationNumber() ); } else // has "Names" { if( this->GetObject()->GetDictionary().HasKey( PdfName("Names") ) && this->GetObject()->GetDictionary().GetKey( PdfName("Names") )->IsArray() ) { limits.push_back( (*this->GetObject()->GetDictionary().GetKey("Names")->GetArray().begin()) ); limits.push_back( (*(this->GetObject()->GetDictionary().GetKey("Names")->GetArray().end()-2)) ); } else PdfError::LogMessage( eLogSeverity_Error, "Object %i %si does not have Names array.", this->GetObject()->Reference().ObjectNumber(), this->GetObject()->Reference().GenerationNumber() ); } if( m_pParent ) { // Root node is not allowed to have a limits key! this->GetObject()->GetDictionary().AddKey("Limits", limits ); } } bool PdfNameTreeNode::Rebalance() { PdfArray* pArray = m_bHasKids ? &(this->GetObject()->GetDictionary().GetKey("Kids")->GetArray()) : &(this->GetObject()->GetDictionary().GetKey("Names")->GetArray()); const PdfName& key = m_bHasKids ? PdfName("Kids") : PdfName("Names"); const unsigned int nLength = m_bHasKids ? BALANCE_TREE_MAX : BALANCE_TREE_MAX * 2; if( !pArray ) return false; if( pArray->size() > nLength ) { PdfArray first; PdfArray second; PdfArray kids; first.insert( first.end(), pArray->begin(), pArray->begin()+(nLength/2)+1 ); second.insert( second.end(), pArray->begin()+(nLength/2)+1, pArray->end() ); PdfObject* pChild1; PdfObject* pChild2 = this->GetObject()->GetOwner()->CreateObject(); if( !m_pParent ) { m_bHasKids = true; pChild1 = this->GetObject()->GetOwner()->CreateObject(); this->GetObject()->GetDictionary().RemoveKey( "Names" ); } else { pChild1 = this->GetObject(); kids = m_pParent->GetObject()->GetDictionary().GetKey("Kids")->GetArray(); } pChild1->GetDictionary().AddKey( key, first ); pChild2->GetDictionary().AddKey( key, second ); PdfArray::iterator it = kids.begin(); while( it != kids.end() ) { if( (*it).GetReference() == pChild1->Reference() ) { ++it; it = kids.insert( it, pChild2->Reference() ); break; } ++it; } if( it == kids.end() ) { kids.push_back( pChild1->Reference() ); kids.push_back( pChild2->Reference() ); } if( m_pParent ) m_pParent->GetObject()->GetDictionary().AddKey( "Kids", kids ); else this->GetObject()->GetDictionary().AddKey( "Kids", kids ); // Important is to the the limits // of the children first, // because SetLimits( pParent ) // depends on the /Limits key of all its children! PdfNameTreeNode( NULL, pChild1 ).SetLimits(); PdfNameTreeNode( NULL, pChild2 ).SetLimits(); // limits do only change if splitting name arrays if( m_bHasKids ) this->SetLimits(); else if( m_pParent ) m_pParent->SetLimits(); return true; } return false; } /////////////////////////////////////////////////////////////////////// /* We use NULL for the PdfElement name, since the NamesTree dict does NOT have a /Type key! */ PdfNamesTree::PdfNamesTree( PdfVecObjects* pParent ) : PdfElement( NULL, pParent ), m_pCatalog( NULL ) { } PdfNamesTree::PdfNamesTree( PdfObject* pObject, PdfObject* pCatalog ) : PdfElement( NULL, pObject ), m_pCatalog( pCatalog ) { } void PdfNamesTree::AddValue( const PdfName & tree, const PdfString & key, const PdfObject & rValue ) { PdfNameTreeNode root( NULL, this->GetRootNode( tree, true ) ); if( !root.AddValue( key, rValue ) ) { PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } } PdfObject* PdfNamesTree::GetValue( const PdfName & tree, const PdfString & key ) const { PdfObject* pObject = this->GetRootNode( tree ); PdfObject* pResult = NULL; if( pObject ) { pResult = this->GetKeyValue( pObject, key ); if( pResult && pResult->IsReference() ) pResult = this->GetObject()->GetOwner()->GetObject( pResult->GetReference() ); } return pResult; } PdfObject* PdfNamesTree::GetKeyValue( PdfObject* pObj, const PdfString & key ) const { if( PdfNamesTree::CheckLimits( pObj, key ) != ePdfNameLimits_Inside ) return NULL; if( pObj->GetDictionary().HasKey("Kids") ) { const PdfArray & kids = pObj->GetDictionary().GetKey("Kids")->GetArray(); PdfArray::const_iterator it = kids.begin(); while( it != kids.end() ) { PdfObject* pChild = this->GetObject()->GetOwner()->GetObject( (*it).GetReference() ); if( pChild ) { PdfObject* pResult = GetKeyValue( pChild, key ); if( pResult ) // If recursive call returns NULL, // continue with the next element // in the kids array. return pResult; } else PdfError::LogMessage( eLogSeverity_Debug, "Object %lu %lu is child of nametree but was not found!", (*it).GetReference().ObjectNumber(), (*it).GetReference().GenerationNumber() ); ++it; } } else { const PdfArray & names = pObj->GetDictionary().GetKey("Names")->GetArray(); PdfArray::const_iterator it = names.begin(); // a names array is a set of PdfString/PdfObject pairs // so we loop in sets of two - getting each pair while( it != names.end() ) { if( (*it).GetString() == key ) { ++it; return this->GetObject()->GetOwner()->GetObject( (*it).GetReference() ); } it += 2; } } return NULL; } PdfObject* PdfNamesTree::GetRootNode( const PdfName & name, bool bCreate ) const { PdfObject* pObj = this->GetObject()->GetIndirectKey( name ); if( !pObj && bCreate ) { pObj = this->GetObject()->GetOwner()->CreateObject(); this->GetNonConstObject()->GetDictionary().AddKey( name, pObj->Reference() ); } return pObj; } bool PdfNamesTree::HasValue( const PdfName & tree, const PdfString & key ) const { return ( this->GetValue( tree, key ) != NULL ); } EPdfNameLimits PdfNamesTree::CheckLimits( const PdfObject* pObj, const PdfString & key ) { if( pObj->GetDictionary().HasKey("Limits") ) { const PdfArray & limits = pObj->GetDictionary().GetKey("Limits")->GetArray(); if( limits[0].GetString() > key ) return ePdfNameLimits_Before; if( limits[1].GetString() < key ) return ePdfNameLimits_After; } else { PdfError::LogMessage( eLogSeverity_Debug, "Name tree object %lu %lu does not have a limits key!", pObj->Reference().ObjectNumber(), pObj->Reference().GenerationNumber() ); } return ePdfNameLimits_Inside; } void PdfNamesTree::ToDictionary( const PdfName & tree, PdfDictionary& rDict ) { rDict.Clear(); PdfObject* pObj = this->GetRootNode( tree ); if( pObj ) AddToDictionary( pObj, rDict ); } void PdfNamesTree::AddToDictionary( PdfObject* pObj, PdfDictionary & rDict ) { if( pObj->GetDictionary().HasKey("Kids") ) { const PdfArray & kids = pObj->GetDictionary().GetKey("Kids")->GetArray(); PdfArray::const_iterator it = kids.begin(); while( it != kids.end() ) { PdfObject* pChild = this->GetObject()->GetOwner()->GetObject( (*it).GetReference() ); if( pChild ) this->AddToDictionary( pChild, rDict ); else PdfError::LogMessage( eLogSeverity_Debug, "Object %lu %lu is child of nametree but was not found!\n", (*it).GetReference().ObjectNumber(), (*it).GetReference().GenerationNumber() ); ++it; } } else if( pObj->GetDictionary().HasKey("Names") ) { const PdfArray & names = pObj->GetDictionary().GetKey("Names")->GetArray(); PdfArray::const_iterator it = names.begin(); // a names array is a set of PdfString/PdfObject pairs // so we loop in sets of two - getting each pair while( it != names.end() ) { // convert all strings into names PdfName name( (*it).GetString().GetString() ); ++it; rDict.AddKey( name, *(it) ); ++it; } } } }; podofo-0.9.5/src/doc/PdfFontSimple.h0000664000175000017500000001113112344436402017101 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FONT_SIMPLE_H_ #define _PDF_FONT_SIMPLE_H_ #include "podofo/base/PdfDefines.h" #include "PdfFont.h" namespace PoDoFo { /** This is a common base class for simple fonts * like truetype or type1 fonts. */ class PdfFontSimple : public PdfFont { public: /** Create a new PdfFont object which will introduce itself * automatically to every page object it is used on. * * The font has a default font size of 12.0pt. * * \param pMetrics pointer to a font metrics object. The font in the PDF * file will match this fontmetrics object. The metrics object is * deleted along with the font. * \param pEncoding the encoding of this font. The font will take ownership of this object * depending on pEncoding->IsAutoDelete() * \param pParent parent of the font object * */ PdfFontSimple( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfVecObjects* pParent ); /** Create a PdfFont based on an existing PdfObject * \param pMetrics pointer to a font metrics object. The font in the PDF * file will match this fontmetrics object. The metrics object is * deleted along with the font. * \param pEncoding the encoding of this font. The font will take ownership of this object * depending on pEncoding->IsAutoDelete() * \param pObject an existing PdfObject */ PdfFontSimple( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfObject* pObject ); // Peter Petrov 24 September 2008 /** Embeds the font into PDF page * */ virtual void EmbedFont(); protected: /** Initialize this font object. * * \param bEmbed if true embed the font data into the PDF file. * \param rsSubType the subtype of the real font. */ void Init( bool bEmbed, const PdfName & rsSubType ); /** Embed the font file directly into the PDF file. * * \param pDescriptor font descriptor object */ virtual void EmbedFontFile( PdfObject* pDescriptor ) = 0; PdfObject* m_pDescriptor; }; }; #endif /* _PDF_FONT_SIMPLE_H_ */ podofo-0.9.5/src/doc/PdfIdentityEncoding.h0000664000175000017500000001567312602051620020270 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_IDENTITY_ENCODING_H_ #define _PDF_IDENTITY_ENCODING_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfEncoding.h" #include "podofo/base/PdfObject.h" namespace PoDoFo { /** PdfIdentityEncoding is a two-byte encoding which can be * used with TrueType fonts to represent all characters * present in a font. If the font contains all unicode * glyphs, PdfIdentityEncoding will support all unicode * characters. */ class PODOFO_DOC_API PdfIdentityEncoding : public PdfEncoding { public: /** * Create a new PdfIdentityEncoding. * * \param nFirstChar the first supported unicode character code (at least 0) * \param nLastChar the last supported unicode character code, * must be larger than nFirstChar (max value is 0xffff) * \param bAutoDelete if true the encoding is deleted by its owning font */ PdfIdentityEncoding( int nFirstChar = 0, int nLastChar = 0xffff, bool bAutoDelete = true, PdfObject* pToUnicode = NULL ); /** Add this encoding object to a dictionary * usually be adding an /Encoding key in font dictionaries. * * \param rDictionary add the encoding to this dictionary */ virtual void AddToDictionary( PdfDictionary & rDictionary ) const; /** Convert a string that is encoded with this encoding * to an unicode PdfString. * * \param rEncodedString a string encoded by this encoding. * Usually this string was read from a content stream. * \param pFont the font for which this string is converted * * \returns an unicode PdfString. */ virtual PdfString ConvertToUnicode( const PdfString & rEncodedString, const PdfFont* pFont ) const; /** Convert a unicode PdfString to a string encoded with this encoding. * * \param rString an unicode PdfString. * \param pFont the font for which this string is converted * * \returns an encoded PdfRefCountedBuffer. The PdfRefCountedBuffer is treated as a series of bytes * and is allowed to have 0 bytes. The returned buffer must not be a unicode string. */ virtual PdfRefCountedBuffer ConvertToEncoding( const PdfString & rString, const PdfFont* pFont ) const; /** * PdfIdentityEncoding is usually delete along with the font. * * \returns true if this encoding should be deleted automatically with the * font. */ virtual bool IsAutoDelete() const; /** * \returns true if this is a single byte encoding with a maximum of 256 values. */ virtual bool IsSingleByteEncoding() const; /** Get the unicode character code for this encoding * at the position nIndex. nIndex is a position between * GetFirstChar() and GetLastChar() * * \param nIndex character code at position index * \returns unicode character code * * \see GetFirstChar * \see GetLastChar * * Will throw an exception if nIndex is out of range. */ virtual pdf_utf16be GetCharCode( int nIndex ) const; protected: /** Get a unique ID for this encoding * which can used for comparisons! * * \returns a unique id for this encoding! */ inline virtual const PdfName & GetID() const; private: /** Gets the unicode value from a char code in this font * * \param lCharCode the character code (i.e. glyph id) * * \returns an unicode value */ pdf_utf16be GetUnicodeValue( pdf_utf16be lCharCode ) const; /** Gets the char code from a uniode value * * \param lUnicodeValue the unicode valye * * \returns the character code (i.e. glyph id) */ pdf_utf16be GetCIDValue( pdf_utf16be lUnicodeValue ) const; private: bool m_bAutoDelete; ///< If true this encoding is deleted by its font. PdfName m_id; ///< Unique ID of this encoding }; // ----------------------------------------------------- // // ----------------------------------------------------- inline const PdfName & PdfIdentityEncoding::GetID() const { return m_id; } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfIdentityEncoding::IsAutoDelete() const { return m_bAutoDelete; } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfIdentityEncoding::IsSingleByteEncoding() const { return false; } }; /* namespace PoDoFo */ #endif // _PDF_IDENTITY_ENCODING_H_ podofo-0.9.5/src/doc/PdfFontCache.cpp0000664000175000017500000007451513043357617017234 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfFontCache.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfDictionary.h" #include "base/PdfInputDevice.h" #include "base/PdfOutputDevice.h" #include "PdfDifferenceEncoding.h" #include "PdfFont.h" #include "PdfFontFactory.h" #include "PdfFontMetricsFreetype.h" #include "PdfFontMetricsBase14.h" #include "PdfFontTTFSubset.h" #include "PdfFontType1.h" #include #ifdef _WIN32 //#include // Undefined stuff which Windows does // define that breaks our build // e.g. GetObject is defined to either GetObjectA or GetObjectW #ifdef GetObject #undef GetObject #endif // GetObject #ifdef CreateFont #undef CreateFont #endif // CreateFont #endif // _WIN32 #include #include FT_FREETYPE_H #if defined(PODOFO_HAVE_FONTCONFIG) #include #include "base/util/PdfMutexWrapper.h" #endif using namespace std; //us: I know the endian functions are redundant, but they are not availabe in a .h file, right? // Ohh, C++ should have these as intrinsic operators, since processors just need one SWAP directive. #ifdef PODOFO_IS_LITTLE_ENDIAN inline unsigned long FromBigEndian(unsigned long i) { return ((i << 24) & 0xFF000000) | ((i << 8) & 0x00FF0000) | ((i >> 8) & 0x0000FF00) | ((i >> 24) & 0x000000FF); } inline unsigned short ShortFromBigEndian(unsigned short i) { return ((i << 8) & 0xFF00) | ((i >> 8) & 0x00FF); } #else inline unsigned long FromBigEndian(unsigned long i) { return i; } inline unsigned short ShortFromBigEndian(unsigned short i) { return i; } #endif namespace PoDoFo { #if defined(_WIN32) && !defined(PODOFO_NO_FONTMANAGER) //This function will recieve the device context for the ttc font, it will then extract necessary tables,and create the correct buffer. //On error function return false static bool GetFontFromCollection(HDC &hdc, char *&buffer, unsigned int &bufferLen) { const DWORD ttcf_const = 0x66637474; unsigned int fileLen = GetFontData(hdc, ttcf_const, 0, 0, 0); unsigned int ttcLen = GetFontData(hdc, 0, 0, 0, 0); if (fileLen == GDI_ERROR || ttcLen == GDI_ERROR) { return false; } char *fileBuffer = (char*)podofo_malloc(fileLen); if (!fileBuffer) { PODOFO_RAISE_ERROR(ePdfError_OutOfMemory); } char *ttcBuffer = (char*)podofo_malloc(ttcLen); if (!ttcBuffer) { podofo_free(fileBuffer); PODOFO_RAISE_ERROR(ePdfError_OutOfMemory); } if (GetFontData(hdc, ttcf_const, 0, fileBuffer, fileLen) == GDI_ERROR) { podofo_free(fileBuffer); podofo_free(ttcBuffer); return false; } if (GetFontData(hdc, 0, 0, ttcBuffer, ttcLen) == GDI_ERROR) { podofo_free(fileBuffer); podofo_free(ttcBuffer); return false; } USHORT numTables = ShortFromBigEndian(*(USHORT *)(ttcBuffer + 4)); unsigned int outLen = 12+16* numTables; char *entry = ttcBuffer + 12; int table; //us: see "http://www.microsoft.com/typography/otspec/otff.htm" for (table = 0; table < numTables; table++) { ULONG length = FromBigEndian(*(ULONG *)(entry + 12)); length = (length + 3) & ~3; entry += 16; outLen += length; } char *outBuffer = (char*)podofo_malloc(outLen); if (!outBuffer) { podofo_free(fileBuffer); podofo_free(ttcBuffer); PODOFO_RAISE_ERROR(ePdfError_OutOfMemory); } // copy font header and table index (offsets need to be still adjusted) memcpy(outBuffer, ttcBuffer, 12 + 16 * numTables); unsigned int dstDataOffset = 12 + 16 * numTables; // process tables char *srcEntry = ttcBuffer + 12; char *dstEntry = outBuffer + 12; for (table = 0; table < numTables; table++) { // read source entry ULONG offset = FromBigEndian(*(ULONG *)(srcEntry + 8)); ULONG length = FromBigEndian(*(ULONG *)(srcEntry + 12)); length = (length + 3) & ~3; // adjust offset // U can use FromBigEndian() also to convert _to_ big endian *(ULONG *)(dstEntry + 8) = FromBigEndian(dstDataOffset); //copy data memcpy(outBuffer + dstDataOffset, fileBuffer + offset, length); dstDataOffset += length; // adjust table entry pointers for loop srcEntry += 16; dstEntry += 16; } podofo_free(fileBuffer); podofo_free(ttcBuffer); buffer = outBuffer; bufferLen = outLen; return true; } static bool GetDataFromHFONT( HFONT hf, char** outFontBuffer, unsigned int& outFontBufferLen, const LOGFONTW* inFont ) { HDC hdc = GetDC(0); if ( hdc == NULL ) return false; HGDIOBJ oldFont = SelectObject(hdc, hf); // Petr Petrov (22 December 2009) bool ok = false; // try get data from true type collection char *buffer = NULL; const DWORD ttcf_const = 0x66637474; unsigned int bufferLen = GetFontData(hdc, 0, 0, 0, 0); unsigned int ttcLen = GetFontData(hdc, ttcf_const, 0, 0, 0); if (bufferLen != GDI_ERROR && ttcLen == GDI_ERROR) { buffer = (char *) podofo_malloc( bufferLen ); if (!buffer) { PODOFO_RAISE_ERROR(ePdfError_OutOfMemory); } ok = GetFontData(hdc, 0, 0, buffer, (DWORD)bufferLen) != GDI_ERROR; } else if (bufferLen != GDI_ERROR) { ok = GetFontFromCollection(hdc, buffer, bufferLen); } // clean up SelectObject(hdc,oldFont); ReleaseDC(0,hdc); if(ok) { // on success set result buffer *outFontBuffer = buffer; outFontBufferLen = bufferLen; } else if(buffer) { // on failure free local buffer podofo_free(buffer); } return ok; } static bool GetDataFromLPFONT( const LOGFONTW* inFont, char** outFontBuffer, unsigned int& outFontBufferLen ) { bool ok = false; HFONT hf = CreateFontIndirectW(inFont); if(hf) { ok = GetDataFromHFONT( hf, outFontBuffer, outFontBufferLen, inFont ); DeleteObject(hf); } return ok; } static bool GetDataFromLPFONT( const LOGFONTA* inFont, char** outFontBuffer, unsigned int& outFontBufferLen ) { bool ok = false; HFONT hf = CreateFontIndirectA(inFont); if(hf) { LOGFONTW inFontW; GetObjectW(hf, sizeof(LOGFONTW), &inFontW); ok = GetDataFromHFONT( hf, outFontBuffer, outFontBufferLen, &inFontW); DeleteObject(hf); } return ok; } #endif // _WIN32 PdfFontCache::PdfFontCache( PdfVecObjects* pParent ) : m_pParent( pParent ) { Init(); } PdfFontCache::PdfFontCache( const PdfFontConfigWrapper & rFontConfig, PdfVecObjects* pParent ) : m_pParent( pParent ), m_fontConfig( rFontConfig ) { Init(); } PdfFontCache::~PdfFontCache() { this->EmptyCache(); if( m_ftLibrary ) { FT_Done_FreeType( m_ftLibrary ); m_ftLibrary = NULL; } } void PdfFontCache::Init(void) { m_sSubsetBasename[0] = 0; char *p = m_sSubsetBasename; int ii; for (ii = 0; ii < SUBSET_BASENAME_LEN; ii++, p++) { *p = 'A'; } p[0] = '+'; p[1] = 0; m_sSubsetBasename[0]--; // Initialize all the fonts stuff if( FT_Init_FreeType( &m_ftLibrary ) ) { PODOFO_RAISE_ERROR( ePdfError_FreeType ); } } void PdfFontCache::EmptyCache() { TISortedFontList itFont = m_vecFonts.begin(); while( itFont != m_vecFonts.end() ) { delete (*itFont).m_pFont; ++itFont; } itFont = m_vecFontSubsets.begin(); while( itFont != m_vecFontSubsets.end() ) { delete (*itFont).m_pFont; ++itFont; } m_vecFonts.clear(); m_vecFontSubsets.clear(); } PdfFont* PdfFontCache::GetFont( PdfObject* pObject ) { TCISortedFontList it = m_vecFonts.begin(); const PdfReference & ref = pObject->Reference(); // Search if the object is a cached normal font while( it != m_vecFonts.end() ) { if( (*it).m_pFont->GetObject()->Reference() == ref ) return (*it).m_pFont; ++it; } // Search if the object is a cached font subset it = m_vecFontSubsets.begin(); while( it != m_vecFontSubsets.end() ) { if( (*it).m_pFont->GetObject()->Reference() == ref ) return (*it).m_pFont; ++it; } // Create a new font PdfFont* pFont = PdfFontFactory::CreateFont( &m_ftLibrary, pObject ); if( pFont ) { TFontCacheElement element; element.m_pFont = pFont; element.m_bBold = pFont->IsBold(); element.m_bItalic = pFont->IsItalic(); element.m_sFontName = pFont->GetFontMetrics()->GetFontname(); element.m_pEncoding = NULL; element.m_bIsSymbolCharset = pFont->GetFontMetrics()->IsSymbol(); m_vecFonts.push_back( element ); // Now sort the font list std::sort( m_vecFonts.begin(), m_vecFonts.end() ); } return pFont; } PdfFont* PdfFontCache::GetFont( const char* pszFontName, bool bBold, bool bItalic, bool bSymbolCharset, bool bEmbedd, EFontCreationFlags eFontCreationFlags, const PdfEncoding * const pEncoding, const char* pszFileName) { PODOFO_ASSERT( pEncoding ); PdfFont* pFont = NULL; PdfFontMetrics* pMetrics = NULL; std::pair it; it = std::equal_range( m_vecFonts.begin(), m_vecFonts.end(), TFontCacheElement( pszFontName, bBold, bItalic, bSymbolCharset, pEncoding ) ); if( it.first == it.second ) { if ( (eFontCreationFlags & eFontCreationFlags_AutoSelectBase14) && PODOFO_Base14FontDef_FindBuiltinData(pszFontName) ) { EPdfFontFlags eFlags = ePdfFont_Normal; if( bBold ) { if( bItalic ) { eFlags = ePdfFont_BoldItalic; } else { eFlags = ePdfFont_Bold; } } else if( bItalic ) eFlags = ePdfFont_Italic; pFont = PdfFontFactory::CreateBase14Font(pszFontName, eFlags, pEncoding, m_pParent); if( pFont ) { TFontCacheElement element; element.m_pFont = pFont; element.m_bBold = pFont->IsBold(); element.m_bItalic = pFont->IsItalic(); element.m_sFontName = pszFontName; element.m_pEncoding = pEncoding; element.m_bIsSymbolCharset = bSymbolCharset; // Do a sorted insert, so no need to sort again //rvecContainer.insert( itSorted, element ); m_vecFonts.insert( it.first, element ); } } if (!pFont) { bool bSubsetting = (eFontCreationFlags & eFontCreationFlags_Type1Subsetting) != 0; std::string sPath; if ( pszFileName == NULL ) sPath = this->GetFontPath( pszFontName, bBold, bItalic ); else sPath = pszFileName; if( sPath.empty() ) { #if defined(_WIN32) && !defined(PODOFO_NO_FONTMANAGER) pFont = GetWin32Font( it.first, m_vecFonts, pszFontName, bBold, bItalic, bSymbolCharset, bEmbedd, pEncoding, bSubsetting ); #endif // _WIN32 } else { pMetrics = new PdfFontMetricsFreetype( &m_ftLibrary, sPath.c_str(), bSymbolCharset, bSubsetting ? genSubsetBasename() : NULL ); pFont = this->CreateFontObject( it.first, m_vecFonts, pMetrics, bEmbedd, bBold, bItalic, pszFontName, pEncoding, bSubsetting ); } } } else pFont = (*it.first).m_pFont; #if !(defined(_WIN32) && !defined(PODOFO_NO_FONTMANAGER)) if (!pFont) PdfError::LogMessage( eLogSeverity_Critical, "No path was found for the specified fontname: %s\n", pszFontName ); #endif return pFont; } #if defined(_WIN32) && !defined(PODOFO_NO_FONTMANAGER) PdfFont* PdfFontCache::GetFont( const wchar_t* pszFontName, bool bBold, bool bItalic, bool bSymbolCharset, bool bEmbedd, const PdfEncoding * const pEncoding ) { PODOFO_ASSERT( pEncoding ); PdfFont* pFont; std::pair it; size_t lMaxLen = wcslen(pszFontName) * 5; if (lMaxLen == 0) PODOFO_RAISE_ERROR_INFO(ePdfError_InternalLogic, "Font name is empty"); char* pmbFontName = static_cast(podofo_malloc(lMaxLen)); if (!pmbFontName) { PODOFO_RAISE_ERROR(ePdfError_OutOfMemory); } if (wcstombs(pmbFontName, pszFontName, lMaxLen) == -1) { podofo_free(pmbFontName); PODOFO_RAISE_ERROR_INFO(ePdfError_InternalLogic, "Conversion to multibyte char failed"); } TFontCacheElement element; element.m_bBold = bBold; element.m_bItalic = bItalic; element.m_pEncoding = pEncoding; element.m_sFontName = pmbFontName; it = std::equal_range( m_vecFonts.begin(), m_vecFonts.end(), element ); if( it.first == it.second ) return GetWin32Font( it.first, m_vecFonts, pszFontName, bBold, bItalic, bSymbolCharset, bEmbedd, pEncoding ); else pFont = (*it.first).m_pFont; return pFont; } PdfFont* PdfFontCache::GetFont( const LOGFONTA &logFont, bool bEmbedd, const PdfEncoding * const pEncoding ) { PODOFO_ASSERT( pEncoding ); PdfFont* pFont; std::pair it; it = std::equal_range( m_vecFonts.begin(), m_vecFonts.end(), TFontCacheElement( logFont.lfFaceName, logFont.lfWeight >= FW_BOLD ? true : false, logFont.lfItalic ? true : false, logFont.lfCharSet == SYMBOL_CHARSET, pEncoding ) ); if( it.first == it.second ) return GetWin32Font( it.first, m_vecFonts, logFont, bEmbedd, pEncoding ); else pFont = (*it.first).m_pFont; return pFont; } PdfFont* PdfFontCache::GetFont( const LOGFONTW &logFont, bool bEmbedd, const PdfEncoding * const pEncoding ) { PODOFO_ASSERT( pEncoding ); PdfFont* pFont; std::pair it; it = std::equal_range( m_vecFonts.begin(), m_vecFonts.end(), TFontCacheElement( logFont.lfFaceName, logFont.lfWeight >= FW_BOLD ? true : false, logFont.lfItalic ? true : false, logFont.lfCharSet == SYMBOL_CHARSET, pEncoding ) ); if( it.first == it.second ) return GetWin32Font( it.first, m_vecFonts, logFont, bEmbedd, pEncoding ); else pFont = (*it.first).m_pFont; return pFont; } #endif // _WIN32 PdfFont* PdfFontCache::GetFont( FT_Face face, bool bSymbolCharset, bool bEmbedd, const PdfEncoding * const pEncoding ) { PdfFont* pFont; PdfFontMetrics* pMetrics; std::pair it; std::string sName = FT_Get_Postscript_Name( face ); if( sName.empty() ) { PdfError::LogMessage( eLogSeverity_Critical, "Could not retrieve fontname for font!\n" ); return NULL; } bool bBold = ((face->style_flags & FT_STYLE_FLAG_BOLD) != 0); bool bItalic = ((face->style_flags & FT_STYLE_FLAG_ITALIC) != 0); it = std::equal_range( m_vecFonts.begin(), m_vecFonts.end(), TFontCacheElement( sName.c_str(), bBold, bItalic, bSymbolCharset, pEncoding ) ); if( it.first == it.second ) { pMetrics = new PdfFontMetricsFreetype( &m_ftLibrary, face, bSymbolCharset ); pFont = this->CreateFontObject( it.first, m_vecFonts, pMetrics, bEmbedd, bBold, bItalic, sName.c_str(), pEncoding ); } else pFont = (*it.first).m_pFont; return pFont; } PdfFont* PdfFontCache::GetDuplicateFontType1( PdfFont * pFont, const char* pszSuffix ) { TCISortedFontList it = m_vecFonts.begin(); std::string id = pFont->GetIdentifier().GetName(); id += pszSuffix; // Search if the object is a cached normal font while( it != m_vecFonts.end() ) { if( (*it).m_pFont->GetIdentifier() == id ) return (*it).m_pFont; ++it; } // Search if the object is a cached font subset it = m_vecFontSubsets.begin(); while( it != m_vecFontSubsets.end() ) { if( (*it).m_pFont->GetIdentifier() == id ) return (*it).m_pFont; ++it; } // Create a copy of the font PODOFO_ASSERT( pFont->GetFontMetrics()->GetFontType() == ePdfFontType_Type1Pfb ); PdfFontMetrics* pMetrics = new PdfFontMetricsFreetype( &m_ftLibrary, pFont->GetFontMetrics()->GetFilename(), pFont->GetFontMetrics()->IsSymbol() ); PdfFont* newFont = new PdfFontType1( static_cast(pFont), pMetrics, pszSuffix, m_pParent ); if( newFont ) { std::string name = newFont->GetFontMetrics()->GetFontname(); name += pszSuffix; TFontCacheElement element; element.m_pFont = newFont; element.m_bBold = newFont->IsBold(); element.m_bItalic = newFont->IsItalic(); element.m_sFontName = name; element.m_pEncoding = newFont->GetEncoding(); element.m_bIsSymbolCharset = pFont->GetFontMetrics()->IsSymbol(); m_vecFonts .push_back( element ); // Now sort the font list std::sort( m_vecFonts.begin(), m_vecFonts.end() ); } return newFont; } PdfFont* PdfFontCache::GetFontSubset( const char* pszFontName, bool bBold, bool bItalic, bool bSymbolCharset, const PdfEncoding * const pEncoding, const char* pszFileName ) { PdfFont* pFont = 0; PdfFontMetrics* pMetrics; std::pair it; // WARNING: The characters are completely ignored right now! it = std::equal_range( m_vecFontSubsets.begin(), m_vecFontSubsets.end(), TFontCacheElement( pszFontName, bBold, bItalic, bSymbolCharset, pEncoding ) ); if( it.first == it.second ) { std::string sPath; if( pszFileName == NULL || *pszFileName == 0) { sPath = this->GetFontPath( pszFontName, bBold, bItalic ); if( sPath.empty() ) { #if defined(_WIN32) && !defined(PODOFO_NO_FONTMANAGER) return GetWin32Font( it.first, m_vecFontSubsets, pszFontName, bBold, bItalic, bSymbolCharset, true, pEncoding, true ); #else PdfError::LogMessage( eLogSeverity_Critical, "No path was found for the specified fontname: %s\n", pszFontName ); return NULL; #endif // _WIN32 } } else { sPath = pszFileName; } pMetrics = PdfFontMetricsFreetype::CreateForSubsetting( &m_ftLibrary, sPath.c_str(), bSymbolCharset, genSubsetBasename() ); pFont = this->CreateFontObject( it.first, m_vecFontSubsets, pMetrics, true, bBold, bItalic, pszFontName, pEncoding, true ); } else pFont = (*it.first).m_pFont; return pFont; } void PdfFontCache::EmbedSubsetFonts() { TCISortedFontList it = m_vecFontSubsets.begin(); while( it != m_vecFontSubsets.end() ) { if( (*it).m_pFont->IsSubsetting() ) { (*it).m_pFont->EmbedSubsetFont(); } ++it; } } #if defined(_WIN32) && !defined(PODOFO_NO_FONTMANAGER) PdfFont* PdfFontCache::GetWin32Font( TISortedFontList itSorted, TSortedFontList & vecContainer, const char* pszFontName, bool bBold, bool bItalic, bool bSymbolCharset, bool bEmbedd, const PdfEncoding * const pEncoding, bool pSubsetting ) { LOGFONTW lf; lf.lfHeight = 0; lf.lfWidth = 0; lf.lfEscapement = 0; lf.lfOrientation = 0; lf.lfWeight = bBold ? FW_BOLD : 0; lf.lfItalic = bItalic; lf.lfUnderline = 0; lf.lfStrikeOut = 0; lf.lfCharSet = bSymbolCharset ? SYMBOL_CHARSET : DEFAULT_CHARSET; lf.lfOutPrecision = OUT_DEFAULT_PRECIS; lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; lf.lfQuality = DEFAULT_QUALITY; lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; if (strlen(pszFontName) >= LF_FACESIZE) return NULL; memset(&(lf.lfFaceName), 0, LF_FACESIZE); //strcpy( lf.lfFaceName, pszFontName ); /*int destLen =*/ MultiByteToWideChar (0, 0, pszFontName, -1, lf.lfFaceName, LF_FACESIZE); return GetWin32Font(itSorted, vecContainer, lf, bEmbedd, pEncoding, pSubsetting); } PdfFont* PdfFontCache::GetWin32Font( TISortedFontList itSorted, TSortedFontList & vecContainer, const wchar_t* pszFontName, bool bBold, bool bItalic, bool bSymbolCharset, bool bEmbedd, const PdfEncoding * const pEncoding, bool pSubsetting ) { LOGFONTW lf; lf.lfHeight = 0; lf.lfWidth = 0; lf.lfEscapement = 0; lf.lfOrientation = 0; lf.lfWeight = bBold ? FW_BOLD : 0; lf.lfItalic = bItalic; lf.lfUnderline = 0; lf.lfStrikeOut = 0; lf.lfCharSet = bSymbolCharset ? SYMBOL_CHARSET : DEFAULT_CHARSET; lf.lfOutPrecision = OUT_DEFAULT_PRECIS; lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; lf.lfQuality = DEFAULT_QUALITY; lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; pdf_long lFontNameLen = wcslen(pszFontName); if (lFontNameLen >= LF_FACESIZE) return NULL; if (lFontNameLen == 0) PODOFO_RAISE_ERROR_INFO(ePdfError_InternalLogic, "Font name is empty"); memset(&(lf.lfFaceName), 0, LF_FACESIZE); wcscpy( static_cast(lf.lfFaceName), pszFontName ); return GetWin32Font(itSorted, vecContainer, lf, bEmbedd, pEncoding, pSubsetting); } PdfFont* PdfFontCache::GetWin32Font( TISortedFontList itSorted, TSortedFontList & vecContainer, const LOGFONTA &logFont, bool bEmbedd, const PdfEncoding * const pEncoding, bool pSubsetting) { char* pBuffer = NULL; unsigned int nLen; if( !GetDataFromLPFONT( &logFont, &pBuffer, nLen ) ) return NULL; PdfFontMetrics* pMetrics; PdfFont* pFont = NULL; try { pMetrics = new PdfFontMetricsFreetype( &m_ftLibrary, pBuffer, nLen, logFont.lfCharSet == SYMBOL_CHARSET, pSubsetting ? genSubsetBasename() : NULL ); pFont = this->CreateFontObject( itSorted, vecContainer, pMetrics, bEmbedd, logFont.lfWeight >= FW_BOLD ? true : false, logFont.lfItalic ? true : false, logFont.lfFaceName, pEncoding, pSubsetting ); } catch( PdfError & error ) { podofo_free( pBuffer ); throw error; } podofo_free( pBuffer ); return pFont; } PdfFont* PdfFontCache::GetWin32Font( TISortedFontList itSorted, TSortedFontList & vecContainer, const LOGFONTW &logFont, bool bEmbedd, const PdfEncoding * const pEncoding, bool pSubsetting) { pdf_long lFontNameLen = wcslen(logFont.lfFaceName); if (lFontNameLen >= LF_FACESIZE) return NULL; pdf_long lMaxLen = lFontNameLen * 5; char* pmbFontName = static_cast(podofo_malloc(lMaxLen)); if( !pmbFontName ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } if( wcstombs( pmbFontName, logFont.lfFaceName, lMaxLen ) == -1 ) { podofo_free( pmbFontName ); PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Conversion to multibyte char failed" ); } char* pBuffer = NULL; unsigned int nLen; if (!GetDataFromLPFONT(&logFont, &pBuffer, nLen)) return NULL; PdfFontMetrics* pMetrics; PdfFont* pFont = NULL; try { pMetrics = new PdfFontMetricsFreetype( &m_ftLibrary, pBuffer, nLen, logFont.lfCharSet == SYMBOL_CHARSET, pSubsetting ? genSubsetBasename() : NULL ); pFont = this->CreateFontObject( itSorted, vecContainer, pMetrics, bEmbedd, logFont.lfWeight >= FW_BOLD ? true : false, logFont.lfItalic ? true : false, pmbFontName, pEncoding, pSubsetting ); podofo_free( pmbFontName ); pmbFontName = NULL; } catch( PdfError & error ) { podofo_free( pmbFontName ); pmbFontName = NULL; podofo_free( pBuffer ); throw error; } podofo_free( pBuffer ); return pFont; } #endif // _WIN32 #if defined(PODOFO_HAVE_FONTCONFIG) std::string PdfFontCache::GetFontConfigFontPath( FcConfig* pConfig, const char* pszFontName, bool bBold, bool bItalic ) { FcPattern* pattern; FcPattern* matched; FcResult result = FcResultMatch; FcValue v; std::string sPath; // Build a pattern to search using fontname, bold and italic pattern = FcPatternBuild (0, FC_FAMILY, FcTypeString, pszFontName, FC_WEIGHT, FcTypeInteger, (bBold ? FC_WEIGHT_BOLD : FC_WEIGHT_MEDIUM), FC_SLANT, FcTypeInteger, (bItalic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN), static_cast(0)); FcDefaultSubstitute( pattern ); if( !FcConfigSubstitute( pConfig, pattern, FcMatchFont ) ) { FcPatternDestroy( pattern ); return sPath; } matched = FcFontMatch( pConfig, pattern, &result ); if( result != FcResultNoMatch ) { result = FcPatternGet( matched, FC_FILE, 0, &v ); sPath = reinterpret_cast(v.u.s); #ifdef PODOFO_VERBOSE_DEBUG PdfError::LogMessage( eLogSeverity_Debug, "Got Font %s for for %s\n", sPath.c_str(), pszFontName ); #endif // PODOFO_DEBUG } FcPatternDestroy( pattern ); FcPatternDestroy( matched ); return sPath; } #endif // PODOFO_HAVE_FONTCONFIG std::string PdfFontCache::GetFontPath( const char* pszFontName, bool bBold, bool bItalic ) { #if defined(PODOFO_HAVE_FONTCONFIG) Util::PdfMutexWrapper mutex(m_fontConfig.GetFontConfigMutex()); FcConfig* pFcConfig = static_cast(m_fontConfig.GetFontConfig()); std::string sPath = this->GetFontConfigFontPath( pFcConfig, pszFontName, bBold, bItalic ); #else std::string sPath = ""; #endif return sPath; } PdfFont* PdfFontCache::CreateFontObject( TISortedFontList itSorted, TSortedFontList & rvecContainer, PdfFontMetrics* pMetrics, bool bEmbedd, bool bBold, bool bItalic, const char* pszFontName, const PdfEncoding * const pEncoding, bool bSubsetting ) { PdfFont* pFont; try { int nFlags = ePdfFont_Normal; if ( bSubsetting ) nFlags |= ePdfFont_Subsetting; if( bEmbedd ) nFlags |= ePdfFont_Embedded; if( bBold ) nFlags |= ePdfFont_Bold; if( bItalic ) nFlags |= ePdfFont_Italic; pFont = PdfFontFactory::CreateFontObject( pMetrics, nFlags, pEncoding, m_pParent ); if( pFont ) { TFontCacheElement element; element.m_pFont = pFont; element.m_bBold = pFont->IsBold(); element.m_bItalic = pFont->IsItalic(); element.m_sFontName = pszFontName; element.m_pEncoding = pEncoding; element.m_bIsSymbolCharset = pMetrics->IsSymbol(); // Do a sorted insert, so no need to sort again rvecContainer.insert( itSorted, element ); } } catch( PdfError & e ) { e.AddToCallstack( __FILE__, __LINE__ ); e.PrintErrorMsg(); PdfError::LogMessage( eLogSeverity_Error, "Cannot initialize font: %s\n", pszFontName ? pszFontName : "" ); return NULL; } return pFont; } const char *PdfFontCache::genSubsetBasename(void) { int ii = 0; while(ii < SUBSET_BASENAME_LEN) { m_sSubsetBasename[ii]++; if (m_sSubsetBasename[ii] <= 'Z') { break; } m_sSubsetBasename[ii] = 'A'; ii++; } return m_sSubsetBasename; } }; podofo-0.9.5/src/doc/PdfPagesTreeCache.h0000664000175000017500000001172712344436402017637 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2009 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_PAGES_TREE_CACHE_H_ #define _PDF_PAGES_TREE_CACHE_H_ #include "podofo/base/PdfDefines.h" namespace PoDoFo { class PdfPage; /** * This class implements a cache infront of a PdfPagesTree * * \see PdfCachedPagesTree */ class PODOFO_DOC_API PdfPagesTreeCache { typedef std::deque< PdfPage* > PdfPageList; public: /** Construct a new PdfCachedPagesTree. * * @param nInitialSize initial size of the pagestree */ PdfPagesTreeCache( int nInitialSize ); /** Close/down destruct a PdfCachedPagesTree */ virtual ~PdfPagesTreeCache(); /** Return a PdfPage for the specified Page index * The returned page is owned by the pages tree and * deleted along with it. * * \param nIndex page index, 0-based * \returns a pointer to the requested page or NULL if it is not cached */ virtual PdfPage* GetPage( int nIndex ); /** * Add a PdfPage object to the cache * @param nIndex index of the page * @param pPage page object */ virtual void AddPageObject( int nIndex, PdfPage* pPage ); /** * Add several PdfPage objects to the cache, replacing any existing at the given index * @param nIndex zero based index of where the first page will be placed * @param vecPages vector of the page objects to add */ virtual void AddPageObjects( int nIndex, std::vector vecPages ); /** * A page was inserted into the pagestree, * therefore the cache has to be updated * * @param nAfterPageIndex zero based index of the page we are inserting after * - may be one of the special values from EPdfPageInsertionPoint. */ virtual void InsertPage( int nAfterPageIndex ); /** * Insert several pages into the pagestree, after the given index * therefore the cache has to be updated * * @param nAfterPageIndex zero based index of the page we are inserting after * - may be one of the special values from EPdfPageInsertionPoint. * @param nCount number of pages that were inserted */ virtual void InsertPages( int nAfterPageIndex, int nCount ); /** * Delete a PdfPage from the cache * @param nIndex index of the page */ virtual void DeletePage( int nIndex ); /** * Clear cache, i.e. remove all elements from the * cache. */ virtual void ClearCache(); private: /** * Avoid construction of empty objects */ PdfPagesTreeCache() { } private: PdfPageList m_deqPageObjs; }; }; #endif // _PDF_PAGES_TREE_CACHE_H_ podofo-0.9.5/src/doc/PdfPainter.h0000664000175000017500000010610612626226641016437 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_PAINTER_H_ #define _PDF_PAINTER_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfRect.h" #include "podofo/base/PdfColor.h" #include namespace PoDoFo { class PdfCanvas; class PdfExtGState; class PdfFont; class PdfImage; class PdfMemDocument; class PdfName; class PdfObject; class PdfReference; class PdfShadingPattern; class PdfStream; class PdfString; class PdfTilingPattern; class PdfXObject; struct TLineElement { TLineElement() : pszStart( NULL ), lLen( 0L ) { } const char* pszStart; pdf_long lLen; }; /** * This class provides an easy to use painter object which allows you to draw on a PDF page * object. * * During all drawing operations, you are still able to access the stream of the object you are * drawing on directly. * * All functions that take coordinates expect these to be in PDF User Units. Keep in mind that PDF has * its coordinate system origin at the bottom left corner. */ class PODOFO_DOC_API PdfPainter { public: /** Create a new PdfPainter object. */ PdfPainter(); virtual ~PdfPainter(); /** Set the page on which the painter should draw. * The painter will draw of course on the pages * contents object. * * Calls FinishPage() on the last page if it was not yet called. * * \param pPage a PdfCanvas object (most likely a PdfPage or PdfXObject). * * \see PdfPage \see PdfXObject * \see FinishPage() * \see GetPage() */ void SetPage( PdfCanvas* pPage ); /** Return the current page that is that on the painter. * * \returns the current page of the painter or NULL if none is set */ inline PdfCanvas* GetPage() const; /** Return the current page canvas stream that is set on the painter. * * \returns the current page canvas stream of the painter or NULL if none is set */ inline PdfStream* GetCanvas() const; /** Finish drawing onto a page. * * This has to be called whenever a page has been drawn complete. */ void FinishPage(); /** Set the color for all following stroking operations * in grayscale colorspace. This operation used the 'G' * PDF operator. * \param g gray scale value in the range 0.0 - 1.0 */ void SetStrokingGray( double g ); /** Set the color for all following non-stroking operations * in grayscale colorspace. This operation used the 'g' * PDF operator. * \param g gray scale value in the range 0.0 - 1.0 */ void SetGray( double g ); /** Set the color for all following stroking operations * in rgb colorspace. This operation used the 'RG' * PDF operator. * \param r red value in the range 0.0 - 1.0 * \param g green value in the range 0.0 - 1.0 * \param b blue value in the range 0.0 - 1.0 */ void SetStrokingColor( double r, double g, double b ); /** Set the color for all following non-stroking operations * in rgb colorspace. This operation used the 'rg' * PDF operator. * * This color is also used when drawing text. * * \param r red value in the range 0.0 - 1.0 * \param g green value in the range 0.0 - 1.0 * \param b blue value in the range 0.0 - 1.0 */ void SetColor( double r, double g, double b ); /** Set the color for all following stroking operations * in cmyk colorspace. This operation used the 'K' * PDF operator. * \param c cyan value in the range 0.0 - 1.0 * \param m magenta value in the range 0.0 - 1.0 * \param y yellow value in the range 0.0 - 1.0 * \param k black value in the range 0.0 - 1.0 */ void SetStrokingColorCMYK( double c, double m, double y, double k ); /** Set the color for all following non-stroking operations * in cmyk colorspace. This operation used the 'k' * PDF operator. * \param c cyan value in the range 0.0 - 1.0 * \param m magenta value in the range 0.0 - 1.0 * \param y yellow value in the range 0.0 - 1.0 * \param k black value in the range 0.0 - 1.0 */ void SetColorCMYK( double c, double m, double y, double k ); /** Set the shading pattern for all following stroking operations. * This operation uses the 'SCN' PDF operator. * * \param rPattern a shading pattern */ void SetStrokingShadingPattern( const PdfShadingPattern & rPattern ); /** Set the shading pattern for all following non-stroking operations. * This operation uses the 'scn' PDF operator. * * \param rPattern a shading pattern */ void SetShadingPattern( const PdfShadingPattern & rPattern ); /** Set the tiling pattern for all following stroking operations. * This operation uses the 'SCN' PDF operator. * * \param rPattern a tiling pattern */ void SetStrokingTilingPattern( const PdfTilingPattern & rPattern ); /** Set the tiling pattern for all following stroking operations by pattern name, * Use when it's already in resources. * This operation uses the 'SCN' PDF operator. * * \param rPatternName a tiling pattern name */ void SetStrokingTilingPattern( const std::string &rPatternName ); /** Set the tiling pattern for all following non-stroking operations. * This operation uses the 'scn' PDF operator. * * \param rPattern a tiling pattern */ void SetTilingPattern( const PdfTilingPattern & rPattern ); /** Set the tiling pattern for all following non-stroking operations by pattern name. * Use when it's already in resources. * This operation uses the 'scn' PDF operator. * * \param rPattern a tiling pattern */ void SetTilingPattern( const std::string & rPatternName ); /** Set the color for all following stroking operations. * * \param rColor a PdfColor object */ void SetStrokingColor( const PdfColor & rColor ); /** Set the color for all following non-stroking operations. * * \param rColor a PdfColor object */ void SetColor( const PdfColor & rColor ); /** Set the line width for all stroking operations. * \param dWidth in PDF User Units. */ void SetStrokeWidth( double dWidth ); /** Set the stoke style for all stroking operations. * \param eStyle style of the stroking operations * \param pszCustom a custom stroking style which is used when * eStyle == ePdfStrokeStyle_Custom. * \param inverted inverted dash style (gaps for drawn spaces), * it is ignored for None, Solid and Custom styles * \param scale scale factor of the stroke style * it is ignored for None, Solid and Custom styles * \param subtractJoinCap if true, subtracts scaled width on filled parts, * thus the line capability still draws into the cell; * is used only if scale is not 1.0 * * Possible values: * ePdfStrokeStyle_None * ePdfStrokeStyle_Solid * ePdfStrokeStyle_Dash * ePdfStrokeStyle_Dot * ePdfStrokeStyle_DashDot * ePdfStrokeStyle_DashDotDot * ePdfStrokeStyle_Custom * */ void SetStrokeStyle( EPdfStrokeStyle eStyle, const char* pszCustom = NULL, bool inverted = false, double scale = 1.0, bool subtractJoinCap = false ); /** Set the line cap style for all stroking operations. * \param eCapStyle the cap style. * * Possible values: * ePdfLineCapStyle_Butt, * ePdfLineCapStyle_Round, * ePdfLineCapStyle_Square */ void SetLineCapStyle( EPdfLineCapStyle eCapStyle ); /** Set the line join style for all stroking operations. * \param eJoinStyle the join style. * * Possible values: * ePdfLineJoinStyle_Miter * ePdfLineJoinStyle_Round * ePdfLineJoinStyle_Bevel */ void SetLineJoinStyle( EPdfLineJoinStyle eJoinStyle ); /** Set the font for all text drawing operations * \param pFont a handle to a valid PdfFont object * * \see DrawText */ void SetFont( PdfFont* pFont ); /** Set the text rendering mode * \param mode What text rendering mode to use. * * Possible values: * ePdfTextRenderingMode_Fill (default mode) * ePdfTextRenderingMode_Stroke * ePdfTextRenderingMode_FillAndStroke * ePdfTextRenderingMode_Invisible * ePdfTextRenderingMode_FillToClipPath * ePdfTextRenderingMode_StrokeToClipPath * ePdfTextRenderingMode_FillAndStrokeToClipPath * ePdfTextRenderingMode_ToClipPath */ void SetTextRenderingMode( EPdfTextRenderingMode mode ); /** Gets current text rendering mode. * Default mode is ePdfTextRenderingMode_Fill. */ inline EPdfTextRenderingMode GetTextRenderingMode(void) const; /** Get the current font: * \returns a font object or NULL if no font was set. */ inline PdfFont* GetFont() const; /** Set a clipping rectangle * * \param dX x coordinate of the rectangle (left coordinate) * \param dY y coordinate of the rectangle (bottom coordinate) * \param dWidth width of the rectangle * \param dHeight absolute height of the rectangle */ void SetClipRect( double dX, double dY, double dWidth, double dHeight ); /** Set a clipping rectangle * * \param rRect rectangle */ inline void SetClipRect( const PdfRect & rRect ); /** Set miter limit. */ void SetMiterLimit(double value); /** Draw a line with the current color and line settings. * \param dStartX x coordinate of the starting point * \param dStartY y coordinate of the starting point * \param dEndX x coordinate of the ending point * \param dEndY y coordinate of the ending point */ void DrawLine( double dStartX, double dStartY, double dEndX, double dEndY ); /** Add a rectangle into the current path * \param dX x coordinate of the rectangle (left coordinate) * \param dY y coordinate of the rectangle (bottom coordinate) * \param dWidth width of the rectangle * \param dHeight absolute height of the rectangle * \param dRoundX rounding factor, x direction * \param dRoundY rounding factor, y direction */ void Rectangle( double dX, double dY, double dWidth, double dHeight, double dRoundX=0.0, double dRoundY=0.0 ); /** Add a rectangle into the current path * * \param rRect the rectangle area * \param dRoundX rounding factor, x direction * \param dRoundY rounding factor, y direction * * \see DrawRect */ inline void Rectangle( const PdfRect & rRect, double dRoundX=0.0, double dRoundY=0.0 ); /** Add an ellipse into the current path * \param dX x coordinate of the ellipse (left coordinate) * \param dY y coordinate of the ellipse (top coordinate) * \param dWidth width of the ellipse * \param dHeight absolute height of the ellipse */ void Ellipse( double dX, double dY, double dWidth, double dHeight ); /** Add a circle into the current path * \param dX x center coordinate of the circle * \param dY y coordinate of the circle * \param dRadius radius of the circle */ void Circle( double dX, double dY, double dRadius ); /** Draw a single-line text string on a page using a given font object. * You have to call SetFont before calling this function. * \param dX the x coordinate * \param dY the y coordinate * \param sText the text string which should be printed * * \see SetFont() */ void DrawText( double dX, double dY, const PdfString & sText); /** Draw a single-line text string on a page using a given font object. * You have to call SetFont before calling this function. * \param dX the x coordinate * \param dY the y coordinate * \param sText the text string which should be printed (is not allowed to be NULL!) * \param lLen draw only lLen characters of pszText * * \see SetFont() */ void DrawText( double dX, double dY, const PdfString & sText, long lLen ); /** Draw multiline text into a rectangle doing automatic wordwrapping. * The current font is used and SetFont has to be called at least once * before using this function * * \param dX the x coordinate of the text area (left) * \param dY the y coordinate of the text area (bottom) * \param dWidth width of the text area * \param dHeight height of the text area * \param rsText the text which should be drawn * \param eAlignment alignment of the individual text lines in the given bounding box * \param eVertical vertical alignment of the text in the given bounding box * \param bClip set the clipping rectangle to the given rRect, otherwise no clipping is performed */ void DrawMultiLineText( double dX, double dY, double dWidth, double dHeight, const PdfString & rsText, EPdfAlignment eAlignment = ePdfAlignment_Left, EPdfVerticalAlignment eVertical = ePdfVerticalAlignment_Top, bool bClip = true ); /** Draw multiline text into a rectangle doing automatic wordwrapping. * The current font is used and SetFont has to be called at least once * before using this function * * \param rRect bounding rectangle of the text * \param rsText the text which should be drawn * \param eAlignment alignment of the individual text lines in the given bounding box * \param eVertical vertical alignment of the text in the given bounding box * \param bClip set the clipping rectangle to the given rRect, otherwise no clipping is performed */ inline void DrawMultiLineText( const PdfRect & rRect, const PdfString & rsText, EPdfAlignment eAlignment = ePdfAlignment_Left, EPdfVerticalAlignment eVertical = ePdfVerticalAlignment_Top, bool bClip = true ); /** Gets the text divided into individual lines, using the current font and clipping rectangle. * * \param dWidth width of the text area * \param rsText the text which should be drawn */ std::vector GetMultiLineTextAsLines( double dWidth, const PdfString & rsText); /** Draw a single line of text horizontally aligned. * \param dX the x coordinate of the text line * \param dY the y coordinate of the text line * \param dWidth the width of the text line * \param rsText the text to draw * \param eAlignment alignment of the text line */ void DrawTextAligned( double dX, double dY, double dWidth, const PdfString & rsText, EPdfAlignment eAlignment ); /** Begin drawing multiple text strings on a page using a given font object. * You have to call SetFont before calling this function. * * If you want more simpler text output and do not need * the advanced text position features of MoveTextPos * use DrawText which is easier. * * \param dX the x coordinate * \param dY the y coordinate * * \see SetFont() * \see AddText() * \see MoveTextPos() * \see EndText() */ void BeginText( double dX, double dY ); /** Draw a string on a page. * You have to call BeginText before the first call of this function * and EndText after the last call. * * If you want more simpler text output and do not need * the advanced text position features of MoveTextPos * use DrawText which is easier. * * \param sText the text string which should be printed * * \see SetFont() * \see MoveTextPos() * \see EndText() */ void AddText( const PdfString & sText ); /** Draw a string on a page. * You have to call BeginText before the first call of this function * and EndText after the last call. * * If you want more simpler text output and do not need * the advanced text position features of MoveTextPos * use DrawText which is easier. * * \param sText the text string which should be printed * \param lStringLen draw only lLen characters of pszText * * \see SetFont() * \see MoveTextPos() * \see EndText() */ void AddText( const PdfString & sText, pdf_long lStringLen ); /** Move position for text drawing on a page. * You have to call BeginText before calling this function * * If you want more simpler text output and do not need * the advanced text position features of MoveTextPos * use DrawText which is easier. * * \param dX the x offset relative to pos of BeginText or last MoveTextPos * \param dY the y offset relative to pos of BeginText or last MoveTextPos * * \see BeginText() * \see AddText() * \see EndText() */ void MoveTextPos( double dX, double dY ); /** End drawing multiple text strings on a page * * If you want more simpler text output and do not need * the advanced text position features of MoveTextPos * use DrawText which is easier. * * \see BeginText() * \see AddText() * \see MoveTextPos() */ void EndText(); /** Draw a single glyph on a page using a given font object. * \param pDocument pointer to the document, needed to generate a copy of the current font * \param dX the x coordinate * \param dY the y coordinate * \param pszGlyphname the name of the glyph which should be printed * * \see SetFont() */ void DrawGlyph( PdfMemDocument* pDocument, double dX, double dY, const char * pszGlyphname ); /** Draw an image on the current page. * \param dX the x coordinate (bottom left position of the image) * \param dY the y coordinate (bottom position of the image) * \param pObject an PdfXObject * \param dScaleX option scaling factor in x direction * \param dScaleY option scaling factor in y direction */ void DrawImage( double dX, double dY, PdfImage* pObject, double dScaleX = 1.0, double dScaleY = 1.0); /** Draw an XObject on the current page. For PdfImage use DrawImage. * * \param dX the x coordinate (bottom left position of the XObject) * \param dY the y coordinate (bottom position of the XObject) * \param pObject an PdfXObject * \param dScaleX option scaling factor in x direction * \param dScaleY option scaling factor in y direction * * \see DrawImage */ void DrawXObject( double dX, double dY, PdfXObject* pObject, double dScaleX = 1.0, double dScaleY = 1.0); /** Closes the current path by drawing a line from the current point * to the starting point of the path. Matches the PDF 'h' operator. * This function is useful to construct an own path * for drawing or clipping. */ void ClosePath(); /** Append a line segment to the current path. Matches the PDF 'l' operator. * This function is useful to construct an own path * for drawing or clipping. * \param dX x position * \param dY y position */ void LineTo( double dX, double dY ); /** Begin a new path. Matches the PDF 'm' operator. * This function is useful to construct an own path * for drawing or clipping. * \param dX x position * \param dY y position */ void MoveTo( double dX, double dY ); /** Append a cubic bezier curve to the current path * Matches the PDF 'c' operator. * * \param dX1 x coordinate of the first control point * \param dY1 y coordinate of the first control point * \param dX2 x coordinate of the second control point * \param dY2 y coordinate of the second control point * \param dX3 x coordinate of the end point, which is the new current point * \param dY3 y coordinate of the end point, which is the new current point */ void CubicBezierTo( double dX1, double dY1, double dX2, double dY2, double dX3, double dY3 ); /** Append a horizontal line to the current path * Matches the SVG 'H' operator * * \param dX x coordinate to draw the line to */ void HorizontalLineTo( double dX ); /** Append a vertical line to the current path * Matches the SVG 'V' operator * * \param dY y coordinate to draw the line to */ void VerticalLineTo( double dY ); /** Append a smooth bezier curve to the current path * Matches the SVG 'S' operator. * * \param dX2 x coordinate of the second control point * \param dY2 y coordinate of the second control point * \param dX3 x coordinate of the end point, which is the new current point * \param dY3 y coordinate of the end point, which is the new current point */ void SmoothCurveTo( double dX2, double dY2, double dX3, double dY3 ); /** Append a quadratic bezier curve to the current path * Matches the SVG 'Q' operator. * * \param dX1 x coordinate of the first control point * \param dY1 y coordinate of the first control point * \param dX3 x coordinate of the end point, which is the new current point * \param dY3 y coordinate of the end point, which is the new current point */ void QuadCurveTo( double dX1, double dY1, double dX3, double dY3 ); /** Append a smooth quadratic bezier curve to the current path * Matches the SVG 'T' operator. * * \param dX3 x coordinate of the end point, which is the new current point * \param dY3 y coordinate of the end point, which is the new current point */ void SmoothQuadCurveTo( double dX3, double dY3 ); /** Append a Arc to the current path * Matches the SVG 'A' operator. * * \param dX x coordinate of the start point * \param dY y coordinate of the start point * \param dRadiusX x coordinate of the end point, which is the new current point * \param dRadiusY y coordinate of the end point, which is the new current point * \param dRotation degree of rotation in radians * \param bLarge large or small portion of the arc * \param bSweep sweep? */ void ArcTo( double dX, double dY, double dRadiusX, double dRadiusY, double dRotation, bool bLarge, bool bSweep); // Peter Petrov 5 January 2009 was delivered from libHaru /** */ bool Arc(double dX, double dY, double dRadius, double dAngle1, double dAngle2); /** Close the current path. Matches the PDF 'h' operator. */ void Close(); /** Stroke the current path. Matches the PDF 'S' operator. * This function is useful to construct an own path * for drawing or clipping. */ void Stroke(); /** Fill the current path. Matches the PDF 'f' operator. * This function is useful to construct an own path * for drawing or clipping. * * \param useEvenOddRule select even-odd rule instead of nonzero winding number rule */ void Fill(bool useEvenOddRule = false); /** Fill then stroke the current path. Matches the PDF 'B' operator. * * \param useEvenOddRule select even-odd rule instead of nonzero winding number rule */ void FillAndStroke(bool useEvenOddRule = false); /** Clip the current path. Matches the PDF 'W' operator. * This function is useful to construct an own path * for drawing or clipping. * * \param useEvenOddRule select even-odd rule instead of nonzero winding number rule */ void Clip( bool useEvenOddRule = false); /** End current pathm without filling or stroking it. * Matches the PDF 'n' operator. */ void EndPath(void); /** Save the current graphics settings onto the graphics * stack. Operator 'q' in PDF. * This call has to be balanced with a corresponding call * to Restore()! * * \see Restore */ void Save(); /** Restore the current graphics settings from the graphics * stack. Operator 'Q' in PDF. * This call has to be balanced with a corresponding call * to Save()! * * \see Save */ void Restore(); /** Set the transformation matrix for the current coordinate system * See the operator 'cm' in PDF. * * The six parameters are a standard 3x3 transformation matrix * where the 3 left parameters are 0 0 1. * * \param a scale in x direction * \param b rotation * \param c rotation * \param d scale in y direction * \param e translate in x direction * \param f translate in y direction * * \see Save() * \see Restore() */ void SetTransformationMatrix( double a, double b, double c, double d, double e, double f ); /** Sets a specific PdfExtGState as being active * \param inGState the specific ExtGState to set */ void SetExtGState( PdfExtGState* inGState ); /** Sets a specific rendering intent * \param intent the specific intent to set */ void SetRenderingIntent( char* intent ); /** Set the tab width for the DrawText operation. * Every tab '\\t' is replaced with nTabWidth * spaces before drawing text. Default is a value of 4 * * \param nTabWidth replace every tabulator by this much spaces * * \see DrawText * \see TabWidth */ inline void SetTabWidth( unsigned short nTabWidth ); /** Get the currently set tab width * \returns by how many spaces a tabulator will be replaced * * \see DrawText * \see TabWidth */ inline unsigned short GetTabWidth() const; /** Set the floating point precision. * * \param inPrec write this many decimal places */ inline void SetPrecision( unsigned short inPrec ); /** Get the currently set floating point precision * \returns how many decimal places will be written out for any floating point value */ inline unsigned short GetPrecision() const; /** Get current path string stream. * Stroke/Fill commands clear current path. * \returns std::ostringstream representing current path */ inline std::ostringstream &GetCurrentPath(void); protected: /** Coverts a rectangle to an array of points which can be used * to draw an ellipse using 4 bezier curves. * * The arrays plPointX and plPointY need space for at least 12 longs * to be stored. * * \param dX x position of the bounding rectangle * \param dY y position of the bounding rectangle * \param dWidth width of the bounding rectangle * \param dHeight height of the bounding rectangle * \param pdPointX pointer to an array were the x coordinates * of the resulting points will be stored * \param pdPointY pointer to an array were the y coordinates * of the resulting points will be stored */ void ConvertRectToBezier( double dX, double dY, double dWidth, double dHeight, double pdPointX[], double pdPointY[] ); protected: /** Register an object in the resource dictionary of this page * so that it can be used for any following drawing operations. * * \param rIdentifier identifier of this object, e.g. /Ft0 * \param rRef reference to the object you want to register * \param rName register under this key in the resource dictionary */ virtual void AddToPageResources( const PdfName & rIdentifier, const PdfReference & rRef, const PdfName & rName ); /** Sets the color that was last set by the user as the current stroking color. * You should always enclose this function by Save() and Restore() * * \see Save() \see Restore() */ void SetCurrentStrokingColor(); bool InternalArc( double x, double y, double ray, double ang1, double ang2, bool cont_flg); /** Expand all tab characters in a string * using spaces. * * \param rsString expand all tabs in this string using spaces * \param lLen use only lLen characters of rsString * \returns an expanded copy of the passed string * \see SetTabWidth */ PdfString ExpandTabs( const PdfString & rsString, pdf_long lLen ) const; #if defined(_MSC_VER) && _MSC_VER <= 1200 // MSC 6.0 has a template-bug PdfString ExpandTabs_char( const char* pszText, long lStringLen, int nTabCnt, const char cTab, const char cSpace ) const; PdfString ExpandTabs_pdf_utf16be( const pdf_utf16be* pszText, long lStringLen, int nTabCnt, const pdf_utf16be cTab, const pdf_utf16be cSpace ) const; #else template PdfString ExpandTabsPrivate( const C* pszText, pdf_long lStringLen, int nTabCnt, const C cTab, const C cSpace ) const; #endif protected: /** All drawing operations work on this stream. * This object may not be NULL. If it is NULL any function accessing it should * return ERROR_PDF_INVALID_HANDLE */ PdfStream* m_pCanvas; /** The page object is needed so that fonts etc. can be added * to the page resource dictionary as appropriate. */ PdfCanvas* m_pPage; /** Font for all drawing operations */ PdfFont* m_pFont; /** Every tab '\\t' is replaced with m_nTabWidth * spaces before drawing text. Default is a value of 4 */ unsigned short m_nTabWidth; /** Save the current color for non stroking colors */ PdfColor m_curColor; /** Is between BT and ET */ bool m_isTextOpen; /** temporary stream buffer */ std::ostringstream m_oss; /** current path */ std::ostringstream m_curPath; EPdfTextRenderingMode currentTextRenderingMode; void SetCurrentTextRenderingMode( void ); double lpx, lpy, lpx2, lpy2, lpx3, lpy3, // points for this operation lcx, lcy, // last "current" point lrx, lry; // "reflect points" }; // ----------------------------------------------------- // // ----------------------------------------------------- PdfCanvas* PdfPainter::GetPage() const { return m_pPage; } // ----------------------------------------------------- // // ----------------------------------------------------- PdfStream* PdfPainter::GetCanvas() const { return m_pCanvas; } // ----------------------------------------------------- // // ----------------------------------------------------- EPdfTextRenderingMode PdfPainter::GetTextRenderingMode(void) const { return currentTextRenderingMode; } // ----------------------------------------------------- // // ----------------------------------------------------- PdfFont* PdfPainter::GetFont() const { return m_pFont; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfPainter::SetTabWidth( unsigned short nTabWidth ) { m_nTabWidth = nTabWidth; } // ----------------------------------------------------- // // ----------------------------------------------------- unsigned short PdfPainter::GetTabWidth() const { return m_nTabWidth; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfPainter::SetPrecision( unsigned short inPrec ) { m_oss.precision( inPrec ); } // ----------------------------------------------------- // // ----------------------------------------------------- unsigned short PdfPainter::GetPrecision() const { return static_cast(m_oss.precision()); } // ----------------------------------------------------- // // ----------------------------------------------------- inline std::ostringstream &PdfPainter::GetCurrentPath(void) { return m_curPath; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfPainter::SetClipRect( const PdfRect & rRect ) { this->SetClipRect( rRect.GetLeft(), rRect.GetBottom(), rRect.GetWidth(), rRect.GetHeight() ); } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfPainter::Rectangle( const PdfRect & rRect, double dRoundX, double dRoundY ) { this->Rectangle( rRect.GetLeft(), rRect.GetBottom(), rRect.GetWidth(), rRect.GetHeight(), dRoundX, dRoundY ); } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfPainter::DrawMultiLineText( const PdfRect & rRect, const PdfString & rsText, EPdfAlignment eAlignment, EPdfVerticalAlignment eVertical, bool bClip) { this->DrawMultiLineText( rRect.GetLeft(), rRect.GetBottom(), rRect.GetWidth(), rRect.GetHeight(), rsText, eAlignment, eVertical, bClip ); } }; #endif // _PDF_PAINTER_H_ podofo-0.9.5/src/doc/PdfXObject.cpp0000664000175000017500000003020312717041646016721 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfXObject.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfDictionary.h" #include "base/PdfLocale.h" #include "base/PdfRect.h" #include "base/PdfVariant.h" #include "PdfImage.h" #include "PdfPage.h" #include "PdfMemDocument.h" #include "PdfDocument.h" #include #define PI 3.141592654f using namespace std; namespace PoDoFo { PdfArray PdfXObject::s_matrix; PdfXObject::PdfXObject( const PdfRect & rRect, PdfDocument* pParent, const char* pszPrefix, bool bWithoutIdentifier ) : PdfElement( "XObject", pParent ), PdfCanvas(), m_rRect( rRect ), m_pResources( NULL ) { InitXObject( rRect, pszPrefix ); if( bWithoutIdentifier ) { m_Identifier = PdfName(pszPrefix); } } PdfXObject::PdfXObject( const PdfRect & rRect, PdfVecObjects* pParent, const char* pszPrefix ) : PdfElement( "XObject", pParent ), PdfCanvas(), m_rRect( rRect ), m_pResources( NULL ) { InitXObject( rRect, pszPrefix ); } PdfXObject::PdfXObject( const PdfMemDocument & rDoc, int nPage, PdfDocument* pParent, const char* pszPrefix, bool bUseTrimBox ) : PdfElement( "XObject", pParent ), PdfCanvas(), m_pResources( NULL ) { m_rRect = PdfRect(); InitXObject( m_rRect, pszPrefix ); // Implementation note: source document must be different from distination if ( pParent == reinterpret_cast(&rDoc) ) { PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } // After filling set correct BBox, independent of rotation m_rRect = pParent->FillXObjectFromDocumentPage( this, rDoc, nPage, bUseTrimBox ); PdfVariant var; m_rRect.ToVariant( var ); this->GetObject()->GetDictionary().AddKey( "BBox", var ); int rotation = rDoc.GetPage( nPage )->GetRotation(); // correct negative rotation if ( rotation < 0 ) rotation = 360 + rotation; // Swap offsets/width/height for vertical rotation switch ( rotation ) { case 90: case 270: { double temp; temp = m_rRect.GetWidth(); m_rRect.SetWidth( m_rRect.GetHeight() ); m_rRect.SetHeight( temp ); temp = m_rRect.GetLeft(); m_rRect.SetLeft( m_rRect.GetBottom() ); m_rRect.SetBottom( temp ); } break; default: break; } // Build matrix for rotation and cropping double alpha = -rotation / 360.0 * 2.0 * PI; double a, b, c, d, e, f; a = cos( alpha ); b = sin( alpha ); c = -sin( alpha ); d = cos( alpha ); switch ( rotation ) { case 90: e = - m_rRect.GetLeft(); f = m_rRect.GetBottom() + m_rRect.GetHeight(); break; case 180: e = m_rRect.GetLeft() + m_rRect.GetWidth(); f = m_rRect.GetBottom() + m_rRect.GetHeight(); break; case 270: e = m_rRect.GetLeft() + m_rRect.GetWidth(); f = - m_rRect.GetBottom(); break; case 0: default: e = - m_rRect.GetLeft(); f = - m_rRect.GetBottom(); break; } PdfArray matrix; matrix.push_back( PdfVariant( a ) ); matrix.push_back( PdfVariant( b ) ); matrix.push_back( PdfVariant( c ) ); matrix.push_back( PdfVariant( d ) ); matrix.push_back( PdfVariant( e ) ); matrix.push_back( PdfVariant( f ) ); this->GetObject()->GetDictionary().AddKey( "Matrix", matrix ); } PdfXObject::PdfXObject( PdfDocument *pDoc, int nPage, const char* pszPrefix, bool bUseTrimBox ) : PdfElement( "XObject", pDoc ), PdfCanvas(), m_pResources( NULL ) { m_rRect = PdfRect(); InitXObject( m_rRect, pszPrefix ); // After filling set correct BBox, independent of rotation m_rRect = pDoc->FillXObjectFromExistingPage( this, nPage, bUseTrimBox ); PdfVariant var; m_rRect.ToVariant( var ); this->GetObject()->GetDictionary().AddKey( "BBox", var ); int rotation = pDoc->GetPage( nPage )->GetRotation(); // correct negative rotation if ( rotation < 0 ) rotation = 360 + rotation; // Swap offsets/width/height for vertical rotation switch ( rotation ) { case 90: case 270: { double temp; temp = m_rRect.GetWidth(); m_rRect.SetWidth( m_rRect.GetHeight() ); m_rRect.SetHeight( temp ); temp = m_rRect.GetLeft(); m_rRect.SetLeft( m_rRect.GetBottom() ); m_rRect.SetBottom( temp ); } break; default: break; } // Build matrix for rotation and cropping double alpha = -rotation / 360.0 * 2.0 * PI; double a, b, c, d, e, f; a = cos( alpha ); b = sin( alpha ); c = -sin( alpha ); d = cos( alpha ); switch ( rotation ) { case 90: e = - m_rRect.GetLeft(); f = m_rRect.GetBottom() + m_rRect.GetHeight(); break; case 180: e = m_rRect.GetLeft() + m_rRect.GetWidth(); f = m_rRect.GetBottom() + m_rRect.GetHeight(); break; case 270: e = m_rRect.GetLeft() + m_rRect.GetWidth(); f = - m_rRect.GetBottom(); break; case 0: default: e = - m_rRect.GetLeft(); f = - m_rRect.GetBottom(); break; } PdfArray matrix; matrix.push_back( PdfVariant( a ) ); matrix.push_back( PdfVariant( b ) ); matrix.push_back( PdfVariant( c ) ); matrix.push_back( PdfVariant( d ) ); matrix.push_back( PdfVariant( e ) ); matrix.push_back( PdfVariant( f ) ); this->GetObject()->GetDictionary().AddKey( "Matrix", matrix ); } PdfXObject::PdfXObject( PdfObject* pObject ) : PdfElement( "XObject", pObject ), PdfCanvas(), m_pResources( NULL ) { ostringstream out; PdfLocaleImbue(out); // Implementation note: the identifier is always // Prefix+ObjectNo. Prefix is /XOb for XObject. out << "XOb" << this->GetObject()->Reference().ObjectNumber(); m_pResources = pObject->GetIndirectKey( "Resources" ); m_Identifier = PdfName( out.str().c_str() ); m_rRect = PdfRect( this->GetObject()->GetIndirectKey( "BBox" )->GetArray() ); m_Reference = this->GetObject()->Reference(); } void PdfXObject::InitXObject( const PdfRect & rRect, const char* pszPrefix ) { PdfVariant var; ostringstream out; PdfLocaleImbue(out); // Initialize static data if( s_matrix.empty() ) { // This matrix is the same for all PdfXObjects so cache it s_matrix.push_back( PdfVariant( static_cast(PODOFO_LL_LITERAL(1)) ) ); s_matrix.push_back( PdfVariant( static_cast(PODOFO_LL_LITERAL(0)) ) ); s_matrix.push_back( PdfVariant( static_cast(PODOFO_LL_LITERAL(0)) ) ); s_matrix.push_back( PdfVariant( static_cast(PODOFO_LL_LITERAL(1)) ) ); s_matrix.push_back( PdfVariant( static_cast(PODOFO_LL_LITERAL(0)) ) ); s_matrix.push_back( PdfVariant( static_cast(PODOFO_LL_LITERAL(0)) ) ); } rRect.ToVariant( var ); this->GetObject()->GetDictionary().AddKey( "BBox", var ); this->GetObject()->GetDictionary().AddKey( PdfName::KeySubtype, PdfName("Form") ); this->GetObject()->GetDictionary().AddKey( "FormType", PdfVariant( static_cast(PODOFO_LL_LITERAL(1)) ) ); // only 1 is only defined in the specification. this->GetObject()->GetDictionary().AddKey( "Matrix", s_matrix ); // The PDF specification suggests that we send all available PDF Procedure sets this->GetObject()->GetDictionary().AddKey( "Resources", PdfObject( PdfDictionary() ) ); m_pResources = this->GetObject()->GetDictionary().GetKey( "Resources" ); m_pResources->GetDictionary().AddKey( "ProcSet", PdfCanvas::GetProcSet() ); // Implementation note: the identifier is always // Prefix+ObjectNo. Prefix is /XOb for XObject. if ( pszPrefix == NULL ) out << "XOb" << this->GetObject()->Reference().ObjectNumber(); else out << pszPrefix << this->GetObject()->Reference().ObjectNumber(); m_Identifier = PdfName( out.str().c_str() ); m_Reference = this->GetObject()->Reference(); } PdfXObject::PdfXObject( const char* pszSubType, PdfDocument* pParent, const char* pszPrefix ) : PdfElement( "XObject", pParent ), m_pResources( NULL ) { ostringstream out; PdfLocaleImbue(out); // Implementation note: the identifier is always // Prefix+ObjectNo. Prefix is /XOb for XObject. if ( pszPrefix == NULL ) out << "XOb" << this->GetObject()->Reference().ObjectNumber(); else out << pszPrefix << this->GetObject()->Reference().ObjectNumber(); m_Identifier = PdfName( out.str().c_str() ); m_Reference = this->GetObject()->Reference(); this->GetObject()->GetDictionary().AddKey( PdfName::KeySubtype, PdfName( pszSubType ) ); } PdfXObject::PdfXObject( const char* pszSubType, PdfVecObjects* pParent, const char* pszPrefix ) : PdfElement( "XObject", pParent ), m_pResources( NULL ) { ostringstream out; PdfLocaleImbue(out); // Implementation note: the identifier is always // Prefix+ObjectNo. Prefix is /XOb for XObject. if ( pszPrefix == NULL ) out << "XOb" << this->GetObject()->Reference().ObjectNumber(); else out << pszPrefix << this->GetObject()->Reference().ObjectNumber(); m_Identifier = PdfName( out.str().c_str() ); m_Reference = this->GetObject()->Reference(); this->GetObject()->GetDictionary().AddKey( PdfName::KeySubtype, PdfName( pszSubType ) ); } PdfXObject::PdfXObject( const char* pszSubType, PdfObject* pObject ) : PdfElement( "XObject", pObject ), m_pResources( NULL ) { ostringstream out; PdfLocaleImbue(out); if( this->GetObject()->GetDictionary().GetKeyAsName( PdfName::KeySubtype ) != pszSubType ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } // Implementation note: the identifier is always // Prefix+ObjectNo. Prefix is /XOb for XObject. out << "XOb" << this->GetObject()->Reference().ObjectNumber(); m_Identifier = PdfName( out.str().c_str() ); m_Reference = this->GetObject()->Reference(); } }; podofo-0.9.5/src/doc/PdfAcroForm.h0000664000175000017500000001174012262234754016544 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_ACRO_FORM_H_ #define _PDF_ACRO_FORM_H_ #include "podofo/base/PdfDefines.h" #include "PdfElement.h" namespace PoDoFo { class PdfDocument; enum EPdfAcroFormDefaulAppearance { ePdfAcroFormDefaultAppearance_None, ///< Do not add a default appearrance ePdfAcroFormDefaultAppearance_BlackText12pt ///< Add a default appearance with Arial embedded and black text 12pt if no other DA key is present }; class PODOFO_DOC_API PdfAcroForm : public PdfElement { public: /** Create a new PdfAcroForm dictionary object * \param pDoc parent of this action * \param eDefaultAppearance specifies if a default appearance should be added */ PdfAcroForm( PdfDocument* pDoc, EPdfAcroFormDefaulAppearance eDefaultAppearance = ePdfAcroFormDefaultAppearance_BlackText12pt ); /** Create a PdfAcroForm dictionary object from an existing PdfObject * \param pDoc parent document * \param pObject the object to create from * \param eDefaultAppearance specifies if a default appearance should be added */ PdfAcroForm( PdfDocument* pDoc, PdfObject* pObject, EPdfAcroFormDefaulAppearance eDefaultAppearance = ePdfAcroFormDefaultAppearance_BlackText12pt ); virtual ~PdfAcroForm() { } /** Get the document that is associated with this * acro forms dictionary. * * \returns a valid pointer to the parent document */ inline PdfDocument* GetDocument(); /** Set the value of the NeedAppearances key in the interactive forms * dictionary. * * \param bNeedAppearances A flag specifying whether to construct appearance streams * and appearance dictionaries for all widget annotations in * the document. Default value is false. */ void SetNeedAppearances( bool bNeedAppearances ); /** Retrieve the value of the NeedAppearances key in the interactive forms * dictionary. * * \returns value of the NeedAppearances key * * \see SetNeedAppearances */ bool GetNeedAppearances() const; private: /** Initialize this object * with a default appearance * \param eDefaultAppearance specifies if a default appearance should be added */ void Init( EPdfAcroFormDefaulAppearance eDefaultAppearance ); private: PdfDocument* m_pDocument; }; // ----------------------------------------------------- // // ----------------------------------------------------- PdfDocument* PdfAcroForm::GetDocument() { return m_pDocument; } }; #endif // _PDF_ACRO_FORM_H_ podofo-0.9.5/src/doc/PdfSignOutputDevice.cpp0000664000175000017500000002055212730052013020613 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2011 by Dominik Seichter * * domseichter@web.de * * by Petr Pytelka * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfSignOutputDevice.h" #include "../base/PdfArray.h" #include namespace PoDoFo { PdfSignOutputDevice::PdfSignOutputDevice(PdfOutputDevice *pRealDevice) { Init(); m_pRealDevice = pRealDevice; } PdfSignOutputDevice::PdfSignOutputDevice(const char* pszFilename) { Init(); m_pRealDevice = new PdfOutputDevice(pszFilename); m_bDevOwner = true; } #ifdef WIN32 PdfSignOutputDevice::PdfSignOutputDevice( const wchar_t* pszFilename ) { Init(); m_pRealDevice = new PdfOutputDevice(pszFilename); m_bDevOwner = true; } #endif void PdfSignOutputDevice::Init() { m_pSignatureBeacon = NULL; m_bBeaconFound = false; m_bDevOwner = false; m_sBeaconPos = 0; } PdfSignOutputDevice::~PdfSignOutputDevice() { if(m_pSignatureBeacon!=NULL) { delete m_pSignatureBeacon; } if(m_bDevOwner) { delete m_pRealDevice; } } void PdfSignOutputDevice::SetSignatureSize(size_t lSignatureSize) { if(m_pSignatureBeacon!=NULL) { delete m_pSignatureBeacon; } const char srcBeacon[] = "###HERE_WILL_BE_SIGNATURE___"; size_t lLen = sizeof(srcBeacon); lSignatureSize = 2*lSignatureSize; char* pData = static_cast(podofo_malloc(lSignatureSize)); if (!pData) { PODOFO_RAISE_ERROR(ePdfError_OutOfMemory); } for(size_t i=0; idata().size() / 2 ); } void PdfSignOutputDevice::SetSignature(const PdfData &sigData) { if(!m_bBeaconFound) { PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } size_t maxSigSize = m_pSignatureBeacon->data().size(); size_t sigByteSize = sigData.data().size(); // check signature size if((sigByteSize*2)> maxSigSize) { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } PdfString sig(sigData.data().c_str(), sigByteSize, true); m_pRealDevice->Seek(m_sBeaconPos); sig.Write(m_pRealDevice, PoDoFo::ePdfWriteMode_Compact); // insert padding size_t numPadding = maxSigSize-2*sigByteSize; if(numPadding>0) { // Seek back m_pRealDevice->Seek(m_pRealDevice->Tell()-1); while(numPadding>0) { char c='0'; m_pRealDevice->Write(&c, 1); numPadding--; } } } void PdfSignOutputDevice::AdjustByteRange() { if(!m_bBeaconFound) { PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } // Get final position size_t sFileEnd = GetLength(); PdfArray arr; arr.push_back( PdfVariant(static_cast(0)) ); arr.push_back( PdfVariant(static_cast(m_sBeaconPos)) ); arr.push_back( PdfVariant(static_cast(m_sBeaconPos+m_pSignatureBeacon->data().size()+2) ) ); arr.push_back( PdfVariant(static_cast(sFileEnd-(m_sBeaconPos+m_pSignatureBeacon->data().size()+2)) ) ); std::string sPosition; PdfVariant(arr).ToString(sPosition, ePdfWriteMode_Compact); // Fill padding unsigned int sPosSize = sizeof("[ 0 1234567890 1234567890 1234567890]")-1; if(sPosition.size()Seek(m_sBeaconPos-sPosition.size()-9); char ch; size_t offset = m_pRealDevice->Tell(); size_t size; /* Sanity tests... */ size = m_pRealDevice->Read(&ch, 1); PODOFO_RAISE_LOGIC_IF( size != 1, "Failed to read 1 byte." ); if (ch == '0') { /* probably clean write mode, whic means two more bytes back */ m_pRealDevice->Seek(m_sBeaconPos-sPosition.size()-11); offset = m_pRealDevice->Tell(); size = m_pRealDevice->Read(&ch, 1); PODOFO_RAISE_LOGIC_IF( size != 1, "Failed to read 1 byte." ); } /* ...the file position should be at the '[' now */ PODOFO_RAISE_LOGIC_IF( ch != '[', "Failed to find byte range array start in the stream." ); m_pRealDevice->Seek(offset); m_pRealDevice->Write(sPosition.c_str(), sPosition.size()); } size_t PdfSignOutputDevice::ReadForSignature(char* pBuffer, size_t lLen) { if(!m_bBeaconFound) { PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } size_t pos = m_pRealDevice->Tell(); size_t numRead = 0; // Check if we are before beacon if(pos0) { numRead = m_pRealDevice->Read(pBuffer, readSize); pBuffer += numRead; lLen -= numRead; if(lLen==0) return numRead; } } // shift at the end of beacon if ( (pos + numRead) >= m_sBeaconPos && pos < ( m_sBeaconPos + (m_pSignatureBeacon->data().size() + 2) ) ) { m_pRealDevice->Seek( m_sBeaconPos + (m_pSignatureBeacon->data().size() + 2) ); } // read after beacon lLen = PODOFO_MIN(lLen, m_pRealDevice->GetLength()-m_pRealDevice->Tell()); if(lLen==0) return numRead; return numRead+m_pRealDevice->Read(pBuffer, lLen); } void PdfSignOutputDevice::Write( const char* pBuffer, size_t lLen ) { // Check if data with beacon if(m_pSignatureBeacon != NULL) { const std::string & data = m_pSignatureBeacon->data(); if(data.size() <= lLen) { const char *pStart = pBuffer; const char *pStop = pStart + (lLen-data.size()); for(; pStart<=pStop; pStart++) { if(memcmp(pStart, data.c_str(), data.size())==0) { // beacon found m_sBeaconPos = Tell(); m_sBeaconPos += (pStart - pBuffer - 1); m_bBeaconFound = true; } } } } m_pRealDevice->Write(pBuffer, lLen); } } podofo-0.9.5/src/doc/PdfStreamedDocument.h0000664000175000017500000003303012344436402020266 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_STREAMED_DOCUMENT_H_ #define _PDF_STREAMED_DOCUMENT_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfImmediateWriter.h" #include "PdfDocument.h" namespace PoDoFo { class PdfOutputDevice; /** PdfStreamedDocument is the preferred class for * creating new PDF documents. * * Page contents, fonts and images are written to disk * as soon as possible and are not kept in memory. * This results in faster document generation and * less memory being used. * * Please use PdfMemDocument if you intend to work * on the object structure of a PDF file. * * One of the design goals of PdfStreamedDocument was * to hide the underlying object structure of a PDF * file as far as possible. * * \see PdfDocument * \see PdfMemDocument * * Example of using PdfStreamedDocument: * * PdfStreamedDocument document( "outputfile.pdf" ); * PdfPage* pPage = document.CreatePage( PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ) ); * PdfFont* pFont = document.CreateFont( "Arial" ); * * PdfPainter painter; * painter.SetPage( pPage ); * painter.SetFont( pFont ); * painter.DrawText( 56.69, pPage->GetPageSize().GetHeight() - 56.69, "Hello World!" ); * painter.FinishPage(); * * document.Close(); */ class PODOFO_DOC_API PdfStreamedDocument : public PdfDocument { friend class PdfImage; friend class PdfElement; public: /** Create a new PdfStreamedDocument. * All data is written to an output device * immediately. * * \param pDevice an output device * \param eVersion the PDF version of the document to write. * The PDF version can only be set in the constructor * as it is the first item written to the document on disk. * \param pEncrypt pointer to an encryption object or NULL. If not NULL * the PdfEncrypt object will be copied and used to encrypt the * created document. * \param eWriteMode additional options for writing the pdf */ PdfStreamedDocument( PdfOutputDevice* pDevice, EPdfVersion eVersion = ePdfVersion_Default, PdfEncrypt* pEncrypt = NULL, EPdfWriteMode eWriteMode = ePdfWriteMode_Default ); /** Create a new PdfStreamedDocument. * All data is written to a file immediately. * * \param pszFilename resulting PDF file * \param eVersion the PDF version of the document to write. * The PDF version can only be set in the constructor * as it is the first item written to the document on disk. * \param pEncrypt pointer to an encryption object or NULL. If not NULL * the PdfEncrypt object will be copied and used to encrypt the * created document. * \param eWriteMode additional options for writing the pdf */ PdfStreamedDocument( const char* pszFilename, EPdfVersion eVersion = ePdfVersion_Default, PdfEncrypt* pEncrypt = NULL, EPdfWriteMode eWriteMode = ePdfWriteMode_Default ); #ifdef _WIN32 /** Create a new PdfStreamedDocument. * All data is written to a file immediately. * * \param pszFilename resulting PDF file * \param eVersion the PDF version of the document to write. * The PDF version can only be set in the constructor * as it is the first item written to the document on disk. * \param pEncrypt pointer to an encryption object or NULL. If not NULL * the PdfEncrypt object will be copied and used to encrypt the * created document. * \param eWriteMode additional options for writing the pdf * * This is an overloaded member function to allow working * with unicode characters. On Unix systes you can also path * UTF-8 to the const char* overload. */ PdfStreamedDocument( const wchar_t* pszFilename, EPdfVersion eVersion = ePdfVersion_Default, PdfEncrypt* pEncrypt = NULL, EPdfWriteMode eWriteMode = ePdfWriteMode_Default ); #endif // _WIN32 ~PdfStreamedDocument(); /** Close the document. The PDF file on disk is finished. * No other member function of this class maybe called * after calling this function. */ void Close(); /** Get the write mode used for wirting the PDF * \returns the write mode */ inline virtual EPdfWriteMode GetWriteMode() const; /** Get the PDF version of the document * \returns EPdfVersion version of the pdf document */ inline virtual EPdfVersion GetPdfVersion() const; /** Returns wether this PDF document is linearized, aka * weboptimized * \returns true if the PDF document is linearized */ inline virtual bool IsLinearized() const; /** Checks if printing this document is allowed. * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to print this document * * \see PdfEncrypt to set own document permissions. */ inline virtual bool IsPrintAllowed() const; /** Checks if modifiying this document (besides annotations, form fields or changing pages) is allowed. * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to modfiy this document * * \see PdfEncrypt to set own document permissions. */ inline virtual bool IsEditAllowed() const; /** Checks if text and graphics extraction is allowed. * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to extract text and graphics from this document * * \see PdfEncrypt to set own document permissions. */ inline virtual bool IsCopyAllowed() const; /** Checks if it is allowed to add or modify annotations or form fields * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to add or modify annotations or form fields * * \see PdfEncrypt to set own document permissions. */ inline virtual bool IsEditNotesAllowed() const; /** Checks if it is allowed to fill in existing form or signature fields * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to fill in existing form or signature fields * * \see PdfEncrypt to set own document permissions. */ inline virtual bool IsFillAndSignAllowed() const; /** Checks if it is allowed to extract text and graphics to support users with disabillities * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to extract text and graphics to support users with disabillities * * \see PdfEncrypt to set own document permissions. */ inline virtual bool IsAccessibilityAllowed() const; /** Checks if it is allowed to insert, create, rotate, delete pages or add bookmarks * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to insert, create, rotate, delete pages or add bookmarks * * \see PdfEncrypt to set own document permissions. */ inline virtual bool IsDocAssemblyAllowed() const; /** Checks if it is allowed to print a high quality version of this document * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to print a high quality version of this document * * \see PdfEncrypt to set own document permissions. */ inline virtual bool IsHighPrintAllowed() const; private: /** Initialize the PdfStreamedDocument with an output device * \param pDevice write to this device * \param eVersion the PDF version of the document to write. * The PDF version can only be set in the constructor * as it is the first item written to the document on disk. * \param pEncrypt pointer to an encryption object or NULL. If not NULL * the PdfEncrypt object will be copied and used to encrypt the * created document. * \param eWriteMode additional options for writing the pdf */ void Init( PdfOutputDevice* pDevice, EPdfVersion eVersion = ePdfVersion_Default, PdfEncrypt* pEncrypt = NULL, EPdfWriteMode eWriteMode = ePdfWriteMode_Default ); private: PdfImmediateWriter* m_pWriter; PdfOutputDevice* m_pDevice; PdfEncrypt* m_pEncrypt; bool m_bOwnDevice; ///< If true m_pDevice is owned by this object and has to be deleted }; // ----------------------------------------------------- // // ----------------------------------------------------- EPdfWriteMode PdfStreamedDocument::GetWriteMode() const { return m_pWriter->GetWriteMode(); } // ----------------------------------------------------- // // ----------------------------------------------------- EPdfVersion PdfStreamedDocument::GetPdfVersion() const { return m_pWriter->GetPdfVersion(); } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfStreamedDocument::IsLinearized() const { // Linearization is currently not supported by PdfStreamedDocument return false; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfStreamedDocument::IsPrintAllowed() const { return m_pEncrypt ? m_pEncrypt->IsPrintAllowed() : true; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfStreamedDocument::IsEditAllowed() const { return m_pEncrypt ? m_pEncrypt->IsEditAllowed() : true; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfStreamedDocument::IsCopyAllowed() const { return m_pEncrypt ? m_pEncrypt->IsCopyAllowed() : true; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfStreamedDocument::IsEditNotesAllowed() const { return m_pEncrypt ? m_pEncrypt->IsEditNotesAllowed() : true; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfStreamedDocument::IsFillAndSignAllowed() const { return m_pEncrypt ? m_pEncrypt->IsFillAndSignAllowed() : true; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfStreamedDocument::IsAccessibilityAllowed() const { return m_pEncrypt ? m_pEncrypt->IsAccessibilityAllowed() : true; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfStreamedDocument::IsDocAssemblyAllowed() const { return m_pEncrypt ? m_pEncrypt->IsDocAssemblyAllowed() : true; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfStreamedDocument::IsHighPrintAllowed() const { return m_pEncrypt ? m_pEncrypt->IsHighPrintAllowed() : true; } }; #endif /* _PDF_STREAMED_DOCUMENT_H_ */ podofo-0.9.5/src/doc/PdfFileSpec.h0000664000175000017500000001500012347312750016514 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FILE_SPEC_H_ #define _PDF_FILE_SPEC_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfString.h" #include "PdfElement.h" namespace PoDoFo { class PdfDocument; /** * A file specification is used in the PDF file to referr to another file. * The other file can be a file outside of the PDF or can be embedded into * the PDF file itself. */ class PODOFO_DOC_API PdfFileSpec : public PdfElement { public: PdfFileSpec( const char* pszFilename, bool bEmbedd, PdfDocument* pParent, bool bStripPath = false); PdfFileSpec( const char* pszFilename, bool bEmbedd, PdfVecObjects* pParent, bool bStripPath = false ); /* Petr P. Petrov 17 September 2009*/ /** Embeds the file in memory from "data" buffer under "pszFileName" fie name. */ PdfFileSpec( const char* pszFilename, const unsigned char* data, ptrdiff_t size, PdfVecObjects* pParent, bool bStripPath = false); PdfFileSpec( const char* pszFilename, const unsigned char* data, ptrdiff_t size, PdfDocument* pParent, bool bStripPath = false); #ifdef _WIN32 PdfFileSpec( const wchar_t* pszFilename, bool bEmbedd, PdfDocument* pParent, bool bStripPath = false ); PdfFileSpec( const wchar_t* pszFilename, bool bEmbedd, PdfVecObjects* pParent, bool bStripPath = false ); PdfFileSpec( const wchar_t* pszFilename, const unsigned char* data, ptrdiff_t size, PdfVecObjects* pParent, bool bStripPath = false); PdfFileSpec( const wchar_t* pszFilename, const unsigned char* data, ptrdiff_t size, PdfDocument* pParent, bool bStripPath = false); #endif PdfFileSpec( PdfObject* pObject ); /** Gets file name for the FileSpec * \param canUnicode Whether can return file name in unicode (/UF) * \returns the filename of this file specification. * if no general name is available * it will try the Unix, Mac and DOS keys too. */ const PdfString & GetFilename(bool canUnicode) const; private: /** Initialize a filespecification from a filename * \param pszFilename filename * \param bEmbedd embedd the file data into the PDF file * \param bStripPath whether to strip path from the file name string */ void Init( const char* pszFilename, bool bEmbedd, bool bStripPath ); /** Initialize a filespecification from an in-memory buffer * \param pszFilename filename * \param data Data of the file * \param size size of the data buffer * \param bStripPath whether to strip path from the file name string */ void Init( const char* pszFilename, const unsigned char* data, ptrdiff_t size, bool bStripPath ); /** Create a file specification string from a filename * \param pszFilename filename * \returns a file specification string */ PdfString CreateFileSpecification( const char* pszFilename ) const; /** Embedd a file into a stream object * \param pStream write the file to this objects stream * \param pszFilename the file to embedd */ void EmbeddFile( PdfObject* pStream, const char* pszFilename ) const; /** Strips path from a file, according to \a bStripPath * \param pszFilename a file name string * \param bStripPath whether to strip path from the file name string * \returns Either unchanged \a pszFilename, if \a bStripPath is false; * or \a pszFilename without a path part, if \a bStripPath is true */ const char *MaybeStripPath( const char* pszFilename, bool bStripPath ) const; #ifdef _WIN32 void Init( const wchar_t* pszFilename, bool bEmbedd, bool bStripPath ); void Init( const wchar_t* pszFilename, const unsigned char* data, ptrdiff_t size, bool bStripPath ); PdfString CreateFileSpecification( const wchar_t* pszFilename ) const; void EmbeddFile( PdfObject* pStream, const wchar_t* pszFilename ) const; const wchar_t *MaybeStripPath( const wchar_t* pszFilename, bool bStripPath ) const; #endif /* Petr P. Petrov 17 September 2009*/ /** Embeds the file from memory */ void EmbeddFileFromMem( PdfObject* pStream, const unsigned char* data, ptrdiff_t size ) const; }; }; #endif // _PDF_FILE_SPEC_H_ podofo-0.9.5/src/doc/PdfContents.h0000664000175000017500000000763212344436402016631 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_CONTENTS_H_ #define _PDF_CONTENTS_H_ #include "podofo/base/PdfDefines.h" #include "PdfElement.h" namespace PoDoFo { class PdfObject; class PdfPage; /** A interface that provides a wrapper around "PDF content" - the instructions that are used to draw on the PDF "canvas". */ class PODOFO_DOC_API PdfContents : private PdfElement { public: /** Construct a new/empty set of contents in the owning objects */ PdfContents( PdfDocument* pParent ); /** Construct a new/empty set of contents in the owning objects */ PdfContents( PdfVecObjects* pParent ); /** Construct the contents from an existing PdfObject */ PdfContents( PdfObject* inObj ); /** Create the contents for an existing page which does not yet * have a contents object. * * \param pParent a /Contents key will be added to this page * and a contents object will be created. */ PdfContents( PdfPage* pParent ); /** Virtual destructor - because ALL destructors should be... */ virtual ~PdfContents() {}; /** Get access to the raw contents object. * It will either be a PdfStream or a PdfArray * \returns a contents object */ virtual PdfObject* GetContents() const { return mContObj; } /** Get access to an object into which you can add contents * at the end of the "stream". */ virtual PdfObject* GetContentsForAppending() const; private: PdfObject* mContObj; }; }; #endif /* _PDF_CONTENTS_H_ */ podofo-0.9.5/src/doc/PdfMemDocument.cpp0000664000175000017500000005656313014343317017610 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #if defined(_MSC_VER) && _MSC_VER <= 1200 #pragma warning(disable: 4786) #endif #include #include #include #include "PdfMemDocument.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfDictionary.h" #include "base/PdfImmediateWriter.h" #include "base/PdfObject.h" #include "base/PdfParserObject.h" #include "base/PdfStream.h" #include "base/PdfVecObjects.h" #include "PdfAcroForm.h" #include "PdfDestination.h" #include "PdfFileSpec.h" #include "PdfFont.h" #include "PdfFontMetrics.h" #include "PdfInfo.h" #include "PdfNamesTree.h" #include "PdfOutlines.h" #include "PdfPage.h" #include "PdfPagesTree.h" using namespace std; namespace PoDoFo { PdfMemDocument::PdfMemDocument() : PdfDocument(), m_pEncrypt( NULL ), m_pParser( NULL ), m_bSoureHasXRefStream( false ), m_lPrevXRefOffset( -1 ), #ifdef _WIN32 m_wchar_pszUpdatingFilename( NULL ), #endif m_pszUpdatingFilename( NULL ), m_pUpdatingInputDevice( NULL ) { m_eVersion = ePdfVersion_Default; m_eWriteMode = ePdfWriteMode_Default; m_bLinearized = false; m_eSourceVersion = m_eVersion; } PdfMemDocument::PdfMemDocument(bool bOnlyTrailer) : PdfDocument(bOnlyTrailer), m_pEncrypt( NULL ), m_pParser( NULL ), m_bSoureHasXRefStream( false ), m_lPrevXRefOffset( -1 ), #ifdef _WIN32 m_wchar_pszUpdatingFilename( NULL ), #endif m_pszUpdatingFilename( NULL ), m_pUpdatingInputDevice( NULL ) { m_eVersion = ePdfVersion_Default; m_eWriteMode = ePdfWriteMode_Default; m_bLinearized = false; m_eSourceVersion = m_eVersion; } PdfMemDocument::PdfMemDocument( const char* pszFilename, bool bForUpdate ) : PdfDocument(), m_pEncrypt( NULL ), m_pParser( NULL ), m_bSoureHasXRefStream( false ), m_lPrevXRefOffset( -1 ), #ifdef _WIN32 m_wchar_pszUpdatingFilename( NULL ), #endif m_pszUpdatingFilename( NULL ), m_pUpdatingInputDevice( NULL ) { this->Load( pszFilename, bForUpdate ); } #ifdef _WIN32 #if defined(_MSC_VER) && _MSC_VER <= 1200 // not for MS Visual Studio 6 #else PdfMemDocument::PdfMemDocument( const wchar_t* pszFilename, bool bForUpdate ) : PdfDocument(), m_pEncrypt( NULL ), m_pParser( NULL ), m_bSoureHasXRefStream( false ), m_lPrevXRefOffset( -1 ), m_wchar_pszUpdatingFilename( NULL ), m_pszUpdatingFilename( NULL ), m_pUpdatingInputDevice( NULL ) { this->Load( pszFilename, bForUpdate ); } #endif #endif // _WIN32 PdfMemDocument::~PdfMemDocument() { this->Clear(); } void PdfMemDocument::Clear() { if( m_pEncrypt ) { delete m_pEncrypt; m_pEncrypt = NULL; } if( m_pParser ) { delete m_pParser; m_pParser = NULL; } m_eWriteMode = ePdfWriteMode_Default; #ifdef _WIN32 if( m_wchar_pszUpdatingFilename ) { podofo_free( m_wchar_pszUpdatingFilename ); m_wchar_pszUpdatingFilename = NULL; } #endif if( m_pszUpdatingFilename ) { podofo_free( m_pszUpdatingFilename ); m_pszUpdatingFilename = NULL; } if( m_pUpdatingInputDevice ) { delete m_pUpdatingInputDevice; m_pUpdatingInputDevice = NULL; } m_bSoureHasXRefStream = false; m_lPrevXRefOffset = -1; GetObjects().SetCanReuseObjectNumbers( true ); PdfDocument::Clear(); } void PdfMemDocument::InitFromParser( PdfParser* pParser ) { m_eVersion = pParser->GetPdfVersion(); m_bLinearized = pParser->IsLinearized(); m_eSourceVersion = m_eVersion; m_bSoureHasXRefStream = pParser->HasXRefStream(); m_lPrevXRefOffset = pParser->GetXRefOffset(); GetObjects().SetCanReuseObjectNumbers( !IsLoadedForUpdate() ); PdfObject* pTrailer = new PdfObject( *(pParser->GetTrailer()) ); this->SetTrailer ( pTrailer ); // Set immediately as trailer // so that pTrailer has an owner // and GetIndirectKey will work if(PdfError::DebugEnabled()) { // OC 17.08.2010: Avoid using cout here: // PdfOutputDevice debug( &(std::cout) ); // pTrailer->Write( &debug ); // debug.Write("\n", 1); // OC 17.08.2010: Append Linefeed PdfRefCountedBuffer buf; PdfOutputDevice debug( &buf ); pTrailer->Write( &debug, m_eWriteMode ); debug.Write("\n", 1); // OC 17.08.2010: Append Linefeed size_t siz = buf.GetSize(); char* ptr = buf.GetBuffer(); PdfError::LogMessage(eLogSeverity_Information, "%.*s", siz, ptr); } PdfObject* pCatalog = pTrailer->GetIndirectKey( "Root" ); if( !pCatalog ) { PODOFO_RAISE_ERROR_INFO( ePdfError_NoObject, "Catalog object not found!" ); } PdfObject* pInfo = pTrailer->GetIndirectKey( "Info" ); PdfInfo* pInfoObj; if( !pInfo ) { pInfoObj = new PdfInfo( PdfDocument::GetObjects() ); pTrailer->GetDictionary().AddKey( "Info", pInfoObj->GetObject()->Reference() ); } else pInfoObj = new PdfInfo( pInfo ); if( pParser->GetEncrypted() ) { // All PdfParser instances have a pointer to a PdfEncrypt object. // So we have to take ownership of it (command the parser to give it). delete m_pEncrypt; m_pEncrypt = pParser->TakeEncrypt(); } this->SetCatalog ( pCatalog ); this->SetInfo ( pInfoObj ); InitPagesTree(); // Delete the temporary pdfparser object. // It is only set to m_pParser so that SetPassword can work delete m_pParser; m_pParser = NULL; if( m_pEncrypt && this->IsLoadedForUpdate() ) { PODOFO_RAISE_ERROR( ePdfError_CannotEncryptedForUpdate ); } } void PdfMemDocument::Load( const char* pszFilename, bool bForUpdate ) { if( !pszFilename || !pszFilename[0] ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } this->Clear(); if( bForUpdate ) { int lLen = strlen( pszFilename ); m_pszUpdatingFilename = static_cast( podofo_malloc( sizeof( char ) * ( lLen + 1 ) ) ); memcpy( m_pszUpdatingFilename, pszFilename, lLen ); m_pszUpdatingFilename[lLen] = '\0'; } // Call parse file instead of using the constructor // so that m_pParser is initialized for encrypted documents m_pParser = new PdfParser( PdfDocument::GetObjects() ); m_pParser->ParseFile( pszFilename, true ); InitFromParser( m_pParser ); } #ifdef _WIN32 void PdfMemDocument::Load( const wchar_t* pszFilename, bool bForUpdate ) { if( !pszFilename || !pszFilename[0] ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } this->Clear(); if( bForUpdate ) { int lLen = wcslen( pszFilename ); m_wchar_pszUpdatingFilename = static_cast( podofo_malloc( sizeof( wchar_t ) * ( lLen + 1 ) ) ); memcpy( m_wchar_pszUpdatingFilename, pszFilename, lLen ); m_wchar_pszUpdatingFilename[lLen] = L'\0'; } // Call parse file instead of using the constructor // so that m_pParser is initialized for encrypted documents m_pParser = new PdfParser( PdfDocument::GetObjects() ); m_pParser->ParseFile( pszFilename, true ); InitFromParser( m_pParser ); } #endif // _WIN32 void PdfMemDocument::Load( const char* pBuffer, long lLen, bool bForUpdate ) { if( !pBuffer || !lLen ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } this->Clear(); if( bForUpdate ) { m_pUpdatingInputDevice = new PdfRefCountedInputDevice( pBuffer, lLen ); } // Call parse file instead of using the constructor // so that m_pParser is initialized for encrypted documents m_pParser = new PdfParser( PdfDocument::GetObjects() ); m_pParser->ParseFile( pBuffer, lLen, true ); InitFromParser( m_pParser ); } void PdfMemDocument::Load( const PdfRefCountedInputDevice & rDevice, bool bForUpdate ) { this->Clear(); if( bForUpdate ) { m_pUpdatingInputDevice = new PdfRefCountedInputDevice( rDevice ); } // Call parse file instead of using the constructor // so that m_pParser is initialized for encrypted documents m_pParser = new PdfParser( PdfDocument::GetObjects() ); m_pParser->ParseFile( rDevice, true ); InitFromParser( m_pParser ); } /** Add a vendor-specific extension to the current PDF version. * \param ns namespace of the extension * \param level level of the extension */ void PdfMemDocument::AddPdfExtension( const char* ns, pdf_int64 level ) { if (!this->HasPdfExtension(ns, level)) { PdfObject* pExtensions = this->GetCatalog()->GetIndirectKey("Extensions"); PdfDictionary newExtension; newExtension.AddKey("BaseVersion", PdfName(s_szPdfVersionNums[m_eVersion])); newExtension.AddKey("ExtensionLevel", PdfVariant(level)); if (pExtensions && pExtensions->IsDictionary()) { pExtensions->GetDictionary().AddKey(ns, newExtension); } else { PdfDictionary extensions; extensions.AddKey(ns, newExtension); this->GetCatalog()->GetDictionary().AddKey("Extensions", extensions); } } } /** Checks whether the documents is tagged to imlpement a vendor-specific * extension to the current PDF version. * \param ns namespace of the extension * \param level level of the extension */ bool PdfMemDocument::HasPdfExtension( const char* ns, pdf_int64 level ) const { PdfObject* pExtensions = this->GetCatalog()->GetIndirectKey("Extensions"); if (pExtensions) { PdfObject* pExtension = pExtensions->GetIndirectKey(ns); if (pExtension) { PdfObject* pLevel = pExtension->GetIndirectKey("ExtensionLevel"); if (pLevel && pLevel->IsNumber() && pLevel->GetNumber() == level) return true; } } return false; } /** Return the list of all vendor-specific extensions to the current PDF version. * \param ns namespace of the extension * \param level level of the extension */ std::vector PdfMemDocument::GetPdfExtensions() const { std::vector result; PdfObject* pExtensions = this->GetCatalog()->GetIndirectKey("Extensions"); if (pExtensions) { // Loop through all declared extensions for (TKeyMap::const_iterator it = pExtensions->GetDictionary().GetKeys().begin(); it != pExtensions->GetDictionary().GetKeys().end(); ++it) { PdfObject *bv = it->second->GetIndirectKey("BaseVersion"); PdfObject *el = it->second->GetIndirectKey("ExtensionLevel"); if (bv && el && bv->IsName() && el->IsNumber()) { // Convert BaseVersion name to EPdfVersion for(int i=0; i<=MAX_PDF_VERSION_STRING_INDEX; i++) { if(bv->GetName().GetName() == s_szPdfVersionNums[i]) { result.push_back(PdfExtension(it->first.GetName().c_str(), static_cast(i), el->GetNumber())); } } } } } return result; } /** Remove a vendor-specific extension to the current PDF version. * \param ns namespace of the extension * \param level level of the extension */ void PdfMemDocument::RemovePdfExtension( const char* ns, pdf_int64 level ) { if (this->HasPdfExtension(ns, level)) this->GetCatalog()->GetIndirectKey("Extensions")->GetDictionary().RemoveKey("ns"); } void PdfMemDocument::SetPassword( const std::string & sPassword ) { PODOFO_RAISE_LOGIC_IF( !m_pParser, "SetPassword called without reading a PDF file." ); m_pParser->SetPassword( sPassword ); InitFromParser( m_pParser ); } void PdfMemDocument::Write( const char* pszFilename ) { /** TODO: * We will get problems here on linux, * if we write to the same filename we read the * document from. * Because the PdfParserObjects will read there streams * data from the file while we are writing it. * The problem is that the stream data won't exist at this time * as we truncated the file already to zero length by opening * it writeable. */ // makes sure pending subset-fonts are embedded m_fontCache.EmbedSubsetFonts(); PdfOutputDevice device( pszFilename ); this->Write( &device ); } #ifdef _WIN32 void PdfMemDocument::Write( const wchar_t* pszFilename ) { /** TODO: * We will get problems here on linux, * if we write to the same filename we read the * document from. * Because the PdfParserObjects will read there streams * data from the file while we are writing it. * The problem is that the stream data won't exist at this time * as we truncated the file already to zero length by opening * it writeable. */ PdfOutputDevice device( pszFilename ); this->Write( &device ); } #endif // _WIN32 void PdfMemDocument::Write( PdfOutputDevice* pDevice ) { /** TODO: * We will get problems here on linux, * if we write to the same filename we read the * document from. * Because the PdfParserObjects will read there streams * data from the file while we are writing it. * The problem is that the stream data won't exist at this time * as we truncated the file already to zero length by opening * it writeable. */ PdfWriter writer( &(this->GetObjects()), this->GetTrailer() ); writer.SetPdfVersion( this->GetPdfVersion() ); writer.SetWriteMode( m_eWriteMode ); if( m_pEncrypt ) writer.SetEncrypted( *m_pEncrypt ); writer.Write( pDevice ); } void PdfMemDocument::WriteUpdate( const char* pszFilename ) { if( !IsLoadedForUpdate() ) { PODOFO_RAISE_ERROR( ePdfError_NotLoadedForUpdate ); } if( !pszFilename ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } // makes sure pending subset-fonts are embedded m_fontCache.EmbedSubsetFonts(); bool bTruncate = !m_pszUpdatingFilename || strcmp( m_pszUpdatingFilename, pszFilename) != 0; PdfOutputDevice device( pszFilename, bTruncate ); this->WriteUpdate( &device, bTruncate ); } #ifdef _WIN32 void PdfMemDocument::WriteUpdate( const wchar_t* pszFilename ) { if( !IsLoadedForUpdate() ) { PODOFO_RAISE_ERROR( ePdfError_NotLoadedForUpdate ); } if( !pszFilename ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } bool bTruncate = !m_wchar_pszUpdatingFilename || wcscmp( m_wchar_pszUpdatingFilename, pszFilename) != 0; PdfOutputDevice device( pszFilename, bTruncate ); this->WriteUpdate( &device, bTruncate ); } #endif // _WIN32 void PdfMemDocument::WriteUpdate( PdfOutputDevice* pDevice, bool bTruncate ) { if( !IsLoadedForUpdate() ) { PODOFO_RAISE_ERROR( ePdfError_NotLoadedForUpdate ); } if( !pDevice ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } /** TODO: * We will get problems here on linux, * if we write to the same filename we read the * document from. * Because the PdfParserObjects will read there streams * data from the file while we are writing it. * The problem is that the stream data won't exist at this time * as we truncated the file already to zero length by opening * it writeable. */ PdfWriter writer( &(this->GetObjects()), this->GetTrailer() ); writer.SetPdfVersion( this->GetPdfVersion() ); writer.SetWriteMode( m_eWriteMode ); writer.SetIncrementalUpdate( true ); // PdfWriter::WriteUpdate() does it too, but let's make it explicit if( m_pEncrypt ) writer.SetEncrypted( *m_pEncrypt ); if( m_eSourceVersion < this->GetPdfVersion() && this->GetCatalog() && this->GetCatalog()->IsDictionary() ) { if( this->GetCatalog()->GetDictionary().HasKey( PdfName( "Version" ) ) ) { this->GetCatalog()->GetDictionary().RemoveKey( PdfName( "Version" ) ); } if( this->GetPdfVersion() < ePdfVersion_1_0 || this->GetPdfVersion() > ePdfVersion_1_7 ) { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } this->GetCatalog()->GetDictionary().AddKey( PdfName( "Version" ), PdfName( s_szPdfVersionNums[this->GetPdfVersion()] ) ); } PdfInputDevice *pSourceContent = NULL; bool bFreeSourceContent = false; bool bRewriteXRefTable; try { if( bTruncate ) { if( m_pszUpdatingFilename ) { pSourceContent = new PdfInputDevice( m_pszUpdatingFilename ); bFreeSourceContent = true; } #ifdef _WIN32 else if( m_wchar_pszUpdatingFilename ) { pSourceContent = new PdfInputDevice( m_wchar_pszUpdatingFilename ); bFreeSourceContent = true; } #endif //_WIN32 else if( m_pUpdatingInputDevice && m_pUpdatingInputDevice->Device() ) { pSourceContent = m_pUpdatingInputDevice->Device(); bFreeSourceContent = false; } else { PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } } /* Rewrite the XRef table when the document is linearized or contains * an XRef stream, to make sure that the objects can be read properly. * Also do not reference the previous XRef table in such cases. */ bRewriteXRefTable = this->IsLinearized() || m_bSoureHasXRefStream; if( bRewriteXRefTable ) writer.SetPrevXRefOffset( 0 ); else writer.SetPrevXRefOffset( m_lPrevXRefOffset ); writer.WriteUpdate( pDevice, pSourceContent, bRewriteXRefTable ); } catch( PdfError & e ) { if( bFreeSourceContent && pSourceContent ) delete pSourceContent; e.AddToCallstack( __FILE__, __LINE__ ); throw e; } if( bFreeSourceContent && pSourceContent ) delete pSourceContent; } PdfObject* PdfMemDocument::GetNamedObjectFromCatalog( const char* pszName ) const { return this->GetCatalog()->GetIndirectKey( PdfName( pszName ) ); } void PdfMemDocument::DeletePages( int inFirstPage, int inNumPages ) { for( int i = 0 ; i < inNumPages ; i++ ) { this->GetPagesTree()->DeletePage( inFirstPage ) ; } } const PdfMemDocument & PdfMemDocument::InsertPages( const PdfMemDocument & rDoc, int inFirstPage, int inNumPages ) { /* This function works a bit different than one might expect. Rather than copying one page at a time - we copy the ENTIRE document and then delete the pages we aren't interested in. We do this because 1) SIGNIFICANTLY simplifies the process 2) Guarantees that shared objects aren't copied multiple times 3) offers MUCH faster performance for the common cases HOWEVER: because PoDoFo doesn't currently do any sort of "object garbage collection" during a Write() - we will end up with larger documents, since the data from unused pages will also be in there. */ // calculate preliminary "left" and "right" page ranges to delete // then offset them based on where the pages were inserted // NOTE: some of this will change if/when we support insertion at locations // OTHER than the end of the document! int leftStartPage = 0 ; int leftCount = inFirstPage ; int rightStartPage = inFirstPage + inNumPages ; int rightCount = rDoc.GetPageCount() - rightStartPage ; int pageOffset = this->GetPageCount(); leftStartPage += pageOffset ; rightStartPage += pageOffset ; // append in the whole document this->Append( rDoc ); // delete if( rightCount > 0 ) this->DeletePages( rightStartPage, rightCount ) ; if( leftCount > 0 ) this->DeletePages( leftStartPage, leftCount ) ; return *this; } void PdfMemDocument::SetEncrypted( const std::string & userPassword, const std::string & ownerPassword, int protection, PdfEncrypt::EPdfEncryptAlgorithm eAlgorithm, PdfEncrypt::EPdfKeyLength eKeyLength ) { delete m_pEncrypt; m_pEncrypt = PdfEncrypt::CreatePdfEncrypt( userPassword, ownerPassword, protection, eAlgorithm, eKeyLength ); } void PdfMemDocument::SetEncrypted( const PdfEncrypt & pEncrypt ) { delete m_pEncrypt; m_pEncrypt = PdfEncrypt::CreatePdfEncrypt( pEncrypt ); } PdfFont* PdfMemDocument::GetFont( PdfObject* pObject ) { return m_fontCache.GetFont( pObject ); } void PdfMemDocument::FreeObjectMemory( const PdfReference & rRef, bool bForce ) { FreeObjectMemory( this->GetObjects().GetObject( rRef ), bForce ); } void PdfMemDocument::FreeObjectMemory( PdfObject* pObj, bool bForce ) { if( !pObj ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } PdfParserObject* pParserObject = dynamic_cast(pObj); if( !pParserObject ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "FreeObjectMemory works only on classes of type PdfParserObject." ); } pParserObject->FreeObjectMemory( bForce ); } }; podofo-0.9.5/src/doc/PdfIdentityEncoding.cpp0000664000175000017500000001222513013650710020613 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfIdentityEncoding.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfDictionary.h" #include "base/PdfLocale.h" #include "PdfFont.h" #include #include #include #include #include using namespace std; namespace PoDoFo { PdfIdentityEncoding::PdfIdentityEncoding( int nFirstChar, int nLastChar, bool bAutoDelete, PdfObject *pToUnicode ) : PdfEncoding( nFirstChar, nLastChar, pToUnicode ), m_bAutoDelete( bAutoDelete ) { // create a unique ID std::ostringstream oss; oss << "/Identity-H" << nFirstChar << "_" << nLastChar; m_id = PdfName( oss.str() ); } void PdfIdentityEncoding::AddToDictionary( PdfDictionary & rDictionary ) const { rDictionary.AddKey( "Encoding", PdfName("Identity-H") ); } pdf_utf16be PdfIdentityEncoding::GetCharCode( int nIndex ) const { if( nIndex < this->GetFirstChar() || nIndex > this->GetLastChar() ) { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } #ifdef PODOFO_IS_LITTLE_ENDIAN return ((nIndex & 0xFF00) >> 8) | ((nIndex & 0x00FF) << 8); #else return static_cast(nIndex); #endif // PODOFO_IS_LITTLE_ENDIAN } PdfString PdfIdentityEncoding::ConvertToUnicode( const PdfString & rEncodedString, const PdfFont* pFont ) const { if(!m_toUnicode.empty()) { return PdfEncoding::ConvertToUnicode(rEncodedString, pFont); } else { /* Identity-H means 1-1 mapping */ //std::cout << "convertToUnicode(" << rEncodedString.IsUnicode() << ")" << std::endl; return ( rEncodedString.IsUnicode() ) ? PdfString(rEncodedString) : rEncodedString.ToUnicode(); } } PdfRefCountedBuffer PdfIdentityEncoding::ConvertToEncoding( const PdfString & rString, const PdfFont* pFont ) const { if(!m_toUnicode.empty()) { return PdfEncoding::ConvertToEncoding(rString, pFont); } else if( pFont ) { PdfString sStr = rString.ToUnicode(); const pdf_utf16be* pStr = sStr.GetUnicode(); PdfRefCountedBuffer buffer( sStr.GetLength() ); char* outp = buffer.GetBuffer(); // Get the string in UTF-16be format long lGlyphId; while( *pStr ) { #ifdef PODOFO_IS_LITTLE_ENDIAN lGlyphId = pFont->GetFontMetrics()->GetGlyphId( (((*pStr << 8) & 0xFF00) | ((*pStr >> 8) & 0x00FF)) ); #else lGlyphId = pFont->GetFontMetrics()->GetGlyphId( *pStr ); #endif // PODOFO_IS_LITTLE_ENDIAN outp[0] = static_cast(lGlyphId >> 8); outp[1] = static_cast(lGlyphId); outp += 2; ++pStr; } return buffer; } else { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } return PdfRefCountedBuffer(); } }; /* namespace PoDoFo */ podofo-0.9.5/src/doc/PdfFontTrueType.cpp0000664000175000017500000001102212626226641017770 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfFontTrueType.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfDictionary.h" #include "base/PdfName.h" #include "base/PdfStream.h" namespace PoDoFo { PdfFontTrueType::PdfFontTrueType( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfVecObjects* pParent, bool bEmbed ) : PdfFontSimple( pMetrics, pEncoding, pParent ) { this->Init( bEmbed, PdfName("TrueType") ); } PdfFontTrueType::PdfFontTrueType( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfObject* pObject ) : PdfFontSimple( pMetrics, pEncoding, pObject ) { } void PdfFontTrueType::EmbedFontFile( PdfObject* pDescriptor ) { PdfObject* pContents; pdf_long lSize = 0; m_bWasEmbedded = true; pContents = this->GetObject()->GetOwner()->CreateObject(); pDescriptor->GetDictionary().AddKey( "FontFile2", pContents->Reference() ); // if the data was loaded from memory - use it from there // otherwise, load from disk if ( m_pMetrics->GetFontDataLen() && m_pMetrics->GetFontData() ) { // FIXME const_cast is dangerous if string literals may ever be passed char* pBuffer = const_cast( m_pMetrics->GetFontData() ); lSize = m_pMetrics->GetFontDataLen(); // Set Length1 before creating the stream // as PdfStreamedDocument does not allow // adding keys to an object after a stream was written pContents->GetDictionary().AddKey( "Length1", PdfVariant( static_cast(lSize) ) ); pContents->GetStream()->Set( pBuffer, lSize ); } else { PdfFileInputStream stream( m_pMetrics->GetFilename() ); lSize = stream.GetFileLength(); // Set Length1 before creating the stream // as PdfStreamedDocument does not allow // adding keys to an object after a stream was written pContents->GetDictionary().AddKey( "Length1", PdfVariant( static_cast(lSize) ) ); pContents->GetStream()->Set( &stream ); } } }; podofo-0.9.5/src/doc/PdfDifferenceEncoding.h0000664000175000017500000003254512347277655020556 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_DIFFERENCE_ENCODING_H_ #define _PDF_DIFFERENCE_ENCODING_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfEncoding.h" #include "PdfElement.h" #include namespace PoDoFo { /** A helper class for PdfDifferenceEncoding that * can be used to create a differences array. */ class PODOFO_DOC_API PdfEncodingDifference { struct TDifference { int nCode; PdfName name; pdf_utf16be unicodeValue; }; typedef std::vector TVecDifferences; typedef std::vector::iterator TIVecDifferences; typedef std::vector::const_iterator TCIVecDifferences; public: /** Create a PdfEncodingDifference object. */ PdfEncodingDifference(); /** Copy a PdfEncodingDifference object. */ PdfEncodingDifference( const PdfEncodingDifference & rhs ); /** Copy a PdfEncodingDifference object. */ const PdfEncodingDifference & operator=( const PdfEncodingDifference & rhs ); /** Add a difference to the object. * * \param nCode unicode code point of the difference (0 to 255 are legal values) * \param unicodeValue actual unicode value for nCode; can be 0 * * \see AddDifference if you know the name of the code point * use the overload below which is faster */ void AddDifference( int nCode, pdf_utf16be unicodeValue ); /** Add a difference to the object. * * \param nCode unicode code point of the difference (0 to 255 are legal values) * \param unicodeValue actual unicode value for nCode; can be 0 * \param rName name of the different code point or .notdef if none * \param bExplicitKeys if true, the unicode value is set to nCode as rName is meaningless (Type3 fonts) */ void AddDifference( int nCode, pdf_utf16be unicodeValue, const PdfName & rName, bool bExplicitNames = false ); /** Tests if the specified code is part of the * differences. * * \param nCode test if the given code is part of the differences * \param rName write the associated name into this object if the * code is part of the difference * \param rValue write the associated unicode value of the name to this value * * \returns true if the code is part of the difference */ bool Contains( int nCode, PdfName & rName, pdf_utf16be & rValue ) const; bool ContainsUnicodeValue( pdf_utf16be unicodeValue, char &rValue ) const; /** Convert the PdfEncodingDifference to an array * * \param rArray write to this array */ void ToArray( PdfArray & rArray ); /** Get the number of differences in this object. * If the user added .notdef as a difference it is * counted, even it is no real difference in the final encoding. * * \returns the number of differences in this object */ inline size_t GetCount() const; private: struct DifferenceComparatorPredicate { public: inline bool operator()( const TDifference & rDif1, const TDifference & rDif2 ) const { return rDif1.nCode < rDif2.nCode; } }; TVecDifferences m_vecDifferences; }; // ----------------------------------------------------- // // ----------------------------------------------------- inline size_t PdfEncodingDifference::GetCount() const { return m_vecDifferences.size(); } /** PdfDifferenceEncoding is an encoding, which is based * on either the fonts encoding or a predefined encoding * and defines differences to this base encoding. */ class PODOFO_DOC_API PdfDifferenceEncoding : public PdfEncoding, private PdfElement { public: /** * Defines the base encoding from which a * PdfDifferenceEncoding differs. */ enum EBaseEncoding { eBaseEncoding_Font, ///< Use The fonts encoding as base eBaseEncoding_WinAnsi, ///< Use WinAnsiEncoding as base encoding eBaseEncoding_MacRoman, ///< Use MacRomanEncoding as base encoding eBaseEncoding_MacExpert ///< Use MacExpertEncoding as base encoding }; /** Create a new PdfDifferenceEncoding which is based on * the fonts encoding. * * \param rDifference the differences in this encoding * \param pParent parent PdfVecObjects. * Add a newly created object to this vector. * \param bAutoDelete if true the encoding is deleted by its owning font */ PdfDifferenceEncoding( const PdfEncodingDifference & rDifference, PdfDocument* pParent, bool bAutoDelete = true ); /** Create a new PdfDifferenceEncoding which is based on * the fonts encoding. * * \param rDifference the differences in this encoding * \param pParent parent PdfDocument. * Add a newly created object to this vector. * \param bAutoDelete if true the encoding is deleted by its owning font */ PdfDifferenceEncoding( const PdfEncodingDifference & rDifference, PdfVecObjects* pParent, bool bAutoDelete = true ); /** Create a new PdfDifferenceEncoding which is based on * a predefined encoding. * * \param rDifference the differences in this encoding * \param eBaseEncoding the base encoding of this font * \param pParent parent PdfDocument. * Add a newly created object to this vector. * \param bAutoDelete if true the encoding is deleted by its owning font */ PdfDifferenceEncoding( const PdfEncodingDifference & rDifference, EBaseEncoding eBaseEncoding, PdfDocument* pParent, bool bAutoDelete = true ); /** Create a new PdfDifferenceEncoding which is based on * a predefined encoding. * * \param rDifference the differences in this encoding * \param eBaseEncoding the base encoding of this font * \param pParent parent PdfVecObjects. * Add a newly created object to this vector. * \param bAutoDelete if true the encoding is deleted by its owning font */ PdfDifferenceEncoding( const PdfEncodingDifference & rDifference, EBaseEncoding eBaseEncoding, PdfVecObjects* pParent, bool bAutoDelete = true ); /** Create a new PdfDifferenceEncoding from an existing object * in a PDF file. * * \param pObject an existing differences encoding * \param bAutoDelete if true the encoding is deleted by its owning font * \param bExplicitNames if true, glyph names are meaningless explicit keys on the font (used for Type3 fonts) */ PdfDifferenceEncoding( PdfObject* pObject, bool bAutoDelete = true, bool bExplicitNames = false ); /** Convert a standard character name to a unicode code point * * \param rName a standard character name * \returns an unicode code point */ static pdf_utf16be NameToUnicodeID( const PdfName & rName ); /** Convert an unicode code point to a standard character name * * \param inCodePoint a code point * \returns a standard character name of /.notdef if none could be found */ static PdfName UnicodeIDToName( pdf_utf16be inCodePoint ); /** Add this encoding object to a dictionary * usually be adding an /Encoding key in font dictionaries. * * \param rDictionary add the encoding to this dictionary */ virtual void AddToDictionary( PdfDictionary & rDictionary ) const; /** Convert a string that is encoded with this encoding * to an unicode PdfString. * * \param rEncodedString a string encoded by this encoding. * Usually this string was read from a content stream. * \param pFont the font for which this string is converted * * \returns an unicode PdfString. */ virtual PdfString ConvertToUnicode( const PdfString & rEncodedString, const PdfFont* pFont ) const; /** Convert a unicode PdfString to a string encoded with this encoding. * * \param rString an unicode PdfString. * \param pFont the font for which this string is converted * * \returns an encoded PdfRefCountedBuffer. The PdfRefCountedBuffer is treated as a series of bytes * and is allowed to have 0 bytes. The returned buffer must not be a unicode string. */ virtual PdfRefCountedBuffer ConvertToEncoding( const PdfString & rString, const PdfFont* pFont ) const; /** * \returns true if this encoding should be deleted automatically with the * font. */ virtual bool IsAutoDelete() const; /** * \returns true if this is a single byte encoding with a maximum of 256 values. */ virtual bool IsSingleByteEncoding() const; /** * Get read-only access to the object containing the actual * differences. * * \returns the container with the actual differences */ inline const PdfEncodingDifference & GetDifferences() const; /** Get the unicode character code for this encoding * at the position nIndex. nIndex is a position between * GetFirstChar() and GetLastChar() * * \param nIndex character code at position index * \returns unicode character code * * \see GetFirstChar * \see GetLastChar * * Will throw an exception if nIndex is out of range. */ virtual pdf_utf16be GetCharCode( int nIndex ) const; protected: /** Get a unique ID for this encoding * which can used for comparisons! * * \returns a unique id for this encoding! */ virtual const PdfName & GetID() const; private: /** Initialize this object */ void Init(); /** Create a unique ID for this encoding */ void CreateID(); /** Get an object of type baseencoding * * \returns a base encoding */ const PdfEncoding* GetBaseEncoding() const; private: PdfEncodingDifference m_differences; bool m_bAutoDelete; ///< If true this encoding is deleted by its font. PdfName m_id; ///< Unique ID of this encoding EBaseEncoding m_baseEncoding; ///< The base encoding of this font }; // ----------------------------------------------------- // // ----------------------------------------------------- inline const PdfName & PdfDifferenceEncoding::GetID() const { return m_id; } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfDifferenceEncoding::IsAutoDelete() const { return m_bAutoDelete; } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfDifferenceEncoding::IsSingleByteEncoding() const { return true; } // ----------------------------------------------------- // // ----------------------------------------------------- inline const PdfEncodingDifference & PdfDifferenceEncoding::GetDifferences() const { return m_differences; } }; /* PoDoFo */ #endif // _PDF_DIFFERENCE_ENCODING_H_ podofo-0.9.5/src/doc/PdfFontCache.h0000664000175000017500000004527612347303775016705 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FONT_CACHE_H_ #define _PDF_FONT_CACHE_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/Pdf3rdPtyForwardDecl.h" #include "podofo/base/PdfEncoding.h" #include "podofo/base/PdfEncodingFactory.h" #include "PdfFont.h" #include "PdfFontConfigWrapper.h" #ifdef _WIN32 // to have LOGFONTA/LOGFONTW available #include // Undefined stuff which windows does // define that breaks are build // e.g. GetObject is defined to either GetObjectA or GetObjectW #ifdef GetObject #undef GetObject #endif // GetObject #ifdef CreateFont #undef CreateFont #endif // CreateFont #ifdef DrawText #undef DrawText #endif // DrawText #endif // __WIN32 namespace PoDoFo { class PdfFontMetrics; class PdfVecObjects; /** A private structure, * which represents a font in the cache. */ struct TFontCacheElement { TFontCacheElement() : m_pFont( NULL ), m_pEncoding( NULL ), m_bBold( false ), m_bItalic( false ), m_bIsSymbolCharset (false) { } TFontCacheElement( const char* pszFontName, bool bBold, bool bItalic, bool bIsSymbolCharset, const PdfEncoding * const pEncoding ) : m_pFont(NULL), m_pEncoding( pEncoding ), m_bBold( bBold ), m_bItalic( bItalic ), m_sFontName( reinterpret_cast(pszFontName) ), m_bIsSymbolCharset (bIsSymbolCharset) { } #if defined(_WIN32) && !defined(PODOFO_NO_FONTMANAGER) TFontCacheElement( const wchar_t* pszFontName, bool bBold, bool bItalic, bool bIsSymbolCharset, const PdfEncoding * const pEncoding ) : m_pFont(NULL), m_pEncoding( pEncoding ), m_bBold( bBold ), m_bItalic( bItalic ), m_sFontName( pszFontName ), m_bIsSymbolCharset (bIsSymbolCharset) { } #endif // _WIN32 TFontCacheElement( const TFontCacheElement & rhs ) { this->operator=(rhs); } const TFontCacheElement & operator=( const TFontCacheElement & rhs ) { m_pFont = rhs.m_pFont; m_pEncoding = rhs.m_pEncoding; m_bBold = rhs.m_bBold; m_bItalic = rhs.m_bItalic; m_sFontName = rhs.m_sFontName; m_bIsSymbolCharset = rhs.m_bIsSymbolCharset; return *this; } bool operator<( const TFontCacheElement & rhs ) const { if (m_bIsSymbolCharset != rhs.m_bIsSymbolCharset) { return m_bIsSymbolCharset < rhs.m_bIsSymbolCharset; } if( m_sFontName == rhs.m_sFontName ) { if( m_pEncoding == NULL || rhs.m_pEncoding == NULL || *m_pEncoding == *rhs.m_pEncoding ) { if( m_bBold == rhs.m_bBold) return m_bItalic < rhs.m_bItalic; else return m_bBold < rhs.m_bBold; } else return *m_pEncoding < *rhs.m_pEncoding; } else return (m_sFontName < rhs.m_sFontName); } inline bool operator()( const TFontCacheElement& r1, const TFontCacheElement& r2 ) const { return r1 < r2; } PdfFont* m_pFont; const PdfEncoding* m_pEncoding; bool m_bBold; bool m_bItalic; PdfString m_sFontName; ///< We use PdfString here as it can easily handle unicode on windows bool m_bIsSymbolCharset; }; /** * This class assists PdfDocument * with caching font information. * * Additional to font caching, this class is also * responsible for font matching. * * PdfFont is an actual font that can be used in * a PDF file (i.e. it does also font embedding) * and PdfFontMetrics provides only metrics informations. * * This class is an internal class of PoDoFo * and should not be used in user applications * * \see PdfDocument */ class PODOFO_DOC_API PdfFontCache { typedef std::vector TSortedFontList; typedef TSortedFontList::iterator TISortedFontList; typedef TSortedFontList::const_iterator TCISortedFontList; public: /** * Flags to control font creation. */ enum EFontCreationFlags { eFontCreationFlags_None = 0, ///< No special settings eFontCreationFlags_AutoSelectBase14 = 1, ///< Create automatically a base14 font if the fontname matches one of them eFontCreationFlags_Type1Subsetting = 2 ///< Create subsetted type1-font, which includes only used characters }; /** Create an empty font cache * * \param pParent a PdfVecObjects which is required * to create new font objects */ PdfFontCache( PdfVecObjects* pParent ); /** Create an empty font cache * * \param rFontConfig provide a handle to fontconfig, as initializing a * new fontconfig intance might be time consuming. * \param pParent a PdfVecObjects which is required * to create new font objects */ PdfFontCache( const PdfFontConfigWrapper & rFontConfig, PdfVecObjects* pParent ); /** Destroy and empty the font cache */ ~PdfFontCache(); /** * Empty the internal font cache. * This should be done when ever a new document * is created or openened. */ void EmptyCache(); /** Get a font from the cache. If the font does not yet * exist, add it to the cache. This font is created * from an existing object. * * \param pObject a PdfObject that is a font * * \returns a PdfFont object or NULL if the font could * not be created or found. */ PdfFont* GetFont( PdfObject* pObject ); /** Get a font from the cache. If the font does not yet * exist, add it to the cache. * * \param pszFontName a valid fontname * \param bBold if true search for a bold font * \param bItalic if true search for an italic font * \param bSymbolCharset whether to use symbol charset, rather than unicode charset * \param bEmbedd if true a font for embedding into * PDF will be created * \param eFontCreationFlags special flag to specify how fonts should be created * \param pEncoding the encoding of the font. The font will not take ownership of this object. * \param pszFileName optional path to a valid font file * * \returns a PdfFont object or NULL if the font could * not be created or found. */ PdfFont* GetFont( const char* pszFontName, bool bBold, bool bItalic, bool bSymbolCharset, bool bEmbedd, EFontCreationFlags eFontCreationFlags = eFontCreationFlags_AutoSelectBase14, const PdfEncoding * const = PdfEncodingFactory::GlobalWinAnsiEncodingInstance(), const char* pszFileName = NULL ); #if defined(_WIN32) && !defined(PODOFO_NO_FONTMANAGER) /** Get a font from the cache. If the font does not yet * exist, add it to the cache. * * \param pszFontName a valid fontname * \param bBold if true search for a bold font * \param bItalic if true search for an italic font * \param bSymbolCharset whether to use symbol charset, rather than unicode charset * \param bEmbedd if true a font for embedding into * PDF will be created * \param pEncoding the encoding of the font. The font will not take ownership of this object. * * \returns a PdfFont object or NULL if the font could * not be created or found. * * This is an overloaded member function to allow working * with unicode characters. On Unix systes you can also path * UTF-8 to the const char* overload. */ PdfFont* GetFont( const wchar_t* pszFontName, bool bBold, bool bItalic, bool bSymbolCharset, bool bEmbedd, const PdfEncoding * const = PdfEncodingFactory::GlobalWinAnsiEncodingInstance() ); PdfFont* GetFont( const LOGFONTA &logFont, bool bEmbedd, const PdfEncoding * const pEncoding ); PdfFont* GetFont( const LOGFONTW &logFont, bool bEmbedd, const PdfEncoding * const pEncoding ); #endif // _WIN32 /** Get a font from the cache. If the font does not yet * exist, add it to the cache. * * \param face a valid freetype font face (will be free'd by PoDoFo) * \param bSymbolCharset whether to use symbol charset, rather than unicode charset * \param bEmbedd if true a font for embedding into * PDF will be created * \param pEncoding the encoding of the font. The font will not take ownership of this object. * * \returns a PdfFont object or NULL if the font could * not be created or found. */ PdfFont* GetFont( FT_Face face, bool bSymbolCharset, bool bEmbedd, const PdfEncoding * const = PdfEncodingFactory::GlobalWinAnsiEncodingInstance() ); /** Get a font with specific id from the cache. If the font does not yet * exist, copy from existing type1-font and set id. * * \param pFont an existing font * \param pszSuffix Suffix to add to font-id * * \returns a PdfFont object or NULL if the font could * not be created or found. */ PdfFont* GetDuplicateFontType1( PdfFont* pFont, const char* pszSuffix ); /** Get a fontsubset from the cache. If the font does not yet * exist, add it to the cache. * * \param pszFontName a valid fontname * \param bBold if true search for a bold font * \param bItalic if true search for an italic font * \param bSymbolCharset whether to use symbol charset, rather than unicode charset * \param pEncoding the encoding of the font. All characters * of the encoding will be included in this subset. * The font will not take ownership of this object. * \param pszFileName optional path to a valid font file * * \returns a PdfFont object or NULL if the font could * not be created or found. */ PdfFont* GetFontSubset( const char* pszFontName, bool bBold, bool bItalic, bool bSymbolCharset, const PdfEncoding * const = PdfEncodingFactory::GlobalWinAnsiEncodingInstance(), const char* pszFileName = NULL); /** Embeds all pending subset-fonts * */ void EmbedSubsetFonts(); #if defined(PODOFO_HAVE_FONTCONFIG) /** Get the path of a font file on a Unix system using fontconfig * * This method is only available if PoDoFo was compiled with * fontconfig support. Make sure to lock any FontConfig mutexes before * calling this method by yourself! * * \param pConfig a handle to an initialized fontconfig library * \param pszFontName name of the requested font * \param bBold if true find a bold font * \param bItalic if true find an italic font * \returns the path to the fontfile or an empty string */ static std::string GetFontConfigFontPath( FcConfig* pConfig, const char* pszFontName, bool bBold, bool bItalic ); #endif // defined(PODOFO_HAVE_FONTCONFIG) // Peter Petrov: 26 April 2008 /** Returns the font library from font cache * * \returns the internal handle to the freetype library */ inline FT_Library GetFontLibrary() const; /** * Set wrapper for the fontconfig library. * Useful to avoid initializing Fontconfig multiple times. * * This setter can be called until first use of Fontconfig * as the library is initialized at first use. */ inline void SetFontConfigWrapper(const PdfFontConfigWrapper & rFontConfig); private: /** * Get the path to a font file for a certain fontname * * \param pszFontName a valid fontname * \param bBold if true search for a bold font * \param bItalic if true search for an italic font * * \returns the path to the fonts file if it was found. */ std::string GetFontPath( const char* pszFontName, bool bBold, bool bItalic ); /** Create a font and put it into the fontcache * * \param itSorted iterator pointing to a location in vecContainer * where a sorted insert can be made * \param vecContainer container where the font object should be added * \param pMetrics a font metrics * \param bEmbedd if true the font will be embedded in the pdf file * \param bBold if true this font will be treated as bold font * \param bItalic if true this font will be treated as italic font * \param pszFontName a font name for debug output * \param pEncoding the encoding of the font. The font will not take ownership of this object. * \param bSubsetting if true the font will be subsetted in the pdf file * * \returns a font handle or NULL in case of error */ PdfFont* CreateFontObject( TISortedFontList itSorted, TSortedFontList & vecContainer, PdfFontMetrics* pMetrics, bool bEmbedd, bool bBold, bool bItalic, const char* pszFontName, const PdfEncoding * const pEncoding, bool bSubsetting = false ); /** Create a font subset. * \param pMetrics a font metrics * \param pszFontName a font name for debug output * \param bBold if true this font will be treated as bold font * \param bItalic if true this font will be treated as italic font * \param vecCharacters a list of Unicode character indeces that should be embedded in the subset * * \returns a font handle or NULL in case of error */ /* PdfFont* CreateFontSubset( PdfFontMetrics* pMetrics, const char* pszFontName, bool bBold, bool bItalic, const std::vector & vecCharacters ); */ #if defined(_WIN32) && !defined(PODOFO_NO_FONTMANAGER) /** Load and create a font with windows API calls * * This method is only available on Windows systems. * * \param itSorted iterator pointing to a location in vecContainer * where a sorted insert can be made * \param vecContainer container where the font object should be added * \param pszFontName a fontname * \param bBold if true search for a bold font * \param bItalic if true search for an italic font * \param bEmbedd if true embedd the font * \param pEncoding the encoding of the font. The font will not take ownership of this object. * * \returns a font handle or NULL in case of error */ PdfFont* GetWin32Font( TISortedFontList itSorted, TSortedFontList & vecContainer, const char* pszFontName, bool bBold, bool bItalic, bool bSymbolCharset, bool bEmbedd, const PdfEncoding * const pEncoding, bool pSubsetting = false ); PdfFont* GetWin32Font( TISortedFontList itSorted, TSortedFontList & vecContainer, const wchar_t* pszFontName, bool bBold, bool bItalic, bool bSymbolCharset, bool bEmbedd, const PdfEncoding * const pEncoding, bool pSubsetting = false ); PdfFont* GetWin32Font( TISortedFontList itSorted, TSortedFontList & vecContainer, const LOGFONTA &logFont, bool bEmbedd, const PdfEncoding * const pEncoding, bool pSubsetting = false ); PdfFont* GetWin32Font( TISortedFontList itSorted, TSortedFontList & vecContainer, const LOGFONTW &logFont, bool bEmbedd, const PdfEncoding * const pEncoding, bool pSubsetting = false ); #endif // _WIN32 #define SUBSET_BASENAME_LEN 6 // + 2 for "+\0" // kind of ABCDEF+ const char *genSubsetBasename(void); protected: void Init(void); private: TSortedFontList m_vecFonts; ///< Sorted list of all fonts, currently in the cache TSortedFontList m_vecFontSubsets; FT_Library m_ftLibrary; ///< Handle to the freetype library PdfVecObjects* m_pParent; ///< Handle to parent for creating new fonts and objects PdfFontConfigWrapper m_fontConfig; ///< Handle to the fontconfig library char m_sSubsetBasename[SUBSET_BASENAME_LEN + 2]; //< For genSubsetBasename() }; // Peter Petrov: 26 April 2008 // ----------------------------------------------------- // // ----------------------------------------------------- FT_Library PdfFontCache::GetFontLibrary() const { return this->m_ftLibrary; } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfFontCache::SetFontConfigWrapper(const PdfFontConfigWrapper & rFontConfig) { m_fontConfig = rFontConfig; } }; #endif /* _PDF_FONT_CACHE_H_ */ podofo-0.9.5/src/doc/PdfFontMetricsFreetype.cpp0000664000175000017500000004557512717070657021352 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfFontMetricsFreetype.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfDictionary.h" #include "base/PdfVariant.h" #include "PdfFontFactory.h" #include #include #include #include #include FT_FREETYPE_H #include FT_TRUETYPE_TABLES_H #define PODOFO_FIRST_READABLE 31 #define PODOFO_WIDTH_CACHE_SIZE 256 namespace PoDoFo { #if defined(__APPLE_CC__) && !defined(PODOFO_HAVE_FONTCONFIG) #include #endif struct Scoped_FT_Face { Scoped_FT_Face() : ftFace(0) { } ~Scoped_FT_Face() { if (ftFace) { FT_Done_Face(ftFace); } } FT_Face ftFace; }; PdfFontMetricsFreetype* PdfFontMetricsFreetype::CreateForSubsetting(FT_Library* pLibrary, const char* pszFilename, bool pIsSymbol, const char* pszSubsetPrefix ) { Scoped_FT_Face scoped_face; FT_Error err = FT_New_Face( *pLibrary, pszFilename, 0, &scoped_face.ftFace ); if (!err) { FT_ULong length = 0; err = FT_Load_Sfnt_Table( scoped_face.ftFace, 0, 0, NULL, &length ); if (!err) { PdfRefCountedBuffer buffer(length); err = FT_Load_Sfnt_Table( scoped_face.ftFace, 0, 0, reinterpret_cast(buffer.GetBuffer()), &length ); if (!err) { return new PdfFontMetricsFreetype( pLibrary, buffer, pIsSymbol, pszSubsetPrefix ); } } // throw an exception PdfError::LogMessage( eLogSeverity_Critical, "FreeType returned the error %i when calling FT_Load_Sfnt_Table for font %s.", err, pszFilename ); PODOFO_RAISE_ERROR( ePdfError_FreeType ); } else { // throw an exception PdfError::LogMessage( eLogSeverity_Critical, "FreeType returned the error %i when calling FT_New_Face for font %s.", err, pszFilename ); PODOFO_RAISE_ERROR( ePdfError_FreeType ); } return 0; } PdfFontMetricsFreetype::PdfFontMetricsFreetype( FT_Library* pLibrary, const char* pszFilename, bool pIsSymbol, const char* pszSubsetPrefix ) : PdfFontMetrics( PdfFontMetrics::FontTypeFromFilename( pszFilename ), pszFilename, pszSubsetPrefix ), m_pLibrary( pLibrary ), m_pFace( NULL ), m_bSymbol( pIsSymbol ) { FT_Error err = FT_New_Face( *pLibrary, pszFilename, 0, &m_pFace ); if ( err ) { // throw an exception PdfError::LogMessage( eLogSeverity_Critical, "FreeType returned the error %i when calling FT_New_Face for font %s.", err, pszFilename ); PODOFO_RAISE_ERROR( ePdfError_FreeType ); } InitFromFace(pIsSymbol); } PdfFontMetricsFreetype::PdfFontMetricsFreetype( FT_Library* pLibrary, const char* pBuffer, unsigned int nBufLen, bool pIsSymbol, const char* pszSubsetPrefix ) : PdfFontMetrics( ePdfFontType_Unknown, "", pszSubsetPrefix ), m_pLibrary( pLibrary ), m_pFace( NULL ), m_bSymbol( pIsSymbol ) { m_bufFontData = PdfRefCountedBuffer( nBufLen ); // const_cast is ok, because we SetTakePossension to false! memcpy( m_bufFontData.GetBuffer(), pBuffer, nBufLen ); InitFromBuffer(pIsSymbol); } PdfFontMetricsFreetype::PdfFontMetricsFreetype( FT_Library* pLibrary, const PdfRefCountedBuffer & rBuffer, bool pIsSymbol, const char* pszSubsetPrefix ) : PdfFontMetrics( ePdfFontType_Unknown, "", pszSubsetPrefix ), m_pLibrary( pLibrary ), m_pFace( NULL ), m_bSymbol( pIsSymbol ), m_bufFontData( rBuffer ) { InitFromBuffer(pIsSymbol); } PdfFontMetricsFreetype::PdfFontMetricsFreetype( FT_Library* pLibrary, FT_Face face, bool pIsSymbol, const char* pszSubsetPrefix ) : PdfFontMetrics( ePdfFontType_TrueType, // Try to initialize the pathname from m_face // so that font embedding will work (face->stream ? reinterpret_cast(face->stream->pathname.pointer) : ""), pszSubsetPrefix ), m_pLibrary( pLibrary ), m_pFace( face ), m_bSymbol( pIsSymbol ) { // asume true type // m_eFontType = ePdfFontType_TrueType; InitFromFace(pIsSymbol); } PdfFontMetricsFreetype::~PdfFontMetricsFreetype() { if ( m_pFace ) { FT_Done_Face( m_pFace ); } } void PdfFontMetricsFreetype::InitFromBuffer(bool pIsSymbol) { FT_Open_Args openArgs; memset(&openArgs, 0, sizeof(openArgs)); openArgs.flags = FT_OPEN_MEMORY; openArgs.memory_base = reinterpret_cast(m_bufFontData.GetBuffer()), openArgs.memory_size = static_cast(m_bufFontData.GetSize()); FT_Error error = FT_Open_Face( *m_pLibrary, &openArgs, 0, &m_pFace ); if( error ) { PdfError::LogMessage( eLogSeverity_Critical, "FreeType returned the error %i when calling FT_New_Face for a buffered font.", error ); PODOFO_RAISE_ERROR( ePdfError_FreeType ); } else { // asume true type this->SetFontType( ePdfFontType_TrueType ); } InitFromFace(pIsSymbol); } void PdfFontMetricsFreetype::InitFromFace(bool pIsSymbol) { if ( m_eFontType == ePdfFontType_Unknown ) { // We need to have identified the font type by this point // Unsupported font. PODOFO_RAISE_ERROR_INFO( ePdfError_UnsupportedFontFormat, m_sFilename.c_str() ); } m_nWeight = 500; m_nItalicAngle = 0; m_dLineSpacing = 0.0; m_dUnderlineThickness = 0.0; m_dUnderlinePosition = 0.0; m_dStrikeOutPosition = 0.0; m_dStrikeOutThickness = 0.0; m_fFontSize = 0.0f; m_bSymbol = pIsSymbol; m_bIsBold = false; m_bIsItalic = false; if ( m_pFace ) { // better be, but just in case... m_dPdfAscent = m_pFace->ascender * 1000.0 / m_pFace->units_per_EM; m_dPdfDescent = m_pFace->descender * 1000.0 / m_pFace->units_per_EM; m_bIsBold = (m_pFace->style_flags & FT_STYLE_FLAG_BOLD) != 0; m_bIsItalic = (m_pFace->style_flags & FT_STYLE_FLAG_ITALIC) != 0; // Try to get a unicode charmap FT_Select_Charmap( m_pFace, pIsSymbol ? FT_ENCODING_MS_SYMBOL : FT_ENCODING_UNICODE ); // Try to determine if it is a symbol font for( int c=0; cnum_charmaps; c++ ) { FT_CharMap charmap = m_pFace->charmaps[c]; if( charmap->encoding == FT_ENCODING_MS_SYMBOL ) { m_bSymbol = true; FT_Set_Charmap( m_pFace, charmap ); break; } // TODO: Also check for FT_ENCODING_ADOBE_CUSTOM and set it? } // we cache the 256 first width entries as they // are most likely needed quite often m_vecWidth.clear(); m_vecWidth.reserve( PODOFO_WIDTH_CACHE_SIZE ); for( unsigned int i=0; i < PODOFO_WIDTH_CACHE_SIZE; i++ ) { if( i < PODOFO_FIRST_READABLE || !m_pFace ) m_vecWidth.push_back( 0.0 ); else { int index = i; // Handle symbol fonts if( m_bSymbol ) { index = index | 0xf000; } if( FT_Load_Char( m_pFace, index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP) == 0 ) // | FT_LOAD_NO_RENDER { m_vecWidth.push_back( static_cast(m_pFace->glyph->metrics.horiAdvance) * 1000.0 / m_pFace->units_per_EM ); continue; } m_vecWidth.push_back( 0.0 ); } } } InitFontSizes(); } void PdfFontMetricsFreetype::InitFontSizes() { if( !m_pFace ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "Cannot set font size on invalid font!" ); } float fSize = 1.0f; // TODO: Maybe we have to set this for charwidth!!! FT_Set_Char_Size( m_pFace, static_cast(fSize*64.0), 0, 72, 72 ); // calculate the line spacing now, as it changes only with the font size m_dLineSpacing = (static_cast(m_pFace->height) / m_pFace->units_per_EM); m_dUnderlineThickness = (static_cast(m_pFace->underline_thickness) / m_pFace->units_per_EM); m_dUnderlinePosition = (static_cast(m_pFace->underline_position) / m_pFace->units_per_EM); m_dAscent = static_cast(m_pFace->ascender) / m_pFace->units_per_EM; m_dDescent = static_cast(m_pFace->descender) / m_pFace->units_per_EM; // Set default values for strikeout, in case the font has no direct values m_dStrikeOutPosition = m_dAscent / 2.0; m_dStrikeOutThickness = m_dUnderlineThickness; TT_OS2* pOs2Table = static_cast(FT_Get_Sfnt_Table( m_pFace, ft_sfnt_os2 )); if( pOs2Table ) { m_dStrikeOutPosition = static_cast(pOs2Table->yStrikeoutPosition) / m_pFace->units_per_EM; m_dStrikeOutThickness = static_cast(pOs2Table->yStrikeoutSize) / m_pFace->units_per_EM; } } const char* PdfFontMetricsFreetype::GetFontname() const { const char* s = FT_Get_Postscript_Name( m_pFace ); return s ? s : ""; } void PdfFontMetricsFreetype::GetWidthArray( PdfVariant & var, unsigned int nFirst, unsigned int nLast, const PdfEncoding* pEncoding ) const { unsigned int i; PdfArray list; if( !m_pFace ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } for( i=nFirst;i<=nLast;i++ ) { if( i < PODOFO_WIDTH_CACHE_SIZE && pEncoding == NULL ) list.push_back( PdfVariant( m_vecWidth[i] ) ); else { if (pEncoding != NULL) { unsigned short shCode = pEncoding->GetCharCode(i); #ifdef PODOFO_IS_LITTLE_ENDIAN shCode = ((shCode & 0x00FF) << 8) | ((shCode & 0xFF00) >> 8); #endif list.push_back( PdfVariant( (pdf_int64)this->GetGlyphWidth(this->GetGlyphId(shCode)) ) ); continue; } else if( FT_Load_Char( m_pFace, i, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) == 0 ) // | FT_LOAD_NO_RENDER { // zero return code is success! list.push_back( PdfVariant( m_pFace->glyph->metrics.horiAdvance * 1000.0 / m_pFace->units_per_EM ) ); continue; } //PODOFO_RAISE_ERROR( ePdfError_FreeType ); list.push_back( PdfVariant( 0.0 ) ); } } var = PdfVariant( list ); } double PdfFontMetricsFreetype::GetGlyphWidth( int nGlyphId ) const { if( !m_pFace ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if( !FT_Load_Glyph( m_pFace, nGlyphId, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) // | FT_LOAD_NO_RENDER { // zero return code is success! return m_pFace->glyph->metrics.horiAdvance * 1000.0 / m_pFace->units_per_EM; } return 0.0; } double PdfFontMetricsFreetype::GetGlyphWidth( const char* pszGlyphname ) const { return GetGlyphWidth( FT_Get_Name_Index( m_pFace, const_cast(pszGlyphname) ) ); } void PdfFontMetricsFreetype::GetBoundingBox( PdfArray & array ) const { if( !m_pFace ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } array.Clear(); array.push_back( PdfVariant( m_pFace->bbox.xMin * 1000.0 / m_pFace->units_per_EM ) ); array.push_back( PdfVariant( m_pFace->bbox.yMin * 1000.0 / m_pFace->units_per_EM ) ); array.push_back( PdfVariant( m_pFace->bbox.xMax * 1000.0 / m_pFace->units_per_EM ) ); array.push_back( PdfVariant( m_pFace->bbox.yMax * 1000.0 / m_pFace->units_per_EM ) ); } double PdfFontMetricsFreetype::CharWidth( unsigned char c ) const { double dWidth = m_vecWidth[static_cast(c)]; return dWidth * static_cast(this->GetFontSize() * this->GetFontScale() / 100.0) / 1000.0 + static_cast( this->GetFontSize() * this->GetFontScale() / 100.0 * this->GetFontCharSpace() / 100.0); } double PdfFontMetricsFreetype::UnicodeCharWidth( unsigned short c ) const { FT_Error ftErr; double dWidth = 0.0; if( static_cast(c) < PODOFO_WIDTH_CACHE_SIZE ) { dWidth = m_vecWidth[static_cast(c)]; } else { ftErr = FT_Load_Char( m_pFace, static_cast(c), FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ); if( ftErr ) return dWidth; dWidth = m_pFace->glyph->metrics.horiAdvance * 1000.0 / m_pFace->units_per_EM; } return dWidth * static_cast(this->GetFontSize() * this->GetFontScale() / 100.0) / 1000.0 + static_cast( this->GetFontSize() * this->GetFontScale() / 100.0 * this->GetFontCharSpace() / 100.0); } long PdfFontMetricsFreetype::GetGlyphId( long lUnicode ) const { long lGlyph = 0L; // Handle symbol fonts! if( m_bSymbol ) { lUnicode = lUnicode | 0xf000; } lGlyph = FT_Get_Char_Index( m_pFace, lUnicode ); return lGlyph; } bool PdfFontMetricsFreetype::IsBold(void) const { return m_bIsBold; } bool PdfFontMetricsFreetype::IsItalic(void) const { return m_bIsItalic; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfFontMetricsFreetype::GetLineSpacing() const { return m_dLineSpacing * this->GetFontSize(); } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfFontMetricsFreetype::GetUnderlinePosition() const { return m_dUnderlinePosition * this->GetFontSize(); } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfFontMetricsFreetype::GetStrikeOutPosition() const { return m_dStrikeOutPosition * this->GetFontSize(); } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfFontMetricsFreetype::GetUnderlineThickness() const { return m_dUnderlineThickness * this->GetFontSize(); } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfFontMetricsFreetype::GetStrikeoutThickness() const { return m_dStrikeOutThickness * this->GetFontSize(); } // ----------------------------------------------------- // // ----------------------------------------------------- const char* PdfFontMetricsFreetype::GetFontData() const { return m_bufFontData.GetBuffer(); } // ----------------------------------------------------- // // ----------------------------------------------------- pdf_long PdfFontMetricsFreetype::GetFontDataLen() const { return m_bufFontData.GetSize(); } // ----------------------------------------------------- // // ----------------------------------------------------- unsigned int PdfFontMetricsFreetype::GetWeight() const { return m_nWeight; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfFontMetricsFreetype::GetAscent() const { return m_dAscent * this->GetFontSize(); } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfFontMetricsFreetype::GetPdfAscent() const { return m_dPdfAscent; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfFontMetricsFreetype::GetDescent() const { return m_dDescent * this->GetFontSize(); } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfFontMetricsFreetype::GetPdfDescent() const { return m_dPdfDescent; } // ----------------------------------------------------- // // ----------------------------------------------------- int PdfFontMetricsFreetype::GetItalicAngle() const { return m_nItalicAngle; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfFontMetricsFreetype::IsSymbol() const { return m_bSymbol; } }; podofo-0.9.5/src/doc/PdfFontType1.h0000664000175000017500000001522012344436402016655 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FONT_TYPE1_H_ #define _PDF_FONT_TYPE1_H_ #include "podofo/base/PdfDefines.h" #include "PdfFontSimple.h" namespace PoDoFo { /** A PdfFont implementation that can be used * to embedd type1 fonts into a PDF file * or to draw with type1 fonts. */ class PdfFontType1 : public PdfFontSimple { public: /** Create a new Type1 font object. * * \param pMetrics pointer to a font metrics object. The font in the PDF * file will match this fontmetrics object. The metrics object is * deleted along with the font. * \param pEncoding the encoding of this font. The font will take ownership of this object * depending on pEncoding->IsAutoDelete() * \param pParent parent of the font object * \param bEmbed if true the font will get embedded. * \param bSubsetting if true the font will use subsetting. * */ PdfFontType1( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfVecObjects* pParent, bool bEmbed, bool bSubsetting = false ); /** Create a PdfFont based on an existing PdfObject * \param pMetrics pointer to a font metrics object. The font in the PDF * file will match this fontmetrics object. The metrics object is * deleted along with the font. * \param pEncoding the encoding of this font. The font will take ownership of this object * depending on pEncoding->IsAutoDelete() * \param pObject an existing PdfObject */ PdfFontType1( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfObject* pObject ); /** Create a PdfFont based on an existing PdfFont with a new id * \param pFont pointer to existing font * \param pMetrics pointer to a font metrics object. The font in the PDF * file will match this fontmetrics object. The metrics object is * deleted along with the font. * \param pszSuffix Suffix to add to font-id * \param pParent parent of the font object */ PdfFontType1( PdfFontType1* pFont, PdfFontMetrics* pMetrics, const char *pszSuffix, PdfVecObjects* pParent ); void InitBase14Font(); protected: /** Remember the glyphs used in the string in case of subsetting * * \param sText the text string which should be printed (is not allowed to be NULL!) * \param lStringLen draw only lLen characters of pszText */ virtual void AddUsedSubsettingGlyphs( const PdfString & sText, long lStringLen ); /** Remember the glyphname in case of subsetting * * \param sGlyphName Name of the glyph to remember */ virtual void AddUsedGlyphname( const char* sGlyphName ); /** Embeds pending subset-font into PDF page * */ virtual void EmbedSubsetFont(); /** Embed the font file directly into the PDF file. * * \param pDescriptor font descriptor object */ virtual void EmbedFontFile( PdfObject* pDescriptor ); private: bool FindSeac( const unsigned char * buffer, int length ); pdf_long FindInBuffer( const char* pszNeedle, const char* pszHaystack, pdf_long lLen ) const; int m_bUsed[8]; // bitmask for usage if char 00..ff std::set m_sUsedGlyph; // array for special chars }; /** Helper Class needed for parsing type1-font for subsetting */ class PdfType1Encrypt { public: /** Create a new PdfTypeEncrypt object. * */ PdfType1Encrypt(); /** Encrypts a character * * \param plain the character to encrypt. * * \return encrypted cipher * */ unsigned char Encrypt( unsigned char plain ); /** Decrypts a character * * \param cipher the cipher to decrypt. * * \return decrypted character * */ unsigned char Decrypt( unsigned char cipher ); protected: unsigned short int m_r; unsigned short int m_c1; unsigned short int m_c2; }; class PdfType1EncryptEexec : public PdfType1Encrypt { public: /** Create a new PdfType1EncryptEexec object. * */ PdfType1EncryptEexec(); }; class PdfType1EncryptCharstring : public PdfType1Encrypt { public: /** Create a new PdfType1EncryptCharstring object. * */ PdfType1EncryptCharstring(); }; }; #endif // _PDF_FONT_TYPE1_H_ podofo-0.9.5/src/doc/PdfFontConfigWrapper.cpp0000664000175000017500000001074413013650710020754 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2011 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfFontConfigWrapper.h" #if defined(PODOFO_HAVE_FONTCONFIG) #include #include "base/util/PdfMutexWrapper.h" #endif namespace PoDoFo { #if defined(PODOFO_HAVE_FONTCONFIG) Util::PdfMutex PdfFontConfigWrapper::m_FcMutex; #endif PdfFontConfigWrapper::PdfFontConfigWrapper() : m_pFontConfig( NULL ) { #if defined(PODOFO_HAVE_FONTCONFIG) this->m_pFontConfig = new TRefCountedFontConfig(); this->m_pFontConfig->m_lRefCount = 1; this->m_pFontConfig->m_bInitialized = false; this->m_pFontConfig->m_pFcConfig = NULL; #endif } PdfFontConfigWrapper::PdfFontConfigWrapper(const PdfFontConfigWrapper & rhs) : m_pFontConfig( NULL ) { this->operator=(rhs); } PdfFontConfigWrapper::~PdfFontConfigWrapper() { this->DerefBuffer(); } const PdfFontConfigWrapper & PdfFontConfigWrapper::operator=(const PdfFontConfigWrapper & rhs) { // Self assignment is a no-op if (this == &rhs) return rhs; DerefBuffer(); this->m_pFontConfig = rhs.m_pFontConfig; if( m_pFontConfig ) { this->m_pFontConfig->m_lRefCount++; } return *this; } void PdfFontConfigWrapper::DerefBuffer() { if ( m_pFontConfig && !(--m_pFontConfig->m_lRefCount) ) { #if defined(PODOFO_HAVE_FONTCONFIG) if( this->m_pFontConfig->m_bInitialized ) { Util::PdfMutexWrapper mutex(m_FcMutex); FcConfigDestroy( static_cast(m_pFontConfig->m_pFcConfig) ); } #endif delete m_pFontConfig; } // Whether or not it still exists, we no longer have anything to do with // the buffer we just released our claim on. m_pFontConfig = NULL; } void PdfFontConfigWrapper::InitializeFontConfig() { #if defined(PODOFO_HAVE_FONTCONFIG) if( !this->m_pFontConfig->m_bInitialized ) { Util::PdfMutexWrapper mutex(m_FcMutex); if( !this->m_pFontConfig->m_bInitialized ) { this->m_pFontConfig->m_pFcConfig = static_cast(FcInitLoadConfigAndFonts()); this->m_pFontConfig->m_bInitialized = true; } } #endif } }; podofo-0.9.5/src/doc/PdfPainterMM.cpp0000664000175000017500000000524512322532431017214 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfPainterMM.h" #include "base/PdfDefinesPrivate.h" namespace PoDoFo { /* Defining the virtual destructor here rather than in the header * ensures that the vtable gets output correctly by all compilers. */ PdfPainterMM::~PdfPainterMM() { } }; podofo-0.9.5/src/doc/PdfDocument.cpp0000664000175000017500000010071113013650710017127 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #if defined(_MSC_VER) && _MSC_VER <= 1200 #pragma warning(disable: 4786) #endif #include #include #include #include "PdfDocument.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfDictionary.h" #include "base/PdfImmediateWriter.h" #include "base/PdfObject.h" #include "base/PdfStream.h" #include "base/PdfVecObjects.h" #include "PdfAcroForm.h" #include "PdfDestination.h" #include "PdfFileSpec.h" #include "PdfFont.h" #include "PdfFontMetrics.h" #include "PdfInfo.h" #include "PdfMemDocument.h" #include "PdfNamesTree.h" #include "PdfOutlines.h" #include "PdfPage.h" #include "PdfPagesTree.h" #include "PdfXObject.h" using namespace std; namespace PoDoFo { PdfDocument::PdfDocument(bool bEmpty) : m_fontCache( &m_vecObjects ), m_pTrailer(NULL), m_pCatalog(NULL), m_pInfo(NULL), m_pPagesTree( NULL ), m_pAcroForms( NULL ), m_pOutlines( NULL ), m_pNamesTree( NULL ) { m_vecObjects.SetParentDocument( this ); if( !bEmpty ) { m_pTrailer = new PdfObject(); // The trailer is NO part of the vector of objects m_pTrailer->SetOwner( &m_vecObjects ); m_pCatalog = m_vecObjects.CreateObject( "Catalog" ); m_pInfo = new PdfInfo( &m_vecObjects ); m_pTrailer->GetDictionary().AddKey( "Root", m_pCatalog->Reference() ); m_pTrailer->GetDictionary().AddKey( "Info", m_pInfo->GetObject()->Reference() ); InitPagesTree(); } } PdfDocument::~PdfDocument() { this->Clear(); } void PdfDocument::Clear() { TIVecObjects it = m_vecObjects.begin(); m_fontCache.EmptyCache(); while( it != m_vecObjects.end() ) { delete (*it); ++it; } m_vecObjects.Clear(); m_vecObjects.SetParentDocument( this ); if( m_pInfo ) { delete m_pInfo; m_pInfo = NULL; } if( m_pNamesTree ) { delete m_pNamesTree; m_pNamesTree = NULL; } if( m_pPagesTree ) { delete m_pPagesTree; m_pPagesTree = NULL; } if( m_pOutlines ) { delete m_pOutlines; m_pOutlines = NULL; } if( m_pAcroForms ) { delete m_pAcroForms; m_pAcroForms = NULL; } if( m_pTrailer ) { delete m_pTrailer; m_pTrailer = NULL; } m_pCatalog = NULL; } void PdfDocument::InitPagesTree() { PdfObject* pagesRootObj = this->GetCatalog()->GetIndirectKey( PdfName( "Pages" ) ); if ( pagesRootObj ) { m_pPagesTree = new PdfPagesTree( pagesRootObj ); } else { m_pPagesTree = new PdfPagesTree( &m_vecObjects ); m_pCatalog->GetDictionary().AddKey( "Pages", m_pPagesTree->GetObject()->Reference() ); } } PdfObject* PdfDocument::GetNamedObjectFromCatalog( const char* pszName ) const { return m_pCatalog->GetIndirectKey( PdfName( pszName ) ); } int PdfDocument::GetPageCount() const { return m_pPagesTree->GetTotalNumberOfPages(); } PdfPage* PdfDocument::GetPage( int nIndex ) const { if( nIndex < 0 || nIndex >= m_pPagesTree->GetTotalNumberOfPages() ) { PODOFO_RAISE_ERROR( ePdfError_PageNotFound ); } return m_pPagesTree->GetPage( nIndex ); } PdfFont* PdfDocument::CreateFont( const char* pszFontName, bool bSymbolCharset, const PdfEncoding * const pEncoding, PdfFontCache::EFontCreationFlags eFontCreationFlags, bool bEmbedd ) { return m_fontCache.GetFont( pszFontName, false, false, bSymbolCharset, bEmbedd, eFontCreationFlags, pEncoding ); } PdfFont* PdfDocument::CreateFont( const char* pszFontName, bool bBold, bool bItalic, bool bSymbolCharset, const PdfEncoding * const pEncoding, PdfFontCache::EFontCreationFlags eFontCreationFlags, bool bEmbedd, const char* pszFileName ) { return m_fontCache.GetFont( pszFontName, bBold, bItalic, bSymbolCharset, bEmbedd, eFontCreationFlags, pEncoding, pszFileName ); } #if defined(_WIN32) && !defined(PODOFO_NO_FONTMANAGER) PdfFont* PdfDocument::CreateFont( const wchar_t* pszFontName, bool bSymbolCharset, const PdfEncoding * const pEncoding, bool bEmbedd ) { return m_fontCache.GetFont( pszFontName, false, false, bSymbolCharset, bEmbedd, pEncoding ); } PdfFont* PdfDocument::CreateFont( const wchar_t* pszFontName, bool bBold, bool bItalic, bool bSymbolCharset, const PdfEncoding * const pEncoding, bool bEmbedd ) { return m_fontCache.GetFont( pszFontName, bBold, bItalic, bSymbolCharset, bEmbedd, pEncoding ); } PdfFont* PdfDocument::CreateFont( const LOGFONTA &logFont, const PdfEncoding * const pEncoding, bool bEmbedd ) { return m_fontCache.GetFont( logFont, bEmbedd, pEncoding ); } PdfFont* PdfDocument::CreateFont( const LOGFONTW &logFont, const PdfEncoding * const pEncoding, bool bEmbedd ) { return m_fontCache.GetFont( logFont, bEmbedd, pEncoding ); } #endif // _WIN32 PdfFont* PdfDocument::CreateFontSubset( const char* pszFontName, bool bBold, bool bItalic, bool bSymbolCharset, const PdfEncoding * const pEncoding, const char* pszFileName ) { return m_fontCache.GetFontSubset( pszFontName, bBold, bItalic, bSymbolCharset, pEncoding, pszFileName ); } #if defined(_WIN32) && !defined(PODOFO_NO_FONTMANAGER) PdfFont* PdfDocument::CreateFontSubset( const wchar_t* pszFontName, bool bBold, bool bItalic, bool bSymbolCharset, const PdfEncoding * const pEncoding) { PODOFO_RAISE_ERROR_INFO( ePdfError_Unknown, "Subsets are not yet implemented for unicode on windows." ); } #endif // _WIN32 PdfFont* PdfDocument::CreateFont( FT_Face face, bool bSymbolCharset, const PdfEncoding * const pEncoding, bool bEmbedd ) { return m_fontCache.GetFont( face, bSymbolCharset, bEmbedd, pEncoding ); } PdfFont* PdfDocument::CreateDuplicateFontType1( PdfFont * pFont, const char * pszSuffix ) { return m_fontCache.GetDuplicateFontType1( pFont, pszSuffix ); } PdfPage* PdfDocument::CreatePage( const PdfRect & rSize ) { return m_pPagesTree->CreatePage( rSize ); } void PdfDocument::CreatePages( const std::vector& vecSizes ) { m_pPagesTree->CreatePages( vecSizes ); } PdfPage* PdfDocument::InsertPage( const PdfRect & rSize, int atIndex) { return m_pPagesTree->InsertPage( rSize, atIndex ); } void PdfDocument::EmbedSubsetFonts() { m_fontCache.EmbedSubsetFonts(); } const PdfDocument & PdfDocument::Append( const PdfMemDocument & rDoc, bool bAppendAll ) { unsigned int difference = static_cast(m_vecObjects.GetSize() + m_vecObjects.GetFreeObjects().size()); // Ulrich Arnold 30.7.2009: Because GetNextObject uses m_nObjectCount instead // of m_vecObjects.GetSize()+m_vecObjects.GetFreeObjects().size()+1 // make sure the free objects are already present before appending to // prevent overlapping obj-numbers // create all free objects again, to have a clean free object list TCIPdfReferenceList itFree = rDoc.GetObjects().GetFreeObjects().begin(); while( itFree != rDoc.GetObjects().GetFreeObjects().end() ) { m_vecObjects.AddFreeObject( PdfReference( (*itFree).ObjectNumber() + difference, (*itFree).GenerationNumber() ) ); ++itFree; } // append all objects first and fix their references TCIVecObjects it = rDoc.GetObjects().begin(); while( it != rDoc.GetObjects().end() ) { PdfObject* pObj = new PdfObject( PdfReference( static_cast((*it)->Reference().ObjectNumber() + difference), (*it)->Reference().GenerationNumber() ), *(*it) ); m_vecObjects.push_back( pObj ); if( (*it)->IsDictionary() && (*it)->HasStream() ) *(pObj->GetStream()) = *((*it)->GetStream()); PdfError::LogMessage( eLogSeverity_Information, "Fixing references in %i %i R by %i\n", pObj->Reference().ObjectNumber(), pObj->Reference().GenerationNumber(), difference ); FixObjectReferences( pObj, difference ); ++it; } if( bAppendAll ) { const PdfName inheritableAttributes[] = { PdfName("Resources"), PdfName("MediaBox"), PdfName("CropBox"), PdfName("Rotate"), PdfName::KeyNull }; // append all pages now to our page tree for(int i=0;iGetObject()->Reference().ObjectNumber() + difference, pPage->GetObject()->Reference().GenerationNumber() ) ); if( pObj->IsDictionary() && pObj->GetDictionary().HasKey( "Parent" ) ) pObj->GetDictionary().RemoveKey( "Parent" ); // Deal with inherited attributes const PdfName* pInherited = inheritableAttributes; while( pInherited->GetLength() != 0 ) { const PdfObject* pAttribute = pPage->GetInheritedKey( *pInherited ); if( pAttribute ) { PdfObject attribute( *pAttribute ); FixObjectReferences( &attribute, difference ); pObj->GetDictionary().AddKey( *pInherited, attribute ); } ++pInherited; } m_pPagesTree->InsertPage( this->GetPageCount()-1, pObj ); } // append all outlines PdfOutlineItem* pRoot = this->GetOutlines(); PdfOutlines* pAppendRoot = const_cast(rDoc).GetOutlines( PoDoFo::ePdfDontCreateObject ); if( pAppendRoot && pAppendRoot->First() ) { // only append outlines if appended document has outlines while( pRoot && pRoot->Next() ) pRoot = pRoot->Next(); PdfReference ref( pAppendRoot->First()->GetObject()->Reference().ObjectNumber() + difference, pAppendRoot->First()->GetObject()->Reference().GenerationNumber() ); pRoot->InsertChild( new PdfOutlines( m_vecObjects.GetObject( ref ) ) ); } } // TODO: merge name trees // ToDictionary -> then iteratate over all keys and add them to the new one return *this; } const PdfDocument &PdfDocument::InsertExistingPageAt( const PdfMemDocument & rDoc, int nPageIndex, int nAtIndex) { /* copy of PdfDocument::Append, only restricts which page to add */ unsigned int difference = static_cast(m_vecObjects.GetSize() + m_vecObjects.GetFreeObjects().size()); // Ulrich Arnold 30.7.2009: Because GetNextObject uses m_nObjectCount instead // of m_vecObjects.GetSize()+m_vecObjects.GetFreeObjects().size()+1 // make sure the free objects are already present before appending to // prevent overlapping obj-numbers // create all free objects again, to have a clean free object list TCIPdfReferenceList itFree = rDoc.GetObjects().GetFreeObjects().begin(); while( itFree != rDoc.GetObjects().GetFreeObjects().end() ) { m_vecObjects.AddFreeObject( PdfReference( (*itFree).ObjectNumber() + difference, (*itFree).GenerationNumber() ) ); ++itFree; } // append all objects first and fix their references TCIVecObjects it = rDoc.GetObjects().begin(); while( it != rDoc.GetObjects().end() ) { PdfObject* pObj = new PdfObject( PdfReference( static_cast((*it)->Reference().ObjectNumber() + difference), (*it)->Reference().GenerationNumber() ), *(*it) ); m_vecObjects.push_back( pObj ); if( (*it)->IsDictionary() && (*it)->HasStream() ) *(pObj->GetStream()) = *((*it)->GetStream()); PdfError::LogMessage( eLogSeverity_Information, "Fixing references in %i %i R by %i\n", pObj->Reference().ObjectNumber(), pObj->Reference().GenerationNumber(), difference ); FixObjectReferences( pObj, difference ); ++it; } const PdfName inheritableAttributes[] = { PdfName("Resources"), PdfName("MediaBox"), PdfName("CropBox"), PdfName("Rotate"), PdfName::KeyNull }; // append all pages now to our page tree for(int i=0;iGetObject()->Reference().ObjectNumber() + difference, pPage->GetObject()->Reference().GenerationNumber() ) ); if( pObj->IsDictionary() && pObj->GetDictionary().HasKey( "Parent" ) ) pObj->GetDictionary().RemoveKey( "Parent" ); // Deal with inherited attributes const PdfName* pInherited = inheritableAttributes; while( pInherited->GetLength() != 0 ) { const PdfObject* pAttribute = pPage->GetInheritedKey( *pInherited ); if( pAttribute ) { PdfObject attribute( *pAttribute ); FixObjectReferences( &attribute, difference ); pObj->GetDictionary().AddKey( *pInherited, attribute ); } ++pInherited; } m_pPagesTree->InsertPage( nAtIndex <= 0 ? ePdfPageInsertionPoint_InsertBeforeFirstPage : nAtIndex - 1, pObj ); } // append all outlines PdfOutlineItem* pRoot = this->GetOutlines(); PdfOutlines* pAppendRoot = const_cast(rDoc).GetOutlines( PoDoFo::ePdfDontCreateObject ); if( pAppendRoot && pAppendRoot->First() ) { // only append outlines if appended document has outlines while( pRoot && pRoot->Next() ) pRoot = pRoot->Next(); PdfReference ref( pAppendRoot->First()->GetObject()->Reference().ObjectNumber() + difference, pAppendRoot->First()->GetObject()->Reference().GenerationNumber() ); pRoot->InsertChild( new PdfOutlines( m_vecObjects.GetObject( ref ) ) ); } // TODO: merge name trees // ToDictionary -> then iteratate over all keys and add them to the new one return *this; } PdfRect PdfDocument::FillXObjectFromDocumentPage( PdfXObject * pXObj, const PdfMemDocument & rDoc, int nPage, bool bUseTrimBox ) { unsigned int difference = static_cast(m_vecObjects.GetSize() + m_vecObjects.GetFreeObjects().size()); Append( rDoc, false ); PdfPage* pPage = rDoc.GetPage( nPage ); return FillXObjectFromPage( pXObj, pPage, bUseTrimBox, difference ); } PdfRect PdfDocument::FillXObjectFromExistingPage( PdfXObject * pXObj, int nPage, bool bUseTrimBox ) { PdfPage* pPage = GetPage( nPage ); return FillXObjectFromPage( pXObj, pPage, bUseTrimBox, 0 ); } PdfRect PdfDocument::FillXObjectFromPage( PdfXObject * pXObj, const PdfPage * pPage, bool bUseTrimBox, unsigned int difference ) { // TODO: remove unused objects: page, ... PdfObject* pObj = m_vecObjects.GetObject( PdfReference( pPage->GetObject()->Reference().ObjectNumber() + difference, pPage->GetObject()->Reference().GenerationNumber() ) ); PdfRect box = pPage->GetMediaBox(); // intersect with crop-box box.Intersect( pPage->GetCropBox() ); // intersect with trim-box according to parameter if ( bUseTrimBox ) box.Intersect( pPage->GetTrimBox() ); // link resources from external doc to x-object if( pObj->IsDictionary() && pObj->GetDictionary().HasKey( "Resources" ) ) pXObj->GetContentsForAppending()->GetDictionary().AddKey( "Resources" , pObj->GetDictionary().GetKey( "Resources" ) ); // copy top-level content from external doc to x-object if( pObj->IsDictionary() && pObj->GetDictionary().HasKey( "Contents" ) ) { // get direct pointer to contents PdfObject* pContents; if( pObj->GetDictionary().GetKey( "Contents" )->IsReference() ) pContents = m_vecObjects.GetObject( pObj->GetDictionary().GetKey( "Contents" )->GetReference() ); else pContents = pObj->GetDictionary().GetKey( "Contents" ); if( pContents->IsArray() ) { // copy array as one stream to xobject PdfArray pArray = pContents->GetArray(); PdfObject* pObj = pXObj->GetContentsForAppending(); PdfStream* pObjStream = pObj->GetStream(); TVecFilters vFilters; vFilters.push_back( ePdfFilter_FlateDecode ); pObjStream->BeginAppend( vFilters ); TIVariantList it; for(it = pArray.begin(); it != pArray.end(); it++) { if ( it->IsReference() ) { // TODO: not very efficient !! PdfObject* pObj = GetObjects()->GetObject( it->GetReference() ); while (pObj!=NULL) { if (pObj->IsReference()) // Recursively look for the stream { pObj = GetObjects()->GetObject( pObj->GetReference() ); } else if (pObj->HasStream()) { PdfStream* pcontStream = pObj->GetStream(); char* pcontStreamBuffer; pdf_long pcontStreamLength; pcontStream->GetFilteredCopy( &pcontStreamBuffer, &pcontStreamLength ); pObjStream->Append( pcontStreamBuffer, pcontStreamLength ); podofo_free( pcontStreamBuffer ); break; } else { PODOFO_RAISE_ERROR( ePdfError_InvalidStream ); break; } } } else { string str; it->ToString( str ); pObjStream->Append( str ); pObjStream->Append( " " ); } } pObjStream->EndAppend(); } else if( pContents->HasStream() ) { // copy stream to xobject PdfObject* pObj = pXObj->GetContentsForAppending(); PdfStream* pObjStream = pObj->GetStream(); PdfStream* pcontStream = pContents->GetStream(); char* pcontStreamBuffer; pdf_long pcontStreamLength; TVecFilters vFilters; vFilters.push_back( ePdfFilter_FlateDecode ); pObjStream->BeginAppend( vFilters ); pcontStream->GetFilteredCopy( &pcontStreamBuffer, &pcontStreamLength ); pObjStream->Append( pcontStreamBuffer, pcontStreamLength ); podofo_free( pcontStreamBuffer ); pObjStream->EndAppend(); } else { PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } } return box; } void PdfDocument::FixObjectReferences( PdfObject* pObject, int difference ) { if( !pObject ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if( pObject->IsDictionary() ) { TKeyMap::iterator it = pObject->GetDictionary().GetKeys().begin(); while( it != pObject->GetDictionary().GetKeys().end() ) { if( (*it).second->IsReference() ) { *(*it).second = PdfReference( (*it).second->GetReference().ObjectNumber() + difference, (*it).second->GetReference().GenerationNumber() ); } else if( (*it).second->IsDictionary() || (*it).second->IsArray() ) { FixObjectReferences( (*it).second, difference ); } ++it; } } else if( pObject->IsArray() ) { PdfArray::iterator it = pObject->GetArray().begin(); while( it != pObject->GetArray().end() ) { if( (*it).IsReference() ) { (*it) = PdfReference( (*it).GetReference().ObjectNumber() + difference, (*it).GetReference().GenerationNumber() ); } else if( (*it).IsDictionary() || (*it).IsArray() ) FixObjectReferences( &(*it), difference ); ++it; } } else if( pObject->IsReference() ) { *pObject = PdfReference( pObject->GetReference().ObjectNumber() + difference, pObject->GetReference().GenerationNumber() ); } } EPdfPageMode PdfDocument::GetPageMode( void ) const { // PageMode is optional; the default value is UseNone EPdfPageMode thePageMode = ePdfPageModeUseNone; PdfObject* pageModeObj = GetCatalog()->GetIndirectKey( PdfName( "PageMode" ) ); if ( pageModeObj != NULL ) { PdfName pmName = pageModeObj->GetName(); if( PdfName( "UseNone" ) == pmName ) thePageMode = ePdfPageModeUseNone ; else if( PdfName( "UseThumbs" ) == pmName ) thePageMode = ePdfPageModeUseThumbs ; else if( PdfName( "UseOutlines" ) == pmName ) thePageMode = ePdfPageModeUseBookmarks ; else if( PdfName( "FullScreen" ) == pmName ) thePageMode = ePdfPageModeFullScreen ; else if( PdfName( "UseOC" ) == pmName ) thePageMode = ePdfPageModeUseOC ; else if( PdfName( "UseAttachments" ) == pmName ) thePageMode = ePdfPageModeUseAttachments ; else PODOFO_RAISE_ERROR( ePdfError_InvalidName ); } return thePageMode ; } void PdfDocument::SetPageMode( EPdfPageMode inMode ) { switch ( inMode ) { default: case ePdfPageModeDontCare: // GetCatalog()->RemoveKey( PdfName( "PageMode" ) ); // this value means leave it alone! break; case ePdfPageModeUseNone: GetCatalog()->GetDictionary().AddKey( PdfName( "PageMode" ), PdfName( "UseNone" ) ); break; case ePdfPageModeUseThumbs: GetCatalog()->GetDictionary().AddKey( PdfName( "PageMode" ), PdfName( "UseThumbs" ) ); break; case ePdfPageModeUseBookmarks: GetCatalog()->GetDictionary().AddKey( PdfName( "PageMode" ), PdfName( "UseOutlines" ) ); break; case ePdfPageModeFullScreen: GetCatalog()->GetDictionary().AddKey( PdfName( "PageMode" ), PdfName( "FullScreen" ) ); break; case ePdfPageModeUseOC: GetCatalog()->GetDictionary().AddKey( PdfName( "PageMode" ), PdfName( "UseOC" ) ); break; case ePdfPageModeUseAttachments: GetCatalog()->GetDictionary().AddKey( PdfName( "PageMode" ), PdfName( "UseAttachments" ) ); break; } } void PdfDocument::SetUseFullScreen( void ) { // first, we get the current mode EPdfPageMode curMode = GetPageMode(); // if current mode is anything but "don't care", we need to move that to non-full-screen if ( curMode != ePdfPageModeDontCare ) SetViewerPreference( PdfName( "NonFullScreenPageMode" ), PdfObject( *(GetCatalog()->GetIndirectKey( PdfName( "PageMode" ) )) ) ); SetPageMode( ePdfPageModeFullScreen ); } void PdfDocument::SetViewerPreference( const PdfName& whichPref, const PdfObject & valueObj ) { PdfObject* prefsObj = GetCatalog()->GetIndirectKey( PdfName( "ViewerPreferences" ) ); if ( prefsObj == NULL ) { // make me a new one and add it PdfDictionary vpDict; vpDict.AddKey( whichPref, valueObj ); GetCatalog()->GetDictionary().AddKey( PdfName( "ViewerPreferences" ), PdfObject( vpDict ) ); } else { // modify the existing one prefsObj->GetDictionary().AddKey( whichPref, valueObj ); } } void PdfDocument::SetViewerPreference( const PdfName& whichPref, bool inValue ) { SetViewerPreference( whichPref, PdfObject( inValue ) ); } void PdfDocument::SetHideToolbar( void ) { SetViewerPreference( PdfName( "HideToolbar" ), true ); } void PdfDocument::SetHideMenubar( void ) { SetViewerPreference( PdfName( "HideMenubar" ), true ); } void PdfDocument::SetHideWindowUI( void ) { SetViewerPreference( PdfName( "HideWindowUI" ), true ); } void PdfDocument::SetFitWindow( void ) { SetViewerPreference( PdfName( "FitWindow" ), true ); } void PdfDocument::SetCenterWindow( void ) { SetViewerPreference( PdfName( "CenterWindow" ), true ); } void PdfDocument::SetDisplayDocTitle( void ) { SetViewerPreference( PdfName( "DisplayDocTitle" ), true ); } void PdfDocument::SetPrintScaling( PdfName& inScalingType ) { SetViewerPreference( PdfName( "PrintScaling" ), inScalingType ); } void PdfDocument::SetBaseURI( const std::string& inBaseURI ) { PdfDictionary uriDict; uriDict.AddKey( PdfName( "Base" ), new PdfObject( PdfString( inBaseURI ) ) ); GetCatalog()->GetDictionary().AddKey( PdfName( "URI" ), new PdfObject( uriDict ) ); } void PdfDocument::SetLanguage( const std::string& inLanguage ) { GetCatalog()->GetDictionary().AddKey( PdfName( "Lang" ), new PdfObject( PdfString( inLanguage ) ) ); } void PdfDocument::SetBindingDirection( PdfName& inDirection ) { SetViewerPreference( PdfName( "Direction" ), inDirection ); } void PdfDocument::SetPageLayout( EPdfPageLayout inLayout ) { switch ( inLayout ) { default: case ePdfPageLayoutIgnore: break; // means do nothing case ePdfPageLayoutDefault: GetCatalog()->GetDictionary().RemoveKey( PdfName( "PageLayout" ) ); break; case ePdfPageLayoutSinglePage: GetCatalog()->GetDictionary().AddKey( PdfName( "PageLayout" ), PdfName( "SinglePage" ) ); break; case ePdfPageLayoutOneColumn: GetCatalog()->GetDictionary().AddKey( PdfName( "PageLayout" ), PdfName( "OneColumn" ) ); break; case ePdfPageLayoutTwoColumnLeft: GetCatalog()->GetDictionary().AddKey( PdfName( "PageLayout" ), PdfName( "TwoColumnLeft" ) ); break; case ePdfPageLayoutTwoColumnRight: GetCatalog()->GetDictionary().AddKey( PdfName( "PageLayout" ), PdfName( "TwoColumnRight" ) ); break; case ePdfPageLayoutTwoPageLeft: GetCatalog()->GetDictionary().AddKey( PdfName( "PageLayout" ), PdfName( "TwoPageLeft" ) ); break; case ePdfPageLayoutTwoPageRight: GetCatalog()->GetDictionary().AddKey( PdfName( "PageLayout" ), PdfName( "TwoPageRight" ) ); break; } } PdfOutlines* PdfDocument::GetOutlines( bool bCreate ) { PdfObject* pObj; if( !m_pOutlines ) { pObj = GetNamedObjectFromCatalog( "Outlines" ); if( !pObj ) { if ( !bCreate ) return NULL; m_pOutlines = new PdfOutlines( &m_vecObjects ); this->GetCatalog()->GetDictionary().AddKey( "Outlines", m_pOutlines->GetObject()->Reference() ); } else if ( pObj->GetDataType() != ePdfDataType_Dictionary ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } else m_pOutlines = new PdfOutlines( pObj ); } return m_pOutlines; } PdfNamesTree* PdfDocument::GetNamesTree( bool bCreate ) { PdfObject* pObj; if( !m_pNamesTree ) { pObj = GetNamedObjectFromCatalog( "Names" ); if( !pObj ) { if ( !bCreate ) return NULL; PdfNamesTree tmpTree ( &m_vecObjects ); pObj = tmpTree.GetObject(); this->GetCatalog()->GetDictionary().AddKey( "Names", pObj->Reference() ); m_pNamesTree = new PdfNamesTree( pObj, this->GetCatalog() ); } else if ( pObj->GetDataType() != ePdfDataType_Dictionary ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } else m_pNamesTree = new PdfNamesTree( pObj, this->GetCatalog() ); } return m_pNamesTree; } PdfAcroForm* PdfDocument::GetAcroForm( bool bCreate, EPdfAcroFormDefaulAppearance eDefaultAppearance ) { PdfObject* pObj; if( !m_pAcroForms ) { pObj = GetNamedObjectFromCatalog( "AcroForm" ); if( !pObj ) { if ( !bCreate ) return NULL; m_pAcroForms = new PdfAcroForm( this, eDefaultAppearance ); this->GetCatalog()->GetDictionary().AddKey( "AcroForm", m_pAcroForms->GetObject()->Reference() ); } else if ( pObj->GetDataType() != ePdfDataType_Dictionary ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } else m_pAcroForms = new PdfAcroForm( this, pObj, eDefaultAppearance ); } return m_pAcroForms; } void PdfDocument::AddNamedDestination( const PdfDestination& rDest, const PdfString & rName ) { PdfNamesTree* nameTree = GetNamesTree(); nameTree->AddValue( PdfName("Dests"), rName, rDest.GetObject()->Reference() ); } void PdfDocument::AttachFile( const PdfFileSpec & rFileSpec ) { PdfNamesTree* pNames = this->GetNamesTree( true ); if( !pNames ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } pNames->AddValue( "EmbeddedFiles", rFileSpec.GetFilename(false), rFileSpec.GetObject()->Reference() ); } PdfFileSpec* PdfDocument::GetAttachment( const PdfString & rName ) { PdfNamesTree* pNames = this->GetNamesTree(); if( !pNames ) { return NULL; } PdfObject* pObj = pNames->GetValue( "EmbeddedFiles", rName ); if( !pObj ) { return NULL; } return new PdfFileSpec(pObj); } void PdfDocument::SetInfo( PdfInfo* pInfo ) { delete m_pInfo; m_pInfo = pInfo; } void PdfDocument::SetTrailer( PdfObject* pObject ) { delete m_pTrailer; m_pTrailer = pObject; // Set owner so that GetIndirectKey will work m_pTrailer->SetOwner( &m_vecObjects ); } }; podofo-0.9.5/src/doc/PdfAcroForm.cpp0000664000175000017500000001347113012706242017070 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfAcroForm.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfDictionary.h" #include "PdfDocument.h" #include "PdfFont.h" #include namespace PoDoFo { /* We use NULL for the PdfElement name, since the AcroForm dict does NOT have a /Type key! */ PdfAcroForm::PdfAcroForm( PdfDocument* pDoc, EPdfAcroFormDefaulAppearance eDefaultAppearance ) : PdfElement( NULL, pDoc ), m_pDocument( pDoc ) { // Initialize with an empty fields array this->GetObject()->GetDictionary().AddKey( PdfName("Fields"), PdfArray() ); Init( eDefaultAppearance ); } PdfAcroForm::PdfAcroForm( PdfDocument* pDoc, PdfObject* pObject, EPdfAcroFormDefaulAppearance eDefaultAppearance ) : PdfElement( NULL, pObject ), m_pDocument( pDoc ) { Init( eDefaultAppearance ); } void PdfAcroForm::Init( EPdfAcroFormDefaulAppearance eDefaultAppearance ) { // Add default appearance: black text, 12pt times // -> only if we do not have a DA key yet // Peter Petrov 27 April 2008 //this->GetObject()->GetDictionary().AddKey( PdfName("NeedAppearances"), PdfVariant(true) ); if( !this->GetObject()->GetDictionary().HasKey("DA") && eDefaultAppearance == ePdfAcroFormDefaultAppearance_BlackText12pt ) { PdfFont* pFont = m_pDocument->CreateFont( "Helvetica", false, PdfEncodingFactory::GlobalWinAnsiEncodingInstance(), PdfFontCache::eFontCreationFlags_AutoSelectBase14, false ); //PdfFont* pFont = m_pDocument->CreateFont( "Arial" ); PdfObject* pResource; PdfObject* pFontDict; // Create DR key if( !this->GetObject()->GetDictionary().HasKey( PdfName("DR") ) ) this->GetObject()->GetDictionary().AddKey( PdfName("DR"), PdfDictionary() ); pResource = this->GetObject()->GetDictionary().GetKey( PdfName("DR") ); if( pResource->IsReference() ) pResource = m_pDocument->GetObjects()->GetObject( pResource->GetReference() ); if( !pResource->GetDictionary().HasKey( PdfName("Font") ) ) pResource->GetDictionary().AddKey( PdfName("Font"), PdfDictionary() ); pFontDict = pResource->GetDictionary().GetKey( PdfName("Font") ); if( pFontDict->IsReference() ) pFontDict = m_pDocument->GetObjects()->GetObject( pFontDict->GetReference() ); pFontDict->GetDictionary().AddKey( pFont->GetIdentifier(), pFont->GetObject()->Reference() ); // Create DA key std::ostringstream oss; PdfLocaleImbue(oss); oss << "0 0 0 rg /" << pFont->GetIdentifier().GetName() << " 12 Tf"; this->GetObject()->GetDictionary().AddKey( PdfName("DA"), PdfString( oss.str() ) ); } } /* int PdfAcroForm::GetCount() { PdfObject* pFields = this->GetObject()->GetDictionary().GetKey( PdfName("Fields") ); if( pFields ) { return pFields->GetArray().size(); } else { PODOFO_RAISE_ERROR( ePdfError_NoObject ); } } */ void PdfAcroForm::SetNeedAppearances( bool bNeedAppearances ) { this->GetObject()->GetDictionary().AddKey( PdfName("NeedAppearances"), PdfVariant(bNeedAppearances) ); } bool PdfAcroForm::GetNeedAppearances() const { return this->GetObject()->GetDictionary().GetKeyAsBool( PdfName("NeedAppearances"), false ); } }; podofo-0.9.5/src/doc/PdfFontFactory.h0000664000175000017500000001326612706443377017305 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FONT_FACTORY_H_ #define _PDF_FONT_FACTORY_H_ #include "podofo/base/PdfDefines.h" #include "PdfFont.h" namespace PoDoFo { class PdfFontMetrics; class PdfVecObjects; enum EPdfFontFlags { ePdfFont_Normal = 0x00, ePdfFont_Embedded = 0x01, ePdfFont_Bold = 0x02, ePdfFont_Italic = 0x04, ePdfFont_BoldItalic = ePdfFont_Bold | ePdfFont_Italic, ePdfFont_Subsetting = 0x08 }; /** This is a factory class which knows * which implementation of PdfFont is required * for a certain font type with certain features (like encoding). */ class PODOFO_DOC_API PdfFontFactory { public: /** Create a new PdfFont object. * * \param pMetrics pointer to a font metrics object. The font in the PDF * file will match this fontmetrics object. The metrics object is * deleted along with the created font. In case of an error, it is deleted * here. * \param nFlags font flags or'ed together, specifying the font style and if it should be embedded * \param pEncoding the encoding of this font. * \param pParent the parent of the created font. * * \returns a new PdfFont object or NULL */ static PdfFont* CreateFontObject( PdfFontMetrics* pMetrics, int nFlags, const PdfEncoding* pEncoding, PdfVecObjects* pParent ); /** Create a new PdfFont from an existing * font in a PDF file. * * \param pLibrary handle to the FreeType library, so that a PdfFontMetrics * can be constructed for this font * \param pObject a PDF font object */ static PdfFont* CreateFont( FT_Library* pLibrary, PdfObject* pObject ); /** * Creates a new base-14 font object (of class PdfFontType1Base14) if * the font name (has to include variant) is one of the base 14 fonts. * The font name is to be given as specified (with an ASCII hyphen). * * \param pszFontName ASCII C string (zero-terminated) of the font name * \param eFlags one flag for font variant (Bold, Italic or BoldItalic) * \param pEncoding an encoding compatible with the font * \param pParent a vector of PDF objects to be the font object's owner */ static PdfFont* CreateBase14Font( const char* pszFontName, EPdfFontFlags eFlags, const PdfEncoding * const pEncoding, PdfVecObjects *pParent ); /** Try to guess the fonttype from a the filename of a font file. * * \param pszFilename filename of a fontfile * \returns the font type */ static EPdfFontType GetFontType( const char* pszFilename ); private: // prohibit instantiation of all-methods-static factory from outside PdfFontFactory(); /** Actually creates the font object for the requested type. * Throws an exception in case of an error. * * \returns a new PdfFont object or NULL */ static PdfFont* CreateFontForType( EPdfFontType eType, PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, bool bEmbed, bool bSubsetting, PdfVecObjects* pParent ); }; }; #endif /* _PDF_FONT_FACTORY_H_ */ podofo-0.9.5/src/doc/PdfMemDocument.h0000664000175000017500000007154213013116642017245 0ustar dominikdominik/************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_MEM_DOCUMENT_H_ #define _PDF_MEM_DOCUMENT_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfObject.h" #include "podofo/base/PdfExtension.h" #include "PdfDocument.h" #include "PdfFontCache.h" namespace PoDoFo { class PdfAcroForm; class PdfDestination; class PdfDictionary; class PdfEncrypt; class PdfFileSpec; class PdfFont; class PdfInfo; class PdfNamesTree; class PdfOutlines; class PdfPage; class PdfPagesTree; class PdfParser; class PdfRect; class PdfWriter; /** PdfMemDocument is the core class for reading and manipulating * PDF files and writing them back to disk. * * PdfMemDocument was designed to allow easy access to the object * structur of a PDF file. * * PdfMemDocument should be used whenever you want to change * the object structure of a PDF file. * * When you are only creating PDF files, please use PdfStreamedDocument * which is usually faster for creating PDFs. * * \see PdfDocument * \see PdfStreamedDocument * \see PdfParser * \see PdfWriter */ class PODOFO_DOC_API PdfMemDocument : public PdfDocument { friend class PdfWriter; public: /** Construct a new (empty) PdfMemDocument */ PdfMemDocument(); /** Construct a new (empty) PdfMemDocument */ PdfMemDocument( bool bOnlyTrailer ); /** Construct a PdfMemDocument from an existing PDF (on disk) * \param pszFilename filename of the file which is going to be parsed/opened * \param bForUpdate whether to load for incremental update * * This might throw a PdfError( ePdfError_InvalidPassword ) exception * if a password is required to read this PDF. * Call SetPassword with the correct password in this case. * * When the bForUpdate is set to true, the pszFilename is copied * for later use by WriteUpdate. * * \see SetPassword, WriteUpdate */ PdfMemDocument( const char* pszFilename, bool bForUpdate = false ); #ifdef _WIN32 #if defined(_MSC_VER) && _MSC_VER <= 1200 // not for MS Visual Studio 6 #else /** Construct a PdfMemDocument from an existing PDF (on disk) * \param pszFilename filename of the file which is going to be parsed/opened * \param bForUpdate whether to load for incremental update * * This might throw a PdfError( ePdfError_InvalidPassword ) exception * if a password is required to read this PDF. * Call SetPassword with the correct password in this case. * * When the bForUpdate is set to true, the pszFilename is copied * for later use by WriteUpdate. * * This is an overloaded member function to allow working * with unicode characters. On Unix systems you can also path * UTF-8 to the const char* overload. * * \see SetPassword, WriteUpdate */ PdfMemDocument( const wchar_t* pszFilename, bool bForUpdate = false ); #endif #endif // _WIN32 /** Close down/destruct the PdfMemDocument */ virtual ~PdfMemDocument(); /** Load a PdfMemDocument from a file * * \param pszFilename filename of the file which is going to be parsed/opened * \param bForUpdate whether to load for incremental update * * This might throw a PdfError( ePdfError_InvalidPassword ) exception * if a password is required to read this PDF. * Call SetPassword with the correct password in this case. * * When the bForUpdate is set to true, the pszFilename is copied * for later use by WriteUpdate. * * \see SetPassword, WriteUpdate */ void Load( const char* pszFilename, bool bForUpdate = false ); #ifdef _WIN32 /** Load a PdfMemDocument from a file * * \param pszFilename filename of the file which is going to be parsed/opened * \param bForUpdate whether to load for incremental update * * This might throw a PdfError( ePdfError_InvalidPassword ) exception * if a password is required to read this PDF. * Call SetPassword with the correct password in this case. * * When the bForUpdate is set to true, the pszFilename is copied * for later use by WriteUpdate. * * This is an overloaded member function to allow working * with unicode characters. On Unix systems you can also path * UTF-8 to the const char* overload. * * \see SetPassword, WriteUpdate */ void Load( const wchar_t* pszFilename, bool bForUpdate = false ); #endif // _WIN32 /** Load a PdfMemDocument from a buffer in memory * * \param pBuffer a memory area containing the PDF data * \param lLen length of the buffer * \param bForUpdate whether to load for incremental update * * This might throw a PdfError( ePdfError_InvalidPassword ) exception * if a password is required to read this PDF. * Call SetPassword with the correct password in this case. * * When the bForUpdate is set to true, the memory buffer is copied * for later use by WriteUpdate. * * \see SetPassword, WriteUpdate */ void Load( const char* pBuffer, long lLen, bool bForUpdate = false ); /** Load a PdfMemDocument from a PdfRefCountedInputDevice * * \param rDevice the input device containing the PDF * \param bForUpdate whether to load for incremental update * * This might throw a PdfError( ePdfError_InvalidPassword ) exception * if a password is required to read this PDF. * Call SetPassword with the correct password in this case. * * When the bForUpdate is set to true, the rDevice is referenced * for later use by WriteUpdate. * * \see SetPassword, WriteUpdate */ void Load( const PdfRefCountedInputDevice & rDevice, bool bForUpdate = false ); /** Returns whether the document is fully loaded. */ inline bool IsLoaded( void ) const; /** Writes the complete document to a file * * \param pszFilename filename of the document * * \see Write, WriteUpdate * * This is an overloaded member function for your convenience. */ void Write( const char* pszFilename ); #ifdef _WIN32 /** Writes the complete document to a file * * \param pszFilename filename of the document * * \see Write, WriteUpdate * * This is an overloaded member function to allow working * with unicode characters. On Unix systems you can also path * UTF-8 to the const char* overload. * * This is an overloaded member function for your convenience. */ void Write( const wchar_t* pszFilename ); #endif // _WIN32 /** Writes the complete document to an output device * * \param pDevice write to this output device * * \see WriteUpdate */ void Write( PdfOutputDevice* pDevice ); /** Writes the document changes to a file * * \param pszFilename filename of the document * * Writes the document changes to a file as an incremental update. * The document should be loaded with bForUpdate = true, otherwise * an exception is thrown. * * Beware when overwriting existing files. Plain file overwrite is allowed * only if the document was loaded with the same filename (and the same overloaded * function), otherwise the destination file cannot be the same as the source file, * because the destination file is truncated first and only then the source file * content is copied into it. * * \see Write, WriteUpdate * * This is an overloaded member function for your convenience. */ void WriteUpdate( const char* pszFilename ); #ifdef _WIN32 /** Writes the document changes to a file * * \param pszFilename filename of the document * * Writes the document changes to a file as an incremental update. * The document should be loaded with bForUpdate = true, otherwise * an exception is thrown. * * Beware when overwriting existing files. Plain file overwrite is allowed * only if the document was loaded with the same filename (and the same overloaded * function), otherwise the destination file cannot be the same as the source file, * because the destination file is truncated first and only then the source file * content is copied into it. * * \see Write, WriteUpdate * * This is an overloaded member function to allow working * with unicode characters. On Unix systems you can also path * UTF-8 to the const char* overload. * * This is an overloaded member function for your convenience. */ void WriteUpdate( const wchar_t* pszFilename ); #endif // _WIN32 /** Writes the document changes to an output device * * \param pDevice write to this output device * \param bTruncate whether to truncate the pDevice first and fill it * with the content of the source document; the default is true. * * Writes the document changes to the output device as an incremental update. * The document should be loaded with bForUpdate = true, otherwise * an exception is thrown. * * The bTruncate is used to determine whether saving to the same file or not. * In case the bTruncate is true, a new source stream is opened and its whole * content is copied to the pDevice first. Otherwise the pDevice is the same * file which had been loaded and the caller is responsible to position * the pDevice at the place, where the update should be written (basically * at the end of the stream). * * \see Write, WriteUpdate */ void WriteUpdate( PdfOutputDevice* pDevice, bool bTruncate = true ); /** Set the write mode to use when writing the PDF. * \param eWriteMode write mode */ void SetWriteMode( EPdfWriteMode eWriteMode ) { m_eWriteMode = eWriteMode; } /** Get the write mode used for wirting the PDF * \returns the write mode */ virtual EPdfWriteMode GetWriteMode() const { return m_eWriteMode; } /** Set the PDF Version of the document. Has to be called before Write() to * have an effect. * \param eVersion version of the pdf document */ void SetPdfVersion( EPdfVersion eVersion ) { m_eVersion = eVersion;} /** Get the PDF version of the document * \returns EPdfVersion version of the pdf document */ EPdfVersion GetPdfVersion() const { return m_eVersion; } /** Add a vendor-specific extension to the current PDF version. * \param ns namespace of the extension * \param level level of the extension */ void AddPdfExtension( const char* ns, pdf_int64 level ); /** Checks whether the documents is tagged to imlpement a vendor-specific * extension to the current PDF version. * \param ns namespace of the extension * \param level level of the extension */ bool HasPdfExtension( const char* ns, pdf_int64 level ) const; /** Remove a vendor-specific extension to the current PDF version. * \param ns namespace of the extension * \param level level of the extension */ void RemovePdfExtension( const char* ns, pdf_int64 level ); /** Return the list of all vendor-specific extensions to the current PDF version. * \param ns namespace of the extension * \param level level of the extension */ std::vector GetPdfExtensions() const; /** If you try to open an encrypted PDF file, which requires * a password to open, PoDoFo will throw a PdfError( ePdfError_InvalidPassword ) * exception. * * If you got such an exception, you have to set a password * which should be used for opening the PDF. * * The usual way will be to ask the user for the password * and set the password using this method. * * PdfParser will immediately continue to read the PDF file. * * \param sPassword a user or owner password which can be used to open an encrypted PDF file * If the password is invalid, a PdfError( ePdfError_InvalidPassword ) exception is thrown! */ void SetPassword( const std::string & sPassword ); /** Encrypt the document during writing. * * \param userPassword the user password (if empty the user does not have * to enter a password to open the document) * \param ownerPassword the owner password * \param protection several EPdfPermissions values or'ed together to set * the users permissions for this document * \param eAlgorithm the revision of the encryption algorithm to be used * \param eKeyLength the length of the encryption key ranging from 40 to 256 bits * (only used if eAlgorithm >= ePdfEncryptAlgorithm_RC4V2) * * \see PdfEncrypt */ void SetEncrypted( const std::string & userPassword, const std::string & ownerPassword, int protection = PdfEncrypt::ePdfPermissions_Print | PdfEncrypt::ePdfPermissions_Edit | PdfEncrypt::ePdfPermissions_Copy | PdfEncrypt::ePdfPermissions_EditNotes | PdfEncrypt::ePdfPermissions_FillAndSign | PdfEncrypt::ePdfPermissions_Accessible | PdfEncrypt::ePdfPermissions_DocAssembly | PdfEncrypt::ePdfPermissions_HighPrint, PdfEncrypt::EPdfEncryptAlgorithm eAlgorithm = PdfEncrypt::ePdfEncryptAlgorithm_AESV2, PdfEncrypt::EPdfKeyLength eKeyLength = PdfEncrypt::ePdfKeyLength_40 ); /** Encrypt the document during writing using a PdfEncrypt object * * \param pEncrypt an encryption object that will be owned by PdfMemDocument */ void SetEncrypted( const PdfEncrypt & pEncrypt ); /** * \returns true if this PdfMemDocument creates an encrypted PDF file */ bool GetEncrypted() const { return (m_pEncrypt != NULL); } /** Returns wether this PDF document is linearized, aka * weboptimized * \returns true if the PDF document is linearized */ bool IsLinearized() const { return m_bLinearized; } /** Get a reference to the sorted internal objects vector. * \returns the internal objects vector. */ const PdfVecObjects & GetObjects() const { return *(PdfDocument::GetObjects()); } /** Get a reference to the sorted internal objects vector. * This is an overloaded function for your convinience. * \returns the internal objects vector. */ PdfVecObjects & GetObjects() { return *(PdfDocument::GetObjects()); } /** Get access to the internal Catalog dictionary * or root object. * * \returns PdfObject the documents catalog or NULL * if no catalog is available */ PdfObject* GetCatalog() { return PdfDocument::GetCatalog(); } /** Get access to the internal Catalog dictionary * or root object. * * \returns PdfObject the documents catalog or NULL * if no catalog is available */ const PdfObject* GetCatalog() const { return PdfDocument::GetCatalog(); } /** Get the trailer dictionary * which can be written unmodified to a pdf file. */ const PdfObject* GetTrailer() const { return PdfDocument::GetTrailer(); } /** Get access to the StructTreeRoot dictionary * \returns PdfObject the StructTreeRoot dictionary */ PdfObject* GetStructTreeRoot() const { return GetNamedObjectFromCatalog( "StructTreeRoot" ); } /** Get access to the Metadata stream * \returns PdfObject the Metadata stream (should be in XML, using XMP grammar) */ PdfObject* GetMetadata() const { return GetNamedObjectFromCatalog( "Metadata" ); } /** Get access to the MarkInfo dictionary (ISO 32000-1:2008 14.7.1) * \returns PdfObject the MarkInfo dictionary */ PdfObject* GetMarkInfo() const { return GetNamedObjectFromCatalog( "MarkInfo" ); } /** Get access to the RFC 3066 natural language id for the document (ISO 32000-1:2008 14.9.2.1) * \returns PdfObject the language ID string */ PdfObject* GetLanguage() const { return GetNamedObjectFromCatalog( "Lang" ); } /** Creates a PdfFont object from an existing font. * * \param pObject a PdfObject that is a font * \returns PdfFont* a pointer to a new PdfFont object. * The returned object is owned by the PdfDocument. */ PdfFont* GetFont( PdfObject* pObject ); /** Copies one or more pages from another PdfMemDocument to this document * \param rDoc the document to append * \param inFirstPage the first page number to copy (0-based) * \param inNumPages the number of pages to copy * \returns this document */ const PdfMemDocument & InsertPages( const PdfMemDocument & rDoc, int inFirstPage, int inNumPages ); /** Deletes one or more pages from this document * It does NOT remove any PdfObjects from memory - just the reference from the pages tree. * If you want to delete resources of this page, you have to delete them yourself, * but the resources might be used by other pages, too. * * \param inFirstPage the first page number to delete (0-based) * \param inNumPages the number of pages to delete * \returns this document */ void DeletePages( int inFirstPage, int inNumPages ); /** Checks if printing this document is allowed. * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to print this document * * \see PdfEncrypt to set own document permissions. */ inline virtual bool IsPrintAllowed() const; /** Checks if modifiying this document (besides annotations, form fields or changing pages) is allowed. * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to modfiy this document * * \see PdfEncrypt to set own document permissions. */ inline virtual bool IsEditAllowed() const; /** Checks if text and graphics extraction is allowed. * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to extract text and graphics from this document * * \see PdfEncrypt to set own document permissions. */ inline virtual bool IsCopyAllowed() const; /** Checks if it is allowed to add or modify annotations or form fields * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to add or modify annotations or form fields * * \see PdfEncrypt to set own document permissions. */ inline virtual bool IsEditNotesAllowed() const; /** Checks if it is allowed to fill in existing form or signature fields * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to fill in existing form or signature fields * * \see PdfEncrypt to set own document permissions. */ inline virtual bool IsFillAndSignAllowed() const; /** Checks if it is allowed to extract text and graphics to support users with disabillities * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to extract text and graphics to support users with disabillities * * \see PdfEncrypt to set own document permissions. */ inline virtual bool IsAccessibilityAllowed() const; /** Checks if it is allowed to insert, create, rotate, delete pages or add bookmarks * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to insert, create, rotate, delete pages or add bookmarks * * \see PdfEncrypt to set own document permissions. */ inline virtual bool IsDocAssemblyAllowed() const; /** Checks if it is allowed to print a high quality version of this document * Every PDF consuming applications has to adhere this value! * * \returns true if you are allowed to print a high quality version of this document * * \see PdfEncrypt to set own document permissions. */ inline virtual bool IsHighPrintAllowed() const; /** Tries to free all memory allocated by the given * PdfObject (variables and streams) and reads * it from disk again if it is requested another time. * * This will only work if load on demand is used. Other- * wise any call to this method will be ignored. Load on * demand is currently always enabled when using PdfMemDocument. * If the object is dirty if will not be free'd. * * \param rRef free all memory allocated by the object * with this reference. * \param bForce if true the object will be free'd * even if IsDirty() returns true. * So you will loose any changes made * to this object. * * This is an overloaded member for your convinience. */ void FreeObjectMemory( const PdfReference & rRef, bool bForce = false ); /** Tries to free all memory allocated by the given * PdfObject (variables and streams) and reads * it from disk again if it is requested another time. * * This will only work if load on demand is used. Other- * wise any call to this method will be ignored. Load on * demand is currently always enabled when using PdfMemDocument. * If the object is dirty if will not be free'd. * * \param pObj free object from memory * \param bForce if true the object will be free'd * even if IsDirty() returns true. * So you will loose any changes made * to this object. * * \see IsDirty */ void FreeObjectMemory( PdfObject* pObj, bool bForce = false ); /** * \returns the parsers encryption object or NULL if the read PDF file was not encrypted */ inline const PdfEncrypt* GetEncrypt() const; private: /** Get a dictioary from the catalog dictionary by its name. * \param pszName will be converted into a PdfName * \returns the dictionary if it was found or NULL */ PdfObject* GetNamedObjectFromCatalog( const char* pszName ) const; /** Internal method to load all objects from a PdfParser object. * The objects will be removed from the parser and are now * owned by the PdfMemDocument. */ void InitFromParser( PdfParser* pParser ); /** Clear all internal variables */ void Clear(); /** Low level APIs for setting a viewer preference * \param whichPrefs the dictionary key to set * \param the object to be set */ void SetViewerPreference( const PdfName& whichPref, const PdfObject & valueObj ) const; void SetViewerPreference( const PdfName& whichPref, bool inValue ) const; private: // Prevent use of copy constructor and assignment operator. These methods // should never be referenced (given that code referencing them outside // PdfMemDocument won't compile), and calling them will result in a link error // as they're not defined. explicit PdfMemDocument(const PdfMemDocument&); PdfMemDocument& operator=(const PdfMemDocument&); bool m_bLinearized; EPdfVersion m_eVersion; PdfEncrypt* m_pEncrypt; PdfParser* m_pParser; ///< This will be temporarily initialized to a PdfParser object so that SetPassword can work EPdfWriteMode m_eWriteMode; bool m_bSoureHasXRefStream; EPdfVersion m_eSourceVersion; pdf_int64 m_lPrevXRefOffset; #ifdef _WIN32 wchar_t *m_wchar_pszUpdatingFilename; #endif char *m_pszUpdatingFilename; PdfRefCountedInputDevice *m_pUpdatingInputDevice; inline bool IsLoadedForUpdate( void ) const; }; // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfMemDocument::IsLoaded( void ) const { return m_pParser == NULL; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfMemDocument::IsPrintAllowed() const { return m_pEncrypt ? m_pEncrypt->IsPrintAllowed() : true; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfMemDocument::IsEditAllowed() const { return m_pEncrypt ? m_pEncrypt->IsEditAllowed() : true; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfMemDocument::IsCopyAllowed() const { return m_pEncrypt ? m_pEncrypt->IsCopyAllowed() : true; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfMemDocument::IsEditNotesAllowed() const { return m_pEncrypt ? m_pEncrypt->IsEditNotesAllowed() : true; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfMemDocument::IsFillAndSignAllowed() const { return m_pEncrypt ? m_pEncrypt->IsFillAndSignAllowed() : true; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfMemDocument::IsAccessibilityAllowed() const { return m_pEncrypt ? m_pEncrypt->IsAccessibilityAllowed() : true; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfMemDocument::IsDocAssemblyAllowed() const { return m_pEncrypt ? m_pEncrypt->IsDocAssemblyAllowed() : true; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfMemDocument::IsHighPrintAllowed() const { return m_pEncrypt ? m_pEncrypt->IsHighPrintAllowed() : true; } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfEncrypt* PdfMemDocument::GetEncrypt() const { return m_pEncrypt; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfMemDocument::IsLoadedForUpdate( void ) const { return m_pszUpdatingFilename || #ifdef _WIN32 m_wchar_pszUpdatingFilename || #endif m_pUpdatingInputDevice; } }; #endif // _PDF_MEM_DOCUMENT_H_ podofo-0.9.5/src/doc/PdfAction.h0000664000175000017500000001260212344436402016242 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_ACTION_H_ #define _PDF_ACTION_H_ #include "podofo/base/PdfDefines.h" #include "PdfElement.h" namespace PoDoFo { class PdfObject; class PdfString; class PdfStreamedDocument; class PdfVecObjects; /** The type of the action. * PDF supports different action types, each of * them has different keys and propeties. * * Not all action types listed here are supported yet. * * Please make also sure that the action type you use is * supported by the PDF version you are using. */ enum EPdfAction { ePdfAction_GoTo = 0, ePdfAction_GoToR, ePdfAction_GoToE, ePdfAction_Launch, ePdfAction_Thread, ePdfAction_URI, ePdfAction_Sound, ePdfAction_Movie, ePdfAction_Hide, ePdfAction_Named, ePdfAction_SubmitForm, ePdfAction_ResetForm, ePdfAction_ImportData, ePdfAction_JavaScript, ePdfAction_SetOCGState, ePdfAction_Rendition, ePdfAction_Trans, ePdfAction_GoTo3DView, ePdfAction_RichMediaExecute, ePdfAction_Unknown = 0xff }; /** An action that can be performed in a PDF document */ class PODOFO_DOC_API PdfAction : public PdfElement { friend class PdfAnnotation; public: /** Create a new PdfAction object * \param eAction type of this action * \param pParent parent of this action */ PdfAction( EPdfAction eAction, PdfVecObjects* pParent ); /** Create a new PdfAction object * \param eAction type of this action * \param pParent parent of this action */ PdfAction( EPdfAction eAction, PdfDocument* pParent ); virtual ~PdfAction() { } /** Create a PdfAction object from an existing * PdfObject */ PdfAction( PdfObject* pObject ); /** Set the URI of an ePdfAction_URI * \param sUri must be a correct URI as PdfString */ void SetURI( const PdfString & sUri ); /** Get the URI of an ePdfAction_URI * \returns an URI */ PdfString GetURI() const; /** * \returns true if this action has an URI */ bool HasURI() const; void SetScript( const PdfString & sScript ); PdfString GetScript() const; bool HasScript() const; /** Get the type of this action * \returns the type of this action */ inline EPdfAction GetType() const; /** Adds this action to an dictionary. * This method handles the all the complexities of making sure it's added correctly * * If this action is empty. Nothing will be added. * * \param dictionary the action will be added to this dictionary */ void AddToDictionary( PdfDictionary & dictionary ) const; private: PdfAction( const PdfAction & rhs ); private: static const long s_lNumActions; static const char* s_names[]; private: EPdfAction m_eType; }; // ----------------------------------------------------- // // ----------------------------------------------------- inline EPdfAction PdfAction::GetType() const { return m_eType; } }; #endif // _PDF_ACTION_H_ podofo-0.9.5/src/doc/PdfFontType3.h0000664000175000017500000001040612344436554016670 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FONT_TYPE3_H_ #define _PDF_FONT_TYPE3_H_ #include "podofo/base/PdfDefines.h" #include "PdfFontSimple.h" namespace PoDoFo { /** A PdfFont implementation that can be used * to embedd type3 fonts into a PDF file * or to draw with type3 fonts. * * Type3 fonts are always embedded. */ class PdfFontType3 : public PdfFontSimple { public: /** Create a new Type3 font. * * It will get embedded automatically. * * \param pMetrics pointer to a font metrics object. The font in the PDF * file will match this fontmetrics object. The metrics object is * deleted along with the font. * \param pEncoding the encoding of this font. The font will take ownership of this object * depending on pEncoding->IsAutoDelete() * \param pParent parent of the font object * \param bEmbed if true the font will get embedded. * */ PdfFontType3( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfVecObjects* pParent, bool bEmbed ); /** Create a PdfFont based on an existing PdfObject * \param pMetrics pointer to a font metrics object. The font in the PDF * file will match this fontmetrics object. The metrics object is * deleted along with the font. * \param pEncoding the encoding of this font. The font will take ownership of this object * depending on pEncoding->IsAutoDelete() * \param pObject an existing PdfObject */ PdfFontType3( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfObject* pObject ); private: /** Embed the font file directly into the PDF file. * * \param pDescriptor font descriptor object */ void EmbedFontFile( PdfObject* pDescriptor ); }; }; #endif // _PDF_FONT_TYPE3_H_ podofo-0.9.5/src/doc/PdfPagesTree.cpp0000664000175000017500000007151413013650710017240 0ustar dominikdominik/*************************************************************************** * Copyriht (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfPagesTree.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfDictionary.h" #include "base/PdfObject.h" #include "base/PdfOutputDevice.h" #include "base/PdfVecObjects.h" #include "PdfPage.h" #include namespace PoDoFo { PdfPagesTree::PdfPagesTree( PdfVecObjects* pParent ) : PdfElement( "Pages", pParent ), m_cache( 0 ) { GetObject()->GetDictionary().AddKey( "Kids", PdfArray() ); // kids->Reference() GetObject()->GetDictionary().AddKey( "Count", PdfObject( static_cast(PODOFO_LL_LITERAL(0)) ) ); } PdfPagesTree::PdfPagesTree( PdfObject* pPagesRoot ) : PdfElement( "Pages", pPagesRoot ), m_cache( GetChildCount( pPagesRoot ) ) { if( !this->GetObject() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } } PdfPagesTree::~PdfPagesTree() { m_cache.ClearCache(); } int PdfPagesTree::GetTotalNumberOfPages() const { return GetChildCount( GetObject() ); } PdfPage* PdfPagesTree::GetPage( int nIndex ) { // if you try to get a page past the end, return NULL // we use >= since nIndex is 0 based if ( nIndex >= GetTotalNumberOfPages() ) return NULL; // Take a look into the cache first PdfPage* pPage = m_cache.GetPage( nIndex ); if( pPage ) return pPage; // Not in cache -> search tree PdfObjectList lstParents; PdfObject* pObj = this->GetPageNode(nIndex, this->GetRoot(), lstParents); if( pObj ) { pPage = new PdfPage( pObj, lstParents ); m_cache.AddPageObject( nIndex, pPage ); return pPage; } return NULL; } PdfPage* PdfPagesTree::GetPage( const PdfReference & ref ) { // We have to search through all pages, // as this is the only way // to instantiate the PdfPage with a correct list of parents for( int i=0;iGetTotalNumberOfPages();i++ ) { PdfPage* pPage = this->GetPage( i ); if( pPage && pPage->GetObject()->Reference() == ref ) return pPage; } return NULL; } void PdfPagesTree::InsertPage( int nAfterPageIndex, PdfPage* inPage ) { this->InsertPage( nAfterPageIndex, inPage->GetObject() ); } void PdfPagesTree::InsertPage( int nAfterPageIndex, PdfObject* pPage ) { bool bInsertBefore = false; if( ePdfPageInsertionPoint_InsertBeforeFirstPage == nAfterPageIndex ) { bInsertBefore = true; nAfterPageIndex = 0; } else if( nAfterPageIndex < 0 ) { // Only ePdfPageInsertionPoint_InsertBeforeFirstPage is valid here PdfError::LogMessage( eLogSeverity_Information, "Invalid argument to PdfPagesTree::InsertPage: %i (Only ePdfPageInsertionPoint_InsertBeforeFirstPage is valid here).", nAfterPageIndex ); return; } //printf("Fetching page node: %i\n", nAfterPageIndex); PdfObjectList lstParents; PdfObject* pPageBefore = NULL; //printf("Searching page=%i\n", nAfterPageIndex ); if( this->GetTotalNumberOfPages() != 0 ) // no GetPageNode call w/o pages { pPageBefore = this->GetPageNode( nAfterPageIndex, this->GetRoot(), lstParents ); } //printf("pPageBefore=%p lstParents=%i\n", pPageBefore,lstParents.size() ); if( !pPageBefore || lstParents.size() == 0 ) { if( this->GetTotalNumberOfPages() != 0 ) { PdfError::LogMessage( eLogSeverity_Critical, "Cannot find page %i or page %i has no parents. Cannot insert new page.", nAfterPageIndex, nAfterPageIndex ); return; } else { // We insert the first page into an empty pages tree PdfObjectList lstPagesTree; lstPagesTree.push_back( this->GetObject() ); // Use -1 as index to insert before the empty kids array InsertPageIntoNode( this->GetObject(), lstPagesTree, -1, pPage ); } } else { PdfObject* pParent = lstParents.back(); //printf("bInsertBefore=%i\n", bInsertBefore ); int nKidsIndex = bInsertBefore ? -1 : this->GetPosInKids( pPageBefore, pParent ); //printf("Inserting into node: %p at pos %i\n", pParent, nKidsIndex ); InsertPageIntoNode( pParent, lstParents, nKidsIndex, pPage ); } m_cache.InsertPage( (bInsertBefore && nAfterPageIndex == 0) ? ePdfPageInsertionPoint_InsertBeforeFirstPage : nAfterPageIndex ); } void PdfPagesTree::InsertPages( int nAfterPageIndex, const std::vector& vecPages ) { bool bInsertBefore = false; if( ePdfPageInsertionPoint_InsertBeforeFirstPage == nAfterPageIndex ) { bInsertBefore = true; nAfterPageIndex = 0; } else if( nAfterPageIndex < 0 ) { // Only ePdfPageInsertionPoint_InsertBeforeFirstPage is valid here PdfError::LogMessage( eLogSeverity_Information, "Invalid argument to PdfPagesTree::InsertPage: %i (Only ePdfPageInsertionPoint_InsertBeforeFirstPage is valid here).", nAfterPageIndex ); return; } PdfObjectList lstParents; PdfObject* pPageBefore = NULL; if( this->GetTotalNumberOfPages() != 0 ) // no GetPageNode call w/o pages { pPageBefore = this->GetPageNode( nAfterPageIndex, this->GetRoot(), lstParents ); } if( !pPageBefore || lstParents.size() == 0 ) { if( this->GetTotalNumberOfPages() != 0 ) { PdfError::LogMessage( eLogSeverity_Critical, "Cannot find page %i or page %i has no parents. Cannot insert new page.", nAfterPageIndex, nAfterPageIndex ); return; } else { // We insert the first page into an empty pages tree PdfObjectList lstPagesTree; lstPagesTree.push_back( this->GetObject() ); // Use -1 as index to insert before the empty kids array InsertPagesIntoNode( this->GetObject(), lstPagesTree, -1, vecPages ); } } else { PdfObject* pParent = lstParents.back(); int nKidsIndex = bInsertBefore ? -1 : this->GetPosInKids( pPageBefore, pParent ); InsertPagesIntoNode( pParent, lstParents, nKidsIndex, vecPages ); } m_cache.InsertPages( (bInsertBefore && nAfterPageIndex == 0) ? ePdfPageInsertionPoint_InsertBeforeFirstPage : nAfterPageIndex, vecPages.size() ); } PdfPage* PdfPagesTree::CreatePage( const PdfRect & rSize ) { PdfPage* pPage = new PdfPage( rSize, GetRoot()->GetOwner() ); InsertPage( this->GetTotalNumberOfPages() - 1, pPage ); m_cache.AddPageObject( this->GetTotalNumberOfPages(), pPage ); return pPage; } PdfPage* PdfPagesTree::InsertPage( const PdfRect & rSize, int atIndex) { PdfPage* pPage = new PdfPage( rSize, GetRoot()->GetOwner() ); if (atIndex < 0 || atIndex >= this->GetTotalNumberOfPages()) { atIndex = this->GetTotalNumberOfPages() - 1; } InsertPage( atIndex - 1, pPage ); m_cache.AddPageObject( atIndex, pPage ); return pPage; } void PdfPagesTree::CreatePages( const std::vector& vecSizes ) { std::vector vecPages; std::vector vecObjects; for (std::vector::const_iterator it = vecSizes.begin(); it != vecSizes.end(); ++it) { PdfPage* pPage = new PdfPage( (*it), GetRoot()->GetOwner() ); vecPages.push_back( pPage ); vecObjects.push_back( pPage->GetObject() ); } InsertPages( this->GetTotalNumberOfPages() - 1, vecObjects ); m_cache.AddPageObjects( this->GetTotalNumberOfPages(), vecPages ); } void PdfPagesTree::DeletePage( int nPageNumber ) { // Delete from cache m_cache.DeletePage( nPageNumber ); // Delete from pages tree PdfObjectList lstParents; PdfObject* pPageNode = this->GetPageNode( nPageNumber, this->GetRoot(), lstParents ); if( !pPageNode ) { PdfError::LogMessage( eLogSeverity_Information, "Invalid argument to PdfPagesTree::DeletePage: %i - Page not found\n", nPageNumber ); PODOFO_RAISE_ERROR( ePdfError_PageNotFound ); } if( lstParents.size() > 0 ) { PdfObject* pParent = lstParents.back(); int nKidsIndex = this->GetPosInKids( pPageNode, pParent ); DeletePageFromNode( pParent, lstParents, nKidsIndex, pPageNode ); } else { PdfError::LogMessage( eLogSeverity_Error, "PdfPagesTree::DeletePage: Page %i has no parent - cannot be deleted.\n", nPageNumber ); PODOFO_RAISE_ERROR( ePdfError_PageNotFound ); } } //////////////////////////////////////////////////// // Private methods //////////////////////////////////////////////////// PdfObject* PdfPagesTree::GetPageNode( int nPageNum, PdfObject* pParent, PdfObjectList & rLstParents ) { if( !pParent ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if( !pParent->GetDictionary().HasKey( PdfName("Kids") ) ) { PODOFO_RAISE_ERROR( ePdfError_InvalidKey ); } const PdfObject* pObj = pParent->GetIndirectKey( "Kids" ); if( pObj == NULL || !pObj->IsArray() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } const PdfArray & rKidsArray = pObj->GetArray(); PdfArray::const_iterator it = rKidsArray.begin(); const size_t numDirectKids = rKidsArray.size(); const size_t numKids = GetChildCount(pParent); // use <= since nPageNum is 0-based if( static_cast(numKids) <= nPageNum ) { PdfError::LogMessage( eLogSeverity_Critical, "Cannot retrieve page %i from a document with only %i pages.", nPageNum, static_cast(numKids) ); return NULL; } //printf("Fetching: %i %i %i\n", numDirectKids, numKids, nPageNum ); if( numDirectKids == numKids && static_cast(nPageNum) < numDirectKids ) { // This node has only page nodes as kids, // so we can access the array directly rLstParents.push_back( pParent ); return GetPageNodeFromArray( nPageNum, rKidsArray, rLstParents ); } else { // We have to traverse the tree while( it != rKidsArray.end() ) { if( (*it).IsArray() ) { // Fixes PDFs broken by having trees with arrays nested once rLstParents.push_back( pParent ); // the following code is to find the reference to log this with const PdfReference & rIterArrayRef = (*it).Reference(); PdfReference refToLog; bool isDirectObject // don't worry about 0-num. indirect ones = ( !(rIterArrayRef.ObjectNumber() ) ); if ( isDirectObject ) { if ( !(pObj->Reference().ObjectNumber() ) ) // rKidsArray's { refToLog = pParent->Reference(); } else { refToLog = pObj->Reference(); } } else { refToLog = rIterArrayRef; } PdfError::LogMessage( eLogSeverity_Error, "Entry in Kids array is itself an array" "%s reference: %s\n", isDirectObject ? " (direct object)" ", in object with" : ",", refToLog.ToString().c_str() ); const PdfArray & rIterArray = (*it).GetArray(); // is the array large enough to potentially have the page? if( static_cast(nPageNum) < rIterArray.GetSize() ) { PdfObject* pPageNode = GetPageNodeFromArray( nPageNum, rIterArray, rLstParents ); if ( pPageNode ) // and if not, search further return pPageNode; } } else if( (*it).IsReference() ) { PdfObject* pChild = GetRoot()->GetOwner()->GetObject( (*it).GetReference() ); if (!pChild) { PdfError::LogMessage( eLogSeverity_Critical, "Requesting page index %i. Child not found: %s\n", nPageNum, (*it).GetReference().ToString().c_str()); return NULL; } if( this->IsTypePages(pChild) ) { int childCount = GetChildCount( pChild ); if( childCount < nPageNum + 1 ) // Pages are 0 based, but count is not { // skip this page node // and go to the next one nPageNum -= childCount; } else { rLstParents.push_back( pParent ); return this->GetPageNode( nPageNum, pChild, rLstParents ); } } else if( this->IsTypePage(pChild) ) { if( 0 == nPageNum ) { rLstParents.push_back( pParent ); return pChild; } // Skip a normal page if(nPageNum > 0 ) nPageNum--; } else { const PdfReference & rLogRef = pChild->Reference(); pdf_objnum nLogObjNum = rLogRef.ObjectNumber(); pdf_gennum nLogGenNum = rLogRef.GenerationNumber(); PdfError::LogMessage( eLogSeverity_Critical, "Requesting page index %i. " "Invalid datatype referenced in kids array: %s\n" "Reference to invalid object: %i %i R\n", nPageNum, pChild->GetDataTypeString(), nLogObjNum, nLogGenNum); } } else { PdfError::LogMessage( eLogSeverity_Critical, "Requesting page index %i. Invalid datatype in kids array: %s\n", nPageNum, (*it).GetDataTypeString()); return NULL; } ++it; } } return NULL; } PdfObject* PdfPagesTree::GetPageNodeFromArray( int nPageNum, const PdfArray & rKidsArray, PdfObjectList & rLstParents ) { if( static_cast(nPageNum) >= rKidsArray.GetSize() ) { PdfError::LogMessage( eLogSeverity_Critical, "Requesting page index %i from array of size %i\n", nPageNum, rKidsArray.size() ); return NULL; } // TODO: Fill cache immediately with all pages // in this kids array PdfVariant rVar = rKidsArray[nPageNum]; while( true ) { if( rVar.IsArray() ) { // Fixes some broken PDFs who have trees with 1 element kids arrays return GetPageNodeFromArray( 0, rVar.GetArray(), rLstParents ); } else if( !rVar.IsReference() ) { PODOFO_RAISE_ERROR_INFO( ePdfError_NotImplemented, "Cannot handle inline pages." ); } PdfObject* pgObject = GetRoot()->GetOwner()->GetObject( rVar.GetReference() ); if(pgObject==NULL) { PODOFO_RAISE_ERROR_INFO( ePdfError_PageNotFound, "Invalid reference." ); } //printf("Reading %s\n", pgObject->Reference().ToString().c_str()); // make sure the object is a /Page and not a /Pages with a single kid if( this->IsTypePage(pgObject) ) { return pgObject; } // it's a /Pages with a single kid, so dereference and try again... if (this->IsTypePages(pgObject) ) { if( !pgObject->GetDictionary().HasKey( "Kids" ) ) return NULL; rLstParents.push_back( pgObject ); rVar = *(pgObject->GetDictionary().GetKey( "Kids" )); } else { // Reference to unexpected object PODOFO_RAISE_ERROR_INFO( ePdfError_PageNotFound, "Reference to unexpected object." ); } } return NULL; } bool PdfPagesTree::IsTypePage(const PdfObject* pObject) const { if( !pObject ) return false; if( pObject->GetDictionary().GetKeyAsName( PdfName( "Type" ) ) == PdfName( "Page" ) ) return true; return false; } bool PdfPagesTree::IsTypePages(const PdfObject* pObject) const { if( !pObject ) return false; if( pObject->GetDictionary().GetKeyAsName( PdfName( "Type" ) ) == PdfName( "Pages" ) ) return true; return false; } int PdfPagesTree::GetChildCount( const PdfObject* pNode ) const { if( !pNode ) return 0; const PdfObject *pCount = pNode->GetIndirectKey( "Count" ); if( pCount != 0 ) { return (pCount->GetDataType() == PoDoFo::ePdfDataType_Number) ? static_cast( pCount->GetNumber() ):0; } else { return 0; } } int PdfPagesTree::GetPosInKids( PdfObject* pPageObj, PdfObject* pPageParent ) { if( !pPageParent ) { //printf("pPageParent=%p\n", pPageParent ); return -1; } const PdfArray & rKids = pPageParent->GetDictionary().GetKey( PdfName("Kids") )->GetArray(); PdfArray::const_iterator it = rKids.begin(); int index = 0; while( it != rKids.end() ) { if( (*it).GetReference() == pPageObj->Reference() ) { //printf("Found at: %i \n", index ); return index; } ++index; ++it; } //printf("Not found %i 0 R in %i 0 R\n", pPageObj->Reference().ObjectNumber(), // pPageParent->Reference().ObjectNumber()); return -1; } void PdfPagesTree::InsertPageIntoNode( PdfObject* pParent, const PdfObjectList & rlstParents, int nIndex, PdfObject* pPage ) { if( !pParent || !pPage ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } // 1. Add the reference of the new page to the kids array of pParent // 2. Increase count of every node in lstParents (which also includes pParent) // 3. Add Parent key to the page // 1. Add reference const PdfArray oldKids = pParent->GetDictionary().GetKey( PdfName("Kids") )->GetArray(); PdfArray::const_iterator it = oldKids.begin(); PdfArray newKids; newKids.reserve( oldKids.GetSize() + 1 ); if( nIndex < 0 ) { newKids.push_back( pPage->Reference() ); } int i = 0; while( it != oldKids.end() ) { newKids.push_back( *it ); if( i == nIndex ) newKids.push_back( pPage->Reference() ); ++i; ++it; } /* PdfVariant var2( newKids ); std::string str2; var2.ToString(str2); printf("newKids= %s\n", str2.c_str() ); */ pParent->GetDictionary().AddKey( PdfName("Kids"), newKids ); // 2. increase count PdfObjectList::const_reverse_iterator itParents = rlstParents.rbegin(); while( itParents != rlstParents.rend() ) { this->ChangePagesCount( *itParents, 1 ); ++itParents; } // 3. add parent key to the page pPage->GetDictionary().AddKey( PdfName("Parent"), pParent->Reference() ); } void PdfPagesTree::InsertPagesIntoNode( PdfObject* pParent, const PdfObjectList & rlstParents, int nIndex, const std::vector& vecPages ) { if( !pParent || !vecPages.size() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } // 1. Add the reference of the new page to the kids array of pParent // 2. Increase count of every node in lstParents (which also includes pParent) // 3. Add Parent key to the page // 1. Add reference const PdfArray oldKids = pParent->GetDictionary().GetKey( PdfName("Kids") )->GetArray(); PdfArray newKids; newKids.reserve( oldKids.GetSize() + vecPages.size() ); bool bIsPushedIn = false; int i=0; for (PdfArray::const_iterator it=oldKids.begin(); it!=oldKids.end(); ++it, ++i ) { if ( !bIsPushedIn && (nIndex < i) ) // Pushing before { for (std::vector::const_iterator itPages=vecPages.begin(); itPages!=vecPages.end(); ++itPages) { newKids.push_back( (*itPages)->Reference() ); // Push all new kids at once } bIsPushedIn = true; } newKids.push_back( *it ); // Push in the old kids } // If new kids are still not pushed in then they may be appending to the end if ( !bIsPushedIn && ( (nIndex + 1) == static_cast(oldKids.size())) ) { for (std::vector::const_iterator itPages=vecPages.begin(); itPages!=vecPages.end(); ++itPages) { newKids.push_back( (*itPages)->Reference() ); // Push all new kids at once } bIsPushedIn = true; } pParent->GetDictionary().AddKey( PdfName("Kids"), newKids ); // 2. increase count for ( PdfObjectList::const_reverse_iterator itParents = rlstParents.rbegin(); itParents != rlstParents.rend(); ++itParents ) { this->ChangePagesCount( *itParents, vecPages.size() ); } // 3. add parent key to each of the pages for (std::vector::const_iterator itPages=vecPages.begin(); itPages!=vecPages.end(); ++itPages) { (*itPages)->GetDictionary().AddKey( PdfName("Parent"), pParent->Reference() ); } } void PdfPagesTree::DeletePageFromNode( PdfObject* pParent, const PdfObjectList & rlstParents, int nIndex, PdfObject* pPage ) { if( !pParent || !pPage ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } // 1. Delete the reference from the kids array of pParent // 2. Decrease count of every node in lstParents (which also includes pParent) // 3. Remove empty page nodes // TODO: Tell cache to free page object // 1. Delete reference this->DeletePageNode( pParent, nIndex ) ; // 2. Decrease count PdfObjectList::const_reverse_iterator itParents = rlstParents.rbegin(); while( itParents != rlstParents.rend() ) { this->ChangePagesCount( *itParents, -1 ); ++itParents; } // 3. Remove empty pages nodes itParents = rlstParents.rbegin(); while( itParents != rlstParents.rend() ) { // Never delete root node if( IsEmptyPageNode( *itParents ) && *itParents != GetRoot() ) { PdfObject* pParentOfNode = *(itParents + 1); int nKidsIndex = this->GetPosInKids( *itParents, pParentOfNode ); DeletePageNode( pParentOfNode, nKidsIndex ); // Delete empty page nodes delete this->GetObject()->GetOwner()->RemoveObject( (*itParents)->Reference() ); } ++itParents; } } void PdfPagesTree::DeletePageNode( PdfObject* pParent, int nIndex ) { PdfArray kids = pParent->GetDictionary().GetKey( PdfName("Kids") )->GetArray(); kids.erase( kids.begin() + nIndex ); pParent->GetDictionary().AddKey( PdfName("Kids"), kids ); } int PdfPagesTree::ChangePagesCount( PdfObject* pPageObj, int nDelta ) { // Increment or decrement inPagesDict's Count by inDelta, and return the new count. // Simply return the current count if inDelta is 0. int cnt = GetChildCount( pPageObj ); if( 0 != nDelta ) { cnt += nDelta ; pPageObj->GetDictionary().AddKey( "Count", PdfVariant( static_cast(cnt) ) ); } return cnt ; } bool PdfPagesTree::IsEmptyPageNode( PdfObject* pPageNode ) { long lCount = GetChildCount( pPageNode ); bool bKidsEmpty = true; if( pPageNode->GetDictionary().HasKey( PdfName("Kids") ) ) { bKidsEmpty = pPageNode->GetDictionary().GetKey( PdfName("Kids") )->GetArray().empty(); } return ( lCount == 0L || bKidsEmpty ); } /* PdfObject* PdfPagesTree::GetPageNode( int nPageNum, PdfObject* pPagesObject, std::deque & rListOfParents ) { // recurse through the pages tree nodes PdfObject* pObj = NULL; if( !pPagesObject->GetDictionary().HasKey( "Kids" ) ) return NULL; pObj = pPagesObject->GetDictionary().GetKey( "Kids" ); if( !pObj->IsArray() ) return NULL; PdfArray& kidsArray = pObj->GetArray(); size_t numKids = kidsArray.size(); size_t kidsCount = GetChildCount( pPagesObject ); // All parents of the page node will be added to this lists, // so that the PdfPage can later access inherited attributes rListOfParents.push_back( pPagesObject ); // the pages tree node represented by pPagesObject has only page nodes in its kids array, // or pages nodes with a kid count of 1, so we can speed things up // by going straight to the desired node if ( numKids == kidsCount ) { if( nPageNum >= static_cast(kidsArray.size()) ) { PdfError::LogMessage( eLogSeverity_Critical, "Requesting page index %i from array of size %i\n", nPageNum, kidsArray.size() ); nPageNum--; } PdfVariant pgVar = kidsArray[ nPageNum ]; while ( true ) { if ( pgVar.IsArray() ) { // Fixes some broken PDFs who have trees with 1 element kids arrays return GetPageNodeFromTree( nPageNum, pgVar.GetArray(), rListOfParents ); } else if ( !pgVar.IsReference() ) return NULL; // can't handle inline pages just yet... PdfObject* pgObject = GetRoot()->GetOwner()->GetObject( pgVar.GetReference() ); // make sure the object is a /Page and not a /Pages with a single kid if ( pgObject->GetDictionary().GetKeyAsName( PdfName( "Type" ) ) == PdfName( "Page" ) ) return pgObject; // it's a /Pages with a single kid, so dereference and try again... if( !pgObject->GetDictionary().HasKey( "Kids" ) ) return NULL; rListOfParents.push_back( pgObject ); pgVar = *(pgObject->GetDictionary().GetKey( "Kids" )); } } else { return GetPageNodeFromTree( nPageNum, kidsArray, rListOfParents ); } // we should never exit from here - we should always have been able to return a page from above // PODOFO_ASSERT( false ) ; return NULL; } */ }; podofo-0.9.5/src/doc/PdfHintStream.h0000664000175000017500000000713612344436402017111 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_HINT_STREAM_H_ #define _PDF_HINT_STREAM_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfWriter.h" #include "PdfElement.h" namespace PoDoFo { class PdfPagesTree; namespace NonPublic { // PdfHintStream is not part of the public API and is NOT exported as part of // the DLL/shared library interface. Do not rely on it. class PdfHintStream : public PdfElement { public: PdfHintStream( PdfVecObjects* pParent, PdfPagesTree* pPagesTree ); ~PdfHintStream(); /** Create the hint stream * \param pXRef pointer to a valid XREF table structure */ //void Create( TVecXRefTable* pXRef ); /** Write a pdf_uint16 to the stream in big endian format. * \param val the value to write to the stream */ void WriteUInt16( pdf_uint16 val ); /** Write a pdf_uint32 to the stream in big endian format. * \param val the value to write to the stream */ void WriteUInt32( pdf_uint32 ); private: //void CreatePageHintTable( TVecXRefTable* pXRef ); void CreateSharedObjectHintTable(); private: PdfPagesTree* m_pPagesTree; }; }; // end namespace NonPublic }; // end namespace PoDoFo #endif /* _PDF_HINT_STREAM_H_ */ podofo-0.9.5/src/doc/PdfFontMetrics.h0000664000175000017500000005044212714722103017263 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FONT_METRICS_H_ #define _PDF_FONT_METRICS_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/Pdf3rdPtyForwardDecl.h" #include "podofo/base/PdfString.h" #include "podofo/base/PdfEncoding.h" namespace PoDoFo { class PdfArray; class PdfObject; class PdfVariant; /** * This abstract class provides access * to fontmetrics informations. */ class PODOFO_DOC_API PdfFontMetrics { public: PdfFontMetrics( EPdfFontType eFontType, const char* pszFilename, const char* pszSubsetPrefix ); virtual ~PdfFontMetrics(); /** Create a width array for this font which is a required part * of every font dictionary. * \param var the final width array is written to this PdfVariant * \param nFirst first character to be in the array * \param nLast last character code to be in the array * \param pEncoding encoding for correct character widths. If not passed default (latin1) encoding is used */ virtual void GetWidthArray( PdfVariant & var, unsigned int nFirst, unsigned int nLast, const PdfEncoding* pEncoding = NULL ) const = 0; /** Get the width of a single glyph id * * \param nGlyphId id of the glyph * \returns the width of a single glyph id */ virtual double GetGlyphWidth( int nGlyphId ) const = 0; /** Get the width of a single named glyph * * \param pszGlyphname name of the glyph * \returns the width of a single named glyph */ virtual double GetGlyphWidth( const char* pszGlyphname ) const = 0; /** Create the bounding box array as required by the PDF reference * so that it can be written directly to a PDF file. * * \param array write the bounding box to this array. */ virtual void GetBoundingBox( PdfArray & array ) const = 0; /** Retrieve the width of a given text string in PDF units when * drawn with the current font * \param rsString a PdfString from which the width shall be calculated * \returns the width in PDF units * * This is an overloaded method for your convinience! */ inline double StringWidth( const PdfString & rsString ) const; /** Retrieve the width of a given text string in PDF units when * drawn with the current font * \param pszText a text string of which the width should be calculated * \param nLength if != 0 only the width of the nLength first characters is calculated * \returns the width in PDF units */ double StringWidth( const char* pszText, pdf_long nLength = 0 ) const; /** Retrieve the width of a given text string in PDF units when * drawn with the current font * \param pszText a text string of which the width should be calculated * \param nLength if != 0 only the width of the nLength first characters is calculated * \returns the width in PDF units */ double StringWidth( const pdf_utf16be* pszText, unsigned int nLength = 0 ) const; #ifndef _WCHAR_T_DEFINED #if defined(_MSC_VER) && _MSC_VER <= 1200 // not for MS Visual Studio 6 #else /** Retrieve the width of a given text string in PDF units when * drawn with the current font * \param pszText a text string of which the width should be calculated * \param nLength if != 0 only the width of the nLength first characters is calculated * \returns the width in PDF units */ double StringWidth( const wchar_t* pszText, unsigned int nLength = 0 ) const; #endif #endif /** Retrieve the width of a given text string in 1/1000th mm when * drawn with the current font * \param pszText a text string of which the width should be calculated * \param nLength if != 0 only the width of the nLength first characters is calculated * \returns the width in 1/1000th mm */ inline unsigned long StringWidthMM( const char* pszText, unsigned int nLength = 0 ) const; /** Retrieve the width of a given text string in 1/1000th mm when * drawn with the current font * \param pszText a text string of which the width should be calculated * \param nLength if != 0 only the width of the nLength first characters is calculated * \returns the width in 1/1000th mm */ inline unsigned long StringWidthMM( const pdf_utf16be* pszText, unsigned int nLength = 0 ) const; #ifndef _WCHAR_T_DEFINED #if defined(_MSC_VER) && _MSC_VER <= 1200 // not for MS Visual Studio 6 #else /** Retrieve the width of a given text string in 1/1000th mm when * drawn with the current font * \param pszText a text string of which the width should be calculated * \param nLength if != 0 only the width of the nLength first characters is calculated * \returns the width in 1/1000th mm */ inline unsigned long StringWidthMM( const wchar_t* pszText, unsigned int nLength = 0 ) const; #endif #endif /** Retrieve the width of the given character in PDF units in the current font * \param c character * \returns the width in PDF units */ virtual double CharWidth( unsigned char c ) const = 0; // Peter Petrov 20 March 2009 /** Retrieve the width of the given character in PDF units in the current font * \param c character * \returns the width in PDF units */ virtual double UnicodeCharWidth( unsigned short c ) const = 0; /** Retrieve the width of the given character in 1/1000th mm in the current font * \param c character * \returns the width in 1/1000th mm */ inline unsigned long CharWidthMM( unsigned char c ) const; /** Retrieve the line spacing for this font * \returns the linespacing in PDF units */ virtual double GetLineSpacing() const = 0; /** Retrieve the line spacing for this font * \returns the linespacing in 1/1000th mm */ inline unsigned long GetLineSpacingMM() const; /** Get the width of the underline for the current * font size in PDF units * \returns the thickness of the underline in PDF units */ virtual double GetUnderlineThickness() const = 0; /** Get the width of the underline for the current * font size in 1/1000th mm * \returns the thickness of the underline in 1/1000th mm */ inline unsigned long GetUnderlineThicknessMM() const; /** Return the position of the underline for the current font * size in PDF units * \returns the underline position in PDF units */ virtual double GetUnderlinePosition() const = 0; /** Return the position of the underline for the current font * size in 1/1000th mm * \returns the underline position in 1/1000th mm */ inline long GetUnderlinePositionMM() const; /** Return the position of the strikeout for the current font * size in PDF units * \returns the underline position in PDF units */ virtual double GetStrikeOutPosition() const = 0; /** Return the position of the strikeout for the current font * size in 1/1000th mm * \returns the underline position in 1/1000th mm */ inline unsigned long GetStrikeOutPositionMM() const; /** Get the width of the strikeout for the current * font size in PDF units * \returns the thickness of the strikeout in PDF units */ virtual double GetStrikeoutThickness() const = 0; /** Get the width of the strikeout for the current * font size in 1/1000th mm * \returns the thickness of the strikeout in 1/1000th mm */ inline unsigned long GetStrikeoutThicknessMM() const; /** Get a pointer to the path of the font file. * \returns a zero terminated string containing the filename of the font file */ inline const char* GetFilename() const; /** Get a pointer to the actual font data - if it was loaded from memory. * \returns a binary buffer of data containing the font data */ virtual const char* GetFontData() const = 0; /** Get the length of the actual font data - if it was loaded from memory. * \returns a the length of the font data */ virtual pdf_long GetFontDataLen() const = 0; /** Get a string with the postscript name of the font. * \returns the postscript name of the font or NULL string if no postscript name is available. */ virtual const char* GetFontname() const = 0; /** * \returns NULL or a 6 uppercase letter and "+" sign prefix * used for font subsets */ inline const char* GetSubsetFontnamePrefix() const; /** Get the weight of this font. * Used to build the font dictionay * \returns the weight of this font (500 is normal). */ virtual unsigned int GetWeight() const = 0; /** Get the ascent of this font in PDF * units for the current font size. * * \returns the ascender for this font * * \see GetPdfAscent */ virtual double GetAscent() const = 0; /** Get the ascent of this font * Used to build the font dictionay * \returns the ascender for this font * * \see GetAscent */ virtual double GetPdfAscent() const = 0; /** Get the descent of this font in PDF * units for the current font size. * This value is usually negative! * * \returns the descender for this font * * \see GetPdfDescent */ virtual double GetDescent() const = 0; /** Get the descent of this font * Used to build the font dictionay * \returns the descender for this font * * \see GetDescent */ virtual double GetPdfDescent() const = 0; /** Get the italic angle of this font. * Used to build the font dictionay * \returns the italic angle of this font. */ virtual int GetItalicAngle() const = 0; /** Set the font size of this metrics object for width and height * calculations. * This is typically called from PdfFont for you. * * \param fSize font size in points */ inline void SetFontSize( float fSize ); /** Retrieve the current font size of this metrics object * \returns the current font size */ inline float GetFontSize() const; /** Set the horizontal scaling of the font for compressing (< 100) and expanding (>100) * This is typically called from PdfFont for you. * * \param fScale scaling in percent */ inline void SetFontScale( float fScale ); /** Retrieve the current horizontal scaling of this metrics object * \returns the current font scaling */ inline float GetFontScale() const; /** Set the character spacing of this metrics object * \param fCharSpace character spacing in percent */ inline void SetFontCharSpace( float fCharSpace ); /** Retrieve the current character spacing of this metrics object * \returns the current font character spacing */ inline float GetFontCharSpace() const; /** Set the word spacing of this metrics object * \param fWordSpace word spacing in PDF units */ inline void SetWordSpace( float fWordSpace ); /** Retrieve the current word spacing of this metrics object * \returns the current font word spacing in PDF units */ inline float GetWordSpace() const; /** * \returns the fonttype of the loaded font */ inline EPdfFontType GetFontType() const; /** Get the glyph id for a unicode character * in the current font. * * \param lUnicode the unicode character value * \returns the glyhph id for the character or 0 if the glyph was not found. */ virtual long GetGlyphId( long lUnicode ) const = 0; /** Symbol fonts do need special treatment in a few cases. * Use this method to check if the current font is a symbol * font. Symbold fonts are detected by checking * if they use FT_ENCODING_MS_SYMBOL as internal encoding. * * \returns true if this is a symbol font */ virtual bool IsSymbol() const = 0; /** Try to detect the internal fonttype from * the file extension of a fontfile. * * \param pszFilename must be the filename of a font file * * \return font type */ static EPdfFontType FontTypeFromFilename( const char* pszFilename ); protected: /** * Set the fonttype. * \param eFontType fonttype */ inline void SetFontType(EPdfFontType eFontType); protected: std::string m_sFilename; float m_fFontSize; float m_fFontScale; float m_fFontCharSpace; float m_fWordSpace; std::vector m_vecWidth; EPdfFontType m_eFontType; std::string m_sFontSubsetPrefix; }; // ----------------------------------------------------- // // ----------------------------------------------------- unsigned long PdfFontMetrics::CharWidthMM( unsigned char c ) const { return static_cast(this->CharWidth( c ) / PODOFO_CONVERSION_CONSTANT); } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfFontMetrics::StringWidth( const PdfString & rsString ) const { return (rsString.IsUnicode() ? this->StringWidth( rsString.GetUnicode() ) : this->StringWidth( rsString.GetString() )); } // ----------------------------------------------------- // // ----------------------------------------------------- unsigned long PdfFontMetrics::StringWidthMM( const char* pszText, unsigned int nLength ) const { return static_cast(this->StringWidth( pszText, nLength ) / PODOFO_CONVERSION_CONSTANT); } // ----------------------------------------------------- // // ----------------------------------------------------- unsigned long PdfFontMetrics::StringWidthMM( const pdf_utf16be* pszText, unsigned int nLength ) const { return static_cast(this->StringWidth( pszText, nLength ) / PODOFO_CONVERSION_CONSTANT); } // ----------------------------------------------------- // // ----------------------------------------------------- #ifndef _WCHAR_T_DEFINED #if defined(_MSC_VER) && _MSC_VER <= 1200 // not for MS Visual Studio 6 #else unsigned long PdfFontMetrics::StringWidthMM( const wchar_t* pszText, unsigned int nLength ) const { return static_cast(this->StringWidth( pszText, nLength ) / PODOFO_CONVERSION_CONSTANT); } #endif #endif // ----------------------------------------------------- // // ----------------------------------------------------- unsigned long PdfFontMetrics::GetLineSpacingMM() const { return static_cast(this->GetLineSpacing() / PODOFO_CONVERSION_CONSTANT); } // ----------------------------------------------------- // // ----------------------------------------------------- long PdfFontMetrics::GetUnderlinePositionMM() const { return static_cast(this->GetUnderlinePosition() / PODOFO_CONVERSION_CONSTANT); } // ----------------------------------------------------- // // ----------------------------------------------------- unsigned long PdfFontMetrics::GetStrikeOutPositionMM() const { return static_cast(this->GetStrikeOutPosition() / PODOFO_CONVERSION_CONSTANT); } // ----------------------------------------------------- // // ----------------------------------------------------- unsigned long PdfFontMetrics::GetUnderlineThicknessMM() const { return static_cast(this->GetUnderlineThickness() / PODOFO_CONVERSION_CONSTANT); } // ----------------------------------------------------- // // ----------------------------------------------------- unsigned long PdfFontMetrics::GetStrikeoutThicknessMM() const { return static_cast(this->GetStrikeoutThickness() / PODOFO_CONVERSION_CONSTANT); } // ----------------------------------------------------- // // ----------------------------------------------------- const char* PdfFontMetrics::GetFilename() const { return m_sFilename.c_str(); } // ----------------------------------------------------- // // ----------------------------------------------------- EPdfFontType PdfFontMetrics::GetFontType() const { return m_eFontType; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfFontMetrics::SetFontType(EPdfFontType eFontType) { m_eFontType = eFontType; } // ----------------------------------------------------- // // ----------------------------------------------------- float PdfFontMetrics::GetFontSize() const { return m_fFontSize; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfFontMetrics::SetFontSize( float fSize ) { m_fFontSize = fSize; } // ----------------------------------------------------- // // ----------------------------------------------------- float PdfFontMetrics::GetFontScale() const { return m_fFontScale; } // ----------------------------------------------------- // // ----------------------------------------------------- float PdfFontMetrics::GetFontCharSpace() const { return m_fFontCharSpace; } // ----------------------------------------------------- // // ----------------------------------------------------- inline float PdfFontMetrics::GetWordSpace() const { return m_fWordSpace; } // ----------------------------------------------------- // // ----------------------------------------------------- const char* PdfFontMetrics::GetSubsetFontnamePrefix() const { return m_sFontSubsetPrefix.c_str(); } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfFontMetrics::SetFontScale( float fScale ) { m_fFontScale = fScale; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfFontMetrics::SetFontCharSpace( float fCharSpace ) { m_fFontCharSpace = fCharSpace; } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfFontMetrics::SetWordSpace( float fWordSpace ) { m_fWordSpace = fWordSpace; } }; #endif // _PDF_FONT_METRICS_H_ podofo-0.9.5/src/doc/PdfFontTrueType.h0000664000175000017500000001051412344436402017435 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FONT_TRUE_TYPE_H_ #define _PDF_FONT_TRUE_TYPE_H_ #include "podofo/base/PdfDefines.h" #include "PdfFontSimple.h" namespace PoDoFo { /** A PdfFont implementation that can be used * to embedd truetype fonts into a PDF file * or to draw with truetype fonts. * * TrueType fonts are always embedded as suggested in the PDF reference. */ class PdfFontTrueType : public PdfFontSimple { public: /** Create a new TrueType font. * * It will get embedded automatically. * * \param pMetrics pointer to a font metrics object. The font in the PDF * file will match this fontmetrics object. The metrics object is * deleted along with the font. * \param pEncoding the encoding of this font. The font will take ownership of this object * depending on pEncoding->IsAutoDelete() * \param pParent parent of the font object * \param bEmbed if true the font will get embedded. * */ PdfFontTrueType( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfVecObjects* pParent, bool bEmbed ); /** Create a PdfFont based on an existing PdfObject * \param pMetrics pointer to a font metrics object. The font in the PDF * file will match this fontmetrics object. The metrics object is * deleted along with the font. * \param pEncoding the encoding of this font. The font will take ownership of this object * depending on pEncoding->IsAutoDelete() * \param pObject an existing PdfObject */ PdfFontTrueType( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfObject* pObject ); private: /** Embed the font file directly into the PDF file. * * \param pDescriptor font descriptor object */ void EmbedFontFile( PdfObject* pDescriptor ); }; }; #endif // _PDF_FONT_TRUE_TYPE_H_ podofo-0.9.5/src/doc/PdfPainterMM.h0000664000175000017500000002573312347306415016675 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_PAINTER_MM_H_ #define _PDF_PAINTER_MM_H_ #include "podofo/base/PdfDefines.h" #include "PdfPainter.h" namespace PoDoFo { class PdfCanvas; class PdfFont; class PdfImage; class PdfName; class PdfObject; class PdfReference; class PdfStream; class PdfString; class PdfXObject; #ifndef CONVERSION_CONSTANT /** \def CONVERSION_CONSTANT * Conversation constant to convert 1/1000th mm to 1/72 inch * Internal use only. */ #define CONVERSION_CONSTANT 0.002834645669291339 #endif // CONVERSION_CONSTANT /** * This class provides an easy to use painter object which allows you to draw on a PDF page * object. * * During all drawing operations, you are still able to access the stream of the object you are * drawing on directly. * * This painter takes all coordinates in 1/1000th mm instead of PDF units. * * Developer note: we use ownership rather than inheritance here, so as to use the same * methods names a PdfPainter AND avoid compiler confusion on picking the right one. * * \see PdfPainter */ class PODOFO_DOC_API PdfPainterMM : public PdfPainter { public: /** Create a new PdfPainterMM object. */ PdfPainterMM() {} virtual ~PdfPainterMM(); /** Set the line width for all stroking operations. * \param lWidth in 1/1000th mm */ inline void SetStrokeWidthMM( long lWidth ); /** Draw a line with the current color and line settings. * \param lStartX x coordinate of the starting point * \param lStartY y coordinate of the starting point * \param lEndX x coordinate of the ending point * \param lEndY y coordinate of the ending point */ inline void DrawLineMM( long lStartX, long lStartY, long lEndX, long lEndY ); /** Add a rectangle into the current path * \param lX x coordinate of the rectangle * \param lY y coordinate of the rectangle * \param lWidth width of the rectangle * \param lHeight absolute height of the rectangle */ inline void RectangleMM( long lX, long lY, long lWidth, long lHeight ); /** Add an ellipse into the current path * \param lX x coordinate of the ellipse (left coordinate) * \param lY y coordinate of the ellipse (top coordinate) * \param lWidth width of the ellipse * \param lHeight absolute height of the ellipse */ inline void EllipseMM( long lX, long lY, long lWidth, long lHeight ); /** Draw a text string on a page using a given font object. * You have to call SetFont before calling this function. * \param lX the x coordinate * \param lY the y coordinate * \param sText the text string which should be printed * * \see PdfPainter::SetFont() */ inline void DrawTextMM( long lX, long lY, const PdfString & sText); /** Draw a text string on a page using a given font object. * You have to call SetFont before calling this function. * \param lX the x coordinate * \param lY the y coordinate * \param sText the text string which should be printed (is not allowed to be NULL!) * \param lLen draw only lLen characters of pszText * * \see PdfPainter::SetFont() */ inline void DrawTextMM( long lX, long lY, const PdfString & sText, long lLen ); /** Draw an image on the current page. * \param lX the x coordinate (bottom left position of the image) * \param lY the y coordinate (bottom position of the image) * \param pObject an PdfXObject * \param dScaleX option scaling factor in x direction * \param dScaleY option scaling factor in y direction */ inline void DrawImageMM( long lX, long lY, PdfImage* pObject, double dScaleX = 1.0, double dScaleY = 1.0); /** Draw an XObject on the current page. * \param lX the x coordinate (bottom left position of the XObject) * \param lY the y coordinate (bottom position of the XObject) * \param pObject an PdfXObject * \param dScaleX option scaling factor in x direction * \param dScaleY option scaling factor in y direction */ inline void DrawXObjectMM( long lX, long lY, PdfXObject* pObject, double dScaleX = 1.0, double dScaleY = 1.0); /** Append a line segment to the current path. Matches the PDF 'l' operator. * This function is useful to construct an own path * for drawing or clipping. * \param lX x position * \param lY y position */ inline void LineToMM( long lX, long lY ); /** Begin a new path. Matches the PDF 'm' operator. * This function is useful to construct an own path * for drawing or clipping. * \param lX x position * \param lY y position */ inline void MoveToMM( long lX, long lY ); }; // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfPainterMM::SetStrokeWidthMM( long lWidth ) { this->SetStrokeWidth( static_cast(lWidth) * CONVERSION_CONSTANT ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfPainterMM::DrawLineMM( long lStartX, long lStartY, long lEndX, long lEndY ) { this->DrawLine( static_cast(lStartX) * CONVERSION_CONSTANT, static_cast(lStartY) * CONVERSION_CONSTANT, static_cast(lEndX) * CONVERSION_CONSTANT, static_cast(lEndY) * CONVERSION_CONSTANT ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfPainterMM::RectangleMM( long lX, long lY, long lWidth, long lHeight ) { this->Rectangle( static_cast(lX) * CONVERSION_CONSTANT, static_cast(lY) * CONVERSION_CONSTANT, static_cast(lWidth) * CONVERSION_CONSTANT, static_cast(lHeight) * CONVERSION_CONSTANT ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfPainterMM::EllipseMM( long lX, long lY, long lWidth, long lHeight ) { this->Ellipse( static_cast(lX) * CONVERSION_CONSTANT, static_cast(lY) * CONVERSION_CONSTANT, static_cast(lWidth) * CONVERSION_CONSTANT, static_cast(lHeight) * CONVERSION_CONSTANT ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfPainterMM::DrawTextMM( long lX, long lY, const PdfString & sText) { this->DrawText( static_cast(lX) * CONVERSION_CONSTANT, static_cast(lY) * CONVERSION_CONSTANT, sText ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfPainterMM::DrawTextMM( long lX, long lY, const PdfString & sText, long lLen ) { this->DrawText( static_cast(lX) * CONVERSION_CONSTANT, static_cast(lY) * CONVERSION_CONSTANT, sText, lLen ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfPainterMM::DrawImageMM( long lX, long lY, PdfImage* pObject, double dScaleX, double dScaleY ) { this->DrawImage( static_cast(lX) * CONVERSION_CONSTANT, static_cast(lY) * CONVERSION_CONSTANT, pObject, dScaleX, dScaleY ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfPainterMM::DrawXObjectMM( long lX, long lY, PdfXObject* pObject, double dScaleX, double dScaleY ) { this->DrawXObject( static_cast(lX) * CONVERSION_CONSTANT, static_cast(lY) * CONVERSION_CONSTANT, pObject, dScaleX, dScaleY ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfPainterMM::LineToMM( long lX, long lY ) { this->LineTo( static_cast(lX) * CONVERSION_CONSTANT, static_cast(lY) * CONVERSION_CONSTANT ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfPainterMM::MoveToMM( long lX, long lY ) { this->MoveTo( static_cast(lX) * CONVERSION_CONSTANT, static_cast(lY) * CONVERSION_CONSTANT ); } }; #endif // _PDF_PAINTER_MM_H_ podofo-0.9.5/src/doc/PdfEncodingObjectFactory.cpp0000664000175000017500000001077112344436554021602 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfEncodingObjectFactory.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfEncodingFactory.h" #include "base/PdfObject.h" #include "base/PdfVecObjects.h" #include "PdfDifferenceEncoding.h" #include "PdfIdentityEncoding.h" #include "PdfCMapEncoding.h" //For temporary purpose #include using namespace std; namespace PoDoFo { const PdfEncoding *PdfEncodingObjectFactory::CreateEncoding (PdfObject *pObject, PdfObject *pToUnicode, bool bExplicitNames) { if (pObject->IsReference ()) { // resolve any references pObject = pObject->GetOwner ()->GetObject (pObject->GetReference ()); } if (pObject->IsName ()) { const PdfName & rName = pObject->GetName (); if (rName == PdfName ("WinAnsiEncoding")) return PdfEncodingFactory::GlobalWinAnsiEncodingInstance (); else if (rName == PdfName ("MacRomanEncoding")) return PdfEncodingFactory::GlobalMacRomanEncodingInstance (); else if (rName == PdfName ("StandardEncoding")) // OC 13.08.2010 return PdfEncodingFactory::GlobalStandardEncodingInstance (); else if (rName == PdfName ("MacExpertEncoding")) // OC 13.08.2010 TODO solved return PdfEncodingFactory::GlobalMacExpertEncodingInstance (); else if (rName == PdfName ("SymbolEncoding")) // OC 13.08.2010 return PdfEncodingFactory::GlobalSymbolEncodingInstance (); else if (rName == PdfName ("ZapfDingbatsEncoding")) // OC 13.08.2010 return PdfEncodingFactory::GlobalZapfDingbatsEncodingInstance (); else if (rName == PdfName ("Identity-H")) return new PdfIdentityEncoding (0, 0xffff, true, pToUnicode); } else if (pObject->HasStream ()) { return new PdfCMapEncoding(pObject, pToUnicode); } else if (pObject->IsDictionary ()) { return new PdfDifferenceEncoding (pObject, true, bExplicitNames); } PODOFO_RAISE_ERROR_INFO (ePdfError_InternalLogic, "Unsupported encoding detected!"); //return NULL; Unreachable code } }; /* namespace PoDoFo */ podofo-0.9.5/src/doc/PdfFontMetricsBase14.h0000664000175000017500000002503712714722103020225 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FONT_METRICS_BASE14_H_ #define _PDF_FONT_METRICS_BASE14_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfRect.h" #include "podofo/base/PdfVariant.h" #include "PdfFontMetrics.h" #include /* The following are the Base 14 fonts data copied from libharu. - kaushik April 12 2010 */ namespace PoDoFo { struct PODOFO_CharData; class PdfArray; /* This is the main class to handle the base14 metric data. The member functions are accessed only through PDFFontmetrics. For eg. pdffontmetrics->GetFontSize would check if it is a base14 font, and call PdfFontMetricsBase14->GetFontSize. This is done to ensure all existing paths work as is. The changes to Base 14 get added without affecting the existing workflow and fit in exactly. Ideally PdfFontMetrics should be abstract or the metric related interface should be seperated out from the implementation details - such as whether the font metric data is read from a file/buffer/hard coded. Kaushik : April 12th 2010 */ class PODOFO_DOC_API PdfFontMetricsBase14 : public PdfFontMetrics { public: PdfFontMetricsBase14(const char *mfont_name, const PODOFO_CharData *mwidths_table, bool mis_font_specific, pdf_int16 mascent, pdf_int16 mdescent, pdf_uint16 mx_height, pdf_uint16 mcap_height, const PdfRect & mbbox); ~PdfFontMetricsBase14(); friend PdfFontMetricsBase14* PODOFO_Base14FontDef_FindBuiltinData (const char *font_name); /** Create a width array for this font which is a required part * of every font dictionary. * \param var the final width array is written to this PdfVariant * \param nFirst first character to be in the array * \param nLast last character code to be in the array * \param pEncoding encoding for correct character widths. If not passed default (latin1) encoding is used */ virtual void GetWidthArray( PdfVariant & var, unsigned int nFirst, unsigned int nLast, const PdfEncoding* pEncoding = NULL ) const; /** Get the width of a single glyph id * * \returns the width of a single glyph id */ virtual double GetGlyphWidth( int nGlyphId ) const; /** Get the width of a single named glyph * * \param pszGlyphname name of the glyph * \returns the width of a single named glyph */ virtual double GetGlyphWidth( const char* pszGlyphname ) const; /** Create the bounding box array as required by the PDF reference * so that it can be written directly to a PDF file. * * \param array write the bounding box to this array. */ virtual void GetBoundingBox( PdfArray & array ) const; /** Retrieve the width of the given character in PDF units in the current font * \param c character * \returns the width in PDF units */ virtual double CharWidth( unsigned char c ) const; // Peter Petrov 20 March 2009 /** Retrieve the width of the given character in PDF units in the current font * \param c character * \returns the width in PDF units */ virtual double UnicodeCharWidth( unsigned short c ) const; /** Retrieve the line spacing for this font * \returns the linespacing in PDF units */ virtual double GetLineSpacing() const; /** Get the width of the underline for the current * font size in PDF units * \returns the thickness of the underline in PDF units */ virtual double GetUnderlineThickness() const; /** Return the position of the underline for the current font * size in PDF units * \returns the underline position in PDF units */ virtual double GetUnderlinePosition() const; /** Return the position of the strikeout for the current font * size in PDF units * \returns the underline position in PDF units */ virtual double GetStrikeOutPosition() const; /** Get the width of the strikeout for the current * font size in PDF units * \returns the thickness of the strikeout in PDF units */ virtual double GetStrikeoutThickness() const; /** Get a string with the postscript name of the font. * \returns the postscript name of the font or NULL string if no postscript name is available. */ virtual const char* GetFontname() const; /** Get the weight of this font. * Used to build the font dictionay * \returns the weight of this font (500 is normal). */ virtual unsigned int GetWeight() const; /** Get the ascent of this font in PDF * units for the current font size. * * \returns the ascender for this font * * \see GetPdfAscent */ virtual double GetAscent() const; /** Get the ascent of this font * Used to build the font dictionay * \returns the ascender for this font * * \see GetAscent */ virtual double GetPdfAscent() const; /** Get the descent of this font in PDF * units for the current font size. * This value is usually negative! * * \returns the descender for this font * * \see GetPdfDescent */ virtual double GetDescent() const; /** Get the descent of this font * Used to build the font dictionay * \returns the descender for this font * * \see GetDescent */ virtual double GetPdfDescent() const; /** Get the italic angle of this font. * Used to build the font dictionay * \returns the italic angle of this font. */ virtual int GetItalicAngle() const; /** Get the glyph id for a unicode character * in the current font. * * \param lUnicode the unicode character value * \returns the glyhph id for the character or 0 if the glyph was not found. */ virtual long GetGlyphId( long lUnicode ) const; /** Symbol fonts do need special treatment in a few cases. * Use this method to check if the current font is a symbol * font. Symbold fonts are detected by checking * if they use FT_ENCODING_MS_SYMBOL as internal encoding. * * \returns true if this is a symbol font */ virtual bool IsSymbol() const; /** Get a pointer to the actual font data - if it was loaded from memory. * \returns a binary buffer of data containing the font data */ virtual const char* GetFontData() const; /** Get the length of the actual font data - if it was loaded from memory. * \returns a the length of the font data */ virtual pdf_long GetFontDataLen() const; inline double GetCapHeight() const; /** Get a glyph ID by Unicode value. This is needed for generation * array of widths to /Font element. * * \param lUnicode the unicode character value * \returns a glyph ID * \see PdfFontType1Base14 */ long GetGlyphIdUnicode( long lUnicode ) const; private : // const PODOFO_Base14FontDefDataRec& base14font_data; const char *font_name; const PODOFO_CharData *widths_table; bool is_font_specific; pdf_int16 ascent; pdf_int16 descent; pdf_uint16 x_height; pdf_uint16 cap_height; PdfRect bbox; bool m_bSymbol; ///< Internal member to singnal a symbol font unsigned int m_nWeight; int m_nItalicAngle; double m_dAscent; double m_dPdfAscent; double m_dDescent; double m_dPdfDescent; double m_dLineSpacing; double m_dUnderlineThickness; double m_dUnderlinePosition; double m_dStrikeOutThickness; double m_dStrikeOutPosition; int units_per_EM; }; PdfFontMetricsBase14* PODOFO_Base14FontDef_FindBuiltinData (const char *font_name); // ----------------------------------------------------- // // ----------------------------------------------------- inline double PdfFontMetricsBase14::GetCapHeight() const { return cap_height; } }; #endif // _PDF_FONT_METRICS_BASE14_H_ podofo-0.9.5/src/doc/PdfImage.h0000664000175000017500000003103212716144273016052 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_IMAGE_H_ #define _PDF_IMAGE_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfFilter.h" #include "PdfXObject.h" namespace PoDoFo { class PdfArray; class PdfDocument; class PdfInputStream; class PdfObject; class PdfVecObjects; /** A PdfImage object is needed when ever you want to embedd an image * file into a PDF document. * The PdfImage object is embedded once and can be drawn as often * as you want on any page in the document using PdfPainter * * \see GetImageReference * \see PdfPainter::DrawImage * * \see SetImageData */ class PODOFO_DOC_API PdfImage : public PdfXObject { public: /** Constuct a new PdfImage object * * \param pParent parent vector of this image * \param pszPrefix optional prefix for XObject-name */ PdfImage( PdfVecObjects* pParent, const char* pszPrefix = NULL ); /** Constuct a new PdfImage object * This is an overloaded constructor. * * \param pParent parent document * \param pszPrefix optional prefix for XObject-name */ PdfImage( PdfDocument* pParent, const char* pszPrefix = NULL ); /** Construct an image from an existing PdfObject * * \param pObject a PdfObject that has to be an image */ PdfImage( PdfObject* pObject ); ~PdfImage(); /** * Get a list of all image formats supported by this PoDoFo build. * * Example: { "JPEG", "TIFF", NULL } * * \returns a zero terminates list of all supported image formats */ static const char** GetSupportedFormats(); /** Set the color space of this image. The default value is * ePdfColorSpace_DeviceRGB. * \param eColorSpace one of ePdfColorSpace_DeviceGray, ePdfColorSpace_DeviceRGB and * ePdfColorSpace_DeviceCMYK, ePdfColorSpace_Indexed * \param indexedData this parameter is required only for ePdfColorSpace_Indexed and * it contains string with one number and then color palette, like "/DeviceRGB 15 <000000 00FF00...>" * or the string array can be a resource name. * * \see SetImageICCProfile to set an ICC profile instead of a simple colorspace */ void SetImageColorSpace( EPdfColorSpace eColorSpace, const PdfArray *indexedData = NULL ); /** Set an ICC profile for this image. * * \param pStream an input stream from which the ICC profiles data can be read * \param lColorComponents the number of colorcomponents of the ICC profile * \param eAlternateColorSpace an alternate colorspace to use if the ICC profile cannot be used * * \see SetImageColorSpace to set an colorspace instead of an ICC profile for this image */ void SetImageICCProfile( PdfInputStream* pStream, long lColorComponents, EPdfColorSpace eAlternateColorSpace = ePdfColorSpace_DeviceRGB ); //EPdfColorSpace GetImageColorSpace() const; /** Set a softmask for this image. * \param pSoftmask a PdfImage pointer to the image, which is to be set as softmask, must be 8-Bit-Grayscale * */ void SetImageSoftmask( const PdfImage* pSoftmask ); /** Get the width of the image when drawn in PDF units * \returns the width in PDF units */ inline double GetWidth() const; /** Get the height of the image when drawn in PDF units * \returns the height in PDF units */ inline double GetHeight() const; /** Set the actual image data from an input stream * * The image data will be flate compressed. * If you want no compression or another filter to be applied * use the overload of SetImageData which takes a TVecFilters * as argument. * * \param nWidth width of the image in pixels * \param nHeight height of the image in pixels * \param nBitsPerComponent bits per color component of the image (depends on the image colorspace you have set * but is 8 in most cases) * \param pStream stream supplieding raw image data * * \see SetImageData */ void SetImageData( unsigned int nWidth, unsigned int nHeight, unsigned int nBitsPerComponent, PdfInputStream* pStream ); /** Set the actual image data from an input stream * * \param nWidth width of the image in pixels * \param nHeight height of the image in pixels * \param nBitsPerComponent bits per color component of the image (depends on the image colorspace you have set * but is 8 in most cases) * \param pStream stream supplieding raw image data * \param vecFilters these filters will be applied to compress the image data */ void SetImageData( unsigned int nWidth, unsigned int nHeight, unsigned int nBitsPerComponent, PdfInputStream* pStream, const TVecFilters & vecFilters ); /** Set the actual image data from an input stream. * The data has to be encoded already and an appropriate * filters key entry has to be set manually before! * * \param nWidth width of the image in pixels * \param nHeight height of the image in pixels * \param nBitsPerComponent bits per color component of the image (depends on the image colorspace you have set * but is 8 in most cases) * \param pStream stream supplieding raw image data */ void SetImageDataRaw( unsigned int nWidth, unsigned int nHeight, unsigned int nBitsPerComponent, PdfInputStream* pStream ); /** Load the image data from a file * \param pszFilename */ void LoadFromFile( const char* pszFilename ); /** Load the image data from bytes * \param pData bytes * \param dwLen number of bytes */ void LoadFromData(const unsigned char* pData, pdf_long dwLen); #ifdef _WIN32 /** Load the image data from a file * \param pszFilename * * This is an overloaded member function to allow working * with unicode characters. On Unix systems you can also pass * UTF-8 to the const char* overload. */ void LoadFromFile( const wchar_t* pszFilename ); #endif // _WIN32 #ifdef PODOFO_HAVE_JPEG_LIB /** Load the image data from a JPEG file * \param pszFilename */ void LoadFromJpeg( const char* pszFilename ); /** Load the image data from JPEG bytes * \param pData JPEG bytes * \param dwLen number of bytes */ void LoadFromJpegData(const unsigned char* pData, pdf_long dwLen); #ifdef _WIN32 /** Load the image data from a JPEG file * \param pszFilename * * This is an overloaded member function to allow working * with unicode characters. On Unix systems you can also pass * UTF-8 to the const char* overload. */ void LoadFromJpeg( const wchar_t* pszFilename ); #endif // _WIN32 #endif // PODOFO_HAVE_JPEG_LIB #ifdef PODOFO_HAVE_TIFF_LIB /** Load the image data from a TIFF file * \param pszFilename */ void LoadFromTiff( const char* pszFilename ); /** Load the image data from TIFF bytes * \param pData TIFF bytes * \param dwLen number of bytes */ void LoadFromTiffData(const unsigned char* pData, pdf_long dwLen); #ifdef _WIN32 /** Load the image data from a TIFF file * \param pszFilename * * This is an overloaded member function to allow working * with unicode characters. On Unix systems you can also pass * UTF-8 to the const char* overload. */ void LoadFromTiff( const wchar_t* pszFilename ); #endif // _WIN32 #endif // PODOFO_HAVE_TIFF_LIB #ifdef PODOFO_HAVE_PNG_LIB /** Load the image data from a PNG file * \param pszFilename */ void LoadFromPng( const char* pszFilename ); /** Load the image data from PNG bytes * \param pData PNG bytes * \param dwLen number of bytes */ void LoadFromPngData(const unsigned char* pData, pdf_long dwLen); #ifdef _WIN32 /** Load the image data from a PNG file * \param pszFilename * * This is an overloaded member function to allow working * with unicode characters. On Unix systems you can also pass * UTF-8 to the const char* overload. */ void LoadFromPng( const wchar_t* pszFilename ); #endif // _WIN32 #endif // PODOFO_HAVE_PNG_LIB /** Set an color/chroma-key mask on an image. * The masked color will not be painted, i.e. masked as being transparent. * * \param r red RGB value of color that should be masked * \param g green RGB value of color that should be masked * \param b blue RGB value of color that should be masked * \param threshold colors are masked that are in the range [(r-threshold, r+threshold),(g-threshold, g+threshold),(b-threshold, b+threshold)] */ void SetImageChromaKeyMask(pdf_int64 r, pdf_int64 g, pdf_int64 b, pdf_int64 threshold = 0); /** * Apply an interpolation to the image if the source resolution * is lower than the resolution of the output device. * Default is false. * \param bValue whether the image should be interpolated */ void SetInterpolate(bool bValue); private: /** Converts a EPdfColorSpace enum to a name key which can be used in a * PDF dictionary. * \param eColorSpace a valid colorspace * \returns a valid key for this colorspace. */ static PdfName ColorspaceToName( EPdfColorSpace eColorSpace ); #ifdef PODOFO_HAVE_JPEG_LIB void LoadFromJpegHandle( PdfFileInputStream* pInStream ); #endif // PODOFO_HAVE_JPEG_LIB #ifdef PODOFO_HAVE_TIFF_LIB void LoadFromTiffHandle( void* pInStream ); #endif // PODOFO_HAVE_TIFF_LIB #ifdef PODOFO_HAVE_PNG_LIB void LoadFromPngHandle( PdfFileInputStream* pInStream ); #endif // PODOFO_HAVE_PNG_LIB }; // ----------------------------------------------------- // // ----------------------------------------------------- inline double PdfImage::GetWidth() const { return this->GetPageSize().GetWidth(); } // ----------------------------------------------------- // // ----------------------------------------------------- inline double PdfImage::GetHeight() const { return this->GetPageSize().GetHeight(); } }; #endif // _PDF_IMAGE_H_ podofo-0.9.5/src/doc/PdfFontSimple.cpp0000664000175000017500000001343513013650710017437 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfFontSimple.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfDictionary.h" #include "base/PdfEncoding.h" #include "base/PdfFilter.h" #include "base/PdfName.h" #include "base/PdfStream.h" namespace PoDoFo { PdfFontSimple::PdfFontSimple( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfVecObjects* pParent ) : PdfFont( pMetrics, pEncoding, pParent ), m_pDescriptor( NULL) { } PdfFontSimple::PdfFontSimple( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfObject* pObject ) : PdfFont( pMetrics, pEncoding, pObject ), m_pDescriptor( NULL) { } void PdfFontSimple::Init( bool bEmbed, const PdfName & rsSubType ) { if( !m_pEncoding ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } PdfObject* pWidth; PdfObject* pDescriptor; PdfVariant var; PdfArray array; pWidth = this->GetObject()->GetOwner()->CreateObject(); if( !pWidth ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } m_pMetrics->GetWidthArray( *pWidth, m_pEncoding->GetFirstChar(), m_pEncoding->GetLastChar(), m_pEncoding ); pDescriptor = this->GetObject()->GetOwner()->CreateObject( "FontDescriptor" ); if( !pDescriptor ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } std::string name; if ( m_bIsSubsetting ) name = this->GetObject()->GetOwner()->GetNextSubsetPrefix(); name += this->GetBaseFont().GetName(); this->GetObject()->GetDictionary().AddKey( PdfName::KeySubtype, rsSubType ); this->GetObject()->GetDictionary().AddKey("BaseFont", PdfName( name ) ); this->GetObject()->GetDictionary().AddKey("FirstChar", PdfVariant( static_cast(m_pEncoding->GetFirstChar()) ) ); this->GetObject()->GetDictionary().AddKey("LastChar", PdfVariant( static_cast(m_pEncoding->GetLastChar()) ) ); m_pEncoding->AddToDictionary( this->GetObject()->GetDictionary() ); // Add encoding key this->GetObject()->GetDictionary().AddKey("Widths", pWidth->Reference() ); this->GetObject()->GetDictionary().AddKey( "FontDescriptor", pDescriptor->Reference() ); m_pMetrics->GetBoundingBox( array ); pDescriptor->GetDictionary().AddKey( "FontName", PdfName( name ) ); //pDescriptor->GetDictionary().AddKey( "FontWeight", (long)m_pMetrics->Weight() ); pDescriptor->GetDictionary().AddKey( PdfName::KeyFlags, PdfVariant( static_cast(PODOFO_LL_LITERAL(32)) ) ); // TODO: 0 ???? pDescriptor->GetDictionary().AddKey( "FontBBox", array ); pDescriptor->GetDictionary().AddKey( "ItalicAngle", PdfVariant( static_cast(m_pMetrics->GetItalicAngle()) ) ); pDescriptor->GetDictionary().AddKey( "Ascent", m_pMetrics->GetPdfAscent() ); pDescriptor->GetDictionary().AddKey( "Descent", m_pMetrics->GetPdfDescent() ); pDescriptor->GetDictionary().AddKey( "CapHeight", m_pMetrics->GetPdfAscent() ); // m_pMetrics->CapHeight() ); pDescriptor->GetDictionary().AddKey( "StemV", PdfVariant( static_cast(PODOFO_LL_LITERAL(1)) ) ); // m_pMetrics->StemV() ); // Peter Petrov 24 September 2008 m_pDescriptor = pDescriptor; if( bEmbed ) { this->EmbedFontFile( pDescriptor ); m_bWasEmbedded = true; } } void PdfFontSimple::EmbedFont() { if (!m_bWasEmbedded) { this->EmbedFontFile( m_pDescriptor ); m_bWasEmbedded = true; } } }; podofo-0.9.5/src/doc/PdfExtGState.cpp0000664000175000017500000001237412347271543017244 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfExtGState.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfDictionary.h" #include "base/PdfWriter.h" #include "base/PdfLocale.h" #include "PdfPage.h" #include namespace PoDoFo { PdfExtGState::PdfExtGState( PdfVecObjects* pParent ) : PdfElement( "ExtGState", pParent ) { std::ostringstream out; // We probably aren't doing anything locale sensitive here, but it's // best to be sure. PdfLocaleImbue(out); // Implementation note: the identifier is always // Prefix+ObjectNo. Prefix is /Ft for fonts. out << "ExtGS" << this->GetObject()->Reference().ObjectNumber(); m_Identifier = PdfName( out.str().c_str() ); this->Init(); } PdfExtGState::PdfExtGState( PdfDocument* pParent ) : PdfElement( "ExtGState", pParent ) { std::ostringstream out; // We probably aren't doing anything locale sensitive here, but it's // best to be sure. PdfLocaleImbue(out); // Implementation note: the identifier is always // Prefix+ObjectNo. Prefix is /Ft for fonts. out << "ExtGS" << this->GetObject()->Reference().ObjectNumber(); m_Identifier = PdfName( out.str().c_str() ); this->Init(); } PdfExtGState::~PdfExtGState() { } void PdfExtGState::Init( void ) { } void PdfExtGState::SetFillOpacity( float opac ) { this->GetObject()->GetDictionary().AddKey( "ca", PdfVariant( static_cast(opac) ) ); } void PdfExtGState::SetStrokeOpacity( float opac ) { this->GetObject()->GetDictionary().AddKey( "CA", PdfVariant( opac ) ); } void PdfExtGState::SetBlendMode( const char* blendMode ) { this->GetObject()->GetDictionary().AddKey( "BM", PdfVariant( PdfName( blendMode ) ) ); } void PdfExtGState::SetOverprint( bool enable ) { this->GetObject()->GetDictionary().AddKey( "OP", PdfVariant( enable ) ); } void PdfExtGState::SetFillOverprint( bool enable ) { this->GetObject()->GetDictionary().AddKey( "op", PdfVariant( enable ) ); } void PdfExtGState::SetStrokeOverprint( bool enable ) { this->GetObject()->GetDictionary().AddKey( "OP", PdfVariant( enable ) ); } void PdfExtGState::SetNonZeroOverprint( bool enable ) { this->GetObject()->GetDictionary().AddKey( "OPM", PdfVariant( static_cast(enable ? PODOFO_LL_LITERAL(1) : PODOFO_LL_LITERAL(0)) ) ); } void PdfExtGState::SetRenderingIntent( const char* intent ) { this->GetObject()->GetDictionary().AddKey( "RI", PdfVariant( PdfName( intent ) ) ); } void PdfExtGState::SetFrequency( double frequency ) { PdfDictionary halftoneDict; halftoneDict.AddKey( "HalftoneType", PdfVariant( static_cast(PODOFO_LL_LITERAL(1)) ) ); halftoneDict.AddKey( "Frequency", PdfVariant( frequency ) ); halftoneDict.AddKey( "Angle", PdfVariant( 45.0 ) ); halftoneDict.AddKey( "SpotFunction", PdfName( "SimpleDot" ) ); this->GetObject()->GetDictionary().AddKey( "HT", halftoneDict); } } // end namespace podofo-0.9.5/src/doc/PdfAnnotation.h0000664000175000017500000003660413016622723017147 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_ANNOTATION_H_ #define _PDF_ANNOTATION_H_ #include "podofo/base/PdfDefines.h" #include "PdfAction.h" #include "PdfDestination.h" #include "PdfElement.h" namespace PoDoFo { class PdfFileSpec; class PdfName; class PdfPage; class PdfRect; class PdfReference; class PdfString; class PdfXObject; /** The type of the annotation. * PDF supports different annotation types, each of * them has different keys and propeties. * * Not all annotation types listed here are supported yet. * * Please make also sure that the annotation type you use is * supported by the PDF version you are using. */ enum EPdfAnnotation { ePdfAnnotation_Text = 0, // - supported ePdfAnnotation_Link, // - supported ePdfAnnotation_FreeText, // PDF 1.3 // - supported ePdfAnnotation_Line, // PDF 1.3 // - supported ePdfAnnotation_Square, // PDF 1.3 ePdfAnnotation_Circle, // PDF 1.3 ePdfAnnotation_Polygon, // PDF 1.5 ePdfAnnotation_PolyLine, // PDF 1.5 ePdfAnnotation_Highlight, // PDF 1.3 ePdfAnnotation_Underline, // PDF 1.3 ePdfAnnotation_Squiggly, // PDF 1.4 ePdfAnnotation_StrikeOut, // PDF 1.3 ePdfAnnotation_Stamp, // PDF 1.3 ePdfAnnotation_Caret, // PDF 1.5 ePdfAnnotation_Ink, // PDF 1.3 ePdfAnnotation_Popup, // PDF 1.3 // - supported ePdfAnnotation_FileAttachement,// PDF 1.3 ePdfAnnotation_Sound, // PDF 1.2 ePdfAnnotation_Movie, // PDF 1.2 ePdfAnnotation_Widget, // PDF 1.2 // - supported ePdfAnnotation_Screen, // PDF 1.5 ePdfAnnotation_PrinterMark, // PDF 1.4 ePdfAnnotation_TrapNet, // PDF 1.3 ePdfAnnotation_Watermark, // PDF 1.6 ePdfAnnotation_3D, // PDF 1.6 ePdfAnnotation_RichMedia, // PDF 1.7 ADBE ExtensionLevel 3 ALX: Petr P. Petrov ePdfAnnotation_WebMedia, // PDF 1.7 IPDF ExtensionLevel 3 ePdfAnnotation_Unknown = 0xff }; /** Flags that control the appearance of a PdfAnnotation. * You can OR them together and pass it to * PdfAnnotation::SetFlags. */ enum EPdfAnnotationFlags { ePdfAnnotationFlags_Invisible = 0x0001, ePdfAnnotationFlags_Hidden = 0x0002, ePdfAnnotationFlags_Print = 0x0004, ePdfAnnotationFlags_NoZoom = 0x0008, ePdfAnnotationFlags_NoRotate = 0x0010, ePdfAnnotationFlags_NoView = 0x0020, ePdfAnnotationFlags_ReadOnly = 0x0040, ePdfAnnotationFlags_Locked = 0x0080, ePdfAnnotationFlags_ToggleNoView = 0x0100, ePdfAnnotationFlags_LockedContents = 0x0200, ePdfAnnotationFlags_Unknow = 0xffff }; /** * Type of the annotation appearance. */ enum EPdfAnnotationAppearance { ePdfAnnotationAppearance_Normal = 0, /**< Normal appearance */ ePdfAnnotationAppearance_Rollover, /**< Rollover appearance; the default is ePdfAnnotationAppearance_Normal */ ePdfAnnotationAppearance_Down /**< Down appearance; the default is ePdfAnnotationAppearance_Normal */ }; /** An annotation to a PdfPage * To create an annotation use PdfPage::CreateAnnotation * * \see PdfPage::CreateAnnotation */ class PODOFO_DOC_API PdfAnnotation : public PdfElement { public: /** Create a new annotation object * * \param pPage the parent page of this annotation * \param eAnnot type of the annotation * \param rRect the rectangle in which the annotation will appear on the page * \param pParent parent of this annotation * * \see PdfPage::CreateAnnotation */ PdfAnnotation( PdfPage* pPage, EPdfAnnotation eAnnot, const PdfRect & rRect, PdfVecObjects* pParent ); /** Create a PdfAnnotation from an existing object * * \param pObject the annotations object * \param pPage the page of the annotation */ PdfAnnotation( PdfObject* pObject, PdfPage* pPage ); ~PdfAnnotation(); /** Set an appearance stream for this object * to specify its visual appearance * \param pObject an XObject * \param eApperance an apperance type to set * \param state the state for which set it the pObject; states depend on the annotation type */ void SetAppearanceStream( PdfXObject* pObject, EPdfAnnotationAppearance eAppearance = ePdfAnnotationAppearance_Normal, const PdfName & state = "" ); /** * \returns true if this annotation has an appearance stream */ bool HasAppearanceStream() const; /** Get the rectangle of this annotation * \returns a rectangle */ PdfRect GetRect() const; /** Set the flags of this annotation. * \param uiFlags is an unsigned 32bit integer with different * EPdfAnnotationFlags OR'ed together. * \see GetFlags */ void SetFlags( pdf_uint32 uiFlags ); /** Get the flags of this annotation. * \returns the flags which is an unsigned 32bit integer with different * EPdfAnnotationFlags OR'ed together. * * \see SetFlags */ pdf_uint32 GetFlags() const; /** Set the annotations border style. * \param dHCorner horitzontal corner radius * \param dVCorner vertical corner radius * \param dWidth width of border */ void SetBorderStyle( double dHCorner, double dVCorner, double dWidth ); /** Set the annotations border style. * \param dHCorner horitzontal corner radius * \param dVCorner vertical corner radius * \param dWidth width of border * \param rStrokeStyle a custom stroke style pattern */ void SetBorderStyle( double dHCorner, double dVCorner, double dWidth, const PdfArray & rStrokeStyle ); /** Set the title of this annotation. * \param sTitle title of the annoation as string in PDF format * * \see GetTitle */ void SetTitle( const PdfString & sTitle ); /** Get the title of this annotation * * \returns the title of this annotation * * \see SetTitle */ PdfString GetTitle() const; /** Set the text of this annotation. * * \param sContents text of the annoation as string in PDF format * * \see GetContents */ void SetContents( const PdfString & sContents ); /** Get the text of this annotation * * \returns the contents of this annotation * * \see SetContents */ PdfString GetContents() const; /** Set the destination for link annotations * \param rDestination target of the link * * \see GetDestination */ void SetDestination( const PdfDestination & rDestination ); /** Get the destination of a link annotations * \param pDoc a PdfDocument owning this annotation. * This is required to resolve names and pages. * \returns a destination object * * \see SetDestination */ PdfDestination GetDestination( PdfDocument* pDoc ) const; /** * \returns true if this annotation has an destination */ bool HasDestination() const; /** Set the action that is executed for this annotation * \param rAction an action object * * \see GetAction */ void SetAction( const PdfAction & rAction ); /** Get the action that is executed for this annotation * \returns an action object. The action object is owned * by the PdfAnnotation. * * \see SetAction */ PdfAction* GetAction() const; /** * \returns true if this annotation has an action */ bool HasAction() const; /** Sets wether this annotation is initialy open. * You should always set this true for popup annotations. * \param b if true open it */ void SetOpen( bool b ); /** * \returns true if this annotation should be opened immediately * by the viewer */ bool GetOpen() const; /** * \returns true if this annotation has a file attachement */ bool HasFileAttachement() const; /** Set a file attachment for this annotation. * The type of this annotation has to be * ePdfAnnotation_FileAttachement for file * attachements to work. * * \param rFileSpec a file specification */ void SetFileAttachement( const PdfFileSpec & rFileSpec ); /** Get a file attachement of this annotation. * \returns a file specification object. The file specification object is owned * by the PdfAnnotation. * * \see SetFileAttachement */ PdfFileSpec* GetFileAttachement() const; /** Get the quad points associated with the annotation (if appropriate). * This array is used in text markup annotations to describe the * regions affected by the markup (i.e. the hilighted words, one * quadrilateral per word) * * \returns a PdfArray of 8xn numbers describing the * x,y coordinates of BL BR TR TL corners of the * quadrilaterals. If inappropriate, returns * an empty array. */ PdfArray GetQuadPoints() const; /** Set the quad points associated with the annotation (if appropriate). * This array is used in text markup annotations to describe the * regions affected by the markup (i.e. the hilighted words, one * quadrilateral per word) * * \param rQuadPoints a PdfArray of 8xn numbers describing the * x,y coordinates of BL BR TR TL corners of the * quadrilaterals. */ void SetQuadPoints( const PdfArray & rQuadPoints ); /** Get the color key of the Annotation dictionary * which defines the color of the annotation, * as per 8.4 of the pdf spec. The PdfArray contains * 0 to four numbers, depending on the colorspace in * which the color is specified * 0 numbers means the annotation is transparent * 1 number specifies the intensity of the color in grayscale * 3 numbers specifie the color in the RGB colorspace and * 4 numbers specify the color in the CMYK colorspace * * \returns a PdfArray of either 0, 1, 3 or 4 numbers * depending on the colorspace in which the color * is specified */ PdfArray GetColor() const; /** Set the C key of the Annotation dictionary, which defines the * color of the annotation, as per 8.4 of the pdf spec. Parameters * give the color in rgb colorspace coordinates * * \param r number from 0 to 1, the intensity of the red channel * \param g number from 0 to 1, the intensity of the green channel * \param b number from 0 to 1, the intensity of the blue channel */ void SetColor( double r, double g, double b ); /** Set the C key of the Annotation dictionary, which defines the * color of the annotation, as per 8.4 of the pdf spec. Parameters * give the color in cmyk colorspace coordinates * * \param c number from 0 to 1, the intensity of the cyan channel * \param m number from 0 to 1, the intensity of the magneta channel * \param y number from 0 to 1, the intensity of the yellow channel * \param k number from 0 to 1, the intensity of the black channel */ void SetColor( double c, double m, double y, double k ); /** Set the C key of the Annotation dictionary, which defines the * color of the annotation, as per 8.4 of the pdf spec. Parameters * give the color in grayscale colorspace coordinates * * \param gray number from 0 to 1, the intensity of the black */ void SetColor( double gray ); /** Set the C key of the Annotation dictionary to an empty array, which, * as per 8.4 of the pdf spec., makes the annotation transparent * */ void SetColor(); /** Get the type of this annotation * \returns the annotation type */ inline EPdfAnnotation GetType() const; /** Get the page of this PdfField * * \returns the page of this PdfField */ inline PdfPage* GetPage() const; private: /** Convert an annotation enum to its string representation * which can be written to the PDF file. * \returns the string representation or NULL for unsupported annotation types */ static const long s_lNumActions; static const char* s_names[]; private: EPdfAnnotation m_eAnnotation; PdfAction* m_pAction; PdfFileSpec* m_pFileSpec; PdfPage* m_pPage; }; // helper function, to avoid code duplication void SetAppearanceStreamForObject( PdfObject* pForObject, PdfXObject* pObject, EPdfAnnotationAppearance eAppearance, const PdfName & state ); // ----------------------------------------------------- // // ----------------------------------------------------- inline EPdfAnnotation PdfAnnotation::GetType() const { return m_eAnnotation; } // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfPage* PdfAnnotation::GetPage() const { return m_pPage; } }; #endif /* _PDF_ANNOTATION_H_ */ podofo-0.9.5/src/doc/PdfElement.cpp0000664000175000017500000001111512344436402016747 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfElement.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfDictionary.h" #include "base/PdfObject.h" #include "base/PdfVecObjects.h" #include "PdfStreamedDocument.h" #include namespace PoDoFo { PdfElement::PdfElement( const char* pszType, PdfVecObjects* pParent ) { m_pObject = pParent->CreateObject( pszType ); } PdfElement::PdfElement( const char* pszType, PdfDocument* pParent ) { m_pObject = pParent->m_vecObjects.CreateObject( pszType ); } PdfElement::PdfElement( const char* pszType, PdfObject* pObject ) { if( !pObject ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } m_pObject = pObject; if( !m_pObject->IsDictionary() ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } if( pszType && m_pObject->GetDictionary().HasKey( PdfName::KeyType ) && m_pObject->GetDictionary().GetKeyAsName( PdfName::KeyType ) != pszType ) { PdfError::LogMessage( eLogSeverity_Debug, "Expected key %s but got key %s.", pszType, m_pObject->GetDictionary().GetKeyAsName( PdfName::KeyType ).GetName().c_str() ); PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } } PdfElement::PdfElement( EPdfDataType eExpectedDataType, PdfObject* pObject ) { if( !pObject ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } m_pObject = pObject; if( m_pObject->GetDataType() != eExpectedDataType ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } } PdfElement::~PdfElement() { } const char* PdfElement::TypeNameForIndex( int i, const char** ppTypes, long lLen ) const { return ( i >= lLen ? NULL : ppTypes[i] ); } int PdfElement::TypeNameToIndex( const char* pszType, const char** ppTypes, long lLen, int nUnknownValue ) const { int i; if( !pszType ) return nUnknownValue; for( i=0; iGetOwner()->CreateObject( pszType ); } }; podofo-0.9.5/src/doc/PdfTable.cpp0000664000175000017500000004343112751345713016421 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfTable.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfCanvas.h" #include "base/PdfRect.h" #include "PdfFont.h" #include "PdfImage.h" #include "PdfPainter.h" #include "PdfPage.h" #include namespace PoDoFo { PdfSimpleTableModel::PdfSimpleTableModel() : m_pFont( NULL ), m_eAlignment( ePdfAlignment_Left ), m_eVerticalAlignment( ePdfVerticalAlignment_Center ), m_bWordWrap( false), m_clForeground( 1.0 ), m_bBackground( false ), m_clBackground( 0.0 ), m_ppData( NULL ), m_nCols( 0 ), m_nRows( 0 ), m_bBorder( true ), m_dBorder( 1.0 ) { } PdfSimpleTableModel::PdfSimpleTableModel( int nCols, int nRows ) : m_pFont( NULL ), m_eAlignment( ePdfAlignment_Left ), m_eVerticalAlignment( ePdfVerticalAlignment_Center ), m_bWordWrap( false ), m_clForeground( 1.0 ), m_bBackground( false ), m_clBackground( 0.0 ), m_nCols( nCols ), m_nRows( nRows ), m_bBorder( true ), m_dBorder( 1.0 ) { m_ppData = static_cast(podofo_calloc( nRows, sizeof(PdfString*) )); if( !m_ppData ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } for( int i=0;iGetCols()]; double* pdRowHeights = new double[this->GetRows()]; bool bBorders = !m_pModel || m_pModel->HasBorders(); // Calculate all necessary sizes this->CalculateTableSize( dX, dY, pPainter->GetPage(), pdColWidths, pdRowHeights, &dWidth, &dHeight ); if( !(!static_cast(rClipRect.GetBottom()) && !static_cast(rClipRect.GetLeft()) && !static_cast(rClipRect.GetWidth()) && !static_cast(rClipRect.GetHeight())) ) m_curClipRect = rClipRect; else { m_curClipRect = PdfRect( 0.0, dX, pPainter->GetPage()->GetPageSize().GetWidth() - dX, dY ); } // Draw the table pPainter->Save(); PdfFont* pDefaultFont = pPainter->GetFont(); // get the default font PdfFont* pFont; // draw contents if( m_pModel ) { pPainter->SetStrokeWidth( m_pModel->GetBorderWidth() ); if( bBorders ) // draw top border this->DrawHorizontalBorders( 0, dX, dY, pPainter, pdColWidths ); for( j=0;jCheckForNewPage( &dY, &dCurY, pdRowHeights[j], pPainter ) && bBorders ) // draw top border on new page this->DrawHorizontalBorders( j, dX, dY, pPainter, pdColWidths ); dCurX = 0.0; dCurY += pdRowHeights[j]; for( i=0;iSave(); pPainter->SetClipRect( dX + dCurX, dY - dCurY, pdColWidths[i], pdRowHeights[j] ); // Draw background double dBorder = bBorders ? m_pModel->GetBorderWidth()/2.0 : 0.0; if( m_pModel->HasBackgroundColor( i, j ) ) { pPainter->Save(); pPainter->SetColor( m_pModel->GetBackgroundColor( i, j ) ); // Make sure that FillRect only fills inside the border // rectangle and not over the border. This is necessary // because we draw the border first and than the contents. pPainter->Rectangle( dX + dCurX + dBorder, dY - dCurY + dBorder, pdColWidths[i] - 2.0 * dBorder, pdRowHeights[j] - 2.0 * dBorder ); pPainter->Fill(); pPainter->Restore(); } // draw an image PdfImage* pImage = m_pModel->GetImage( i, j ); double dImageWidth = 0.0; if( m_pModel->HasImage( i, j ) && pImage ) { double dScaleX = (pdColWidths[i]) / pImage->GetPageSize().GetWidth(); double dScaleY = (pdRowHeights[j] - 2.0 * dBorder) / pImage->GetPageSize().GetHeight(); double dScale = PDF_MIN( dScaleX, dScaleY ); dImageWidth = pImage->GetPageSize().GetWidth() * dScale; pPainter->DrawImage( dX + dCurX, dY - dCurY + dBorder, pImage, dScale, dScale ); } // Set the correct font pFont = m_pModel->GetFont( i, j ); pFont = pFont ? pFont : pDefaultFont; pPainter->SetFont( pFont ); pPainter->SetColor( m_pModel->GetForegroundColor( i, j ) ); // draw text if( m_pModel->HasWordWrap( i, j ) ) { // Make sure we have at least 1 dot free space at each side of the rectangle pPainter->DrawMultiLineText( dX + dCurX + 1.0 + dImageWidth, dY - dCurY, pdColWidths[i] - 2.0 - dImageWidth, pdRowHeights[j], m_pModel->GetText( i, j ), m_pModel->GetAlignment( i, j ), m_pModel->GetVerticalAlignment( i, j ) ); } else { // calculate vertical alignment switch( m_pModel->GetVerticalAlignment( i, j ) ) { default: case ePdfVerticalAlignment_Top: dVertical = 0.0; break; case ePdfVerticalAlignment_Center: dVertical = (pdRowHeights[j] - pFont->GetFontMetrics()->GetLineSpacing()) / 2.0; break; case ePdfVerticalAlignment_Bottom: dVertical = (pdRowHeights[j] - pFont->GetFontMetrics()->GetLineSpacing()); break; } // Make sure we have at least 1 dot free space at each side of the rectangle pPainter->DrawTextAligned( dX + dCurX + 1 + dImageWidth, dY - dCurY + dVertical, pdColWidths[i] - 2.0 - dImageWidth, m_pModel->GetText( i, j ), m_pModel->GetAlignment( i, j ) ); } pPainter->Restore(); if( bBorders ) // draw left x border { // use always the border color of the left to the current cell pPainter->SetStrokingColor( m_pModel->GetBorderColor( i>0 ? i-1 : i, j ) ); pPainter->DrawLine( dX + dCurX, dY - dCurY, dX + dCurX, dY - dCurY + pdRowHeights[j] ); } dCurX += pdColWidths[i]; } if( bBorders ) { // Draw last X border if( i > 0 ) { pPainter->SetStrokingColor( m_pModel->GetBorderColor( i-1, j ) ); pPainter->DrawLine( dX + dCurX, dY - dCurY, dX + dCurX, dY - dCurY + pdRowHeights[j] ); } // draw border below row this->DrawHorizontalBorders( j, dX, dY - dCurY, pPainter, pdColWidths ); } } } pPainter->Restore(); if( pdLastX ) *pdLastX = dX + dWidth; if( pdLastY ) *pdLastY = dY - dCurY; // Free allocated memory delete [] pdColWidths; delete [] pdRowHeights; } void PdfTable::DrawHorizontalBorders( int nRow, double dX, double dY, PdfPainter* pPainter, double* pdColWidths ) { double dCurX = 0.0; pPainter->Save(); pPainter->SetLineCapStyle( ePdfLineCapStyle_Square ); for( int i=0;iSetStrokingColor( m_pModel->GetBorderColor( i, nRow ) ); pPainter->DrawLine( dX + dCurX, dY, dX + dCurX + pdColWidths[i], dY ); dCurX += pdColWidths[i]; } pPainter->Restore(); } double PdfTable::GetWidth( double dX, double dY, PdfCanvas* pPage ) const { double dWidth; double dHeight; double* pdColWidths = new double[this->GetCols()]; double* pdRowHeights = new double[this->GetRows()]; // Calculate all necessary sizes this->CalculateTableSize( dX, dY, pPage, pdColWidths, pdRowHeights, &dWidth, &dHeight ); delete [] pdColWidths; delete [] pdRowHeights; return dWidth; } double PdfTable::GetHeight( double dX, double dY, PdfCanvas* pPage ) const { double dWidth; double dHeight; double* pdColWidths = new double[this->GetCols()]; double* pdRowHeights = new double[this->GetRows()]; // Calculate all necessary sizes this->CalculateTableSize( dX, dY, pPage, pdColWidths, pdRowHeights, &dWidth, &dHeight ); delete [] pdColWidths; delete [] pdRowHeights; return dHeight; } void PdfTable::CalculateTableSize( const double dX, const double dY, const PdfCanvas* pCanvas, double* pdWidths, double* pdHeights, double* pdWidth, double* pdHeight ) const { int i; double dWidth = m_dColWidth; double dHeight = m_dRowHeight; // ----------------------------------------------------- // This functions works as follows: // (Description only for width, but the is true for height) // // If the user specified an array of row-widths using SetColumnWidths // just copy the array and use this values. // // Else check if the user has specified a total width for the table // devide the table width through the amount of rows and use the same // width for each row. // // If the user has not specified a table width, use the page width // and devide the page width through the amount of rows. // ----------------------------------------------------- if( m_pdColWidths ) memcpy( pdWidths, m_pdColWidths, sizeof(double) * m_nCols ); else { if( dWidth <= 0.0 ) { double dTableWidth = m_dTableWidth; if( (dTableWidth <= 0.0) ) { // Remove the x border at both sides of the table! dTableWidth = pCanvas->GetPageSize().GetWidth() - dX * 2.0; } dWidth = dTableWidth / static_cast(m_nCols); } for(i=0;i(m_nRows); } for(i=0;iRestore(); PdfPage* pPage = (*m_fpCallback)( m_curClipRect, m_pCustomData ); pPainter->SetPage( pPage ); pPainter->Save(); *pdY = m_curClipRect.GetBottom() + m_curClipRect.GetHeight(); *pdCurY = 0.0; return true; } return false; } void PdfTable::SetColumnWidths( double* pdWidths ) { if( m_pdColWidths ) { delete [] m_pdColWidths; m_pdColWidths = NULL; } if( pdWidths ) { m_pdColWidths = new double[this->GetCols()]; memcpy( m_pdColWidths, pdWidths, this->GetCols() * sizeof(double) ); } } void PdfTable::SetRowHeights( double* pdHeights ) { if( m_pdRowHeights ) { delete [] m_pdRowHeights; m_pdRowHeights = NULL; } if( pdHeights ) { m_pdRowHeights = new double[this->GetRows()]; memcpy( m_pdRowHeights, pdHeights, this->GetRows() * sizeof(double) ); } } /* void CReport::CreateTable( double dX, double dY, int iCols, int iRows, const char** apsTable, double* pdColWidths, double* pdRowHeights, bool bFillBackground ) { int i, j; double dWidth = 0.0; double dHeight = 0.0; const double dcTableBorder = 1000.0 * CONVERSION; mcPainter.Save(); PdfFont* pFont = mpDocument->CreateFont( "Arial" ); pFont->SetFontSize( 8.0f ); mcPainter.SetFont( pFont ); mcPainter.SetStrokeWidth( 1.0 * CONVERSION ); for( i=0;im_pFcConfig; } else { return NULL; } } #if defined(PODOFO_HAVE_FONTCONFIG) // ----------------------------------------------------- // // ----------------------------------------------------- Util::PdfMutex & PdfFontConfigWrapper::GetFontConfigMutex() { return m_FcMutex; } #endif }; // PoDoFo #endif // _PDF_FONT_WRAPPER_H_ podofo-0.9.5/src/doc/PdfFontMetricsFreetype.h0000664000175000017500000003110712714722103020764 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FONT_METRICS_FREETYPE_H_ #define _PDF_FONT_METRICS_FREETYPE_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/Pdf3rdPtyForwardDecl.h" #include "podofo/base/PdfString.h" #include "PdfFontMetrics.h" namespace PoDoFo { class PdfArray; class PdfObject; class PdfVariant; class PODOFO_DOC_API PdfFontMetricsFreetype : public PdfFontMetrics { public: /** Create a font metrics object for a given true type file * \param pLibrary handle to an initialized FreeType2 library handle * \param pszFilename filename of a truetype file * \param pIsSymbol whether use a symbol encoding, rather than unicode * \param pszSubsetPrefix unique prefix for font subsets (see GetFontSubsetPrefix) */ PdfFontMetricsFreetype( FT_Library* pLibrary, const char* pszFilename, bool pIsSymbol, const char* pszSubsetPrefix = NULL ); /** Create a font metrics object for a given memory buffer * \param pLibrary handle to an initialized FreeType2 library handle * \param pBuffer block of memory representing the font data (PdfFontMetricsFreetype will copy the buffer) * \param nBufLen the length of the buffer * \param pIsSymbol whether use a symbol encoding, rather than unicode * \param pszSubsetPrefix unique prefix for font subsets (see GetFontSubsetPrefix) */ PdfFontMetricsFreetype( FT_Library* pLibrary, const char* pBuffer, unsigned int nBufLen, bool pIsSymbol, const char* pszSubsetPrefix = NULL); /** Create a font metrics object for a given true type file * \param pLibrary handle to an initialized FreeType2 library handle * \param rBuffer a buffer containing a font file * \param pIsSymbol whether use a symbol encoding, rather than unicode * \param pszSubsetPrefix unique prefix for font subsets (see GetFontSubsetPrefix) */ PdfFontMetricsFreetype( FT_Library* pLibrary, const PdfRefCountedBuffer & rBuffer, bool pIsSymbol, const char* pszSubsetPrefix = NULL); /** Create a font metrics object for a given freetype font. * \param pLibrary handle to an initialized FreeType2 library handle * \param face a valid freetype font face * \param pIsSymbol whether use a symbol encoding, rather than unicode * \param pszSubsetPrefix unique prefix for font subsets (see GetFontSubsetPrefix) */ PdfFontMetricsFreetype( FT_Library* pLibrary, FT_Face face, bool pIsSymbol, const char* pszSubsetPrefix = NULL); /** Create a font metrics object based on an existing PdfObject * * \param pLibrary handle to an initialized FreeType2 library handle * \param pObject an existing font descriptor object */ PdfFontMetricsFreetype( FT_Library* pLibrary, PdfObject* pDescriptor ); /** Create a font metrics object suitable for subsetting for a given true type file * \param pLibrary handle to an initialized FreeType2 library handle * \param pszFilename filename of a truetype file * \param pIsSymbol whether use a symbol encoding, rather than unicode * \param pszSubsetPrefix unique prefix for font subsets (see GetFontSubsetPrefix) */ static PdfFontMetricsFreetype* CreateForSubsetting(FT_Library* pLibrary, const char* pszFilename, bool pIsSymbol, const char* pszSubsetPrefix ); virtual ~PdfFontMetricsFreetype(); /** Create a width array for this font which is a required part * of every font dictionary. * \param var the final width array is written to this PdfVariant * \param nFirst first character to be in the array * \param nLast last character code to be in the array * \param pEncoding encoding for correct character widths. If not passed default (latin1) encoding is used */ virtual void GetWidthArray( PdfVariant & var, unsigned int nFirst, unsigned int nLast, const PdfEncoding* pEncoding = NULL ) const; /** Get the width of a single glyph id * * \param nGlyphId id of the glyph * \returns the width of a single glyph id */ virtual double GetGlyphWidth( int nGlyphId ) const; /** Get the width of a single named glyph * * \param pszGlyphname name of the glyph * \returns the width of a single named glyph */ virtual double GetGlyphWidth( const char* pszGlyphname ) const; /** Create the bounding box array as required by the PDF reference * so that it can be written directly to a PDF file. * * \param array write the bounding box to this array. */ virtual void GetBoundingBox( PdfArray & array ) const; /** Retrieve the width of the given character in PDF units in the current font * \param c character * \returns the width in PDF units */ virtual double CharWidth( unsigned char c ) const; // Peter Petrov 20 March 2009 /** Retrieve the width of the given character in PDF units in the current font * \param c character * \returns the width in PDF units */ virtual double UnicodeCharWidth( unsigned short c ) const; /** Retrieve the line spacing for this font * \returns the linespacing in PDF units */ virtual double GetLineSpacing() const; /** Get the width of the underline for the current * font size in PDF units * \returns the thickness of the underline in PDF units */ virtual double GetUnderlineThickness() const; /** Return the position of the underline for the current font * size in PDF units * \returns the underline position in PDF units */ virtual double GetUnderlinePosition() const; /** Return the position of the strikeout for the current font * size in PDF units * \returns the underline position in PDF units */ virtual double GetStrikeOutPosition() const; /** Get the width of the strikeout for the current * font size in PDF units * \returns the thickness of the strikeout in PDF units */ virtual double GetStrikeoutThickness() const; /** Get a string with the postscript name of the font. * \returns the postscript name of the font or NULL string if no postscript name is available. */ virtual const char* GetFontname() const; /** Get the weight of this font. * Used to build the font dictionay * \returns the weight of this font (500 is normal). */ virtual unsigned int GetWeight() const; /** Get the ascent of this font in PDF * units for the current font size. * * \returns the ascender for this font * * \see GetPdfAscent */ virtual double GetAscent() const; /** Get the ascent of this font * Used to build the font dictionay * \returns the ascender for this font * * \see GetAscent */ virtual double GetPdfAscent() const; /** Get the descent of this font in PDF * units for the current font size. * This value is usually negative! * * \returns the descender for this font * * \see GetPdfDescent */ virtual double GetDescent() const; /** Get the descent of this font * Used to build the font dictionay * \returns the descender for this font * * \see GetDescent */ virtual double GetPdfDescent() const; /** Get the italic angle of this font. * Used to build the font dictionay * \returns the italic angle of this font. */ virtual int GetItalicAngle() const; /** Get the glyph id for a unicode character * in the current font. * * \param lUnicode the unicode character value * \returns the glyhph id for the character or 0 if the glyph was not found. */ virtual long GetGlyphId( long lUnicode ) const; /** Symbol fonts do need special treatment in a few cases. * Use this method to check if the current font is a symbol * font. Symbold fonts are detected by checking * if they use FT_ENCODING_MS_SYMBOL as internal encoding. * * \returns true if this is a symbol font */ virtual bool IsSymbol() const; /** Get a pointer to the actual font data - if it was loaded from memory. * \returns a binary buffer of data containing the font data */ virtual const char* GetFontData() const; /** Get the length of the actual font data - if it was loaded from memory. * \returns a the length of the font data */ virtual pdf_long GetFontDataLen() const; /** Get whether the internal font style flags contain the Bold flag. * \returns whether the Bold style flag is set on the font */ bool IsBold(void) const; /** Get whether the internal font style flags contain the Italic flag. * \returns whether the Italic style flag is set on the font */ bool IsItalic(void) const; /** Get direct access to the internal FreeType handle * * \returns the internal freetype handle */ inline FT_Face GetFace(); private: /** Initialize this object from an in memory buffer * Called internally by the constructors * \param pIsSymbol Whether use a symbol charset, rather than unicode */ void InitFromBuffer(bool pIsSymbol); /** Load the metric data from the FTFace data * Called internally by the constructors * \param pIsSymbol Whether use a symbol charset, rather than unicode */ void InitFromFace(bool pIsSymbol); void InitFontSizes(); protected: FT_Library* m_pLibrary; FT_Face m_pFace; private: bool m_bSymbol; ///< Internal member to singnal a symbol font bool m_bIsBold; bool m_bIsItalic; unsigned int m_nWeight; int m_nItalicAngle; double m_dAscent; double m_dPdfAscent; double m_dDescent; double m_dPdfDescent; double m_dLineSpacing; double m_dUnderlineThickness; double m_dUnderlinePosition; double m_dStrikeOutThickness; double m_dStrikeOutPosition; PdfRefCountedBuffer m_bufFontData; std::vector m_vecWidth; }; // ----------------------------------------------------- // // ----------------------------------------------------- FT_Face PdfFontMetricsFreetype::GetFace() { return m_pFace; } }; #endif // _PDF_FONT_METRICS_FREETYPE_H_ podofo-0.9.5/src/doc/PdfField.h0000664000175000017500000012224112730052013016040 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FIELD_H_ #define _PDF_FIELD_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfName.h" #include "podofo/base/PdfString.h" #include "PdfAnnotation.h" namespace PoDoFo { class PdfAcroForm; class PdfAction; class PdfAnnotation; class PdfDocument; class PdfObject; class PdfPage; class PdfRect; class PdfReference; class PdfStreamedDocument; /** The type of PDF field */ enum EPdfField { ePdfField_PushButton, ePdfField_CheckBox, ePdfField_RadioButton, ePdfField_TextField, ePdfField_ComboBox, ePdfField_ListBox, ePdfField_Signature, ePdfField_Unknown = 0xff }; /** The possible highlighting modes * for a PdfField. I.e the visual effect * that is to be used when the mouse * button is pressed. * * The default value is * ePdfHighlightingMode_Invert */ enum EPdfHighlightingMode { ePdfHighlightingMode_None, ///< Do no highlighting ePdfHighlightingMode_Invert, ///< Invert the PdfField ePdfHighlightingMode_InvertOutline, ///< Invert the fields border ePdfHighlightingMode_Push, ///< Display the fields down appearance (requires an additional appearance stream to be set) ePdfHighlightingMode_Unknown = 0xff }; class PODOFO_DOC_API PdfField { enum { ePdfField_ReadOnly = 0x0001, ePdfField_Required = 0x0002, ePdfField_NoExport = 0x0004 }; protected: /** Create a new PdfAcroForm dictionary object * \param pParent parent of this action */ PdfField( EPdfField eField, PdfAnnotation* pWidget, PdfAcroForm* pParent ); PdfField( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfAcroForm* pParent ); PdfField( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc ); PdfField( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfStreamedDocument* pDoc ); PdfField( EPdfField eField, PdfAnnotation* pWidget, PdfAcroForm* pParent, PdfDocument* pDoc); PdfField( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc, bool bDefaultApperance); /** Create a copy of a PdfField object. * Not the field on the page is copied - only the PdfField * object referring to the field on the page is copied! * * \param rhs the field to copy * \returns this field */ //inline virtual const PdfField & operator=( const PdfField & rhs ); /** * Set a bit in the field flags value of the fields dictionary. * * \param lValue the value specifying the bits to set * \param bSet if true the value will be set otherwise * they will be cleared. * * \see GetFieldFlag */ void SetFieldFlag( long lValue, bool bSet ); /** * \param lValue it is checked if these bits are set * \param bDefault the returned value if no field flags are specified * * \returns true if given bits are set in the field flags * * \see SetFieldFlag */ bool GetFieldFlag( long lValue, bool bDefault ) const; /** * \param bCreate create the dictionary if it does not exist * * \returns a pointer to the appearance characteristics dictionary * of this object or NULL if it does not exists. */ PdfObject* GetAppearanceCharacteristics( bool bCreate ) const; public: /** Create a PdfAcroForm dictionary object from an existing PdfObject * \param pObject the object to create from * \param pWidget the widget annotation of this field */ PdfField( PdfObject* pObject, PdfAnnotation* pWidget ); /** Create a copy of a PdfField object. * Not the field on the page is copied - only the PdfField * object referring to the field on the page is copied! * * \param rhs the field to copy */ PdfField( const PdfField & rhs ); virtual ~PdfField() { } /** Get the page of this PdfField * * \returns the page of this PdfField */ inline PdfPage* GetPage() const; /** Set the highlighting mode which should be used when the user * presses the mouse button over this widget. * * \param eMode the highliting mode * * The default value is ePdfHighlightingMode_Invert */ void SetHighlightingMode( EPdfHighlightingMode eMode ); /** * \returns the highlighting mode to be used when the user * presses the mouse button over this widget */ EPdfHighlightingMode GetHighlightingMode() const; /** * Sets the border color of the field to be transparent */ void SetBorderColorTransparent(); /** * Sets the border color of the field * * \param dGray gray value of the color */ void SetBorderColor( double dGray ); /** * Sets the border color of the field * * \param dRed red * \param dGreen green * \param dBlue blue */ void SetBorderColor( double dRed, double dGreen, double dBlue ); /** * Sets the border color of the field * * \param dCyan cyan * \param dMagenta magenta * \param dYellow yellow * \param dBlack black */ void SetBorderColor( double dCyan, double dMagenta, double dYellow, double dBlack ); /** * Sets the background color of the field to be transparent */ void SetBackgroundColorTransparent(); /** * Sets the background color of the field * * \param dGray gray value of the color */ void SetBackgroundColor( double dGray ); /** * Sets the background color of the field * * \param dRed red * \param dGreen green * \param dBlue blue */ void SetBackgroundColor( double dRed, double dGreen, double dBlue ); /** * Sets the background color of the field * * \param dCyan cyan * \param dMagenta magenta * \param dYellow yellow * \param dBlack black */ void SetBackgroundColor( double dCyan, double dMagenta, double dYellow, double dBlack ); /** Sets the field name of this PdfField * * PdfFields require a field name to work correctly in acrobat reader! * This name can be used to access the field in JavaScript actions. * * \param rsName the field name of this pdf field */ void SetFieldName( const PdfString & rsName ); /** \returns the field name of this PdfField */ PdfString GetFieldName() const; /** * Set the alternate name of this field which * is used to display the fields name to the user * (e.g. in error messages). * * \param rsName a name that can be displayed to the user */ void SetAlternateName( const PdfString & rsName ); /** \returns the fields alternate name */ PdfString GetAlternateName() const; /** * Sets the fields mapping name which is used when exporting * the fields data * * \param rsName the mapping name of this PdfField */ void SetMappingName( const PdfString & rsName ); /** \returns the mapping name of this field */ PdfString GetMappingName() const; /** Set this field to be readonly. * I.e. it will not interact with the user * and respond to mouse button events. * * This is useful for fields that are pure calculated. * * \param bReadOnly specifies if this field is read-only. */ inline void SetReadOnly( bool bReadOnly ); /** * \returns true if this field is read-only * * \see SetReadOnly */ inline bool IsReadOnly() const; /** Required fields must have a value * at the time the value is exported by a submit action * * \param bRequired if true this field requires a value for submit actions */ inline void SetRequired( bool bRequired ); /** * \returns true if this field is required for submit actions * * \see SetRequired */ inline bool IsRequired() const; /** Sets if this field can be exported by a submit action * * Fields can be exported by default. * * \param bExport if false this field cannot be exported by submit actions */ inline void SetExport( bool bExport ); /** * \returns true if this field can be exported by submit actions * * \see SetExport */ inline bool IsExport() const; inline void SetMouseEnterAction( const PdfAction & rAction ); inline void SetMouseLeaveAction( const PdfAction & rAction ); inline void SetMouseDownAction( const PdfAction & rAction ); inline void SetMouseUpAction( const PdfAction & rAction ); inline void SetFocusEnterAction( const PdfAction & rAction ); inline void SetFocusLeaveAction( const PdfAction & rAction ); inline void SetPageOpenAction( const PdfAction & rAction ); inline void SetPageCloseAction( const PdfAction & rAction ); inline void SetPageVisibleAction( const PdfAction & rAction ); inline void SetPageInvisibleAction( const PdfAction & rAction ); /* Peter Petrov 15 October 2008 */ inline void SetKeystrokeAction( const PdfAction & rAction ); inline void SetValidateAction( const PdfAction & rAction ); /** * \returns the type of this field */ inline EPdfField GetType() const; private: /** * Initialize this PdfField. * * \param pParent parent acro forms dictionary */ void Init( PdfAcroForm* pParent ); void AddAlternativeAction( const PdfName & rsName, const PdfAction & rAction ); protected: PdfObject* m_pObject; PdfAnnotation* m_pWidget; private: EPdfField m_eField; // Peter Petrov 27 April 2008 public: inline PdfAnnotation* GetWidgetAnnotation() const; inline PdfObject* GetFieldObject() const; }; // ----------------------------------------------------- // // ----------------------------------------------------- /* inline const PdfField & PdfField::operator=( const PdfField & rhs ) { // DominikS: Reference counted vectors could be nice here. In case // the PdfField handling makes sense the way it is now, // we could discuss using reference counted vectors // and implement PdfAction, PdfAnnotation ... similar to PdfField m_pObject = rhs.m_pObject; m_pWidget = rhs.m_pWidget; m_eField = rhs.m_eField; return *this; }*/ // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfField::SetReadOnly( bool bReadOnly ) { this->SetFieldFlag( static_cast(ePdfField_ReadOnly), bReadOnly ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfField::IsReadOnly() const { return this->GetFieldFlag( static_cast(ePdfField_ReadOnly), false ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfField::SetRequired( bool bRequired ) { this->SetFieldFlag( static_cast(ePdfField_Required), bRequired ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfField::IsRequired() const { return this->GetFieldFlag( static_cast(ePdfField_Required), false ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfField::SetExport( bool bExport ) { this->SetFieldFlag( static_cast(ePdfField_NoExport), bExport ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfField::IsExport() const { return this->GetFieldFlag( static_cast(ePdfField_NoExport), true ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfPage* PdfField::GetPage() const { return m_pWidget->GetPage(); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfField::SetMouseEnterAction( const PdfAction & rAction ) { this->AddAlternativeAction( PdfName("E"), rAction ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfField::SetMouseLeaveAction( const PdfAction & rAction ) { this->AddAlternativeAction( PdfName("X"), rAction ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfField::SetMouseDownAction( const PdfAction & rAction ) { this->AddAlternativeAction( PdfName("D"), rAction ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfField::SetMouseUpAction( const PdfAction & rAction ) { this->AddAlternativeAction( PdfName("U"), rAction ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfField::SetFocusEnterAction( const PdfAction & rAction ) { this->AddAlternativeAction( PdfName("Fo"), rAction ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfField::SetFocusLeaveAction( const PdfAction & rAction ) { this->AddAlternativeAction( PdfName("BI"), rAction ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfField::SetPageOpenAction( const PdfAction & rAction ) { this->AddAlternativeAction( PdfName("PO"), rAction ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfField::SetPageCloseAction( const PdfAction & rAction ) { this->AddAlternativeAction( PdfName("PC"), rAction ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfField::SetPageVisibleAction( const PdfAction & rAction ) { this->AddAlternativeAction( PdfName("PV"), rAction ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfField::SetPageInvisibleAction( const PdfAction & rAction ) { this->AddAlternativeAction( PdfName("PI"), rAction ); } /* Peter Petrov 15 October 2008 */ // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfField::SetKeystrokeAction( const PdfAction & rAction ) { this->AddAlternativeAction( PdfName("K"), rAction); } /* Peter Petrov 15 October 2008 */ // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfField::SetValidateAction( const PdfAction & rAction ) { this->AddAlternativeAction( PdfName("V"), rAction); } // ----------------------------------------------------- // // ----------------------------------------------------- inline EPdfField PdfField::GetType() const { return m_eField; } // Peter Petrov 27 April 2008 // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfAnnotation* PdfField::GetWidgetAnnotation() const { return m_pWidget; } // Peter Petrov 27 April 2008 // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfObject* PdfField::GetFieldObject() const { return m_pObject; } class PODOFO_DOC_API PdfButton : public PdfField { protected: enum { ePdfButton_NoToggleOff = 0x0004000, ePdfButton_Radio = 0x0008000, ePdfButton_PushButton = 0x0010000, ePdfButton_RadioInUnison = 0x2000000 }; /** Create a new PdfButton */ PdfButton( EPdfField eField, PdfAnnotation* pWidget, PdfAcroForm* pParent ); /** Create a new PdfButton */ PdfButton( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfAcroForm* pParent ); /** Create a new PdfButton */ PdfButton( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc ); /** Create a new PdfButton */ PdfButton( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfStreamedDocument* pDoc ); public: /** Create a PdfButton from a PdfField * \param rhs a PdfField that is a button * * Internal usage only. */ PdfButton( const PdfField & rhs ); /** * \returns true if this is a pushbutton */ inline bool IsPushButton() const; /** * \returns true if this is a checkbox */ inline bool IsCheckBox() const; /** * \returns true if this is a radiobutton */ inline bool IsRadioButton() const; /** Set the normal caption of this button * * \param rsText the caption */ void SetCaption( const PdfString & rsText ); /** * \returns the caption of this button */ const PdfString GetCaption() const; }; // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfButton::IsPushButton() const { return this->GetFieldFlag( static_cast(ePdfButton_PushButton), false ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfButton::IsCheckBox() const { return (!this->GetFieldFlag( static_cast(ePdfButton_Radio), false ) && !this->GetFieldFlag( static_cast(ePdfButton_PushButton), false ) ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfButton::IsRadioButton() const { return this->GetFieldFlag( static_cast(ePdfButton_Radio), false ); } /** A push button is a button which has no state and value * but can toggle actions. */ class PODOFO_DOC_API PdfPushButton : public PdfButton { public: /** Create a new PdfPushButton */ PdfPushButton( PdfAnnotation* pWidget, PdfAcroForm* pParent ); /** Create a new PdfPushButton */ PdfPushButton( PdfPage* pPage, const PdfRect & rRect, PdfAcroForm* pParent ); /** Create a new PdfPushButton */ PdfPushButton( PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc ); /** Create a new PdfPushButton */ PdfPushButton( PdfPage* pPage, const PdfRect & rRect, PdfStreamedDocument* pDoc ); /** Create a PdfPushButton from a PdfField * \param rhs a PdfField that is a push button button * * Raises an error if PdfField::GetType() != ePdfField_PushButton */ PdfPushButton( const PdfField & rhs ); /** Set the rollover caption of this button * which is displayed when the cursor enters the field * without the mouse button being pressed * * \param rsText the caption */ void SetRolloverCaption( const PdfString & rsText ); /** * \returns the rollover caption of this button */ const PdfString GetRolloverCaption() const; /** Set the alternate caption of this button * which is displayed when the button is pressed. * * \param rsText the caption */ void SetAlternateCaption( const PdfString & rsText ); /** * \returns the rollover caption of this button */ const PdfString GetAlternateCaption() const; private: void Init(); }; /** A checkbox can be checked or unchecked by the user */ class PODOFO_DOC_API PdfCheckBox : public PdfButton { public: /** Create a new PdfCheckBox */ PdfCheckBox( PdfAnnotation* pWidget, PdfAcroForm* pParent ); /** Create a new PdfCheckBox */ PdfCheckBox( PdfPage* pPage, const PdfRect & rRect, PdfAcroForm* pParent ); /** Create a new PdfCheckBox */ PdfCheckBox( PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc ); /** Create a new PdfCheckBox */ PdfCheckBox( PdfPage* pPage, const PdfRect & rRect, PdfStreamedDocument* pDoc ); /** Create a PdfCheckBox from a PdfField * \param rhs a PdfField that is a check box * * Raises an error if PdfField::GetType() != ePdfField_CheckBox */ PdfCheckBox( const PdfField & rhs ); /** Set the appearance stream which is displayed when the checkbox * is checked. * * \param rXObject an xobject which contains the drawing commands for a checked checkbox */ void SetAppearanceChecked( const PdfXObject & rXObject ); /** Set the appearance stream which is displayed when the checkbox * is unchecked. * * \param rXObject an xobject which contains the drawing commands for an unchecked checkbox */ void SetAppearanceUnchecked( const PdfXObject & rXObject ); /** Sets the state of this checkbox * * \param bChecked if true the checkbox will be checked */ void SetChecked( bool bChecked ); /** * \returns true if the checkbox is checked */ bool IsChecked() const; private: void Init(); /** Add a appearance stream to this checkbox * * \param rName name of the appearance stream * \param rReference reference to the XObject containing the appearance stream */ void AddAppearanceStream( const PdfName & rName, const PdfReference & rReference ); }; // TODO: Dominiks PdfRadioButton /** A textfield in a PDF file. * * Users can enter text into a text field. * Single and multi line text is possible, * as well as richtext. The text can be interpreted * as path to a file which is going to be submitted. */ class PODOFO_DOC_API PdfTextField : public PdfField { private: enum { ePdfTextField_MultiLine = 0x0001000, ePdfTextField_Password = 0x0002000, ePdfTextField_FileSelect = 0x0100000, ePdfTextField_NoSpellcheck = 0x0400000, ePdfTextField_NoScroll = 0x0800000, ePdfTextField_Comb = 0x1000000, ePdfTextField_RichText = 0x2000000 }; public: /** Create a new PdfTextField */ PdfTextField( PdfAnnotation* pWidget, PdfAcroForm* pParent ); /** Create a new PdfTextField */ PdfTextField( PdfPage* pPage, const PdfRect & rRect, PdfAcroForm* pParent ); /** Create a new PdfTextField */ PdfTextField( PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc ); /** Create a new PdfTextField */ PdfTextField( PdfPage* pPage, const PdfRect & rRect, PdfStreamedDocument* pDoc ); /** Create a PdfTextField from a PdfField * * \param rhs a PdfField that is a PdfTextField * * Raises an error if PdfField::GetType() != ePdfField_TextField */ PdfTextField( const PdfField & rhs ); /** Sets the text contents of this text field. * * \param rsText the text of this field */ void SetText( const PdfString & rsText ); /** * \returns the text contents of this text field */ PdfString GetText() const; /** Sets the max length in characters of this textfield * \param nMaxLen the max length of this textfields in characters */ void SetMaxLen( pdf_long nMaxLen ); /** * \returns the max length of this textfield in characters or -1 * if no max length was specified */ pdf_long GetMaxLen() const; /** * Create a multi-line text field that can contains multiple lines of text. * \param bMultiLine if true a multi line field is generated, otherwise * the text field can contain only a single line of text. * * The default is to create a single line text field. */ inline void SetMultiLine( bool bMultiLine ); /** * \returns true if this text field can contain multiple lines of text */ inline bool IsMultiLine() const; /** * Create a password text field that should not echo entered * characters visibly to the screen. * * \param bPassword if true a password field is created * * The default is to create no password field */ inline void SetPasswordField( bool bPassword ); /** * \returns true if this field is a password field that does * not echo entered characters on the screen */ inline bool IsPasswordField() const; /** * Create a file selection field. * The entered contents are treated as filename to a file * whose contents are submitted as the value of the field. * * \param bFile if true the contents are treated as a pathname * to a file to submit */ inline void SetFileField( bool bFile ); /** * \returns true if the contents are treated as filename */ inline bool IsFileField() const; /** * Enable/disable spellchecking for this text field * * \param bSpellcheck if true spellchecking will be enabled * * Text fields are spellchecked by default */ inline void SetSpellcheckingEnabled( bool bSpellcheck ); /** * \returns true if spellchecking is enabled for this text field */ inline bool IsSpellcheckingEnabled() const; /** * Enable/disable scrollbars for this text field * * \param bScroll if true scrollbars will be enabled * * Text fields have scrollbars by default */ inline void SetScrollBarsEnabled( bool bScroll ); /** * \returns true if scrollbars are enabled for this text field */ inline bool IsScrollBarsEnabled() const; /** * Divide the text field into max-len equal * combs. * * \param bCombs if true enable division into combs * * By default combs are disabled. Requires the max-len * property to be set. * * \see SetMaxLen */ inline void SetCombs( bool bCombs ); /** * \returns true if the text field has a division into equal combs set on it */ inline bool IsCombs() const; /** * Creates a richtext field. * * \param bRichText if true creates a richtext field * * By default richtext is disabled. */ inline void SetRichText( bool bRichText ); /** * \returns true if this is a richtext text field */ inline bool IsRichText() const; private: void Init(); }; // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfTextField::SetMultiLine( bool bMultiLine ) { this->SetFieldFlag( static_cast(ePdfTextField_MultiLine), bMultiLine ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfTextField::IsMultiLine() const { return this->GetFieldFlag( static_cast(ePdfTextField_MultiLine), false ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfTextField::SetPasswordField( bool bPassword ) { this->SetFieldFlag( static_cast(ePdfTextField_Password), bPassword ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfTextField::IsPasswordField() const { return this->GetFieldFlag( static_cast(ePdfTextField_Password), false ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfTextField::SetFileField( bool bFile ) { this->SetFieldFlag( static_cast(ePdfTextField_FileSelect), bFile ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfTextField::IsFileField() const { return this->GetFieldFlag( static_cast(ePdfTextField_FileSelect), false ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfTextField::SetSpellcheckingEnabled( bool bSpellcheck ) { this->SetFieldFlag( static_cast(ePdfTextField_NoSpellcheck), !bSpellcheck ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfTextField::IsSpellcheckingEnabled() const { return this->GetFieldFlag( static_cast(ePdfTextField_NoSpellcheck), true ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfTextField::SetScrollBarsEnabled( bool bScroll ) { this->SetFieldFlag( static_cast(ePdfTextField_NoScroll), !bScroll ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfTextField::IsScrollBarsEnabled() const { return this->GetFieldFlag( static_cast(ePdfTextField_NoScroll), true ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfTextField::SetCombs( bool bCombs ) { this->SetFieldFlag( static_cast(ePdfTextField_Comb), bCombs ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfTextField::IsCombs() const { return this->GetFieldFlag( static_cast(ePdfTextField_Comb), false ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfTextField::SetRichText( bool bRichText ) { this->SetFieldFlag( static_cast(ePdfTextField_RichText), bRichText); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfTextField::IsRichText() const { return this->GetFieldFlag( static_cast(ePdfTextField_RichText), false ); } /** A list of items in a PDF file. * You cannot create this object directly, use * PdfComboBox or PdfListBox instead. * * \see PdfComboBox * \see PdfListBox */ class PODOFO_DOC_API PdfListField : public PdfField { protected: enum { ePdfListField_Combo = 0x0020000, ePdfListField_Edit = 0x0040000, ePdfListField_Sort = 0x0080000, ePdfListField_MultiSelect = 0x0200000, ePdfListField_NoSpellcheck = 0x0400000, ePdfListField_CommitOnSelChange = 0x4000000 }; /** Create a new PdfTextField */ PdfListField( EPdfField eField, PdfAnnotation* pWidget, PdfAcroForm* pParent ); /** Create a new PdfTextField */ PdfListField( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfAcroForm* pParent ); /** Create a new PdfTextField */ PdfListField( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc ); /** Create a new PdfTextField */ PdfListField( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfStreamedDocument* pDoc ); public: /** Create a PdfListField from a PdfField * \param rhs a PdfField that is a list field * * Internal usage only. */ PdfListField( const PdfField & rhs ); //const PdfString & GetSelectedItem(); /// ??? /** * Inserts a new item into the list * * @param rsValue the value of the item * @param rsDisplayName an optional display string that is displayed in the viewer * instead of the value */ void InsertItem( const PdfString & rsValue, const PdfString & rsDisplayName = PdfString::StringNull ); /** * Removes an item for the list * * @param nIndex index of the item to remove */ void RemoveItem( int nIndex ); /** * @param nIndex index of the item * @returns the value of the item at the specified index */ const PdfString GetItem( int nIndex ) const; /** * @param nIndex index of the item * @returns the display text of the item or if it has no display text * its value is returned. This call is equivalent to GetItem() * in this case * * \see GetItem */ const PdfString GetItemDisplayText( int nIndex ) const; /** * \returns the number of items in this list */ size_t GetItemCount() const; /** Sets the currently selected item * \param nIndex index of the currently selected item */ void SetSelectedItem( int nIndex ); /** Sets the currently selected item * * \returns the selected item or -1 if no item was selected */ int GetSelectedItem() const; #if 0 // TODO: #error "Only allow these if multiselect is true!" void SetSelectedItems( ... ); PdfArray GetSelectedItems() ; #endif /** * \returns true if this PdfListField is a PdfComboBox and false * if it is a PdfListBox */ inline bool IsComboBox() const; /** * Enable/disable spellchecking for this combobox * * \param bSpellcheck if true spellchecking will be enabled * * combobox are spellchecked by default */ inline void SetSpellcheckingEnabled( bool bSpellcheck ); /** * \returns true if spellchecking is enabled for this combobox */ inline bool IsSpellcheckingEnabled() const; /** * Enable or disable sorting of items. * The sorting does not happen in acrobat reader * but whenever adding items using PoDoFo or another * PDF editing application. * * \param bSorted enable/disable sorting */ inline void SetSorted( bool bSorted ); /** * \returns true if sorting is enabled */ inline bool IsSorted() const; /** * Sets wether multiple items can be selected by the * user in the list. * * \param bMulti if true multiselect will be enabled * * By default multiselection is turned off. */ inline void SetMultiSelect( bool bMulti ); /** * \returns true if multi selection is enabled * for this list */ inline bool IsMultiSelect() const; inline void SetCommitOnSelectionChange( bool bCommit ); inline bool IsCommitOnSelectionChange() const; }; // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfListField::IsComboBox() const { return this->GetFieldFlag( static_cast(ePdfListField_Combo), false ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfListField::SetSpellcheckingEnabled( bool bSpellcheck ) { this->SetFieldFlag( static_cast(ePdfListField_NoSpellcheck), !bSpellcheck ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfListField::IsSpellcheckingEnabled() const { return this->GetFieldFlag( static_cast(ePdfListField_NoSpellcheck), true ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfListField::SetSorted( bool bSorted ) { this->SetFieldFlag( static_cast(ePdfListField_Sort), bSorted ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfListField::IsSorted() const { return this->GetFieldFlag( static_cast(ePdfListField_Sort), false ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfListField::SetMultiSelect( bool bMulti ) { this->SetFieldFlag( static_cast(ePdfListField_MultiSelect), bMulti ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfListField::IsMultiSelect() const { return this->GetFieldFlag( static_cast(ePdfListField_MultiSelect), false ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfListField::SetCommitOnSelectionChange( bool bCommit ) { this->SetFieldFlag( static_cast(ePdfListField_CommitOnSelChange), bCommit ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfListField::IsCommitOnSelectionChange() const { return this->GetFieldFlag( static_cast(ePdfListField_CommitOnSelChange), false ); } /** A combo box with a drop down list of items. */ class PODOFO_DOC_API PdfComboBox : public PdfListField { public: /** Create a new PdfTextField */ PdfComboBox( PdfAnnotation* pWidget, PdfAcroForm* pParent ); /** Create a new PdfTextField */ PdfComboBox( PdfPage* pPage, const PdfRect & rRect, PdfAcroForm* pParent ); /** Create a new PdfTextField */ PdfComboBox( PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc ); /** Create a new PdfTextField */ PdfComboBox( PdfPage* pPage, const PdfRect & rRect, PdfStreamedDocument* pDoc ); /** Create a PdfComboBox from a PdfField * * \param rhs a PdfField that is a PdfComboBox * * Raises an error if PdfField::GetType() != ePdfField_ComboBox */ PdfComboBox( const PdfField & rhs ); /** * Sets the combobox to be editable * * \param bEdit if true the combobox can be edited by the user * * By default a combobox is not editable */ inline void SetEditable( bool bEdit ); /** * \returns true if this is an editable combobox */ inline bool IsEditable() const; }; // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfComboBox::SetEditable( bool bEdit ) { this->SetFieldFlag( static_cast(ePdfListField_Edit), bEdit); } // ----------------------------------------------------- // // ----------------------------------------------------- inline bool PdfComboBox::IsEditable() const { return this->GetFieldFlag( static_cast(ePdfListField_Edit), false ); } /** A list box */ class PODOFO_DOC_API PdfListBox : public PdfListField { public: /** Create a new PdfTextField */ PdfListBox( PdfAnnotation* pWidget, PdfAcroForm* pParent ); /** Create a new PdfTextField */ PdfListBox( PdfPage* pPage, const PdfRect & rRect, PdfAcroForm* pParent ); /** Create a new PdfTextField */ PdfListBox( PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc ); /** Create a new PdfTextField */ PdfListBox( PdfPage* pPage, const PdfRect & rRect, PdfStreamedDocument* pDoc ); /** Create a PdfListBox from a PdfField * * \param rhs a PdfField that is a PdfComboBox * * Raises an error if PdfField::GetType() != ePdfField_ListBox */ PdfListBox( const PdfField & rhs ); }; }; #endif // _PDF_ACRO_FORM_H__PDF_NAMES_TREE_H_ podofo-0.9.5/src/doc/PdfPagesTreeCache.cpp0000664000175000017500000001301612344436402020163 0ustar dominikdominik/*************************************************************************** * Copyriht (C) 2009 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfPagesTreeCache.h" #include "base/PdfDefinesPrivate.h" #include "PdfPage.h" #include "PdfPagesTree.h" namespace PoDoFo { PdfPagesTreeCache::PdfPagesTreeCache( int nInitialSize ) { m_deqPageObjs.resize( nInitialSize ); } PdfPagesTreeCache::~PdfPagesTreeCache() { this->ClearCache(); } PdfPage* PdfPagesTreeCache::GetPage( int nIndex ) { if( nIndex < 0 || nIndex >= static_cast(m_deqPageObjs.size()) ) { PdfError::LogMessage( eLogSeverity_Error, "PdfPagesTreeCache::GetPage( %i ) index out of range. Size of cache is %i\n", nIndex, m_deqPageObjs.size() ); return NULL; } return m_deqPageObjs[nIndex]; } void PdfPagesTreeCache::AddPageObject( int nIndex, PdfPage* pPage ) { // Delete an old page if it is at the same position PdfPage* pOldPage = GetPage( nIndex ); delete pOldPage; if( nIndex >= static_cast(m_deqPageObjs.size()) ) { m_deqPageObjs.resize( nIndex + 1 ); } m_deqPageObjs[nIndex] = pPage; } void PdfPagesTreeCache::AddPageObjects( int nIndex, std::vector vecPages ) { if( (nIndex + static_cast(vecPages.size())) >= static_cast(m_deqPageObjs.size()) ) { m_deqPageObjs.resize( nIndex + vecPages.size() + 1 ); } for (size_t i=0; i= static_cast(m_deqPageObjs.size()) ) m_deqPageObjs.resize( nBeforeIndex + 1 ); m_deqPageObjs.insert( m_deqPageObjs.begin() + nBeforeIndex, static_cast(NULL) ); } void PdfPagesTreeCache::InsertPages( int nAfterPageIndex, int nCount ) { const int nBeforeIndex = ( nAfterPageIndex == ePdfPageInsertionPoint_InsertBeforeFirstPage ) ? 0 : nAfterPageIndex+1; if( nBeforeIndex+nCount >= static_cast(m_deqPageObjs.size()) ) m_deqPageObjs.resize( nBeforeIndex + nCount + 1 ); for (int i=0; i(NULL) ); } void PdfPagesTreeCache::DeletePage( int nIndex ) { if( nIndex < 0 || nIndex >= static_cast(m_deqPageObjs.size()) ) { PdfError::LogMessage( eLogSeverity_Error, "PdfPagesTreeCache::DeletePage( %i ) index out of range. Size of cache is %i\n", nIndex, m_deqPageObjs.size() ); return; } delete m_deqPageObjs[nIndex]; m_deqPageObjs.erase( m_deqPageObjs.begin() + nIndex ); } void PdfPagesTreeCache::ClearCache() { PdfPageList::iterator it = m_deqPageObjs.begin(); while( it != m_deqPageObjs.end() ) { delete (*it); ++it; } m_deqPageObjs.clear(); } }; podofo-0.9.5/src/doc/PdfFunction.cpp0000664000175000017500000001605712347271543017163 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfFunction.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfDictionary.h" #include "base/PdfStream.h" namespace PoDoFo { PdfFunction::PdfFunction( EPdfFunctionType eType, const PdfArray & rDomain, PdfVecObjects* pParent ) : PdfElement( NULL, pParent ) { Init( eType, rDomain ); } PdfFunction::PdfFunction( EPdfFunctionType eType, const PdfArray & rDomain, PdfDocument* pParent ) : PdfElement( NULL, pParent ) { Init( eType, rDomain ); } PdfFunction::~PdfFunction() { } void PdfFunction::Init( EPdfFunctionType eType, const PdfArray & rDomain ) { this->GetObject()->GetDictionary().AddKey( PdfName("FunctionType"), static_cast(eType) ); this->GetObject()->GetDictionary().AddKey( PdfName("Domain"), rDomain ); } ///////////////////////////////////////////////////////////////////////////// PdfSampledFunction::PdfSampledFunction( const PdfArray & rDomain, const PdfArray & rRange, const PdfFunction::Sample & rlstSamples, PdfVecObjects* pParent ) : PdfFunction( ePdfFunctionType_Sampled, rDomain, pParent ) { Init( rDomain, rRange, rlstSamples ); } PdfSampledFunction::PdfSampledFunction( const PdfArray & rDomain, const PdfArray & rRange, const PdfFunction::Sample & rlstSamples, PdfDocument* pParent ) : PdfFunction( ePdfFunctionType_Sampled, rDomain, pParent ) { Init( rDomain, rRange, rlstSamples ); } void PdfSampledFunction::Init( const PdfArray & rDomain, const PdfArray & rRange, const PdfFunction::Sample & rlstSamples ) { PdfArray Size; for( unsigned i = 0; i < rDomain.GetSize() / 2; i++ ) Size.push_back( PdfObject( static_cast(rDomain.GetSize() / 2L )) ); this->GetObject()->GetDictionary().AddKey( PdfName("Domain"), rDomain ); this->GetObject()->GetDictionary().AddKey( PdfName("Range"), rRange ); this->GetObject()->GetDictionary().AddKey( PdfName("Size"), Size ); this->GetObject()->GetDictionary().AddKey( PdfName("Order"), PdfObject( static_cast(PODOFO_LL_LITERAL(1)) ) ); this->GetObject()->GetDictionary().AddKey( PdfName("BitsPerSample"), PdfObject( static_cast(PODOFO_LL_LITERAL(8)) ) ); this->GetObject()->GetStream()->BeginAppend(); PdfFunction::Sample::const_iterator it = rlstSamples.begin(); while( it != rlstSamples.end() ) { this->GetObject()->GetStream()->Append( & ( *it ), 1 ); ++it; } this->GetObject()->GetStream()->EndAppend(); } ///////////////////////////////////////////////////////////////////////////// PdfExponentialFunction::PdfExponentialFunction( const PdfArray & rDomain, const PdfArray & rC0, const PdfArray & rC1, double dExponent, PdfVecObjects* pParent ) : PdfFunction( ePdfFunctionType_Exponential, rDomain, pParent ) { Init( rC0, rC1, dExponent ); } PdfExponentialFunction::PdfExponentialFunction( const PdfArray & rDomain, const PdfArray & rC0, const PdfArray & rC1, double dExponent, PdfDocument* pParent ) : PdfFunction( ePdfFunctionType_Exponential, rDomain, pParent ) { Init( rC0, rC1, dExponent ); } void PdfExponentialFunction::Init( const PdfArray & rC0, const PdfArray & rC1, double dExponent ) { this->GetObject()->GetDictionary().AddKey( PdfName("C0"), rC0 ); this->GetObject()->GetDictionary().AddKey( PdfName("C1"), rC1 ); this->GetObject()->GetDictionary().AddKey( PdfName("N"), dExponent ); } ///////////////////////////////////////////////////////////////////////////// PdfStitchingFunction::PdfStitchingFunction( const PdfFunction::List & rlstFunctions, const PdfArray & rDomain, const PdfArray & rBounds, const PdfArray & rEncode, PdfVecObjects* pParent ) : PdfFunction( ePdfFunctionType_Stitching, rDomain, pParent ) { Init( rlstFunctions, rBounds, rEncode ); } PdfStitchingFunction::PdfStitchingFunction( const PdfFunction::List & rlstFunctions, const PdfArray & rDomain, const PdfArray & rBounds, const PdfArray & rEncode, PdfDocument* pParent ) : PdfFunction( ePdfFunctionType_Stitching, rDomain, pParent ) { Init( rlstFunctions, rBounds, rEncode ); } void PdfStitchingFunction::Init( const PdfFunction::List & rlstFunctions, const PdfArray & rBounds, const PdfArray & rEncode ) { PdfArray functions; PdfFunction::List::const_iterator it = rlstFunctions.begin(); functions.reserve( rlstFunctions.size() ); while( it != rlstFunctions.end() ) { functions.push_back( (*it).GetObject()->Reference() ); ++it; } this->GetObject()->GetDictionary().AddKey( PdfName("Functions"), functions ); this->GetObject()->GetDictionary().AddKey( PdfName("Bounds"), rBounds ); this->GetObject()->GetDictionary().AddKey( PdfName("Encode"), rEncode ); } }; podofo-0.9.5/src/doc/podofo-doc.rc0000664000175000017500000000504312626641131016602 0ustar dominikdominik#define PODOFO_COMPILE_RC #include "base/podofoapi.h" #include "base/PdfDefines.h" #include "base/PdfVersion.h" #include "winresrc.h" #undef PODOFO_COMPILE_RC #define VER_PRODUCTVERSION PODOFO_MAJOR,PODOFO_MINOR,PODOFO_REVISION,0 #define VER_PRODUCTVERSION_STR PODOFO_VERSION_STRING #define VER_FILEVERSION VER_PRODUCTVERSION #define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR #define VER_PRIVATEBUILD_STR "Custom Build\0" #ifndef DEBUG #define VER_DEBUG 0 #else #define VER_DEBUG VS_FF_DEBUG #endif #if defined(COMPILING_SHARED_PODOFO) #define VER_FILETYPE VFT_DLL #define VER_FILEDESCRIPTION_STR "PoDoFo Dynamic Link Library\0" #define VER_ORIGINALFILENAME_STR "podofo.dll\0" #else #define VER_FILETYPE VFT_STATIC_LIB #define VER_FILEDESCRIPTION_STR "PoDoFo Static Library\0" #define VER_ORIGINALFILENAME_STR "podofo.lib\0" #endif #if 1 #define VER_PRERELEASE VS_FF_PRERELEASE #else #define VER_PRERELEASE 0L #endif VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION PRODUCTVERSION VER_PRODUCTVERSION FILEFLAGSMASK VS_FFI_FILEFLAGSMASK FILEFLAGS (VS_FF_PRIVATEBUILD|VER_PRERELEASE|VER_DEBUG) FILEOS VOS__WINDOWS32 FILETYPE VER_FILETYPE FILESUBTYPE VFT2_UNKNOWN BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" BEGIN VALUE "FileVersion", VER_FILEVERSION_STR VALUE "ProductVersion", VER_PRODUCTVERSION_STR VALUE "Comments", "PoDoFo Doc PDF Library\0" VALUE "CompanyName", "PoDoFo\0" VALUE "InternalName", "podofo\0" VALUE "ProductName", "PoDoFo\0" VALUE "LegalCopyright", "Copyright (C) 2010 Dominik Seichter, Craig Ringer, The PoDoFo Developers\0" VALUE "FileDescription", VER_FILEDESCRIPTION_STR VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR VALUE "PrivateBuild", VER_PRIVATEBUILD_STR END END BLOCK "VarFileInfo" BEGIN /* The following line should only be modified for localized versions. */ /* It consists of any number of WORD,WORD pairs, with each pair */ /* describing a language,codepage combination supported by the file. */ /* */ /* For example, a file might have values "0x409,1252" indicating that it */ /* supports English language (0x409) in the Windows ANSI codepage (1252). */ VALUE "Translation", 0x409, 1252 END END podofo-0.9.5/src/doc/PdfExtGState.h0000664000175000017500000000571612347276455016722 0ustar dominikdominik #ifndef _PDF_EXTGSTATE_H_ #define _PDF_EXTGSTATE_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfName.h" #include "PdfElement.h" namespace PoDoFo { class PdfObject; class PdfPage; class PdfWriter; /** This class wraps the ExtGState object used in the Resource * Dictionary of a Content-supporting element (page, Pattern, etc.) * The main usage is for transparency, but it also support a variety * of prepress features. */ class PODOFO_DOC_API PdfExtGState : public PdfElement { public: /** Create a new PdfExtGState object which will introduce itself * automatically to every page object it is used on. * * \param pParent parent vector of objects * */ PdfExtGState( PdfVecObjects* pParent ); /** Create a new PdfExtGState object which will introduce itself * automatically to every page object it is used on. * * \param pParent parent document * */ PdfExtGState( PdfDocument* pParent ); virtual ~PdfExtGState(); /** Returns the identifier of this ExtGState how it is known * in the pages resource dictionary. * \returns PdfName containing the identifier (e.g. /ExtGS13) */ inline const PdfName & GetIdentifier() const; /** Sets the opacity value to be used for fill operations * \param opac a floating point value from 0 (transparent) to 1 (opaque) */ void SetFillOpacity( float opac ); /** Sets the opacity value to be used for stroking operations * \param opac a floating point value from 0 (transparent) to 1 (opaque) */ void SetStrokeOpacity( float opac ); /** Sets the transparency blend mode * \param blendMode one of the predefined blending modes (see PodofoDefines.h) */ void SetBlendMode( const char* blendMode ); /** Enables/Disables overprinting for both Fill & Stroke * \param enable enable or disable */ void SetOverprint( bool enable=true ); /** Enables/Disables overprinting for Fill operations * \param enable enable or disable */ void SetFillOverprint( bool enable=true ); /** Enables/Disables overprinting for Stroke operations * \param enable enable or disable */ void SetStrokeOverprint( bool enable=true ); /** Enables/Disables non-zero overprint mode * \param enable enable or disable */ void SetNonZeroOverprint( bool enable=true ); /** Set the Rendering Intent * \param intent one of the predefined intents (see Podofo.h) */ void SetRenderingIntent( const char* intent ); /** Set the frequency for halftones * \param frequency screen frequency, measured in halftone cells per inch in device space */ void SetFrequency( double frequency ); private: /** Initialize the object */ void Init( void ); private: PdfName m_Identifier; }; const PdfName & PdfExtGState::GetIdentifier() const { return m_Identifier; } }; #endif // _PDF_EXTGSTATE_H_ podofo-0.9.5/src/doc/PdfSignOutputDevice.h0000664000175000017500000001213112716141341020261 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2011 by Dominik Seichter * * domseichter@web.de * * by Petr Pytelka * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PODOFO_SIGN_OUTPUT_DEVICE_H_ #define _PODOFO_SIGN_OUTPUT_DEVICE_H_ #include "../base/PdfOutputDevice.h" #include "../base/PdfData.h" #include "../base/PdfString.h" namespace PoDoFo { /** Signer class * * Class is used to locate place for signature in the stream. * Usage: * 1. Locate signature and adjust ByteRange * 2. Generate signature * 3. Insert new signature */ class PODOFO_DOC_API PdfSignOutputDevice :public PdfOutputDevice { public: PdfSignOutputDevice(PdfOutputDevice *pRealDevice); PdfSignOutputDevice(const char* pszFilename); #ifdef WIN32 PdfSignOutputDevice( const wchar_t* pszFilename ); #endif virtual ~PdfSignOutputDevice(); /** Set string to lookup for * * \param lSignatureSize Total space reserved for signature */ virtual void SetSignatureSize(size_t lSignatureSize); /** Get expected size of signature. * * If reserved size if zero no signatures will be added. * \return Total space reserved for signature. */ virtual size_t GetSignatureSize()const; /** Return signature beacon * */ virtual const PdfData *GetSignatureBeacon()const{ return m_pSignatureBeacon; } virtual bool HasSignaturePosition()const { return m_bBeaconFound; } /** Modify ByteRange entry according to signature position * */ virtual void AdjustByteRange(); /** Read data for signature */ virtual size_t ReadForSignature(char* pBuffer, size_t lLen); /** Embed real signature in the PDF */ virtual void SetSignature(const PdfData &sigData); virtual inline size_t GetLength() const { return m_pRealDevice->GetLength(); } virtual void Print( const char* pszFormat, ... ) { va_list args; long lBytes; va_start( args, pszFormat ); lBytes = m_pRealDevice->PrintVLen(pszFormat, args); va_end( args ); va_start( args, pszFormat ); m_pRealDevice->PrintV(pszFormat, lBytes, args); va_end( args ); } virtual void Write( const char* pBuffer, size_t lLen ); virtual size_t Read( char* pBuffer, size_t lLen ) { return m_pRealDevice->Read(pBuffer, lLen); } virtual void Seek( size_t offset ) { m_pRealDevice->Seek(offset); } virtual inline size_t Tell() const { return m_pRealDevice->Tell(); } virtual void Flush() { m_pRealDevice->Flush(); } private: void Init(); PdfOutputDevice* m_pRealDevice; bool m_bDevOwner; PdfData* m_pSignatureBeacon; size_t m_sBeaconPos; bool m_bBeaconFound; }; } #endif podofo-0.9.5/src/doc/PdfHintStream.cpp0000664000175000017500000003242412715331116017440 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfHintStream.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfData.h" #include "base/PdfDictionary.h" #include "base/PdfStream.h" #include "base/PdfVariant.h" #include "base/PdfVecObjects.h" #include "PdfPage.h" #include "PdfPagesTree.h" // See PdfWriter.cpp #define LINEARIZATION_PADDING "1234567890" using namespace PoDoFo; namespace { struct TPageEntrySharedObjectInfo { pdf_uint16 nIndex; pdf_uint16 nNumerator; }; typedef std::vector TVecPageEntrySharedObjectInfo; typedef TVecPageEntrySharedObjectInfo::iterator TIVecPageEntrySharedObjectInfo; typedef TVecPageEntrySharedObjectInfo::const_iterator TCIVecPageEntrySharedObjectInfo; #if 0 class PdfPageOffsetEntry { public: PdfPageOffsetEntry() : nObjectsPerPage( 0 ), nPageLength( 0 ), nSharedObjects( 0 ), nContentsOffset( 0 ), nContentsLength( 0 ) { vecSharedObjects.resize( 0 ); } pdf_uint16 nObjectsPerPage; pdf_uint16 nPageLength; pdf_uint16 nSharedObjects; // item4 and item5: TVecPageEntrySharedObjectInfo vecSharedObjects; pdf_uint16 nContentsOffset; pdf_uint16 nContentsLength; public: void Write( PoDoFo::NonPublic::PdfHintStream* pHint ); }; void PdfPageOffsetEntry::Write( PoDoFo::NonPublic::PdfHintStream* pHint ) { TCIVecPageEntrySharedObjectInfo it; pHint->WriteUInt16( nObjectsPerPage ); pHint->WriteUInt16( nPageLength ); pHint->WriteUInt16( nSharedObjects ); it = vecSharedObjects.begin(); while( it != vecSharedObjects.end() ) { pHint->WriteUInt16( (*it).nIndex ); ++it; } it = vecSharedObjects.begin(); while( it != vecSharedObjects.end() ) { pHint->WriteUInt16( (*it).nNumerator ); ++it; } pHint->WriteUInt16( nContentsOffset ); pHint->WriteUInt16( nContentsLength ); } #endif class PdfPageOffsetHeader { public: PdfPageOffsetHeader() : nLeastNumberOfObjects( 0 ), nFirstPageObject( 0 ), nBitsPageObject( 0 ), nLeastPageLength( 0 ), nBitsPageLength( 0 ), nOffsetContentStream( 0 ), nBitsContentStream( 0 ), nLeastContentStreamLength( 0 ), nBitsLeastContentStreamLength( 0 ), nBitsNumSharedObjects( 0 ), nBitsGreatestSharedObject( 0 ), nItem12( 0 ), nItem13( 0 ) { } // item1: The least number of objects in a page including the page itself pdf_uint32 nLeastNumberOfObjects; // item2: The location of the first pages page object pdf_uint32 nFirstPageObject; // (*pXRef)[0].vecOffsets[ m_pPagesTree->GetPage( 0 )->Object()->Reference().ObjectNumber() ].lOffset; // item3: The number of bits needed to represent the difference between the // greatest and least number of objects in a page pdf_uint16 nBitsPageObject; // (pdf_uint16)ceil( logb( (double)(max-least) ) ); // item4: The least length of a page in bytes pdf_uint32 nLeastPageLength; // item5: The number of bits needed to represent the greatest difference // between the greatest and the least length of a page in bytes pdf_uint16 nBitsPageLength; // item6: The least offset of the start of a content stream, relative // to the beginning of a file. // --> Always set to 0 by acrobat pdf_uint32 nOffsetContentStream; // item7: The number of bits needed to represent the greatest difference // between the greatest and the least offset of a the start of a content // stream relative to the beginning of a file // --> Always set to 0 by acrobat pdf_uint16 nBitsContentStream; // item8: The least content stream length pdf_uint32 nLeastContentStreamLength; // item9: The number of bits needed to represent the greatest difference // between the greatest and the least length of a content stream pdf_uint16 nBitsLeastContentStreamLength; // item10: The number of bits needed to represent the greatest number // of shared object references. pdf_uint16 nBitsNumSharedObjects; // item11: The number of bits needed to represent the nummerically // greatest shared object identifyer used by pages pdf_uint16 nBitsGreatestSharedObject; // item12: pdf_uint16 nItem12; // item13: pdf_uint16 nItem13; void Write( PoDoFo::NonPublic::PdfHintStream* pHint ) { pHint->WriteUInt32( nLeastNumberOfObjects ); pHint->WriteUInt32( nFirstPageObject ); pHint->WriteUInt16( nBitsPageObject ); pHint->WriteUInt32( nLeastPageLength ); pHint->WriteUInt16( nBitsPageLength ); pHint->WriteUInt32( nOffsetContentStream ); pHint->WriteUInt16( nBitsContentStream ); pHint->WriteUInt32( nLeastContentStreamLength ); pHint->WriteUInt16( nBitsLeastContentStreamLength ); pHint->WriteUInt16( nBitsNumSharedObjects ); pHint->WriteUInt16( nBitsGreatestSharedObject ); pHint->WriteUInt16( nItem12 ); pHint->WriteUInt16( nItem13 ); } }; class PdfSharedObjectHeader { public: PdfSharedObjectHeader() : nFirstObjectNumber( 0 ), nFirstObjectLocation( 0 ), nNumSharedObjectsFirstPage( 0 ), nNumSharedObjects( 0 ), nNumBits( 0 ), nLeastLength( 0 ), nNumBitsLengthDifference( 0 ) { } pdf_uint32 nFirstObjectNumber; pdf_uint32 nFirstObjectLocation; pdf_uint32 nNumSharedObjectsFirstPage; pdf_uint32 nNumSharedObjects; // i.e. including nNumSharedObjectsFirstPage pdf_uint16 nNumBits; pdf_uint32 nLeastLength; pdf_uint16 nNumBitsLengthDifference; public: void Write( PoDoFo::NonPublic::PdfHintStream* pHint ) { pHint->WriteUInt32( nFirstObjectNumber ); pHint->WriteUInt32( nFirstObjectLocation ); pHint->WriteUInt32( nNumSharedObjectsFirstPage ); pHint->WriteUInt32( nNumSharedObjects ); pHint->WriteUInt16( nNumBits ); pHint->WriteUInt32( nLeastLength ); pHint->WriteUInt16( nNumBitsLengthDifference ); } }; }; // end anon namespace namespace PoDoFo { namespace NonPublic { PdfHintStream::PdfHintStream( PdfVecObjects* pParent, PdfPagesTree* pPagesTree ) : PdfElement( NULL, pParent ), m_pPagesTree( pPagesTree ) { // This is overwritten later with valid data! PdfVariant place_holder( PdfData( LINEARIZATION_PADDING ) ); this->GetObject()->GetDictionary().AddKey( "S", place_holder ); // shared object hint table } PdfHintStream::~PdfHintStream() { } /* void PdfHintStream::Create( TVecXRefTable* pXRef ) { this->CreatePageHintTable( pXRef ); this->CreateSharedObjectHintTable(); } void PdfHintStream::CreatePageHintTable( TVecXRefTable* pXRef ) { TPdfReferenceList lstPages; TCIPdfReferenceList it; int i; int nPageCount = m_pPagesTree->GetTotalNumberOfPages(); PdfPageOffsetHeader header; #if 1 // this will init/construct each of the objects in the vector // AND it compiles on all platforms - where the below code // isn't 100% valid for all C++ compilers std::vector< PdfPageOffsetEntry > vecPages( nPageCount ); #else // use an array instead of an vector, // to make sure the constructors are called, // which they are apparently not when using vector.resize PdfPageOffsetEntry vecPages[nPageCount]; #endif pdf_uint32 max; pdf_uint32 least = 0; pdf_uint32 maxNumberOfObjects = 0; pdf_uint32 maxPageLength = 0; pdf_uint32 value; PdfReference maxRef; for( i=0;iGetObject()->GetParent()->GetObjectDependencies( m_pPagesTree->GetPage( i )->GetObject(), &lstPages ); vecPages[i].nObjectsPerPage = lstPages.size(); if( !header.nLeastNumberOfObjects || header.nLeastNumberOfObjects > lstPages.size() ) header.nLeastNumberOfObjects = lstPages.size(); if( !maxNumberOfObjects || maxNumberOfObjects < lstPages.size() ) maxNumberOfObjects = lstPages.size(); it = lstPages.begin(); least = 0; max = 0; while( it != lstPages.end() ) { value = (*pXRef)[0].vecOffsets[ (*it).ObjectNumber() ].lOffset; if( !least || least > value ) least = value; if( !max || max < value ) { max = value; maxRef = *it; } ++it; } max += this->GetObject()->GetParent()->GetObject( maxRef )->GetObjectLength(); vecPages[i].nPageLength = max - least; if( !header.nLeastPageLength || header.nLeastPageLength > vecPages[i].nPageLength ) header.nLeastPageLength = vecPages[i].nPageLength; if( !maxPageLength || maxPageLength < max ) maxPageLength = max; vecPages[i].nSharedObjects = 0; vecPages[i].nContentsOffset = 0; vecPages[i].nContentsLength = 0; } header.nFirstPageObject = (*pXRef)[0].vecOffsets[ m_pPagesTree->GetPage( 0 )->GetObject()->Reference().ObjectNumber() ].lOffset; header.nBitsPageObject = (pdf_uint16)ceil( logb( static_cast(maxNumberOfObjects-header.nLeastNumberOfObjects) ) ); header.nBitsPageLength = (pdf_uint16)ceil( logb( static_cast(maxPageLength - header.nLeastPageLength) ) ); header.nOffsetContentStream = 0; // acrobat sets this to 0 and ignores it header.nBitsContentStream = 0; // acrobat sets this to 0 and ignores it header.nLeastContentStreamLength = 0; // acrobat sets this to 0 and ignores it header.nBitsLeastContentStreamLength = 0; // acrobat sets this to 0 and ignores it header.nBitsNumSharedObjects = 0; header.nBitsGreatestSharedObject = 0; header.nItem12 = 0; header.nItem13 = 0; for( i=0;i(this->GetObject()->GetStream()->GetLength()) ); offset.SetPaddingLength( LINEARIZATION_PADDING ); this->GetObject()->GetDictionary().AddKey( "S", offset ); // shared object hint table } */ void PdfHintStream::WriteUInt16( pdf_uint16 val ) { val = ::PoDoFo::compat::podofo_htons(val); this->GetObject()->GetStream()->Append( reinterpret_cast(&val), 2 ); } void PdfHintStream::WriteUInt32( pdf_uint32 val ) { val = ::PoDoFo::compat::podofo_htonl(val); this->GetObject()->GetStream()->Append( reinterpret_cast(&val), 4 ); } }; // end namespace PoDoFo::NonPublic }; // end namespace PoDoFo podofo-0.9.5/src/doc/PdfXObject.h0000664000175000017500000002026612347310654016373 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_XOBJECT_H_ #define _PDF_XOBJECT_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfArray.h" #include "podofo/base/PdfCanvas.h" #include "podofo/base/PdfRect.h" #include "PdfElement.h" namespace PoDoFo { class PdfDictionary; class PdfObject; class PdfMemDocument; /** A XObject is a content stream with several drawing commands and data * which can be used throughout a PDF document. * * You can draw on a XObject like you would draw onto a page and can draw * this XObject later again using a PdfPainter. * * \see PdfPainter */ class PODOFO_DOC_API PdfXObject : public PdfElement, public PdfCanvas { public: /** Create a new XObject with a specified dimension * in a given document * * \param rRect the size of the XObject * \param pParent the parent document of the XObject * \param pszPrefix optional prefix for XObject-name * \param bWithoutObjNum do not create an object identifier name */ PdfXObject( const PdfRect & rRect, PdfDocument* pParent, const char* pszPrefix = NULL, bool bWithoutObjNum = false); /** Create a new XObject with a specified dimension * in a given vector of PdfObjects * * \param rRect the size of the XObject * \param pParent the parent vector of the XObject * \param pszPrefix optional prefix for XObject-name */ PdfXObject( const PdfRect & rRect, PdfVecObjects* pParent, const char* pszPrefix = NULL ); /** Create a new XObject from a page of another document * in a given document * * \param rSourceDoc the document to create the XObject from * \param nPage the page-number in rDoc to create the XObject from * \param pParent the parent document of the XObject * \param pszPrefix optional prefix for XObject-name * \param bUseTrimBox if true try to use trimbox for size of xobject */ PdfXObject( const PdfMemDocument & rSourceDoc, int nPage, PdfDocument* pParent, const char* pszPrefix = NULL, bool bUseTrimBox = false ); /** Create a new XObject from an existing page * * \param pDoc the document to create the XObject at * \param nPage the page-number in pDoc to create the XObject from * \param pszPrefix optional prefix for XObject-name * \param bUseTrimBox if true try to use trimbox for size of xobject */ PdfXObject( PdfDocument *pDoc, int nPage, const char* pszPrefix = NULL, bool bUseTrimBox = false ); /** Create a XObject from an existing PdfObject * * \param pObject an existing object which has to be * a XObject */ PdfXObject( PdfObject* pObject ); virtual ~PdfXObject() { } /** Get access to the contents object of this page. * If you want to draw onto the page, you have to add * drawing commands to the stream of the Contents object. * * The contents object is a this pointer in this case. * * \returns a contents object */ inline virtual PdfObject* GetContents() const; /** Get access to the contents object of this page. * If you want to draw onto the page, you have to add * drawing commands to the stream of the Contents object. * * The contents object is a this pointer in this case. * * \returns a contents object */ inline virtual PdfObject* GetContentsForAppending() const { return GetContents(); } /** Get access to the resources object of this page. * This is most likely an internal object. * \returns a resources object */ inline virtual PdfObject* GetResources() const; /** Get the current page size in PDF Units * \returns a PdfRect containing the page size available for drawing */ inline virtual const PdfRect GetPageSize() const; /** Get the identifier used for drawig this object * \returns identifier */ inline const PdfName & GetIdentifier() const; /** Get the reference to the XObject in the PDF file * without having to access the PdfObject. * * This allows to work with XObjects which have been * written to disk already. * * \returns the reference of the PdfObject for this XObject */ inline const PdfReference & GetObjectReference() const; protected: void InitXObject( const PdfRect & rRect, const char* pszPrefix = NULL ); PdfXObject( const char* pszSubType, PdfDocument* pParent, const char* pszPrefix = NULL ); PdfXObject( const char* pszSubType, PdfVecObjects* pParent, const char* pszPrefix = NULL ); PdfXObject( const char* pszSubType, PdfObject* pObject ); protected: PdfRect m_rRect; private: static PdfArray s_matrix; PdfObject* m_pResources; PdfName m_Identifier; PdfReference m_Reference; }; // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfObject* PdfXObject::GetContents() const { return this->GetNonConstObject(); } // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfObject* PdfXObject::GetResources() const { return m_pResources; } // ----------------------------------------------------- // // ----------------------------------------------------- inline const PdfRect PdfXObject::GetPageSize() const { return m_rRect; } // ----------------------------------------------------- // // ----------------------------------------------------- inline const PdfName & PdfXObject::GetIdentifier() const { return m_Identifier; } // ----------------------------------------------------- // // ----------------------------------------------------- inline const PdfReference & PdfXObject::GetObjectReference() const { return m_Reference; } }; #endif /* _PDF_XOBJECT_H_ */ podofo-0.9.5/src/doc/PdfOutlines.cpp0000664000175000017500000003077512742477611017206 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfOutlines.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfDictionary.h" #include "base/PdfObject.h" #include "PdfAction.h" #include "PdfDestination.h" namespace PoDoFo { PdfOutlineItem::PdfOutlineItem( const PdfString & sTitle, const PdfDestination & rDest, PdfOutlineItem* pParentOutline, PdfVecObjects* pParent ) : PdfElement( NULL, pParent ), m_pParentOutline( pParentOutline ), m_pPrev( NULL ), m_pNext( NULL ), m_pFirst( NULL ), m_pLast( NULL ), m_pDestination( NULL ), m_pAction( NULL ) { if( pParentOutline ) this->GetObject()->GetDictionary().AddKey( "Parent", pParentOutline->GetObject()->Reference() ); this->SetTitle( sTitle ); this->SetDestination( rDest ); } PdfOutlineItem::PdfOutlineItem( const PdfString & sTitle, const PdfAction & rAction, PdfOutlineItem* pParentOutline, PdfVecObjects* pParent ) : PdfElement( NULL, pParent ), m_pParentOutline( pParentOutline ), m_pPrev( NULL ), m_pNext( NULL ), m_pFirst( NULL ), m_pLast( NULL ), m_pDestination( NULL ), m_pAction( NULL ) { if( pParentOutline ) this->GetObject()->GetDictionary().AddKey( "Parent", pParentOutline->GetObject()->Reference() ); this->SetTitle( sTitle ); this->SetAction( rAction ); } PdfOutlineItem::PdfOutlineItem( PdfObject* pObject, PdfOutlineItem* pParentOutline, PdfOutlineItem* pPrevious ) : PdfElement( NULL, pObject ), m_pParentOutline( pParentOutline ), m_pPrev( pPrevious ), m_pNext( NULL ), m_pFirst( NULL ), m_pLast( NULL ), m_pDestination( NULL ), m_pAction( NULL ) { PdfReference first, next; if( this->GetObject()->GetDictionary().HasKey( "First" ) ) { first = this->GetObject()->GetDictionary().GetKey("First")->GetReference(); m_pFirst = new PdfOutlineItem( pObject->GetOwner()->GetObject( first ), this, NULL ); } if( this->GetObject()->GetDictionary().HasKey( "Next" ) ) { next = this->GetObject()->GetDictionary().GetKey("Next")->GetReference(); PdfObject* pObj = pObject->GetOwner()->GetObject( next ); m_pNext = new PdfOutlineItem( pObj, NULL, this ); } else { // if there is no next key, // we have to set ourself as the last item of the parent if( m_pParentOutline ) m_pParentOutline->SetLast( this ); } } PdfOutlineItem::PdfOutlineItem( PdfVecObjects* pParent ) : PdfElement( "Outlines", pParent ), m_pParentOutline( NULL ), m_pPrev( NULL ), m_pNext( NULL ), m_pFirst( NULL ), m_pLast( NULL ), m_pDestination( NULL ), m_pAction( NULL ) { } PdfOutlineItem::~PdfOutlineItem() { delete m_pNext; delete m_pFirst; } PdfOutlineItem* PdfOutlineItem::CreateChild( const PdfString & sTitle, const PdfDestination & rDest ) { PdfOutlineItem* pItem = new PdfOutlineItem( sTitle, rDest, this, this->GetObject()->GetOwner() ); this->InsertChild( pItem ); return pItem; } void PdfOutlineItem::InsertChild( PdfOutlineItem* pItem ) { PdfOutlineItem* pItemToCheckParent = pItem; PdfOutlineItem* pRoot = NULL; PdfOutlineItem* pRootOfThis = NULL; if ( !pItemToCheckParent ) return; while ( pItemToCheckParent ) { while ( pItemToCheckParent->GetParentOutline() ) pItemToCheckParent = pItemToCheckParent->GetParentOutline(); if ( pItemToCheckParent == pItem ) // item can't have a parent { pRoot = pItem; // needed later, "root" can mean "standalone" here break; // for performance in standalone or doc-merge case } if ( !pRoot ) { pRoot = pItemToCheckParent; pItemToCheckParent = this; } else { pRootOfThis = pItemToCheckParent; pItemToCheckParent = NULL; } } if ( pRoot == pRootOfThis ) // latter NULL if check skipped for performance PODOFO_RAISE_ERROR( ePdfError_OutlineItemAlreadyPresent ); if( m_pLast ) { m_pLast->SetNext( pItem ); pItem->SetPrevious( m_pLast ); } m_pLast = pItem; if( !m_pFirst ) m_pFirst = m_pLast; this->GetObject()->GetDictionary().AddKey( "First", m_pFirst->GetObject()->Reference() ); this->GetObject()->GetDictionary().AddKey( "Last", m_pLast->GetObject()->Reference() ); } PdfOutlineItem* PdfOutlineItem::CreateNext ( const PdfString & sTitle, const PdfDestination & rDest ) { PdfOutlineItem* pItem = new PdfOutlineItem( sTitle, rDest, m_pParentOutline, this->GetObject()->GetOwner() ); if( m_pNext ) { m_pNext->SetPrevious( pItem ); pItem->SetNext( m_pNext ); } m_pNext = pItem; m_pNext->SetPrevious( this ); this->GetObject()->GetDictionary().AddKey( "Next", m_pNext->GetObject()->Reference() ); if( m_pParentOutline && !m_pNext->Next() ) m_pParentOutline->SetLast( m_pNext ); return m_pNext; } PdfOutlineItem* PdfOutlineItem::CreateNext ( const PdfString & sTitle, const PdfAction & rAction ) { PdfOutlineItem* pItem = new PdfOutlineItem( sTitle, rAction, m_pParentOutline, this->GetObject()->GetOwner() ); if( m_pNext ) { m_pNext->SetPrevious( pItem ); pItem->SetNext( m_pNext ); } m_pNext = pItem; m_pNext->SetPrevious( this ); this->GetObject()->GetDictionary().AddKey( "Next", m_pNext->GetObject()->Reference() ); if( m_pParentOutline && !m_pNext->Next() ) m_pParentOutline->SetLast( m_pNext ); return m_pNext; } void PdfOutlineItem::SetPrevious( PdfOutlineItem* pItem ) { m_pPrev = pItem; if( m_pPrev ) this->GetObject()->GetDictionary().AddKey( "Prev", m_pPrev->GetObject()->Reference() ); else this->GetObject()->GetDictionary().RemoveKey( "Prev" ); } void PdfOutlineItem::SetNext( PdfOutlineItem* pItem ) { m_pNext = pItem; if( m_pNext ) this->GetObject()->GetDictionary().AddKey( "Next", m_pNext->GetObject()->Reference() ); else this->GetObject()->GetDictionary().RemoveKey( "Next" ); } void PdfOutlineItem::SetLast( PdfOutlineItem* pItem ) { m_pLast = pItem; if( m_pLast ) this->GetObject()->GetDictionary().AddKey( "Last", m_pLast->GetObject()->Reference() ); else this->GetObject()->GetDictionary().RemoveKey( "Last" ); } void PdfOutlineItem::SetFirst( PdfOutlineItem* pItem ) { m_pFirst = pItem; if( m_pFirst ) this->GetObject()->GetDictionary().AddKey( "First", m_pFirst->GetObject()->Reference() ); else this->GetObject()->GetDictionary().RemoveKey( "First" ); } void PdfOutlineItem::Erase() { while( m_pFirst ) { // erase will set a new first // if it has a next item m_pFirst->Erase(); } if( m_pPrev ) { m_pPrev->SetNext( m_pNext ); } if( m_pNext ) { m_pNext->SetPrevious( m_pPrev ); } if( !m_pPrev && m_pParentOutline && this == m_pParentOutline->First() ) m_pParentOutline->SetFirst( m_pNext ); if( !m_pNext && m_pParentOutline && this == m_pParentOutline->Last() ) m_pParentOutline->SetLast( m_pPrev ); m_pNext = NULL; delete this; } void PdfOutlineItem::SetDestination( const PdfDestination & rDest ) { delete m_pDestination; m_pDestination = NULL; rDest.AddToDictionary( this->GetObject()->GetDictionary() ); } PdfDestination* PdfOutlineItem::GetDestination( PdfDocument* pDoc ) { if( !m_pDestination ) { PdfObject* dObj = this->GetObject()->GetIndirectKey( "Dest" ); if ( !dObj ) return NULL; m_pDestination = new PdfDestination( dObj, pDoc ); } return m_pDestination; } void PdfOutlineItem::SetAction( const PdfAction & rAction ) { delete m_pAction; m_pAction = NULL; rAction.AddToDictionary( this->GetObject()->GetDictionary() ); } PdfAction* PdfOutlineItem::GetAction( void ) { if( !m_pAction ) { PdfObject* dObj = this->GetObject()->GetIndirectKey( "A" ); if ( !dObj ) return NULL; m_pAction = new PdfAction( dObj ); } return m_pAction; } void PdfOutlineItem::SetTitle( const PdfString & sTitle ) { this->GetObject()->GetDictionary().AddKey( "Title", sTitle ); } const PdfString & PdfOutlineItem::GetTitle() const { return this->GetObject()->GetIndirectKey( "Title" )->GetString(); } void PdfOutlineItem::SetTextFormat( EPdfOutlineFormat eFormat ) { this->GetObject()->GetDictionary().AddKey( "F", static_cast(eFormat) ); } EPdfOutlineFormat PdfOutlineItem::GetTextFormat() const { if( this->GetObject()->GetDictionary().HasKey( "F" ) ) return static_cast(this->GetObject()->GetIndirectKey( "F" )->GetNumber()); return ePdfOutlineFormat_Default; } void PdfOutlineItem::SetTextColor( double r, double g, double b ) { PdfArray color; color.push_back( r ); color.push_back( g ); color.push_back( b ); this->GetObject()->GetDictionary().AddKey( "C", color ); } double PdfOutlineItem::GetTextColorRed() const { if( this->GetObject()->GetDictionary().HasKey( "C" ) ) return this->GetObject()->GetIndirectKey( "C" )->GetArray()[0].GetReal(); return 0.0; } double PdfOutlineItem::GetTextColorGreen() const { if( this->GetObject()->GetDictionary().HasKey( "C" ) ) return this->GetObject()->GetIndirectKey( "C" )->GetArray()[1].GetReal(); return 0.0; } double PdfOutlineItem::GetTextColorBlue() const { if( this->GetObject()->GetDictionary().HasKey( "C" ) ) return this->GetObject()->GetIndirectKey( "C" )->GetArray()[2].GetReal(); return 0.0; } /////////////////////////////////////////////////////////////////////////////////// // PdfOutlines /////////////////////////////////////////////////////////////////////////////////// PdfOutlines::PdfOutlines( PdfVecObjects* pParent ) : PdfOutlineItem( pParent ) { } PdfOutlines::PdfOutlines( PdfObject* pObject ) : PdfOutlineItem( pObject, NULL, NULL ) { } PdfOutlineItem* PdfOutlines::CreateRoot( const PdfString & sTitle ) { return this->CreateChild( sTitle, PdfDestination( GetObject()->GetOwner() ) ); } }; podofo-0.9.5/src/doc/PdfFontMetricsBase14.cpp0000664000175000017500000002203713013650710020552 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfFontMetricsBase14.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "PdfFontFactoryBase14Data.h" namespace PoDoFo { PdfFontMetricsBase14::PdfFontMetricsBase14(const char *mfont_name, const PODOFO_CharData *mwidths_table, bool mis_font_specific, pdf_int16 mascent, pdf_int16 mdescent, pdf_uint16 mx_height, pdf_uint16 mcap_height, const PdfRect & mbbox) : PdfFontMetrics( ePdfFontType_Type1Base14, "", NULL), font_name(mfont_name), widths_table(mwidths_table), is_font_specific(mis_font_specific), ascent(mascent), descent(mdescent), x_height(mx_height), cap_height(mcap_height), bbox(mbbox), m_bSymbol(is_font_specific) { m_nWeight = 500; m_nItalicAngle = 0; m_dLineSpacing = 0.0; m_dUnderlineThickness = 0.0; m_dUnderlinePosition = 0.0; m_dStrikeOutPosition = 0.0; m_dStrikeOutThickness = 0.0; units_per_EM = 1000; m_dPdfAscent = ascent * 1000 / units_per_EM; m_dPdfDescent = descent * 1000 / units_per_EM; m_dAscent = ascent; m_dDescent = descent; // calculate the line spacing now, as it changes only with the font size m_dLineSpacing = (static_cast(ascent + abs(descent)) / units_per_EM); m_dAscent = static_cast(ascent) / units_per_EM; m_dDescent = static_cast(descent) / units_per_EM; // Set default values for strikeout, in case the font has no direct values m_dStrikeOutPosition = m_dAscent / 2.0; // m_dStrikeOutThickness = m_dUnderlineThickness; } PdfFontMetricsBase14::~PdfFontMetricsBase14() { } double PdfFontMetricsBase14::GetGlyphWidth( int nGlyphId ) const { return widths_table[static_cast(nGlyphId)].width; } double PdfFontMetricsBase14::GetGlyphWidth( const char* ) const { return 0.0; } double PdfFontMetricsBase14::CharWidth( unsigned char c ) const { double dWidth = widths_table[static_cast(GetGlyphId(c) )].width; return dWidth * static_cast(this->GetFontSize() * this->GetFontScale() / 100.0) / 1000.0 + static_cast( this->GetFontSize() * this->GetFontScale() / 100.0 * this->GetFontCharSpace() / 100.0); } double PdfFontMetricsBase14::UnicodeCharWidth( unsigned short c ) const { double dWidth = 0.0; dWidth = widths_table[static_cast(GetGlyphIdUnicode(c) )].width; return dWidth * static_cast(this->GetFontSize() * this->GetFontScale() / 100.0) / 1000.0 + static_cast( this->GetFontSize() * this->GetFontScale() / 100.0 * this->GetFontCharSpace() / 100.0); } inline double PdfFontMetricsBase14::GetLineSpacing() const { return m_dLineSpacing * this->GetFontSize(); } inline double PdfFontMetricsBase14::GetUnderlineThickness() const { return m_dUnderlineThickness * this->GetFontSize(); } inline double PdfFontMetricsBase14::GetUnderlinePosition() const { return m_dUnderlinePosition * this->GetFontSize(); } inline double PdfFontMetricsBase14::GetStrikeOutPosition() const { return m_dStrikeOutPosition * this->GetFontSize(); } inline double PdfFontMetricsBase14::GetStrikeoutThickness() const { return m_dStrikeOutThickness * this->GetFontSize(); } const char* PdfFontMetricsBase14::GetFontname() const { #ifdef MYASSERT PODOFO_ASSERT(font_name != NULL); #endif return font_name; } unsigned int PdfFontMetricsBase14::GetWeight() const { return m_nWeight; } double PdfFontMetricsBase14::GetAscent() const { return m_dAscent * this->GetFontSize(); } double PdfFontMetricsBase14::GetPdfAscent() const { return m_dPdfAscent; } double PdfFontMetricsBase14::GetDescent() const { return m_dDescent * this->GetFontSize(); } double PdfFontMetricsBase14::GetPdfDescent() const { return m_dPdfDescent; } int PdfFontMetricsBase14::GetItalicAngle() const { return m_nItalicAngle; } long PdfFontMetricsBase14::GetGlyphIdUnicode( long lUnicode ) const { long lGlyph = 0; // Handle symbol fonts! /* if( m_bSymbol ) { lUnicode = lUnicode | 0xf000; } */ for(int i = 0; widths_table[i].unicode != 0xFFFF ; ++i) { if (widths_table[i].unicode == lUnicode) { lGlyph = i; //widths_table[i].char_cd ; break; } } //FT_Get_Char_Index( m_face, lUnicode ); return lGlyph; } long PdfFontMetricsBase14::GetGlyphId( long charId ) const { long lGlyph = 0; // Handle symbol fonts! /* if( m_bSymbol ) { charId = charId | 0xf000; } */ for(int i = 0; widths_table[i].unicode != 0xFFFF ; ++i) { if (widths_table[i].char_cd == charId) { lGlyph = i; //widths_table[i].char_cd ; break; } } //FT_Get_Char_Index( m_face, lUnicode ); return lGlyph; } inline bool PdfFontMetricsBase14::IsSymbol() const { return m_bSymbol; } void PdfFontMetricsBase14::GetBoundingBox( PdfArray & array ) const { array.Clear(); array.push_back( PdfVariant( bbox.GetLeft() * 1000.0 / units_per_EM ) ); array.push_back( PdfVariant( bbox.GetBottom() * 1000.0 / units_per_EM ) ); array.push_back( PdfVariant( bbox.GetWidth() * 1000.0 / units_per_EM ) ); array.push_back( PdfVariant( bbox.GetHeight() * 1000.0 / units_per_EM ) ); return; } void PdfFontMetricsBase14::GetWidthArray( PdfVariant & var, unsigned int nFirst, unsigned int nLast, const PdfEncoding* pEncoding ) const { unsigned int i; PdfArray list; for( i=nFirst;i<=nLast;i++ ) { if (pEncoding != NULL) { unsigned short shCode = pEncoding->GetCharCode(i); #ifdef PODOFO_IS_LITTLE_ENDIAN shCode = ((shCode & 0x00FF) << 8) | ((shCode & 0xFF00) >> 8); #endif list.push_back(PdfObject( (pdf_int64)this->GetGlyphWidth(this->GetGlyphIdUnicode(shCode) ))); } else { list.push_back( PdfVariant( double(widths_table[i].width) ) ); } } var = PdfVariant( list ); } const char* PdfFontMetricsBase14::GetFontData() const { return NULL; } pdf_long PdfFontMetricsBase14::GetFontDataLen() const { return 0; } }; podofo-0.9.5/src/doc/PdfFontMetrics.cpp0000664000175000017500000010157612715357362017637 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfFontMetrics.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfDictionary.h" #include "base/PdfVariant.h" #include "PdfFontFactory.h" #include #include #include #include FT_FREETYPE_H #include FT_TRUETYPE_TABLES_H #define PODOFO_FIRST_READABLE 31 #define PODOFO_WIDTH_CACHE_SIZE 256 namespace PoDoFo { #if defined(__APPLE_CC__) && !defined(PODOFO_HAVE_FONTCONFIG) #include #endif PdfFontMetrics::PdfFontMetrics( EPdfFontType eFontType, const char* pszFilename, const char* pszSubsetPrefix ) : m_sFilename( pszFilename ), m_fFontSize( 0.0f ), m_fFontScale( 100.0f ), m_fFontCharSpace( 0.0f ), m_fWordSpace( 0.0f ), m_eFontType( eFontType ), m_sFontSubsetPrefix( pszSubsetPrefix ? pszSubsetPrefix : "" ) { } /* PdfFontMetrics::PdfFontMetrics( FT_Library* pLibrary, PdfObject* pDescriptor ) : m_sFilename( "" ), m_pLibrary( pLibrary ), m_pMetrics_base14(NULL), m_bSymbol( false ), m_fFontSize( 0.0f ), m_fFontScale( 100.0f ), m_fFontCharSpace( 0.0f ), m_eFontType( ePdfFontType_Unknown ) { m_face = NULL; if( !pDescriptor ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } PdfName sName = pDescriptor->GetDictionary().GetKey( "FontName" )->GetName(); m_nWeight = static_cast(pDescriptor->GetDictionary().GetKeyAsLong( "FontWeight", 400L )); m_nItalicAngle = static_cast(pDescriptor->GetDictionary().GetKeyAsLong( "ItalicAngle", 0L )); m_dPdfAscent = pDescriptor->GetDictionary().GetKeyAsReal( "Ascent", 0.0 ); m_dPdfDescent = pDescriptor->GetDictionary().GetKeyAsReal( "Descent", 0.0 ); } */ PdfFontMetrics::~PdfFontMetrics() { } #if defined(__APPLE_CC__) && !defined(PODOFO_HAVE_FONTCONFIG) && !defined(PODOFO_NO_FONTMANAGER) FT_Error My_FT_GetFile_From_Mac_ATS_Name( const char* fontName, FSSpec* pathSpec, FT_Long* face_index ) { CFStringRef cf_fontName; ATSFontRef ats_font_id; *face_index = 0; cf_fontName = CFStringCreateWithCString( NULL, fontName, kCFStringEncodingMacRoman ); ats_font_id = ATSFontFindFromName( cf_fontName, kATSOptionFlagsUnRestrictedScope ); if ( ats_font_id == 0 || ats_font_id == 0xFFFFFFFFUL ) return FT_Err_Unknown_File_Format; if ( 0 != ATSFontGetFileSpecification( ats_font_id, pathSpec ) ) return FT_Err_Unknown_File_Format; /* face_index calculation by searching preceding fontIDs */ /* with same FSRef */ { int i; FSSpec f; for ( i = 1; i < ats_font_id; i++ ) { if ( 0 != ATSFontGetFileSpecification( ats_font_id - i, &f ) || f.vRefNum != pathSpec->vRefNum || f.parID != pathSpec->parID || f.name[0] != pathSpec->name[0] || 0 != ft_strncmp( (char *)f.name + 1, (char *)pathSpec->name + 1, f.name[0] ) ) break; } *face_index = ( i - 1 ); } return FT_Err_Ok; } FT_Error My_FT_GetFile_From_Mac_Name( const char* fontName, FSSpec* pathSpec, FT_Long* face_index ) { OptionBits options = kFMUseGlobalScopeOption; FMFontFamilyIterator famIter; OSStatus status = FMCreateFontFamilyIterator( NULL, NULL, options, &famIter ); FMFont the_font = NULL; FMFontFamily family = NULL; *face_index = 0; while ( status == 0 && !the_font ) { status = FMGetNextFontFamily( &famIter, &family ); if ( status == 0 ) { int stat2; FMFontFamilyInstanceIterator instIter; Str255 famNameStr; char famName[256]; /* get the family name */ FMGetFontFamilyName( family, famNameStr ); ( famNameStr, famName ); // inLog.Debug( boost::format( "Found FontFamily: '%s'\n" ) % famName ); /* iterate through the styles */ FMCreateFontFamilyInstanceIterator( family, &instIter ); *face_index = 0; stat2 = 0; while ( stat2 == 0 && !the_font ) { FMFontStyle style; FMFontSize size; FMFont font; stat2 = FMGetNextFontFamilyInstance( &instIter, &font, &style, &size ); if ( stat2 == 0 && size == 0 ) { char fullName[256]; /* build up a complete face name */ ft_strcpy( fullName, famName ); if ( style & bold ) strcat( fullName, " Bold" ); if ( style & italic ) strcat( fullName, " Italic" ); // inLog.Debug( boost::format( "Checking Face: '%s'\n" ) % fullName ); /* compare with the name we are looking for */ if ( ft_strcmp( fullName, fontName ) == 0 ) { /* found it! */ the_font = font; } else ++(*face_index); } } FMDisposeFontFamilyInstanceIterator( &instIter ); } } FMDisposeFontFamilyIterator( &famIter ); if ( the_font ) { FMGetFontContainer( the_font, pathSpec ); return FT_Err_Ok; } else return FT_Err_Unknown_File_Format; } /* Given a PostScript font name, create the Macintosh LWFN file name. */ static void create_lwfn_name( char* ps_name, Str255 lwfn_file_name ) { int max = 5, count = 0; FT_Byte* p = lwfn_file_name; FT_Byte* q = (FT_Byte*)ps_name; lwfn_file_name[0] = 0; while ( *q ) { if ( ft_isupper( *q ) ) { if ( count ) max = 3; count = 0; } if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) ) { *++p = *q; lwfn_file_name[0]++; count++; } q++; } } static short count_faces_sfnt( char *fond_data ) { /* The count is 1 greater than the value in the FOND. */ /* Isn't that cute? :-) */ return 1 + *( (short *)( fond_data + sizeof ( FamRec ) ) ); } static void parse_fond( char* fond_data, short* have_sfnt, short* sfnt_id, char* ps_name, Str255 lwfn_file_name, short face_index ) { AsscEntry* assoc; AsscEntry* base_assoc; FamRec* fond; *sfnt_id = 0; *have_sfnt = 0; lwfn_file_name[0] = 0; fond = (FamRec*)fond_data; assoc = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 ); base_assoc = assoc; /* Let's do a little range checking before we get too excited here */ if ( face_index < count_faces_sfnt( fond_data ) ) { assoc += face_index; /* add on the face_index! */ /* if the face at this index is not scalable, fall back to the first one (old behavior) */ if ( assoc->fontSize == 0 ) { *have_sfnt = 1; *sfnt_id = assoc->fontID; } else if ( base_assoc->fontSize == 0 ) { *have_sfnt = 1; *sfnt_id = base_assoc->fontID; } } if ( fond->ffStylOff ) { unsigned char* p = (unsigned char*)fond_data; StyleTable* style; unsigned short string_count; unsigned char* names[64]; int i; // inLog.Debug( "Font has StylOff\n" ); p += fond->ffStylOff; style = (StyleTable*)p; p += sizeof ( StyleTable ); string_count = *(unsigned short*)(p); p += sizeof ( short ); for ( i = 0 ; i < string_count && i < 64; i++ ) { names[i] = p; p += names[i][0]; p++; // inLog.Debug( boost::format( "Name[%d] is '%s'\n" ) % i % &names[i][1] ); } { size_t ps_name_len = (size_t)names[0][0]; if ( ps_name_len != 0 ) { ft_memcpy(ps_name, names[0] + 1, ps_name_len); ps_name[ps_name_len] = 0; } if ( style->indexes[0] > 1 ) { unsigned char* suffixes = names[style->indexes[0] - 1]; // inLog.Debug( boost::format( "string_count = %d\tsuffixes = %d\n" ) % string_count % (int)suffixes[0] ); for ( i = 1; i <= suffixes[0]; i++ ) { unsigned char* s; size_t j = suffixes[i] - 1; if ( j < string_count && ( s = names[j] ) != NULL ) { size_t s_len = (size_t)s[0]; s[s_len] = 0; // inLog.Debug( boost::format( "Suffix %d:'%s'\n" ) % i % &s[1] ); if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) ) { ft_memcpy( ps_name + ps_name_len, s + 1, s_len ); ps_name_len += s_len; ps_name[ps_name_len] = 0; } } } } } // inLog.Debug( boost::format( "Found PSName is '%s'\n" ) % ps_name ); create_lwfn_name( ps_name, lwfn_file_name ); } } /* Given a file reference, answer its location as a vRefNum and a dirID. */ static FT_Error get_file_location( short ref_num, short* v_ref_num, long* dir_id, unsigned char* file_name ) { FCBPBRec pb; OSErr error; pb.ioNamePtr = file_name; pb.ioVRefNum = 0; pb.ioRefNum = ref_num; pb.ioFCBIndx = 0; error = PBGetFCBInfoSync( &pb ); if ( error == noErr ) { *v_ref_num = pb.ioFCBVRefNum; *dir_id = pb.ioFCBParID; } return error; } /* Return the file type of the file specified by spec. */ static OSType get_file_type( const FSSpec* spec ) { FInfo finfo; if ( FSpGetFInfo( spec, &finfo ) != noErr ) return 0; /* file might not exist */ return finfo.fdType; } /* Make a file spec for an LWFN file from a FOND resource and a file name. */ static FT_Error make_lwfn_spec( Handle fond, const unsigned char* file_name, FSSpec* spec ) { FT_Error error; short ref_num, v_ref_num; long dir_id; Str255 fond_file_name; ref_num = HomeResFile( fond ); error = ResError(); if ( !error ) error = get_file_location( ref_num, &v_ref_num, &dir_id, fond_file_name ); if ( !error ) error = FSMakeFSSpec( v_ref_num, dir_id, file_name, spec ); return error; } /* Read Type 1 data from the POST resources inside the LWFN file, return a PFB buffer. This is somewhat convoluted because the FT2 PFB parser wants the ASCII header as one chunk, and the LWFN chunks are often not organized that way, so we'll glue chunks of the same type together. */ static FT_Error read_lwfn( short res_ref, FT_Byte** pfb_data, FT_ULong* size ) { FT_Error error = FT_Err_Ok; short res_id; unsigned char *buffer, *p, *size_p = NULL; FT_ULong total_size = 0; FT_ULong post_size, pfb_chunk_size; Handle post_data; char code, last_code; UseResFile( res_ref ); /* First pass: load all POST resources, and determine the size of */ /* the output buffer. */ res_id = 501; last_code = -1; for (;;) { post_data = Get1Resource( 'POST', res_id++ ); if ( post_data == NULL ) break; /* we're done */ code = (*post_data)[0]; if ( code != last_code ) { if ( code == 5 ) total_size += 2; /* just the end code */ else total_size += 6; /* code + 4 bytes chunk length */ } total_size += GetHandleSize( post_data ) - 2; last_code = code; } buffer = (unsigned char*)podofo_malloc( total_size ); if ( buffer == NULL ) goto Error; /* Second pass: append all POST data to the buffer, add PFB fields. */ /* Glue all consecutive chunks of the same type together. */ p = buffer; res_id = 501; last_code = -1; pfb_chunk_size = 0; for (;;) { post_data = Get1Resource( 'POST', res_id++ ); if ( post_data == NULL ) break; /* we're done */ post_size = (FT_ULong)GetHandleSize( post_data ) - 2; code = (*post_data)[0]; if ( code != last_code ) { if ( last_code != -1 ) { /* we're done adding a chunk, fill in the size field */ if ( size_p != NULL ) { *size_p++ = (FT_Byte)( pfb_chunk_size & 0xFF ); *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8 ) & 0xFF ); *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF ); *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF ); } pfb_chunk_size = 0; } *p++ = 0x80; if ( code == 5 ) *p++ = 0x03; /* the end */ else if ( code == 2 ) *p++ = 0x02; /* binary segment */ else *p++ = 0x01; /* ASCII segment */ if ( code != 5 ) { size_p = p; /* save for later */ p += 4; /* make space for size field */ } } ft_memcpy( p, *post_data + 2, post_size ); pfb_chunk_size += post_size; p += post_size; last_code = code; } *pfb_data = buffer; *size = total_size; Error: CloseResFile( res_ref ); return error; } static short count_faces( Handle fond ) { short sfnt_id, have_sfnt, have_lwfn = 0; Str255 lwfn_file_name; FSSpec lwfn_spec; char ps_name[256]; HLock( fond ); parse_fond( *fond, &have_sfnt, &sfnt_id, ps_name, lwfn_file_name, 0 ); HUnlock( fond ); if ( lwfn_file_name[0] ) { if ( make_lwfn_spec( fond, lwfn_file_name, &lwfn_spec ) == FT_Err_Ok ) have_lwfn = 1; /* yeah, we got one! */ else have_lwfn = 0; /* no LWFN file found */ } if ( have_lwfn && ( !have_sfnt /*|| PREFER_LWFN*/ ) ) return 1; else return count_faces_sfnt( *fond ); } static FT_Error LoadFontFromLWFN( FSRef inFileRef, FSSpec inSpec, const char* inFontName, FT_Long inFaceIndex, char** outBuffer, long& outBufLen ) { FT_Error error = FT_Err_Ok; short res_ref; FT_Byte* pfb_data; FT_ULong pfb_size; // open up the resource file error = FSOpenResourceFile( &inFileRef, 0, NULL, fsRdPerm, &res_ref ); if ( error != noErr ) { // try old fashioned way // inLog.Debug( boost::format( "FSOpenResourceFile failed - Error %d\n" ) % error ); res_ref = FSpOpenResFile( &inSpec, fsRdPerm ); if ( res_ref < 0 ) { // inLog.Debug( boost::format( "FSpOpenResFile failed- Error %d\n" ) % res_ref ); return FT_Err_Cannot_Open_Resource; } else { // inLog.Debug( "FSpOpenResFile Succeeded!\n" ); } error = 0; // reset it } UseResFile( res_ref ); error = read_lwfn( res_ref, &pfb_data, &pfb_size ); if ( !error ) { *outBuffer = (char*)pfb_data; outBufLen = pfb_size; } else { // inLog.Debug( "read_lwfn failed\n" ); } Error: CloseResFile( res_ref ); return error; } static FT_Error LoadFontFromDFont( FSRef inFileRef, FSSpec inSpec, const char* inFontName, FT_Long inFaceIndex, char** outBuffer, long& outBufLen ) { const bool PREFER_LWFN=false; FT_Error error = FT_Err_Ok; short res_ref, res_index = 1; Handle fond; short sfnt_id = 0, have_sfnt =0, have_lwfn = 0; short num_faces; char ps_name[128]; Str255 lwfn_file_name; FSSpec lwfn_spec; char localFontName[256]; #if 1 int j = 0; bool foundSpace = false; for ( int i=0; i(pszFontname), &fSpec, &fIndex ); if ( error ) { // try use the alternate name... std::string altName = Std2AltFontName( pszFontname ); // mLog.Debug( boost::format("Unable to locate - trying alternate '%s'\n") % altName.c_str() ); error = My_FT_GetFile_From_Mac_ATS_Name( const_cast(altName.c_str()), &fSpec, &fIndex ); if ( error ) { // mLog.Debug( boost::format("Unable to locate - trying as Postscript\n") ); // see if this is a Postscript name... CFStringRef cstr = CFStringCreateWithCString( NULL, pszFontname, kCFStringEncodingUTF8 ); if ( cstr != NULL ) { ATSFontRef fontRef = ATSFontFindFromPostScriptName( cstr, kATSOptionFlagsDefault ); if ( fontRef != kATSFontRefUnspecified ) { // mLog.Debug( "**Found it!\n" ); error = ATSFontGetFileSpecification( fontRef, &fSpec ); } else { // mLog.Debug( boost::format("*Unable to locate as Postscript - giving up!\n") ); } CFRelease( cstr ); } } } if ( !error ) { FSRef ref; OSErr err = FSpMakeFSRef( &fSpec, &ref ); if ( !err ) { CFURLRef url = CFURLCreateFromFSRef( kCFAllocatorDefault, &ref ); CFStringRef pathRef = CFURLCopyFileSystemPath( url, kCFURLPOSIXPathStyle ); CFIndex length = CFStringGetLength( pathRef ) + 0x02; char* path = (char *)podofo_calloc( length, sizeof( *path ) ); if ( CFStringGetCString( pathRef, path, length, kCFStringEncodingUTF8 ) ) { std::string fontPath( path ); if ( (fontPath.find( ".ttf" ) != fontPath.npos) || (fontPath.find( ".otf" ) != fontPath.npos) ) { // mLog.Debug( boost::format("Found matching TTF/OTF font for '%s', index %d\n") % pszFontname % fIndex ); #if 1 //def FILE_BASED CPDFFTFont* ftFont = new CPDFFTFont( *this, fontPath, fIndex ); #else std::string fontBufStr; StringUtils::ReadFileIntoString( fontPath, fontBufStr ); ASInt32 fontBufferLen = fontBufStr.length(); if (fontBufferLen == 0) { CFRelease( pathRef ); CFRelease( url ); podofo_free(path); return NULL; } char* fontBuffer = (char*)ASmalloc( fontBufferLen ); memcpy( fontBuffer, fontBufStr.c_str(), fontBufferLen ); CPDFFTFont* ftFont = new CPDFFTFont( *this, fontBuffer, fontBufferLen, fIndex ); #endif retFont = reinterpret_cast< CPDFFont* >( ftFont ); } else if ( fontPath.find( ".dfont" ) != fontPath.npos ) { char* fontBuffer = NULL; ASInt32 fontBufferLen = 0; // mLog.Debug( boost::format("Found a matching .dfont for '%s', index %d\n") % pszFontname % fIndex ); FT_Error dfErr = LoadFontFromDFont( mLog, ref, fSpec, pszFontname, fIndex, &fontBuffer, fontBufferLen ); if ( !dfErr ) { CPDFFTFont* ftFont = new CPDFFTFont( *this, fontBuffer, fontBufferLen, fIndex ); retFont = reinterpret_cast< CPDFFont* >( ftFont ); } } else { char* fontBuffer = NULL; ASInt32 fontBufferLen = 0; fSpec.name[ fSpec.name[0]+1 ] = 0; // zero term for C func // mLog.Debug( boost::format("Found a matching CLASSIC font for '%s' at '%s', index %d\n") % pszFontname % &fSpec.name[1] % fIndex ); FT_Error dfErr = 0; OSType file_type = get_file_type( &fSpec ); if ( file_type == 'LWFN' ) { // mLog.Debug( "Loading from LWFN...\n" ); if ( fIndex > 0 ) fIndex = 0; // don't need it anymore... dfErr = LoadFontFromLWFN( mLog, ref, fSpec, pszFontname, fIndex, &fontBuffer, fontBufferLen ); } else { // mLog.Debug( "Loading from Suitcase...\n" ); dfErr = LoadFontFromDFont( mLog, ref, fSpec, pszFontname, fIndex, &fontBuffer, fontBufferLen ); } if ( !dfErr ) { CPDFFTFont* ftFont = new CPDFFTFont( *this, fontBuffer, fontBufferLen, fIndex ); retFont = reinterpret_cast< CPDFFont* >( ftFont ); } else { // mLog.Debug( boost::format("FTError: '%d'\n") % dfErr ); } } } else { // mLog.Debug( boost::format("Unable to locate a matching font for '%s'\n") % pszFontname ); } podofo_free( path ); CFRelease( pathRef ); CFRelease( url ); } } else { // mLog.Debug( boost::format("Unable to locate a matching font for '%s'\n") % pszFontname ); } } #endif // apple double PdfFontMetrics::StringWidth( const char* pszText, pdf_long nLength ) const { double dWidth = 0.0; if( !pszText ) return dWidth; if( !nLength ) nLength = strlen( pszText ); const char *localText = pszText; for ( pdf_long i=0; iGetFontScale() / 100.0; localText++; } return dWidth; } double PdfFontMetrics::StringWidth( const pdf_utf16be* pszText, unsigned int nLength ) const { double dWidth = 0.0; unsigned short uChar; if( !pszText ) return dWidth; if( !nLength ) { const pdf_utf16be* pszCount = pszText; while( *pszCount ) { ++pszCount; ++nLength; } } const pdf_utf16be* localText = pszText; for ( unsigned int i=0; i(((*localText & 0x00ff) << 8 | (*localText & 0xff00) >> 8)); #else uChar = static_cast(*localText); #endif // PODOFO_IS_LITTLE_ENDIAN dWidth += UnicodeCharWidth( uChar ); if ( uChar == 0x0020 ) dWidth += m_fWordSpace * this->GetFontScale() / 100.0; localText++; } return dWidth; } #ifndef _WCHAR_T_DEFINED #if defined(_MSC_VER) && _MSC_VER <= 1200 // not for MS Visual Studio 6 #else double PdfFontMetrics::StringWidth( const wchar_t* pszText, unsigned int nLength ) const { double dWidth = 0.0; if( !pszText ) return dWidth; if( !nLength ) nLength = static_cast(wcslen( pszText )); const wchar_t *localText = pszText; for ( unsigned int i=0; i(*localText) ); if ( static_cast(*localText) == 0x0020 ) dWidth += m_fWordSpace * this->GetFontScale() / 100.0; localText++; } return dWidth; } #endif #endif EPdfFontType PdfFontMetrics::FontTypeFromFilename( const char* pszFilename ) { EPdfFontType eFontType = PdfFontFactory::GetFontType( pszFilename ); if( eFontType == ePdfFontType_Unknown ) PdfError::DebugMessage( "Warning: Unrecognized FontFormat: %s\n", pszFilename ); return eFontType; } }; podofo-0.9.5/src/doc/PdfTTFWriter.h0000664000175000017500000006511712344436402016670 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_TTF_WRITER_H_ #define _PDF_TTF_WRITER_H_ #error "THIS SOURCE FILE WAS REPLACED BY PdfFontTTFSubset.h !" #include "PdfDefines.h" #include "PdfRefCountedBuffer.h" namespace PoDoFo { class PdfInputDevice; class PdfOutputDevice; namespace NonPublic { /** An internal class which can parse a TrueType font file * and write a subset of this TrueType font back to an output device. * * This class is used internally to do font subsetting. * * The usual way to use this class is: * * PdfTTFWriter writer; * writer.Read ( [an input device] ); // read the font from a device * writer.Subset ( ); // do the subsetting * writer.Write ( [an output device] ); // write the font back to a device */ class PODOFO_API PdfTTFWriter { // Some common datatypes used in TTF files typedef pdf_uint32 pdf_ttf_fixed; typedef pdf_uint16 pdf_ttf_ushort; typedef pdf_int16 pdf_ttf_short; typedef pdf_uint32 pdf_ttf_ulong; typedef pdf_int16 pdf_ttf_fword; typedef pdf_uint16 pdf_ttf_ufword; typedef pdf_int16 pdf_ttf_f2dot14; #pragma pack(1) /** The table dictionary is the starting point when reading * or writing a TTF file. */ struct TTableDirectory { pdf_ttf_fixed sfnt_version; ///< 0x00010000 for version 1.0 pdf_ttf_ushort numTables; ///< Number of tables in this file pdf_ttf_ushort searchRange; ///< (Maximum power of 2 <= numTables) * 16 pdf_ttf_ushort entrySelector; ///< Log2( Maximum power of 2 <= numTables) pdf_ttf_ushort rangeShift; ///< numTables * 16 - searchRange }; struct TTableDirectoryEntry { pdf_ttf_ulong tag; ///< 4 character identifier pdf_ttf_ulong checkSum; ///< Checksum of the table pdf_ttf_ulong offset; ///< Offset from the beginning of the file pdf_ttf_ulong length; ///< Length of this table }; typedef std::vector TVecTableDirectoryEntries; typedef TVecTableDirectoryEntries::iterator TIVecTableDirectoryEntries; typedef TVecTableDirectoryEntries::const_iterator TCIVecTableDirectoryEntries; struct TTable { TTable() : data( NULL ) { } ~TTable() { /* if( data ) free( data ); */ } pdf_ttf_ulong tag; ///< 4 character identifier pdf_ttf_ulong length; ///< Length of this table char* data; ///< Actual table data buffer }; typedef std::vector TVecTable; typedef TVecTable::iterator TIVecTable; typedef TVecTable::const_iterator TCIVecTable; struct TMaxP { pdf_ttf_fixed version; ///< The table versions 0x00010000 for version 1.0 pdf_ttf_ushort numGlyphs; ///< The number of glyphs in this font pdf_ttf_ushort maxPoints; ///< Maximum number of points in a non composite glyph pdf_ttf_ushort maxContours; ///< Maximum number of contours in a non composite glyph pdf_ttf_ushort maxCompositePoints; ///< Maximum number of points in a composite glyph pdf_ttf_ushort maxCompositeContours; ///< Maximum number of contours in a composite glyph pdf_ttf_ushort maxZones; ///< 1 if instrutions do not use Z0 or 2 if instrutions do use Z0 (twilight zone) pdf_ttf_ushort maxTwilightPoints; ///< Maximum points used in Z0 pdf_ttf_ushort maxStorage; ///< Maximum number of storage area locations pdf_ttf_ushort maxFunctionsDefs; ///< Number of FDEF's pdf_ttf_ushort maxInstructionDefs; ///< Number of IDEF's pdf_ttf_ushort maxStackElements; ///< Maximum stack depth pdf_ttf_ushort maxSizeOfInstruction; ///< Maximum byte count for glyph instruction pdf_ttf_ushort maxComponentElements; ///< Maximum number of components referenced at top level for composite glyph pdf_ttf_ushort maxComponentDepth; ///< Maximum level of recursions; 1 for simple components }; struct THead { pdf_ttf_fixed version; ///< The table versions 0x00010000 for version 1.0 pdf_ttf_fixed revision; ///< The revision set by the font manufacturer pdf_ttf_ulong checkSumAdjustment; ///< To compute: set it to 0, sum the entire font as ULONG, then store 0xB1B0AFBA - sum pdf_ttf_ulong magicNumber; ///< Set to 0x5F0F3CF5 pdf_ttf_ushort flags; ///< Font flags pdf_ttf_ushort unitsPerEm; char created[8]; char modified[8]; pdf_ttf_fword xMin; pdf_ttf_fword yMin; pdf_ttf_fword xMax; pdf_ttf_fword yMax; pdf_ttf_ushort macStyle; pdf_ttf_ushort lowestRecPPEM; pdf_ttf_short fontDirectionHint; pdf_ttf_short indexToLocForm; ///< 0 for short offsets, 1 for long offsets pdf_ttf_short glyphDataFormat; ///< 0 for current format }; struct TCMapEntry { pdf_ttf_ushort platformId; pdf_ttf_ushort encodingId; pdf_ttf_ulong offset; }; /** * Header of a single glyph in the glyf table */ struct TGlyphHeader { pdf_ttf_short numberOfContours; ///< If greater or equal 0, this is a single glyph, if negative it is a composite pdf_ttf_fword xMin; pdf_ttf_fword yMin; pdf_ttf_fword xMax; pdf_ttf_fword yMax; }; #pragma pack() class PdfTTFGlyph { public: /** Create a new glyph object. * * \param nIndex glyph index. * \param bComposite if true, this is a composite glyph * otherwise this object is simple glyph */ PdfTTFGlyph( int nIndex ) : m_nPosition( 0 ), m_nIndex( nIndex ), m_bComposite( false ), m_nInstructionLength( 0 ), m_pInstructions( NULL ) { printf("m_nIndex=%i\n", m_nIndex ); } PdfTTFGlyph( const PdfTTFGlyph & rhs ) { operator=( rhs ); } const PdfTTFGlyph & operator=( const PdfTTFGlyph & rhs ) { m_nIndex = rhs.m_nIndex; m_bComposite = rhs.m_bComposite; m_tHeader = rhs.m_tHeader; m_nPosition = rhs.m_nPosition; m_nInstructionLength = rhs.m_nInstructionLength; m_pInstructions = rhs.m_pInstructions; // simple vecEndPoints = rhs.vecEndPoints; vecXCoordinates = rhs.vecXCoordinates; vecYCoordinates = rhs.vecYCoordinates; vecFlags = rhs.vecFlags; vecFlagsOrig = rhs.vecFlagsOrig; // composite arg1 = rhs.arg1; arg2 = rhs.arg2; xx = rhs.xx; yy = rhs.yy; xy = rhs.xy; yx = rhs.yx; m_buffer = rhs.m_buffer; return *this; } inline bool IsComposite() const { return m_bComposite; } inline void SetComposite( bool b ) { m_bComposite = b; } inline int GetIndex() const { return m_nIndex; } inline int GetPosition() const { return m_nPosition; } inline void SetPosition( int nPos ) { m_nPosition = nPos; } inline pdf_ttf_ushort GetInstrunctionLength() const { return m_nInstructionLength; }; inline const char* GetInstrunctions() const { return m_pInstructions; } public: // TODO: add accessors int m_nPosition; PdfRefCountedBuffer m_buffer; // common int m_nIndex; bool m_bComposite; TGlyphHeader m_tHeader; pdf_ttf_ushort m_nInstructionLength; char* m_pInstructions; // simple glyph std::vector vecEndPoints; std::vector vecXCoordinates; std::vector vecYCoordinates; std::vector vecFlags; ///< Parsed font flags which are used to read glyf coordinates std::vector vecFlagsOrig; ///< Compressed files can be written out 1to1 to disk // composite pdf_ttf_short arg1; pdf_ttf_short arg2; pdf_ttf_short xx; pdf_ttf_short yy; pdf_ttf_short xy; pdf_ttf_short yx; }; #pragma pack(1) struct TCMapFormat4 { pdf_ttf_ushort format; pdf_ttf_ushort length; pdf_ttf_ushort version; pdf_ttf_ushort segCountX2; ///< 2 x segCount pdf_ttf_ushort searchRange; ///< 2 x (2**floor(log2(segCount))) pdf_ttf_ushort entrySelector; ///< log2(searchRange/2) pdf_ttf_ushort rangeShift; ///< 2 x segCount - searchRange }; struct TCMapRange { pdf_ttf_ushort nStart; pdf_ttf_ushort nEnd; pdf_ttf_short nDelta; pdf_ttf_ushort nOffset; TCMapRange() { } TCMapRange( const TCMapRange & rhs ) { this->operator=( rhs ); } const TCMapRange & operator=( const TCMapRange & rhs ) { nStart = rhs.nStart; nEnd = rhs.nEnd; nDelta = rhs.nDelta; nOffset = rhs.nOffset; return *this; } bool operator<( const TCMapRange & rhs ) const { return nStart < rhs.nStart; } }; typedef std::vector TVecGlyphs; typedef TVecGlyphs::iterator TIVecGlyphs; typedef TVecGlyphs::const_iterator TCIVecGlyphs; typedef std::vector TVecLoca; typedef TVecLoca::iterator TIVecLoca; typedef TVecLoca::const_iterator TCIVecLoca; struct THHea { pdf_ttf_fixed version; ///< version 0x00010000 pdf_ttf_fword ascender; pdf_ttf_fword descender; pdf_ttf_fword linegap; pdf_ttf_fword advanceWidthMax; ///< maximum advance width value in "hmtx" table pdf_ttf_fword minLeftSideBearing; ///< minimum left side bearing in hmtx table pdf_ttf_fword minRightSideBearing;///< minimum right side bearing in hmtx table pdf_ttf_fword xMaxExtent; ///< Max( lsb + (xMax - xMin) ); pdf_ttf_short caretSlopeRise; pdf_ttf_short caretSlopeRun; pdf_ttf_short reserved1; pdf_ttf_short reserved2; pdf_ttf_short reserved3; pdf_ttf_short reserved4; pdf_ttf_short reserved5; pdf_ttf_short metricDataFormat; pdf_ttf_ushort numberOfHMetrics; ///< Number of entries in the hmtx table }; struct TOs2 { pdf_ttf_ushort version; ///< version 0x00010000 pdf_ttf_short xAvgCharWidth; pdf_ttf_ushort usWeightClass; pdf_ttf_ushort usWidthClass; pdf_ttf_short fsType; pdf_ttf_short ySubscriptXSize; pdf_ttf_short ySubscriptYSize; pdf_ttf_short ySubscriptXOffset; pdf_ttf_short ySubscriptYOffset; pdf_ttf_short ySuperscriptXSize; pdf_ttf_short ySuperscriptYSize; pdf_ttf_short ySuperscriptXOffset; pdf_ttf_short ySuperscriptYOffset; pdf_ttf_short yStrikeoutSize; pdf_ttf_short yStrikeoutPosition; pdf_ttf_short sFamilyClass; char panose[10]; ///< Panose information pdf_ttf_ulong ulUnicodeRange1; pdf_ttf_ulong ulUnicodeRange2; pdf_ttf_ulong ulUnicodeRange3; pdf_ttf_ulong ulUnicodeRange4; char achVendID[4]; pdf_ttf_ushort fsSelection; pdf_ttf_ushort usFirstCharIndex; ///< The minimum unicode char index in this font pdf_ttf_ushort usLastCharIndex; ///< The maximum unicode char index in this font pdf_ttf_ushort sTypoAscender; pdf_ttf_ushort sTypoDescender; pdf_ttf_ushort sTypoLineGap; pdf_ttf_ushort usWinAscent; pdf_ttf_ushort usWinDescent; pdf_ttf_ulong ulCodePageRange1; pdf_ttf_ulong ulCodePageRange2; }; struct TLongHorMetric { pdf_ttf_ufword advanceWidth; pdf_ttf_fword leftSideBearing; }; struct TNameTable { // header pdf_ttf_ushort format; ///< 0 pdf_ttf_ushort numRecords; ///< 1 pdf_ttf_ushort offset; ///< 6 // body pdf_ttf_ushort platformId; ///< 3 (Microsoft) pdf_ttf_ushort encodingId; ///< 1 (Unicode) pdf_ttf_ushort languageId; ///< 0x0809 (british English) pdf_ttf_ushort nameId; ///< 1 (font family name) pdf_ttf_ushort stringLength; pdf_ttf_ushort stringOffset;///< 0 }; /** The postscript table */ struct TPost { pdf_ttf_fixed format; pdf_ttf_fixed italicAngle; pdf_ttf_fword underlinePosition; pdf_ttf_fword underlineThickness; pdf_ttf_ulong isFixedPitch; pdf_ttf_ulong minMemType42; pdf_ttf_ulong maxMemType42; pdf_ttf_ulong minMemType1; pdf_ttf_ulong maxMemType1; }; #pragma pack() public: /** Create a PdfTTFWriter object. * For testing purposes. * * TODO: Remove */ PdfTTFWriter(); PdfTTFWriter( const std::vector & rvecGlyphs ); ~PdfTTFWriter(); /** Fills the internal data structures * using an existing TrueType font. * * \param pDevice the TTF is read from this device */ void Read( PdfInputDevice* pDevice ); /** Do the actual subsetting of the font data * TODO */ void Subset(); /** Write a TTF font from the current internal structures * to an output device. * * \param pDevice write the font to this device */ void Write( PdfOutputDevice* pDevice ); private: /** Create a tag name from four characters, * so that the user readable tag can be put into * TTableDirectoryEntry. * * \returns the tag as a pdf_ttf_ulong */ inline pdf_ttf_ulong CreateTag( char a, char b, char c, char d ) const; /** Calculate the checksum of a table. * * The table is interpreted as a byte stream of unsigned longs * and has to be padded to a multiple of 4 bytes * * \param pTable pointer to the beginning of the table * \param lLength length of the table * * \returns the checksum of the table */ pdf_ttf_ulong CalculateChecksum( const pdf_ttf_ulong* pTable, pdf_ttf_ulong lLength ) const; /** Convert a pdf_ttf_ushort between big and little endian * * \param pShort a value to swap */ inline void SwapUShort( pdf_ttf_ushort* pShort ) const; /** Convert a pdf_ttf_short between big and little endian * * \param pShort a value to swap */ inline void SwapShort( pdf_ttf_short* pShort ) const; /** Convert a pdf_ttf_fword between big and little endian * * \param pFword a value to swap */ inline void SwapFWord( pdf_ttf_fword* pFword ) const; /** Convert a pdf_ttf_ulong between big and little endian * * \param pShort a value to swap */ inline void SwapULong( pdf_ttf_ulong* pLong ) const; /** Reads the table directory from the current position * of the input device, handling any necessary * conversion from big to little endian. * * \param pDevice read from the current position of this device. * * \see m_tTableDirectory */ void ReadTableDirectory( PdfInputDevice* pDevice ); /** Reads a table directory entry from the current position * of the input device, handling any necessary * conversion from big to little endian. * * \param pDevice read from the current position of this device. * \param pEntry store the result at this memory location */ void ReadTableDirectoryEntry( PdfInputDevice* pDevice, TTableDirectoryEntry* pEntry ); /** Writes a table directory entry at the current position * of the output device, handling any necessary * conversion from big to little endian. * * \param pDevice write at the current position of this device. * \param pEntry the entry which should be written */ void WriteTableDirectoryEntry( PdfOutputDevice* pDevice, TTableDirectoryEntry* pEntry ); /** Reads the head table from the current position of * the input device, handling any necessary conversion * from big to little endian. * * \param pDevice read from the current position of this device. * * \see m_tHead */ void ReadHeadTable( PdfInputDevice* pDevice ); /** Swap the endianess of the head table. * \see m_tHead */ void SwapHeadTable(); void ReadMaxpTable( PdfInputDevice* pDevice ); void ReadLocaTable( PdfInputDevice* pDevice ); void ReadHHeaTable( PdfInputDevice* pDevice ); void ReadCmapTable( PdfInputDevice* pDevice ); void ReadGlyfTable( PdfInputDevice* pDevice ); void ReadOs2Table ( PdfInputDevice* pDevice ); void ReadHmtxTable( PdfInputDevice* pDevice ); void ReadPostTable( PdfInputDevice* pDevice ); /** Writes the table directory at the current position * of the output device, handling any necessary * conversion from big to little endian. * * \param pDevice write at the current position of this device. * * \see m_tTableDirectory */ void WriteTableDirectory( PdfOutputDevice* pDevice ); /** Writes the head table at the current position * of the output device, handling any necessary * conversion from big to little endian. * * \param pDevice write at the current position of this device. * * \see m_tHead */ void WriteHeadTable( PdfOutputDevice* pDevice ); /** Writes the maxp table at the current position * of the output device, handling any necessary * conversion from big to little endian. * * \param pDevice write at the current position of this device. * * \see m_tMaxp */ void WriteMaxpTable( PdfOutputDevice* pDevice ); void WriteHHeaTable( PdfOutputDevice* pDevice ); void WriteLocaTable( PdfOutputDevice* pDevice ); void WriteCMapTable( PdfOutputDevice* pDevice ); void WriteGlyfTable( PdfOutputDevice* pDevice ); void WriteOs2Table ( PdfOutputDevice* pDevice ); void WriteNameTable( PdfOutputDevice* pDevice ); void WriteHmtxTable( PdfOutputDevice* pDevice ); void WritePostTable( PdfOutputDevice* pDevice ); /** * Write a table to an output device and create a table directory for it * with a correctly calculated checksum. * * \param pDevice the output device on which the table should be written * \param rToc add a table directory entry to this table directory. * \param tag the tag of the table (e.g. 'name' or 'os/2'). * \param WriteTableFunc a member function pointer to the function that actually write the data * * \see CreateTag */ void WriteTable( PdfOutputDevice* pDevice, TVecTableDirectoryEntries & rToc, pdf_ttf_ulong tag, void (PdfTTFWriter::*WriteTableFunc)( PdfOutputDevice* ) ); void SwapGlyfHeader( TGlyphHeader* pHeader ); /** Swap the endianess of the maxp table. * \see m_tMaxp */ void SwapMaxpTable(); void SwapHHeaTable(); void SwapOs2Table(); void SwapPostTable(); /** Read the glyph coordinates from an input device. * * \param pDevice read from this device * \param rvecFlags a vector of flags describing the coordinates to load * For each flag ONE coordinate is read. Not more, not less. * \param rvecCoordinates store all coordinates in this vector * \param nFlagShort the flag to use for x and y coordinates which determines a short coordinate * \param nFlag the flag to use (0x10 for x coordinates and 0x20 for y coordinates) */ void ReadSimpleGlyfCoordinates( PdfInputDevice* pDevice, const std::vector & rvecFlags, std::vector & rvecCoordinates, int nFlagShort, int nFlag ); void WriteSimpleGlyfCoordinates( PdfOutputDevice* pDevice, const std::vector & rvecFlags, std::vector & rvecCoordinates, int nFlagShort, int nFlag ); /** Get the offset to the location of the glyphs data. * * \param nIndex unicode index of the glyph to load * \param plLength pointer to an address where the length of the glyphdata can be stored * \param pDevice an input device which can be used to read the CMap table which is required for certain glyphs * * \return the offset to the glyph data or -1 if the glyph does not exist */ long GetGlyphDataLocation( unsigned int nIndex, long* plLength, PdfInputDevice* pDevice ) const; /** Load a glyph from an input device at a certain offset * * \param nIndex the index of the glyph to load * \param lOffset the offset at which the glyph is located in the file * \param pDevice the input device to read from * */ void LoadGlyph( int nIndex, long lOffset, PdfInputDevice* pDevice ); private: long m_lGlyphDataOffset; ///< Offset to the glyph data table long m_lCMapOffset; ///< Offset to the cmap table std::vector m_vecGlyphIndeces; ///< List of glyph indeces we would like to embedd TTableDirectory m_tTableDirectory; ///< The TTF header TVecTable m_vecTableData; ///< The actual data of the tables TMaxP m_tMaxp; ///< The maximum memory requirements of this font THead m_tHead; ///< The head table THHea m_tHHea; ///< The hhea table TOs2 m_tOs2; ///< The OS/2 table TPost m_tPost; ///< The post table TVecLoca m_tLoca; ///< The loca table in long format which is read in TVecLoca m_vecLoca; ///< The loca table in long format which is written out TVecGlyphs m_vecGlyphs; ///< All glyphs including their outlines std::vector m_ranges; ///< CMap ranges TCMapFormat4 format4; std::vector m_vecGlyphIds; std::vector m_vecHmtx; ///< Hmtx table in long format PdfRefCountedBuffer* m_pRefBuffer; ///< A temporary buffer which is used during writing a TTF file }; // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfTTFWriter::pdf_ttf_ulong PdfTTFWriter::CreateTag( char a, char b, char c, char d ) const { return ( ( a << 24 )| ( b << 16 ) | ( c << 8 ) | d ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfTTFWriter::SwapUShort( pdf_ttf_ushort* pShort ) const { *pShort = ((*pShort << 8) & 0xFF00) | ((*pShort >> 8) & 0x00FF); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfTTFWriter::SwapShort( pdf_ttf_short* pShort ) const { *pShort = ((*pShort << 8) & 0xFF00) | ((*pShort >> 8) & 0x00FF); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfTTFWriter::SwapFWord( pdf_ttf_fword* pFword ) const { *pFword = ((*pFword << 8) & 0xFF00) | ((*pFword >> 8) & 0x00FF); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfTTFWriter::SwapULong( pdf_ttf_ulong* pLong ) const { *pLong = ((*pLong << 24) & 0xFF000000) | ((*pLong << 8) & 0x00FF0000) | ((*pLong >> 8) & 0x0000FF00) | ((*pLong >> 24) & 0x000000FF) ; } }; }; #endif // _PDF_TTF_WRITER_H_ podofo-0.9.5/src/doc/PdfFont.cpp0000664000175000017500000001505612715357362016305 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfFont.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfEncoding.h" #include "base/PdfInputStream.h" #include "base/PdfStream.h" #include "base/PdfWriter.h" #include "base/PdfLocale.h" #include "PdfFontMetrics.h" #include "PdfPage.h" #include #include #include using namespace std; namespace PoDoFo { PdfFont::PdfFont( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfVecObjects* pParent ) : PdfElement( "Font", pParent ), m_pEncoding( pEncoding ), m_pMetrics( pMetrics ), m_bBold( false ), m_bItalic( false ), m_isBase14( false ), m_bIsSubsetting( false ) { this->InitVars(); } PdfFont::PdfFont( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfObject* pObject ) : PdfElement( "Font", pObject ), m_pEncoding( pEncoding ), m_pMetrics( pMetrics ), m_bBold( false ), m_bItalic( false ), m_isBase14( false ), m_bIsSubsetting( false ) { this->InitVars(); // Implementation note: the identifier is always // Prefix+ObjectNo. Prefix is /Ft for fonts. ostringstream out; PdfLocaleImbue(out); out << "PoDoFoFt" << this->GetObject()->Reference().ObjectNumber(); m_Identifier = PdfName( out.str().c_str() ); } PdfFont::~PdfFont() { if (m_pMetrics) delete m_pMetrics; if( m_pEncoding && m_pEncoding->IsAutoDelete() ) delete m_pEncoding; } void PdfFont::InitVars() { ostringstream out; PdfLocaleImbue(out); m_pMetrics->SetFontSize( 12.0 ); m_pMetrics->SetFontScale( 100.0 ); m_pMetrics->SetFontCharSpace( 0.0 ); // Peter Petrov 24 Spetember 2008 m_bWasEmbedded = false; m_bUnderlined = false; m_bStrikedOut = false; // Implementation note: the identifier is always // Prefix+ObjectNo. Prefix is /Ft for fonts. out << "Ft" << this->GetObject()->Reference().ObjectNumber(); m_Identifier = PdfName( out.str().c_str() ); // replace all spaces in the base font name as suggested in // the PDF reference section 5.5.2# int curPos = 0; std::string sTmp = m_pMetrics->GetFontname(); const char* pszPrefix = m_pMetrics->GetSubsetFontnamePrefix(); if( pszPrefix ) { std::string sPrefix = pszPrefix; sTmp = sPrefix + sTmp; } for(unsigned int i = 0; i < sTmp.size(); i++) { if(sTmp[i] != ' ') sTmp[curPos++] = sTmp[i]; } sTmp.resize(curPos); m_BaseFont = PdfName( sTmp.c_str() ); } inline char ToHex( const char byte ) { static const char* s_pszHex = "0123456789ABCDEF"; return s_pszHex[byte % 16]; } void PdfFont::WriteStringToStream( const PdfString & rsString, PdfStream* pStream ) { if( !m_pEncoding ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } PdfRefCountedBuffer buffer = m_pEncoding->ConvertToEncoding( rsString, this ); pdf_long lLen = 0; char* pBuffer = NULL; std::auto_ptr pFilter = PdfFilterFactory::Create( ePdfFilter_ASCIIHexDecode ); pFilter->Encode( buffer.GetBuffer(), buffer.GetSize(), &pBuffer, &lLen ); pStream->Append( "<", 1 ); pStream->Append( pBuffer, lLen ); pStream->Append( ">", 1 ); podofo_free( pBuffer ); } // Peter Petrov 5 January 2009 void PdfFont::EmbedFont() { if (!m_bWasEmbedded) { // Now we embed the font // Now we set the flag m_bWasEmbedded = true; } } void PdfFont::EmbedSubsetFont() { //virtual function is only implemented in derived class PODOFO_RAISE_ERROR_INFO( ePdfError_NotImplemented, "Subsetting not implemented for this font type." ); } void PdfFont::AddUsedSubsettingGlyphs( const PdfString & , long ) { //virtual function is only implemented in derived class PODOFO_RAISE_ERROR_INFO( ePdfError_NotImplemented, "Subsetting not implemented for this font type." ); } void PdfFont::AddUsedGlyphname( const char * ) { //virtual function is only implemented in derived class PODOFO_RAISE_ERROR_INFO( ePdfError_NotImplemented, "Subsetting not implemented for this font type." ); } void PdfFont::SetBold( bool bBold ) { m_bBold = bBold; } void PdfFont::SetItalic( bool bItalic ) { m_bItalic = bItalic; } }; podofo-0.9.5/src/doc/PdfElement.h0000664000175000017500000001741312344436402016423 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_ELEMENT_H_ #define _PDF_ELEMENT_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfObject.h" namespace PoDoFo { class PdfStreamedDocument; class PdfVecObjects; /** PdfElement is a common base class for all elements * in a PDF file. For example pages, action and annotations. * * Every PDF element has one PdfObject and provides an easier * interface to modify the contents of the dictionary. * * A PdfElement base class can be created from an existing PdfObject * or created from scratch. In the later case, the PdfElement creates * a PdfObject and adds it to a vector of objects. * * A PdfElement cannot be created directly. Use one * of the subclasses which implement real functionallity. * * \see PdfPage \see PdfAction \see PdfAnnotation */ class PODOFO_DOC_API PdfElement { public: virtual ~PdfElement(); /** Get access to the internal object * \returns the internal PdfObject */ inline PdfObject* GetObject(); /** Get access to the internal object * This is an overloaded member function. * * \returns the internal PdfObject */ inline const PdfObject* GetObject() const; protected: /** Creates a new PdfElement * \param pszType type entry of the elements object * \param pParent parent vector of objects. * Add a newly created object to this vector. */ PdfElement( const char* pszType, PdfVecObjects* pParent ); /** Creates a new PdfElement * \param pszType type entry of the elements object * \param pParent parent PdfDocument. * Add a newly created object to this vector. */ PdfElement( const char* pszType, PdfDocument* pParent ); /** Create a PdfElement from an existing PdfObject * The object must be a dictionary. * * \param pszType type entry of the elements object. * Throws an exception if the type in the * PdfObject differs from pszType. * \param pObject pointer to the PdfObject that is modified * by this PdfElement */ PdfElement( const char* pszType, PdfObject* pObject ); /** Create a PdfElement from an existing PdfObject * The object might be of any data type, * PdfElement will throw an exception if the PdfObject * if not of the same datatype as the expected one. * This is necessary in rare cases. E.g. in PdfContents. * * \param eExpectedDataType the expected datatype of this object * \param pObject pointer to the PdfObject that is modified * by this PdfElement */ PdfElement( EPdfDataType eExpectedDataType, PdfObject* pObject ); /** Convert an enum or index to its string representation * which can be written to the PDF file. * * This is a helper function for various PdfElement * subclasses that need strings and enums for their * SubTypes keys. * * \param i the index or enum value * \param ppTypes an array of strings containing * the string mapping of the index * \param lLen the length of the string array * * \returns the string representation or NULL for * values out of range */ const char* TypeNameForIndex( int i, const char** ppTypes, long lLen ) const; /** Convert a string type to an array index or enum. * * This is a helper function for various PdfElement * subclasses that need strings and enums for their * SubTypes keys. * * \param pszType the type as string * \param ppTypes an array of strings containing * the string mapping of the index * \param lLen the length of the string array * \param nUnknownValue the value that is returned when the type is unknown * * \returns the index of the string in the array */ int TypeNameToIndex( const char* pszType, const char** ppTypes, long lLen, int nUnknownValue ) const; /** Create a PdfObject in the parent of this PdfElement which * might either be a PdfStreamedDocument, a PdfDocument or * a PdfVecObjects * * Use this function in an own subclass of PdfElement to create new * PdfObjects. * * \param pszType an optional /Type key of the created object * * \returns a PdfObject which is owned by the parent */ PdfObject* CreateObject( const char* pszType = NULL ); /** Get access to the internal object. * Use this method if you need access to the internal * object in a const-method without having to do a const cast. * * \returns the internal PdfObject */ inline PdfObject* GetNonConstObject() const; private: PdfObject* m_pObject; }; // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfObject* PdfElement::GetObject() { return m_pObject; } // ----------------------------------------------------- // // ----------------------------------------------------- inline const PdfObject* PdfElement::GetObject() const { return m_pObject; } // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfObject* PdfElement::GetNonConstObject() const { return const_cast(this)->m_pObject; } }; #endif // PDF_ELEMENT_H_ podofo-0.9.5/src/doc/PdfEncodingObjectFactory.h0000664000175000017500000000661712344436554021253 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_ENCODING_OBJECT_FACTORY_H_ #define _PDF_ENCODING_OBJECT_FACTORY_H_ #include "podofo/base/PdfDefines.h" namespace PoDoFo { class PdfEncoding; class PdfObject; /** This factory creates a PdfEncoding * from an existing object in the PDF. */ class PODOFO_DOC_API PdfEncodingObjectFactory { public: /** Create a new PdfEncoding from either an * encoding name or an encoding dictionary. * * \param pObject must be a name or an encoding dictionary * \param pToUnicode the optional ToUnicode dictionary * \param bExplicitNames if true, glyph names are meaningless explicit keys on the font (used for Type3 fonts) * * \returns a PdfEncoding or NULL */ static const PdfEncoding* CreateEncoding( PdfObject* pObject, PdfObject *pToUnicode = NULL, bool bExplicitNames = false ); private: /** * Hidden default constructor */ PdfEncodingObjectFactory(); }; }; /* namespace PoDoFo */ #endif // _PDF_ENCODING_OBJECT_FACTORY_H_ podofo-0.9.5/src/doc/PdfImage.cpp0000664000175000017500000011216013013650710016374 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfImage.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfColor.h" #include "base/PdfStream.h" #include "base/PdfFiltersPrivate.h" #include #include #include // TIFF and JPEG headers already included through "base/PdfFiltersPrivate.h", // although in opposite order (first JPEG, then TIFF), if available of course #ifdef PODOFO_HAVE_PNG_LIB #include #endif /// PODOFO_HAVE_PNG_LIB // defines an annoying GetObject macro that changes uses of GetObject to // GetObjectA . Since macros aren't scope and namespace aware that breaks our code. // Since we won't be using the Win32 resource manager API here, just undefine it. #if defined(GetObject) #undef GetObject #endif using namespace std; namespace PoDoFo { PdfImage::PdfImage( PdfVecObjects* pParent, const char* pszPrefix ) : PdfXObject( "Image", pParent, pszPrefix ) { m_rRect = PdfRect(); this->SetImageColorSpace( ePdfColorSpace_DeviceRGB ); } PdfImage::PdfImage( PdfDocument* pParent, const char* pszPrefix ) : PdfXObject( "Image", pParent, pszPrefix ) { m_rRect = PdfRect(); this->SetImageColorSpace( ePdfColorSpace_DeviceRGB ); } PdfImage::PdfImage( PdfObject* pObject ) : PdfXObject( "Image", pObject ) { m_rRect.SetHeight( static_cast(this->GetObject()->GetDictionary().GetKey( "Height" )->GetNumber()) ); m_rRect.SetWidth ( static_cast(this->GetObject()->GetDictionary().GetKey( "Width" )->GetNumber()) ); } PdfImage::~PdfImage() { } /* Example: { "JPEG", "TIFF", NULL } * * \returns a zero terminates list of all supported image formats */ const char** PdfImage::GetSupportedFormats() { static const char* ppszFormats[] = { #ifdef PODOFO_HAVE_JPEG_LIB "JPEG", #endif // PODOFO_HAVE_JPEG_LIB #ifdef PODOFO_HAVE_PNG_LIB "PNG", #endif // PODOFO_HAVE_PNG_LIB #ifdef PODOFO_HAVE_TIFF_LIB "TIFF", #endif // PODOFO_HAVE_TIFF_LIB NULL }; return ppszFormats; } void PdfImage::SetImageColorSpace( EPdfColorSpace eColorSpace, const PdfArray *indexedData ) { if (eColorSpace == ePdfColorSpace_Indexed) { PODOFO_RAISE_LOGIC_IF( !indexedData, "PdfImage::SetImageColorSpace: indexedData cannot be NULL for Indexed color space." ); PdfArray array(*indexedData); array.insert(array.begin(), ColorspaceToName( eColorSpace )); this->GetObject()->GetDictionary().AddKey( PdfName("ColorSpace"), array ); } else { this->GetObject()->GetDictionary().AddKey( PdfName("ColorSpace"), ColorspaceToName( eColorSpace ) ); } } void PdfImage::SetImageICCProfile( PdfInputStream* pStream, long lColorComponents, EPdfColorSpace eAlternateColorSpace ) { // Check lColorComponents for a valid value if( lColorComponents != 1 && lColorComponents != 3 && lColorComponents != 4 ) { PODOFO_RAISE_ERROR_INFO( ePdfError_ValueOutOfRange, "SetImageICCProfile lColorComponents must be 1,3 or 4!" ); } // Create a colorspace object PdfObject* pIccObject = this->GetObject()->GetOwner()->CreateObject(); pIccObject->GetDictionary().AddKey( PdfName("Alternate"), ColorspaceToName( eAlternateColorSpace ) ); pIccObject->GetDictionary().AddKey( PdfName("N"), static_cast(lColorComponents) ); pIccObject->GetStream()->Set( pStream ); // Add the colorspace to our image PdfArray array; array.push_back( PdfName("ICCBased") ); array.push_back( pIccObject->Reference() ); this->GetObject()->GetDictionary().AddKey( PdfName("ColorSpace"), array ); } void PdfImage::SetImageSoftmask( const PdfImage* pSoftmask ) { GetObject()->GetDictionary().AddKey( "SMask", pSoftmask->GetObject()->Reference() ); } void PdfImage::SetImageData( unsigned int nWidth, unsigned int nHeight, unsigned int nBitsPerComponent, PdfInputStream* pStream ) { TVecFilters vecFlate; vecFlate.push_back( ePdfFilter_FlateDecode ); this->SetImageData( nWidth, nHeight, nBitsPerComponent, pStream, vecFlate ); } void PdfImage::SetImageData( unsigned int nWidth, unsigned int nHeight, unsigned int nBitsPerComponent, PdfInputStream* pStream, const TVecFilters & vecFilters ) { m_rRect.SetWidth( nWidth ); m_rRect.SetHeight( nHeight ); this->GetObject()->GetDictionary().AddKey( "Width", PdfVariant( static_cast(nWidth) ) ); this->GetObject()->GetDictionary().AddKey( "Height", PdfVariant( static_cast(nHeight) ) ); this->GetObject()->GetDictionary().AddKey( "BitsPerComponent", PdfVariant( static_cast(nBitsPerComponent) ) ); PdfVariant var; m_rRect.ToVariant( var ); this->GetObject()->GetDictionary().AddKey( "BBox", var ); this->GetObject()->GetStream()->Set( pStream, vecFilters ); } void PdfImage::SetImageDataRaw( unsigned int nWidth, unsigned int nHeight, unsigned int nBitsPerComponent, PdfInputStream* pStream ) { m_rRect.SetWidth( nWidth ); m_rRect.SetHeight( nHeight ); this->GetObject()->GetDictionary().AddKey( "Width", PdfVariant( static_cast(nWidth) ) ); this->GetObject()->GetDictionary().AddKey( "Height", PdfVariant( static_cast(nHeight) ) ); this->GetObject()->GetDictionary().AddKey( "BitsPerComponent", PdfVariant( static_cast(nBitsPerComponent) ) ); PdfVariant var; m_rRect.ToVariant( var ); this->GetObject()->GetDictionary().AddKey( "BBox", var ); this->GetObject()->GetStream()->SetRawData( pStream, -1 ); } void PdfImage::LoadFromFile( const char* pszFilename ) { if( pszFilename && strlen( pszFilename ) > 3 ) { const char* pszExtension = pszFilename + strlen( pszFilename ) - 3; #ifdef PODOFO_HAVE_TIFF_LIB if( PoDoFo::compat::strncasecmp( pszExtension, "tif", 3 ) == 0 || PoDoFo::compat::strncasecmp( pszExtension, "iff", 3 ) == 0 ) // "tiff" { LoadFromTiff( pszFilename ); return; } #endif #ifdef PODOFO_HAVE_JPEG_LIB if( PoDoFo::compat::strncasecmp( pszExtension, "jpg", 3 ) == 0 ) { LoadFromJpeg( pszFilename ); return; } #endif #ifdef PODOFO_HAVE_PNG_LIB if( PoDoFo::compat::strncasecmp( pszExtension, "png", 3 ) == 0 ) { LoadFromPng( pszFilename ); return; } #endif } PODOFO_RAISE_ERROR_INFO( ePdfError_UnsupportedImageFormat, pszFilename ); } #ifdef _WIN32 void PdfImage::LoadFromFile( const wchar_t* pszFilename ) { if( pszFilename && wcslen( pszFilename ) > 3 ) { const wchar_t* pszExtension = pszFilename + wcslen( pszFilename ) - 3; #ifdef PODOFO_HAVE_TIFF_LIB #if TIFFLIB_VERSION >= 20120922 // TiffOpenW needs at least version 4.0.3 if( _wcsnicmp( pszExtension, L"tif", 3 ) == 0 || _wcsnicmp( pszExtension, L"iff", 3 ) == 0 ) // "tiff" { LoadFromTiff( pszFilename ); return; } #endif #endif #ifdef PODOFO_HAVE_JPEG_LIB if( _wcsnicmp( pszExtension, L"jpg", 3 ) == 0 ) { LoadFromJpeg( pszFilename ); return; } #endif #ifdef PODOFO_HAVE_PNG_LIB if( _wcsnicmp( pszExtension, L"png", 3 ) == 0 ) { LoadFromPng( pszFilename ); return; } #endif } PdfError e( ePdfError_UnsupportedImageFormat, __FILE__, __LINE__ ); e.SetErrorInformation( pszFilename ); throw e; } #endif // _WIN32 void PdfImage::LoadFromData(const unsigned char* pData, pdf_long dwLen) { if (dwLen > 4) { unsigned char magic[4]; memcpy(magic, pData, 4); #ifdef PODOFO_HAVE_TIFF_LIB if((magic[0] == 0x4d && magic[1] == 0x4d && magic[2] == 0x00 && magic[3] == 0x2a) || (magic[0] == 0x49 && magic[1] == 0x49 && magic[2] == 0x2a && magic[3] == 0x00)) { LoadFromTiffData(pData, dwLen); return; } #endif #ifdef PODOFO_HAVE_JPEG_LIB if( magic[0] == 0xff && magic[1] == 0xd8 ) { LoadFromJpegData(pData, dwLen); return; } #endif #ifdef PODOFO_HAVE_PNG_LIB if( magic[0] == 0x89 && magic[1] == 0x50 && magic[2] == 0x4e && magic[3] == 0x47 ) { LoadFromPngData(pData, dwLen); return; } #endif } PODOFO_RAISE_ERROR_INFO( ePdfError_UnsupportedImageFormat, "Unknown magic number" ); } #ifdef PODOFO_HAVE_JPEG_LIB void PdfImage::LoadFromJpeg( const char* pszFilename ) { /* Constructor will throw exception */ PdfFileInputStream stream( pszFilename ); LoadFromJpegHandle( &stream ); } #ifdef _WIN32 void PdfImage::LoadFromJpeg( const wchar_t* pszFilename ) { PdfFileInputStream stream( pszFilename ); LoadFromJpegHandle( &stream ); } #endif // _WIN32 void PdfImage::LoadFromJpegHandle( PdfFileInputStream* pInStream ) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = &JPegErrorExit; jerr.emit_message = &JPegErrorOutput; jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, pInStream->GetHandle()); if( jpeg_read_header(&cinfo, TRUE) <= 0 ) { (void) jpeg_destroy_decompress(&cinfo); PODOFO_RAISE_ERROR( ePdfError_UnexpectedEOF ); } jpeg_start_decompress(&cinfo); m_rRect.SetWidth( cinfo.output_width ); m_rRect.SetHeight( cinfo.output_height ); // I am not sure wether this switch is fully correct. // it should handle all cases though. // Index jpeg files might look strange as jpeglib+ // returns 1 for them. switch( cinfo.output_components ) { case 3: this->SetImageColorSpace( ePdfColorSpace_DeviceRGB ); break; case 4: { this->SetImageColorSpace( ePdfColorSpace_DeviceCMYK ); // The jpeg-doc ist not specific in this point, but cmyk's seem to be stored // in a inverted fashion. Fix by attaching a decode array PdfArray decode; decode.push_back( 1.0 ); decode.push_back( 0.0 ); decode.push_back( 1.0 ); decode.push_back( 0.0 ); decode.push_back( 1.0 ); decode.push_back( 0.0 ); decode.push_back( 1.0 ); decode.push_back( 0.0 ); this->GetObject()->GetDictionary().AddKey( PdfName("Decode"), decode ); } break; default: this->SetImageColorSpace( ePdfColorSpace_DeviceGray ); break; } // Set the filters key to DCTDecode this->GetObject()->GetDictionary().AddKey( PdfName::KeyFilter, PdfName( "DCTDecode" ) ); // Do not apply any filters as JPEG data is already DCT encoded. fseeko( pInStream->GetHandle(), 0L, SEEK_SET ); this->SetImageDataRaw( cinfo.output_width, cinfo.output_height, 8, pInStream ); (void) jpeg_destroy_decompress(&cinfo); } void PdfImage::LoadFromJpegData(const unsigned char* pData, pdf_long dwLen) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = &JPegErrorExit; jerr.emit_message = &JPegErrorOutput; jpeg_create_decompress(&cinfo); jpeg_memory_src(&cinfo, pData, dwLen); if( jpeg_read_header(&cinfo, TRUE) <= 0 ) { (void) jpeg_destroy_decompress(&cinfo); PODOFO_RAISE_ERROR( ePdfError_UnexpectedEOF ); } jpeg_start_decompress(&cinfo); m_rRect.SetWidth( cinfo.output_width ); m_rRect.SetHeight( cinfo.output_height ); // I am not sure wether this switch is fully correct. // it should handle all cases though. // Index jpeg files might look strange as jpeglib+ // returns 1 for them. switch( cinfo.output_components ) { case 3: this->SetImageColorSpace( ePdfColorSpace_DeviceRGB ); break; case 4: { this->SetImageColorSpace( ePdfColorSpace_DeviceCMYK ); // The jpeg-doc ist not specific in this point, but cmyk's seem to be stored // in a inverted fashion. Fix by attaching a decode array PdfArray decode; decode.push_back( 1.0 ); decode.push_back( 0.0 ); decode.push_back( 1.0 ); decode.push_back( 0.0 ); decode.push_back( 1.0 ); decode.push_back( 0.0 ); decode.push_back( 1.0 ); decode.push_back( 0.0 ); this->GetObject()->GetDictionary().AddKey( PdfName("Decode"), decode ); } break; default: this->SetImageColorSpace( ePdfColorSpace_DeviceGray ); break; } // Set the filters key to DCTDecode this->GetObject()->GetDictionary().AddKey( PdfName::KeyFilter, PdfName( "DCTDecode" ) ); PdfMemoryInputStream fInpStream( (const char*)pData, (pdf_long) dwLen); this->SetImageDataRaw( cinfo.output_width, cinfo.output_height, 8, &fInpStream ); (void) jpeg_destroy_decompress(&cinfo); } #endif // PODOFO_HAVE_JPEG_LIB #ifdef PODOFO_HAVE_TIFF_LIB static void TIFFErrorWarningHandler(const char*, const char*, va_list) { } void PdfImage::LoadFromTiffHandle(void* hInHandle) { TIFF* hInTiffHandle = (TIFF*)hInHandle; int32 row, width, height; uint16 samplesPerPixel, bitsPerSample; uint16* sampleInfo; uint16 extraSamples; uint16 planarConfig, photoMetric, orientation; int32 resolutionUnit; TIFFGetField(hInTiffHandle, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(hInTiffHandle, TIFFTAG_IMAGELENGTH, &height); TIFFGetFieldDefaulted(hInTiffHandle, TIFFTAG_BITSPERSAMPLE, &bitsPerSample); TIFFGetFieldDefaulted(hInTiffHandle, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel); TIFFGetFieldDefaulted(hInTiffHandle, TIFFTAG_PLANARCONFIG, &planarConfig); TIFFGetFieldDefaulted(hInTiffHandle, TIFFTAG_PHOTOMETRIC, &photoMetric); TIFFGetFieldDefaulted(hInTiffHandle, TIFFTAG_EXTRASAMPLES, &extraSamples, &sampleInfo); TIFFGetFieldDefaulted(hInTiffHandle, TIFFTAG_ORIENTATION, &orientation); resolutionUnit = 0; float resX; float resY; TIFFGetFieldDefaulted(hInTiffHandle, TIFFTAG_XRESOLUTION, &resX); TIFFGetFieldDefaulted(hInTiffHandle, TIFFTAG_YRESOLUTION, &resY); TIFFGetFieldDefaulted(hInTiffHandle, TIFFTAG_RESOLUTIONUNIT, &resolutionUnit); int colorChannels = samplesPerPixel - extraSamples; int bitsPixel = bitsPerSample * samplesPerPixel; // TODO: implement special cases if( TIFFIsTiled(hInTiffHandle) ) { TIFFClose(hInTiffHandle); PODOFO_RAISE_ERROR( ePdfError_UnsupportedImageFormat ); } if ( planarConfig != PLANARCONFIG_CONTIG && colorChannels != 1 ) { TIFFClose(hInTiffHandle); PODOFO_RAISE_ERROR( ePdfError_UnsupportedImageFormat ); } if ( orientation != ORIENTATION_TOPLEFT ) { TIFFClose(hInTiffHandle); PODOFO_RAISE_ERROR( ePdfError_UnsupportedImageFormat ); } switch(photoMetric) { case PHOTOMETRIC_MINISBLACK: { if( bitsPixel == 1 ) { PdfArray decode; decode.insert( decode.end(), PdfVariant( static_cast(0) ) ); decode.insert( decode.end(), PdfVariant( static_cast(1) ) ); this->GetObject()->GetDictionary().AddKey( PdfName("Decode"), decode ); this->GetObject()->GetDictionary().AddKey( PdfName("ImageMask"), PdfVariant( true ) ); this->GetObject()->GetDictionary().RemoveKey( PdfName("ColorSpace") ); } else if ( bitsPixel == 8 || bitsPixel == 16) SetImageColorSpace(ePdfColorSpace_DeviceGray); else { TIFFClose(hInTiffHandle); PODOFO_RAISE_ERROR( ePdfError_UnsupportedImageFormat ); } } break; case PHOTOMETRIC_MINISWHITE: { if( bitsPixel == 1 ) { PdfArray decode; decode.insert( decode.end(), PdfVariant( static_cast(1) ) ); decode.insert( decode.end(), PdfVariant( static_cast(0) ) ); this->GetObject()->GetDictionary().AddKey( PdfName("Decode"), decode ); this->GetObject()->GetDictionary().AddKey( PdfName("ImageMask"), PdfVariant( true ) ); this->GetObject()->GetDictionary().RemoveKey( PdfName("ColorSpace") ); } else if ( bitsPixel == 8 || bitsPixel == 16) SetImageColorSpace(ePdfColorSpace_DeviceGray); else { TIFFClose(hInTiffHandle); PODOFO_RAISE_ERROR( ePdfError_UnsupportedImageFormat ); } } break; case PHOTOMETRIC_RGB: if ( bitsPixel != 24 ) { TIFFClose(hInTiffHandle); PODOFO_RAISE_ERROR( ePdfError_UnsupportedImageFormat ); } SetImageColorSpace(ePdfColorSpace_DeviceRGB); break; case PHOTOMETRIC_SEPARATED: if( bitsPixel != 32) { TIFFClose(hInTiffHandle); PODOFO_RAISE_ERROR( ePdfError_UnsupportedImageFormat ); } SetImageColorSpace(ePdfColorSpace_DeviceCMYK); break; case PHOTOMETRIC_PALETTE: { int numColors = (1 << bitsPixel); PdfArray decode; decode.insert( decode.end(), PdfVariant( static_cast(0) ) ); decode.insert( decode.end(), PdfVariant( static_cast(numColors-1) ) ); this->GetObject()->GetDictionary().AddKey( PdfName("Decode"), decode ); uint16 * rgbRed; uint16 * rgbGreen; uint16 * rgbBlue; TIFFGetField(hInTiffHandle, TIFFTAG_COLORMAP, &rgbRed, &rgbGreen, &rgbBlue); char *datap = new char[numColors*3]; for ( int clr = 0; clr < numColors; clr++ ) { datap[3*clr+0] = rgbRed[clr]/257; datap[3*clr+1] = rgbGreen[clr]/257; datap[3*clr+2] = rgbBlue[clr]/257; } PdfMemoryInputStream stream( datap, numColors*3 ); // Create a colorspace object PdfObject* pIdxObject = this->GetObject()->GetOwner()->CreateObject(); pIdxObject->GetStream()->Set( &stream ); // Add the colorspace to our image PdfArray array; array.push_back( PdfName("Indexed") ); array.push_back( PdfName("DeviceRGB") ); array.push_back( static_cast(numColors-1) ); array.push_back( pIdxObject->Reference() ); this->GetObject()->GetDictionary().AddKey( PdfName("ColorSpace"), array ); delete[] datap; } break; default: TIFFClose(hInTiffHandle); PODOFO_RAISE_ERROR( ePdfError_UnsupportedImageFormat ); break; } int32 scanlineSize = TIFFScanlineSize(hInTiffHandle); long bufferSize = scanlineSize * height; char *buffer = new char[bufferSize]; if( !buffer ) { TIFFClose(hInTiffHandle); PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } for(row = 0; row < height; row++) { if(TIFFReadScanline(hInTiffHandle, &buffer[row * scanlineSize], row) == (-1)) { TIFFClose(hInTiffHandle); PODOFO_RAISE_ERROR( ePdfError_UnsupportedImageFormat ); } } PdfMemoryInputStream stream(buffer, bufferSize); SetImageData(static_cast(width), static_cast(height), static_cast(bitsPerSample), &stream); delete[] buffer; TIFFClose(hInTiffHandle); } void PdfImage::LoadFromTiff( const char* pszFilename ) { TIFFSetErrorHandler(TIFFErrorWarningHandler); TIFFSetWarningHandler(TIFFErrorWarningHandler); if( !pszFilename ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } TIFF* hInfile = TIFFOpen(pszFilename, "rb"); if( !hInfile ) { PODOFO_RAISE_ERROR_INFO( ePdfError_FileNotFound, pszFilename ); } LoadFromTiffHandle(hInfile); } #ifdef _WIN32 void PdfImage::LoadFromTiff( const wchar_t* pszFilename ) { #if TIFFLIB_VERSION >= 20120922 // TiffOpenW needs at least version 4.0.3 TIFFSetErrorHandler(TIFFErrorWarningHandler); TIFFSetWarningHandler(TIFFErrorWarningHandler); if( !pszFilename ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } TIFF* hInfile = TIFFOpenW(pszFilename, "rb"); if( !hInfile ) { PdfError e( ePdfError_FileNotFound, __FILE__, __LINE__ ); e.SetErrorInformation( pszFilename ); throw e; } LoadFromTiffHandle(hInfile); #else PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); #endif // TIFFLIB_VERSION } #endif // _WIN32 struct tiffData { tiffData(const unsigned char* data, tsize_t size):_data(data), _pos(0), _size(size) {} tsize_t read(tdata_t data, tsize_t length) { tsize_t bytesRead = 0; if (length > _size - static_cast(_pos)) { memcpy(data, &_data[_pos], _size - _pos); bytesRead = _size - _pos; _pos = _size; } else { memcpy(data, &_data[_pos], length); bytesRead = length; _pos += length; } return bytesRead; } toff_t size() { return _size; } toff_t seek(toff_t pos, int whence) { if (pos == 0xFFFFFFFF) { return 0xFFFFFFFF; } switch(whence) { case SEEK_SET: if (static_cast(pos) > _size) { _pos = _size; } else { _pos = pos; } break; case SEEK_CUR: if (static_cast(pos + _pos) > _size) { _pos = _size; } else { _pos += pos; } break; case SEEK_END: if (static_cast(pos) > _size) { _pos = 0; } else { _pos = _size - pos; } break; } return _pos; } private: const unsigned char* _data; toff_t _pos; tsize_t _size; }; tsize_t tiff_Read(thandle_t st, tdata_t buffer, tsize_t size) { tiffData* data = (tiffData*)st; return data->read(buffer, size); }; tsize_t tiff_Write(thandle_t /*st*/, tdata_t /*buffer*/, tsize_t /*size*/) { return 0; }; int tiff_Close(thandle_t) { return 0; }; toff_t tiff_Seek(thandle_t st, toff_t pos, int whence) { tiffData* data = (tiffData*)st; return data->seek(pos, whence); }; toff_t tiff_Size(thandle_t st) { tiffData* data = (tiffData*)st; return data->size(); }; int tiff_Map(thandle_t, tdata_t*, toff_t*) { return 0; }; void tiff_Unmap(thandle_t, tdata_t, toff_t) { return; }; void PdfImage::LoadFromTiffData(const unsigned char* pData, pdf_long dwLen) { TIFFSetErrorHandler(TIFFErrorWarningHandler); TIFFSetWarningHandler(TIFFErrorWarningHandler); if( !pData ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } tiffData data(pData, dwLen); TIFF* hInHandle = TIFFClientOpen("Memory", "r", (thandle_t)&data, tiff_Read, tiff_Write, tiff_Seek, tiff_Close, tiff_Size, tiff_Map, tiff_Unmap); if( !hInHandle ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } LoadFromTiffHandle(hInHandle); } #endif // PODOFO_HAVE_TIFF_LIB #ifdef PODOFO_HAVE_PNG_LIB void PdfImage::LoadFromPng( const char* pszFilename ) { PdfFileInputStream stream( pszFilename ); LoadFromPngHandle( &stream ); } #ifdef _WIN32 void PdfImage::LoadFromPng( const wchar_t* pszFilename ) { PdfFileInputStream stream( pszFilename ); LoadFromPngHandle( &stream ); } #endif // _WIN32 void PdfImage::LoadFromPngHandle( PdfFileInputStream* pInStream ) { FILE* hFile = pInStream->GetHandle(); png_byte header[8]; if( fread( header, 1, 8, hFile ) != 8 || png_sig_cmp( header, 0, 8 ) ) { PODOFO_RAISE_ERROR_INFO( ePdfError_UnsupportedImageFormat, "The file could not be recognized as a PNG file." ); } png_structp pPng = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if( !pPng ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } png_infop pInfo = png_create_info_struct(pPng); if( !pInfo ) { png_destroy_read_struct(&pPng, (png_infopp)NULL, (png_infopp)NULL); PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if( setjmp(png_jmpbuf(pPng)) ) { png_destroy_read_struct(&pPng, &pInfo, (png_infopp)NULL); PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } png_init_io(pPng, hFile); png_set_sig_bytes(pPng, 8); png_read_info(pPng, pInfo); // Begin png_uint_32 width; png_uint_32 height; int depth; int color_type; int interlace; png_get_IHDR (pPng, pInfo, &width, &height, &depth, &color_type, &interlace, NULL, NULL); /* convert palette/gray image to rgb */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(pPng); if (color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(pPng); #if 0 /* expand gray bit depth if needed */ if (color_type == PNG_COLOR_TYPE_GRAY) { #if PNG_LIBPNG_VER >= 10209 png_set_expand_gray_1_2_4_to_8 (pPng); #else png_set_gray_1_2_4_to_8 (pPng); #endif } #endif /* transform transparency to alpha */ if (png_get_valid (pPng, pInfo, PNG_INFO_tRNS)) png_set_tRNS_to_alpha (pPng); if (depth == 16) png_set_strip_16(pPng); if (depth < 8) png_set_packing(pPng); #if 0 /* convert grayscale to RGB */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb (pPng); } #endif if (interlace != PNG_INTERLACE_NONE) png_set_interlace_handling(pPng); //png_set_filler (pPng, 0xff, PNG_FILLER_AFTER); /* recheck header after setting EXPAND options */ png_read_update_info(pPng, pInfo); png_get_IHDR (pPng, pInfo, &width, &height, &depth, &color_type, &interlace, NULL, NULL); // End // // Read the file if( setjmp(png_jmpbuf(pPng)) ) { png_destroy_read_struct(&pPng, &pInfo, (png_infopp)NULL); PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } long lLen = static_cast(png_get_rowbytes(pPng, pInfo) * height); char* pBuffer = static_cast(podofo_calloc(lLen, sizeof(char))); if (!pBuffer) { PODOFO_RAISE_ERROR(ePdfError_OutOfMemory); } png_bytepp pRows = static_cast(podofo_calloc(height, sizeof(png_bytep))); if (!pRows) { PODOFO_RAISE_ERROR(ePdfError_OutOfMemory); } for(unsigned int y=0; y(pBuffer + (y * png_get_rowbytes(pPng, pInfo))); } png_read_image(pPng, pRows); m_rRect.SetWidth( width ); m_rRect.SetHeight( height ); switch( png_get_channels( pPng, pInfo ) ) { case 3: this->SetImageColorSpace( ePdfColorSpace_DeviceRGB ); break; case 4: { this->SetImageColorSpace( ePdfColorSpace_DeviceCMYK ); // The jpeg-doc ist not specific in this point, but cmyk's seem to be stored // in a inverted fashion. Fix by attaching a decode array PdfArray decode; decode.push_back( 1.0 ); decode.push_back( 0.0 ); decode.push_back( 1.0 ); decode.push_back( 0.0 ); decode.push_back( 1.0 ); decode.push_back( 0.0 ); decode.push_back( 1.0 ); decode.push_back( 0.0 ); this->GetObject()->GetDictionary().AddKey( PdfName("Decode"), decode ); } break; default: this->SetImageColorSpace( ePdfColorSpace_DeviceGray ); break; } // Set the image data and flate compress it PdfMemoryInputStream stream( pBuffer, lLen ); this->SetImageData( width, height, depth, &stream ); podofo_free(pBuffer); podofo_free(pRows); png_destroy_read_struct(&pPng, &pInfo, (png_infopp)NULL); } struct pngData { pngData(const unsigned char* data, png_size_t size):_data(data), _pos(0), _size(size) {} void read(png_bytep data, png_size_t length) { if (length > _size - _pos) { memcpy(data, &_data[_pos], _size - _pos); _pos = _size; } else { memcpy(data, &_data[_pos], length); _pos += length; } } private: const unsigned char* _data; png_size_t _pos; png_size_t _size; }; void pngReadData(png_structp pngPtr, png_bytep data, png_size_t length) { pngData* a = (pngData*)png_get_io_ptr(pngPtr); a->read(data, length); } void PdfImage::LoadFromPngData(const unsigned char* pData, pdf_long dwLen) { if( !pData ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } pngData data(pData, dwLen); png_byte header[8]; data.read(header, 8); if( png_sig_cmp(header, 0, 8) ) { PODOFO_RAISE_ERROR_INFO( ePdfError_UnsupportedImageFormat, "The file could not be recognized as a PNG file." ); } png_structp pPng = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if( !pPng ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } png_infop pInfo = png_create_info_struct(pPng); if( !pInfo ) { png_destroy_read_struct(&pPng, (png_infopp)NULL, (png_infopp)NULL); PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if( setjmp(png_jmpbuf(pPng)) ) { png_destroy_read_struct(&pPng, &pInfo, (png_infopp)NULL); PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } png_set_read_fn(pPng, (png_voidp)&data, pngReadData); png_set_sig_bytes(pPng, 8); png_read_info(pPng, pInfo); // Begin png_uint_32 width; png_uint_32 height; int depth; int color_type; int interlace; png_get_IHDR (pPng, pInfo, &width, &height, &depth, &color_type, &interlace, NULL, NULL); /* convert palette/gray image to rgb */ if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(pPng); if (color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(pPng); #if 0 /* expand gray bit depth if needed */ if (color_type == PNG_COLOR_TYPE_GRAY) { #if PNG_LIBPNG_VER >= 10209 png_set_expand_gray_1_2_4_to_8 (pPng); #else png_set_gray_1_2_4_to_8 (pPng); #endif } #endif /* transform transparency to alpha */ if (png_get_valid (pPng, pInfo, PNG_INFO_tRNS)) png_set_tRNS_to_alpha (pPng); if (depth == 16) png_set_strip_16(pPng); if (depth < 8) png_set_packing(pPng); #if 0 /* convert grayscale to RGB */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { png_set_gray_to_rgb (pPng); } #endif if (interlace != PNG_INTERLACE_NONE) png_set_interlace_handling(pPng); //png_set_filler (pPng, 0xff, PNG_FILLER_AFTER); /* recheck header after setting EXPAND options */ png_read_update_info(pPng, pInfo); png_get_IHDR (pPng, pInfo, &width, &height, &depth, &color_type, &interlace, NULL, NULL); // End // // Read the file if( setjmp(png_jmpbuf(pPng)) ) { png_destroy_read_struct(&pPng, &pInfo, (png_infopp)NULL); PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } long lLen = static_cast(png_get_rowbytes(pPng, pInfo) * height); char* pBuffer = static_cast(podofo_calloc(lLen, sizeof(char))); if (!pBuffer) { PODOFO_RAISE_ERROR(ePdfError_OutOfMemory); } png_bytepp pRows = static_cast(podofo_calloc(height, sizeof(png_bytep))); if (!pRows) { PODOFO_RAISE_ERROR(ePdfError_OutOfMemory); } for(unsigned int y=0; y(pBuffer + (y * png_get_rowbytes(pPng, pInfo))); } png_read_image(pPng, pRows); m_rRect.SetWidth( width ); m_rRect.SetHeight( height ); switch( png_get_channels( pPng, pInfo ) ) { case 3: this->SetImageColorSpace( ePdfColorSpace_DeviceRGB ); break; case 4: { this->SetImageColorSpace( ePdfColorSpace_DeviceCMYK ); // The jpeg-doc ist not specific in this point, but cmyk's seem to be stored // in a inverted fashion. Fix by attaching a decode array PdfArray decode; decode.push_back( 1.0 ); decode.push_back( 0.0 ); decode.push_back( 1.0 ); decode.push_back( 0.0 ); decode.push_back( 1.0 ); decode.push_back( 0.0 ); decode.push_back( 1.0 ); decode.push_back( 0.0 ); this->GetObject()->GetDictionary().AddKey( PdfName("Decode"), decode ); } break; default: this->SetImageColorSpace( ePdfColorSpace_DeviceGray ); break; } // Set the image data and flate compress it PdfMemoryInputStream stream( pBuffer, lLen ); this->SetImageData( width, height, depth, &stream ); podofo_free(pBuffer); podofo_free(pRows); png_destroy_read_struct(&pPng, &pInfo, (png_infopp)NULL); } #endif // PODOFO_HAVE_PNG_LIB PdfName PdfImage::ColorspaceToName( EPdfColorSpace eColorSpace ) { return PdfColor::GetNameForColorSpace( eColorSpace ).GetName(); } void PdfImage::SetImageChromaKeyMask(pdf_int64 r, pdf_int64 g, pdf_int64 b, pdf_int64 threshold) { PdfArray array; array.push_back(r - threshold); array.push_back(r + threshold); array.push_back(g - threshold); array.push_back(g + threshold); array.push_back(b - threshold); array.push_back(b + threshold); this->GetObject()->GetDictionary().AddKey( "Mask", array); } void PdfImage::SetInterpolate(bool bValue) { this->GetObject()->GetDictionary().AddKey( "Interpolate", PdfVariant(bValue)); } }; podofo-0.9.5/src/doc/PdfSignatureField.cpp0000664000175000017500000002301413032764463020272 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2011 by Dominik Seichter * * domseichter@web.de * * by Petr Pytelka * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfSignatureField.h" #include "../base/PdfDictionary.h" #include "../base/PdfData.h" #include "PdfXObject.h" #include namespace PoDoFo { PdfSignatureField::PdfSignatureField( PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc ) :PdfField(PoDoFo::ePdfField_Signature, pPage, rRect, pDoc) { m_pSignatureObj = NULL; Init(); } PdfSignatureField::PdfSignatureField( PdfAnnotation* pWidget, PdfAcroForm* pParent, PdfDocument* pDoc, bool bInit ) :PdfField(PoDoFo::ePdfField_Signature, pWidget, pParent, pDoc) { m_pSignatureObj = NULL; if( bInit ) Init(); } PdfSignatureField::PdfSignatureField( PdfAnnotation* pWidget ) :PdfField( pWidget->GetObject(), pWidget ) { m_pSignatureObj = NULL; // do not call Init() here if( this->GetFieldObject()->GetDictionary().HasKey( "V" ) ) { m_pSignatureObj = this->GetFieldObject()->GetOwner()->GetObject( this->GetFieldObject()->GetDictionary().GetKey( "V" )->GetReference() ); } } void PdfSignatureField::SetAppearanceStream( PdfXObject* pObject, EPdfAnnotationAppearance eAppearance, const PdfName & state ) { if( !pObject ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } SetAppearanceStreamForObject( m_pObject, pObject, eAppearance, state ); this->GetAppearanceCharacteristics( true ); } void PdfSignatureField::Init() { m_pSignatureObj = NULL; EnsureSignatureObject (); } void PdfSignatureField::SetSignatureReason(const PdfString & rsText) { if( !m_pSignatureObj ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if(m_pSignatureObj->GetDictionary().HasKey(PdfName("Reason"))) { m_pSignatureObj->GetDictionary().RemoveKey(PdfName("Reason")); } m_pSignatureObj->GetDictionary().AddKey(PdfName("Reason"), rsText); } void PdfSignatureField::SetSignatureDate(const PdfDate &sigDate) { if( !m_pSignatureObj ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if(m_pSignatureObj->GetDictionary().HasKey(PdfName("M"))) { m_pSignatureObj->GetDictionary().RemoveKey(PdfName("M")); } PdfString sDate; sigDate.ToString(sDate); m_pSignatureObj->GetDictionary().AddKey(PdfName("M"), sDate); } void PdfSignatureField::SetSignature(const PdfData &sSignatureData) { // Prepare source data size_t lSigLen = sSignatureData.data().size(); char* pData = static_cast(podofo_malloc( lSigLen + 2 )); if (!pData) { PODOFO_RAISE_ERROR(ePdfError_OutOfMemory); } pData[0] = '<'; pData[lSigLen + 1] = '>'; memcpy(pData + 1, sSignatureData.data().c_str(), lSigLen); PdfData signatureData(pData, lSigLen + 2); podofo_free(pData); // Content of the signature if( !m_pSignatureObj ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } // Remove old data if(m_pSignatureObj->GetDictionary().HasKey("ByteRange")) { m_pSignatureObj->GetDictionary().RemoveKey("ByteRange"); } if(m_pSignatureObj->GetDictionary().HasKey(PdfName::KeyContents)) { m_pSignatureObj->GetDictionary().RemoveKey(PdfName::KeyContents); } // Byte range PdfData rangeData("[ 0 1234567890 1234567890 1234567890]"); m_pSignatureObj->GetDictionary().AddKey("ByteRange", PdfVariant(rangeData) ); m_pSignatureObj->GetDictionary().AddKey(PdfName::KeyContents, PdfVariant(signatureData) ); } void PdfSignatureField::SetSignatureLocation( const PdfString & rsText ) { if( !m_pSignatureObj ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if(m_pSignatureObj->GetDictionary().HasKey(PdfName("Location"))) { m_pSignatureObj->GetDictionary().RemoveKey(PdfName("Location")); } m_pSignatureObj->GetDictionary().AddKey(PdfName("Location"), rsText); } void PdfSignatureField::SetSignatureCreator( const PdfName & creator ) { if( !m_pSignatureObj ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if( m_pSignatureObj->GetDictionary().HasKey( PdfName( "Prop_Build" ) ) ) { PdfObject* propBuild = m_pSignatureObj->GetDictionary().GetKey( PdfName( "Prop_Build" ) ); if( propBuild->GetDictionary().HasKey( PdfName( "App" ) ) ) { PdfObject* app = propBuild->GetDictionary().GetKey( PdfName( "App" ) ); if( app->GetDictionary().HasKey( PdfName( "Name" ) ) ) { app->GetDictionary().RemoveKey( PdfName( "Name" ) ); } propBuild->GetDictionary().RemoveKey( PdfName("App") ); } m_pSignatureObj->GetDictionary().RemoveKey(PdfName("Prop_Build")); } m_pSignatureObj->GetDictionary().AddKey( PdfName( "Prop_Build" ), PdfDictionary() ); PdfObject* propBuild = m_pSignatureObj->GetDictionary().GetKey( PdfName( "Prop_Build" ) ); propBuild->GetDictionary().AddKey( PdfName( "App" ), PdfDictionary() ); PdfObject* app = propBuild->GetDictionary().GetKey( PdfName( "App" ) ); app->GetDictionary().AddKey( PdfName( "Name" ), creator ); } void PdfSignatureField::AddCertificationReference( PdfObject* pDocumentCatalog, EPdfCertPermission perm ) { if( !m_pSignatureObj ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if (m_pSignatureObj->GetDictionary().HasKey(PdfName("Reference"))) { m_pSignatureObj->GetDictionary().RemoveKey(PdfName("Reference")); } PdfObject *pSigRef = this->GetFieldObject()->GetOwner()->CreateObject( "SigRef" ); pSigRef->GetDictionary().AddKey(PdfName("TransformMethod"), PdfName("DocMDP")); PdfObject *pTransParams = this->GetFieldObject()->GetOwner()->CreateObject( "TransformParams" ); pTransParams->GetDictionary().AddKey(PdfName("V"), PdfName("1.2")); pTransParams->GetDictionary().AddKey(PdfName("P"), PdfVariant((pdf_int64)perm)); pSigRef->GetDictionary().AddKey(PdfName("TransformParams"), pTransParams); if (pDocumentCatalog != NULL) { PdfObject permObject; permObject.GetDictionary().AddKey("DocMDP", this->GetFieldObject()->GetDictionary().GetKey("V")->GetReference()); if (pDocumentCatalog->GetDictionary().HasKey(PdfName("Perms"))) { pDocumentCatalog->GetDictionary().RemoveKey(PdfName("Perms")); } pDocumentCatalog->GetDictionary().AddKey(PdfName("Perms"), permObject); } PdfArray refers; refers.push_back(*pSigRef); m_pSignatureObj->GetDictionary().AddKey(PdfName("Reference"), PdfVariant(refers)); } PdfObject* PdfSignatureField::GetSignatureObject( void ) const { return m_pSignatureObj; } void PdfSignatureField::EnsureSignatureObject( void ) { if( m_pSignatureObj ) return; m_pSignatureObj = this->GetFieldObject()->GetOwner()->CreateObject( "Sig" ); if( !m_pSignatureObj ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } GetFieldObject()->GetDictionary().AddKey( "V" , m_pSignatureObj->Reference() ); PdfDictionary &dict = m_pSignatureObj->GetDictionary(); dict.AddKey( PdfName::KeyFilter, PdfName( "Adobe.PPKLite" ) ); dict.AddKey( "SubFilter", PdfName( "adbe.pkcs7.detached" ) ); } } podofo-0.9.5/src/doc/PdfFont.h0000664000175000017500000003467412347316204015750 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FONT_H_ #define _PDF_FONT_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfName.h" #include "podofo/base/PdfEncodingFactory.h" #include "PdfElement.h" #include "PdfFontMetrics.h" namespace PoDoFo { class PdfObject; class PdfPage; class PdfWriter; /** Before you can draw text on a PDF document, you have to create * a font object first. You can reuse this font object as often * as you want. * * Use PdfDocument::CreateFont to create a new font object. * It will choose a correct subclass using PdfFontFactory. * * This is only an abstract base class which is implemented * for different font formats. */ class PODOFO_DOC_API PdfFont : public PdfElement { friend class PdfFontFactory; public: /** Create a new PdfFont object which will introduce itself * automatically to every page object it is used on. * * The font has a default font size of 12.0pt. * * \param pMetrics pointer to a font metrics object. The font in the PDF * file will match this fontmetrics object. The metrics object is * deleted along with the font. * \param pEncoding the encoding of this font. The font will take ownership of this object * depending on pEncoding->IsAutoDelete() * \param pParent parent of the font object * */ PdfFont( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfVecObjects* pParent ); /** Create a PdfFont based on an existing PdfObject * \param pMetrics pointer to a font metrics object. The font in the PDF * file will match this fontmetrics object. The metrics object is * deleted along with the font. * \param pEncoding the encoding of this font. The font will take ownership of this object * depending on pEncoding->IsAutoDelete() * \param pObject an existing PdfObject */ PdfFont( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfObject* pObject ); virtual ~PdfFont(); /** Set the font size before drawing with this font. * \param fSize font size in points */ inline void SetFontSize( float fSize ); /** Retrieve the current font size of this font object * \returns the current font size */ inline float GetFontSize() const; /** Set the horizontal scaling of the font for compressing (< 100) and expanding (>100) * \param fScale scaling in percent */ inline void SetFontScale( float fScale ); /** Retrieve the current horizontal scaling of this font object * \returns the current font scaling */ inline float GetFontScale() const; /** Set the character spacing of the font * \param fCharSpace character spacing in percent */ inline void SetFontCharSpace( float fCharSpace ); /** Retrieve the current character spacing of this font object * \returns the current font character spacing */ inline float GetFontCharSpace() const; /** Set the word spacing of the font * \param fWordSpace word spacing in PDF units */ inline void SetWordSpace( float fWordSpace ); /** Retrieve the current word spacing of this font object * \returns the current font word spacing in PDF units */ inline float GetWordSpace() const; /** Set the underlined property of the font * \param bUnder if true any text drawn with this font * by a PdfPainter will be underlined. * Default is false */ inline void SetUnderlined( bool bUnder ); /** \returns true if the font is underlined * \see IsBold * \see IsItalic */ inline bool IsUnderlined() const; /** \returns true if this font is bold * \see IsItalic * \see IsUnderlined */ inline bool IsBold() const; /** \returns true if this font is italic * \see IsBold * \see IsUnderlined */ inline bool IsItalic() const; /** Set the strikeout property of the font * \param bStrikeOut if true any text drawn with this font * by a PdfPainter will be strikedout. * Default is false */ inline void SetStrikeOut( bool bStrikeOut ); /** \returns true if the font is striked out */ inline bool IsStrikeOut() const; /** Returns the identifier of this font how it is known * in the pages resource dictionary. * \returns PdfName containing the identifier (e.g. /Ft13) */ inline const PdfName & GetIdentifier() const; /** Returns a reference to the fonts encoding * \returns a PdfEncoding object. */ inline const PdfEncoding* GetEncoding() const; /** Returns a handle to the fontmetrics object of this font. * This can be used for size calculations of text strings when * drawn using this font. * \returns a handle to the font metrics object */ inline const PdfFontMetrics* GetFontMetrics() const; // Peter Petrov 19 March 2009 /** Returns a handle to the fontmetrics object of this font. * This can be used for size calculations of text strings when * drawn using this font. * \returns a handle to the font metrics object */ inline PdfFontMetrics* GetFontMetrics2(); /** Write a PdfString to a PdfStream in a format so that it can * be used with this font. * This is used by PdfPainter::DrawText to display a text string. * The following PDF operator will be Tj * * \param rsString a unicode or ansi string which will be displayed * \param pStream the string will be appended to pStream without any leading * or following whitespaces. */ virtual void WriteStringToStream( const PdfString & rsString, PdfStream* pStream ); // Peter Petrov 24 September 2008 /** Embeds the font into PDF page * */ virtual void EmbedFont(); /** Remember the glyphs used in the string in case of subsetting * * \param sText the text string which should be printed (is not allowed to be NULL!) * \param lStringLen draw only lLen characters of pszText * * Only call if IsSubsetting() returns true. Might throw an exception otherwise. * * \see IsSubsetting */ virtual void AddUsedSubsettingGlyphs( const PdfString & sText, long lStringLen ); /** Remember the glyphname in case of subsetting * * \param pszGlyphName Name of the glyph to remember */ virtual void AddUsedGlyphname( const char * pszGlyphName ); /** Embeds pending subset-font into PDF page * Only call if IsSubsetting() returns true. Might throw an exception otherwise. * * \see IsSubsetting */ virtual void EmbedSubsetFont(); /** Check if this is a subsetting font. * \returns true if this is a subsetting font */ inline bool IsSubsetting() const; protected: /** Get the base font name of this font * * \returns the base font name */ inline const PdfName& GetBaseFont() const; void InitBase14Font(); const PdfEncoding* const m_pEncoding; PdfFontMetrics* m_pMetrics; bool m_bBold; bool m_bItalic; bool m_bUnderlined; bool m_bStrikedOut; bool m_bWasEmbedded; bool m_isBase14; bool m_bIsSubsetting; PdfName m_Identifier; /** Used to specify if this represents a bold font * \param bBold if true this is a bold font. * * \see IsBold * * This can be called by PdfFontFactory to tell this font * object that it belongs to a bold font. */ virtual void SetBold( bool bBold ); /** Used to specify if this represents an italic font * \param bItalic if true this is an italic font. * * \see IsItalc * * This can be called by PdfFontFactory to tell this font * object that it belongs to an italic font. */ virtual void SetItalic( bool bItalic ); private: /** default constructor, not implemented */ PdfFont(void); /** copy constructor, not implemented */ PdfFont(const PdfFont& rhs); /** assignment operator, not implemented */ PdfFont& operator=(const PdfFont& rhs); /** Initialize all variables */ void InitVars(); PdfName m_BaseFont; }; // ----------------------------------------------------- // // ----------------------------------------------------- const PdfName& PdfFont::GetBaseFont() const { return m_BaseFont; } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfName & PdfFont::GetIdentifier() const { return m_Identifier; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfFont::SetFontSize( float fSize ) { m_pMetrics->SetFontSize( fSize ); } // ----------------------------------------------------- // // ----------------------------------------------------- float PdfFont::GetFontSize() const { return m_pMetrics->GetFontSize(); } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfFont::SetFontScale( float fScale ) { m_pMetrics->SetFontScale( fScale ); } // ----------------------------------------------------- // // ----------------------------------------------------- float PdfFont::GetFontScale() const { return m_pMetrics->GetFontScale(); } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfFont::SetFontCharSpace( float fCharSpace ) { m_pMetrics->SetFontCharSpace( fCharSpace ); } // ----------------------------------------------------- // // ----------------------------------------------------- float PdfFont::GetFontCharSpace() const { return m_pMetrics->GetFontCharSpace(); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfFont::SetWordSpace( float fWordSpace ) { m_pMetrics->SetWordSpace( fWordSpace ); } // ----------------------------------------------------- // // ----------------------------------------------------- inline float PdfFont::GetWordSpace() const { return m_pMetrics->GetWordSpace(); } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfEncoding* PdfFont::GetEncoding() const { return m_pEncoding; } // ----------------------------------------------------- // // ----------------------------------------------------- PdfFontMetrics* PdfFont::GetFontMetrics2() { return m_pMetrics; } // ----------------------------------------------------- // // ----------------------------------------------------- const PdfFontMetrics* PdfFont::GetFontMetrics() const { return m_pMetrics; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfFont::SetUnderlined( bool bUnder ) { m_bUnderlined = bUnder; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfFont::IsUnderlined() const { return m_bUnderlined; } // ----------------------------------------------------- // // ----------------------------------------------------- void PdfFont::SetStrikeOut( bool bStrikeOut ) { m_bStrikedOut = bStrikeOut; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfFont::IsStrikeOut() const { return m_bStrikedOut; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfFont::IsBold() const { return m_bBold; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfFont::IsItalic() const { return m_bItalic; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfFont::IsSubsetting() const { return m_bIsSubsetting; } }; #endif // _PDF_FONT_H_ podofo-0.9.5/src/doc/PdfFileSpec.cpp0000664000175000017500000002703712347313527017067 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfFileSpec.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfDictionary.h" #include "base/PdfInputStream.h" #include "base/PdfObject.h" #include "base/PdfStream.h" #include namespace PoDoFo { PdfFileSpec::PdfFileSpec( const char* pszFilename, bool bEmbedd, PdfDocument* pParent, bool bStripPath) : PdfElement( "Filespec", pParent ) { Init( pszFilename, bEmbedd, bStripPath ); } PdfFileSpec::PdfFileSpec( const char* pszFilename, bool bEmbedd, PdfVecObjects* pParent, bool bStripPath) : PdfElement( "Filespec", pParent ) { Init( pszFilename, bEmbedd, bStripPath ); } PdfFileSpec::PdfFileSpec( const char* pszFilename, const unsigned char* data, ptrdiff_t size, PdfVecObjects* pParent, bool bStripPath) : PdfElement( "Filespec", pParent ) { Init( pszFilename, data, size, bStripPath ); } PdfFileSpec::PdfFileSpec( const char* pszFilename, const unsigned char* data, ptrdiff_t size, PdfDocument* pParent, bool bStripPath) : PdfElement( "Filespec", pParent ) { Init( pszFilename, data, size, bStripPath ); } PdfFileSpec::PdfFileSpec( PdfObject* pObject ) : PdfElement( "Filespec", pObject ) { } #ifdef _WIN32 PdfFileSpec::PdfFileSpec( const wchar_t* pszFilename, bool bEmbedd, PdfDocument* pParent, bool bStripPath) : PdfElement( "Filespec", pParent ) { Init( pszFilename, bEmbedd, bStripPath ); } PdfFileSpec::PdfFileSpec( const wchar_t* pszFilename, bool bEmbedd, PdfVecObjects* pParent, bool bStripPath) : PdfElement( "Filespec", pParent ) { Init( pszFilename, bEmbedd, bStripPath ); } PdfFileSpec::PdfFileSpec( const wchar_t* pszFilename, const unsigned char* data, ptrdiff_t size, PdfVecObjects* pParent, bool bStripPath) : PdfElement( "Filespec", pParent ) { Init( pszFilename, data, size, bStripPath ); } PdfFileSpec::PdfFileSpec( const wchar_t* pszFilename, const unsigned char* data, ptrdiff_t size, PdfDocument* pParent, bool bStripPath) : PdfElement( "Filespec", pParent ) { Init( pszFilename, data, size, bStripPath ); } void PdfFileSpec::Init( const wchar_t* pszFilename, bool bEmbedd, bool bStripPath) { PdfObject* pEmbeddedStream; PdfString filename; filename.setFromWchar_t( MaybeStripPath( pszFilename, true) ); this->GetObject()->GetDictionary().AddKey( "F", this->CreateFileSpecification( MaybeStripPath( pszFilename, bStripPath ) ) ); this->GetObject()->GetDictionary().AddKey( "UF", filename.ToUnicode () ); if( bEmbedd ) { PdfDictionary ef; pEmbeddedStream = this->CreateObject( "EmbeddedFile" ); this->EmbeddFile( pEmbeddedStream, pszFilename ); ef.AddKey( "F", pEmbeddedStream->Reference() ); this->GetObject()->GetDictionary().AddKey( "EF", ef ); } } void PdfFileSpec::Init( const wchar_t* pszFilename, const unsigned char* data, ptrdiff_t size, bool bStripPath) { PdfObject* pEmbeddedStream; PdfString filename; filename.setFromWchar_t( MaybeStripPath( pszFilename, true) ); this->GetObject()->GetDictionary().AddKey( "F", this->CreateFileSpecification( MaybeStripPath( pszFilename, bStripPath ) ) ); this->GetObject()->GetDictionary().AddKey( "UF", filename.ToUnicode() ); PdfDictionary ef; pEmbeddedStream = this->CreateObject( "EmbeddedFile" ); this->EmbeddFileFromMem( pEmbeddedStream, data, size ); ef.AddKey( "F", pEmbeddedStream->Reference() ); this->GetObject()->GetDictionary().AddKey( "EF", ef ); } PdfString PdfFileSpec::CreateFileSpecification( const wchar_t* pszFilename ) const { std::ostringstream str; size_t nLen = wcslen( pszFilename ); char buff[5]; // Construct a platform independent file specifier for( size_t i=0;i= L'a' && ch <= L'z') || (ch >= L'A' && ch <= L'Z') || (ch >= L'0' && ch <= L'9') || ch == L'_') { str.put( ch & 0xFF ); } else if (ch == L'/') { str.put( '\\' ); str.put( '\\' ); str.put( '/' ); } else { sprintf(buff, "%04X", ch & 0xFFFF); str << buff; } } return PdfString( str.str() ); } void PdfFileSpec::EmbeddFile( PdfObject* pStream, const wchar_t* pszFilename ) const { PdfFileInputStream stream( pszFilename ); pStream->GetStream()->Set( &stream ); // Add additional information about the embedded file to the stream PdfDictionary params; params.AddKey( "Size", static_cast(stream.GetFileLength()) ); // TODO: CreationDate and ModDate pStream->GetDictionary().AddKey("Params", params ); } const wchar_t *PdfFileSpec::MaybeStripPath( const wchar_t* pszFilename, bool bStripPath ) const { if (!bStripPath) { return pszFilename; } const wchar_t *lastFrom = pszFilename; while (pszFilename && *pszFilename) { if ( #ifdef _WIN32 *pszFilename == L':' || *pszFilename == L'\\' || #endif // _WIN32 *pszFilename == L'/') { lastFrom = pszFilename + 1; } pszFilename++; } return lastFrom; } #endif // _WIN32 void PdfFileSpec::Init( const char* pszFilename, bool bEmbedd, bool bStripPath ) { PdfObject* pEmbeddedStream; PdfString filename( MaybeStripPath( pszFilename, true) ); this->GetObject()->GetDictionary().AddKey( "F", this->CreateFileSpecification( MaybeStripPath( pszFilename, bStripPath ) ) ); this->GetObject()->GetDictionary().AddKey( "UF", filename.ToUnicode () ); if( bEmbedd ) { PdfDictionary ef; pEmbeddedStream = this->CreateObject( "EmbeddedFile" ); this->EmbeddFile( pEmbeddedStream, pszFilename ); ef.AddKey( "F", pEmbeddedStream->Reference() ); this->GetObject()->GetDictionary().AddKey( "EF", ef ); } } void PdfFileSpec::Init( const char* pszFilename, const unsigned char* data, ptrdiff_t size, bool bStripPath ) { PdfObject* pEmbeddedStream; PdfString filename( MaybeStripPath( pszFilename, true) ); this->GetObject()->GetDictionary().AddKey( "F", this->CreateFileSpecification( MaybeStripPath( pszFilename, bStripPath) ) ); this->GetObject()->GetDictionary().AddKey( "UF", filename.ToUnicode () ); PdfDictionary ef; pEmbeddedStream = this->CreateObject( "EmbeddedFile" ); this->EmbeddFileFromMem( pEmbeddedStream, data, size ); ef.AddKey( "F", pEmbeddedStream->Reference() ); this->GetObject()->GetDictionary().AddKey( "EF", ef ); } PdfString PdfFileSpec::CreateFileSpecification( const char* pszFilename ) const { std::ostringstream str; size_t nLen = strlen( pszFilename ); char buff[5]; // Construct a platform independent file specifier for( size_t i=0;i= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch == '_') { str.put( ch & 0xFF ); } else if (ch == '/') { str.put( '\\' ); str.put( '\\' ); str.put( '/' ); } else { sprintf(buff, "%02X", ch & 0xFF); str << buff; } } return PdfString( str.str() ); } void PdfFileSpec::EmbeddFile( PdfObject* pStream, const char* pszFilename ) const { PdfFileInputStream stream( pszFilename ); pStream->GetStream()->Set( &stream ); // Add additional information about the embedded file to the stream PdfDictionary params; params.AddKey( "Size", static_cast(stream.GetFileLength()) ); // TODO: CreationDate and ModDate pStream->GetDictionary().AddKey("Params", params ); } const char *PdfFileSpec::MaybeStripPath( const char* pszFilename, bool bStripPath ) const { if (!bStripPath) { return pszFilename; } const char *lastFrom = pszFilename; while (pszFilename && *pszFilename) { if ( #ifdef _WIN32 *pszFilename == ':' || *pszFilename == '\\' || #endif // _WIN32 *pszFilename == '/') { lastFrom = pszFilename + 1; } pszFilename++; } return lastFrom; } void PdfFileSpec::EmbeddFileFromMem( PdfObject* pStream, const unsigned char* data, ptrdiff_t size ) const { PdfMemoryInputStream memstream(reinterpret_cast(data),size); pStream->GetStream()->Set( &memstream ); // Add additional information about the embedded file to the stream PdfDictionary params; params.AddKey( "Size", static_cast(size) ); pStream->GetDictionary().AddKey("Params", params ); } const PdfString & PdfFileSpec::GetFilename(bool canUnicode) const { if( canUnicode && this->GetObject()->GetDictionary().HasKey( "UF" ) ) { return this->GetObject()->GetDictionary().GetKey( "UF" )->GetString(); } if( this->GetObject()->GetDictionary().HasKey( "F" ) ) { return this->GetObject()->GetDictionary().GetKey( "F" )->GetString(); } PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } }; podofo-0.9.5/src/doc/PdfFontMetricsObject.cpp0000664000175000017500000003105113013650710020735 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfFontMetricsObject.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfDictionary.h" #include "base/PdfName.h" #include "base/PdfObject.h" #include "base/PdfVariant.h" namespace PoDoFo { PdfFontMetricsObject::PdfFontMetricsObject( PdfObject* pFont, PdfObject* pDescriptor, const PdfEncoding* const pEncoding ) : PdfFontMetrics( ePdfFontType_Unknown, "", NULL ), m_pEncoding( pEncoding ), m_dDefWidth(0.0) { m_missingWidth = NULL; const PdfName & rSubType = pFont->GetDictionary().GetKey( PdfName::KeySubtype )->GetName(); // OC 15.08.2010 BugFix: /FirstChar /LastChar /Widths are in the Font dictionary and not in the FontDescriptor if ( rSubType == PdfName("Type1") || rSubType == PdfName("Type3") || rSubType == PdfName("TrueType") ) { if ( pDescriptor ) { if (pDescriptor->GetDictionary().HasKey( "FontName" )) m_sName = pDescriptor->GetIndirectKey( "FontName" )->GetName(); if (pDescriptor->GetDictionary().HasKey( "FontBBox" )) m_bbox = pDescriptor->GetIndirectKey( "FontBBox" )->GetArray(); } else { if (pFont->GetDictionary().HasKey( "Name" )) m_sName = pFont->GetIndirectKey( "Name" )->GetName(); if (pFont->GetDictionary().HasKey( "FontBBox" )) m_bbox = pFont->GetIndirectKey( "FontBBox" )->GetArray(); } if (pFont->GetDictionary().HasKey( "FontMatrix" )) { // Type3 fonts have a custom FontMatrix m_matrix = pFont->GetIndirectKey( "FontMatrix" )->GetArray(); } m_nFirst = static_cast(pFont->GetDictionary().GetKeyAsLong( "FirstChar", 0L )); m_nLast = static_cast(pFont->GetDictionary().GetKeyAsLong( "LastChar", 0L )); // OC 15.08.2010 BugFix: GetIndirectKey() instead of GetDictionary().GetKey() and "Widths" instead of "Width" PdfObject* widths = pFont->GetIndirectKey( "Widths" ); if( widths != NULL ) { m_width = widths->GetArray(); m_missingWidth = NULL; } else { if ( pDescriptor ) { widths = pDescriptor->GetDictionary().GetKey( "MissingWidth" ); } else { widths = pFont->GetDictionary().GetKey( "MissingWidth" ); } if( widths == NULL ) { PODOFO_RAISE_ERROR_INFO( ePdfError_NoObject, "Font object defines neither Widths, nor MissingWidth values!" ); } m_missingWidth = widths; } } else if ( rSubType == PdfName("CIDFontType0") || rSubType == PdfName("CIDFontType2") ) { PdfObject *pObj = pDescriptor->GetIndirectKey( "FontName" ); if (pObj) { m_sName = pObj->GetName(); } pObj = pDescriptor->GetIndirectKey( "FontBBox" ); if (pObj) { m_bbox = pObj->GetArray(); } m_nFirst = 0; m_nLast = 0; m_dDefWidth = static_cast(pFont->GetDictionary().GetKeyAsLong( "DW", 1000L )); PdfVariant default_width(m_dDefWidth); PdfObject * pw = pFont->GetIndirectKey( "W" ); for (int i = m_nFirst; i <= m_nLast; ++i) { m_width.push_back(default_width); } if (pw) { PdfArray w = pw->GetArray(); int pos = 0; while (pos < static_cast(w.GetSize())) { int start = static_cast(w[pos++].GetNumber()); PODOFO_ASSERT (start >= 0); if (w[pos].IsArray()) { PdfArray widths = w[pos++].GetArray(); int length = start + static_cast(widths.GetSize()); PODOFO_ASSERT (length >= start); if (length > static_cast(m_width.GetSize())) { m_width.resize(length, default_width); } for (int i = 0; i < static_cast(widths.GetSize()); ++i) { m_width[start + i] = widths[i]; } } else { int end = static_cast(w[pos++].GetNumber()); int length = end + 1; PODOFO_ASSERT (length >= start); if (length > static_cast(m_width.GetSize())) { m_width.resize(length, default_width); } pdf_int64 width = w[pos++].GetNumber(); for (int i = start; i <= end; ++i) m_width[i] = PdfVariant(width); } } } m_nLast = m_width.GetSize() - 1; } else { PODOFO_RAISE_ERROR_INFO( ePdfError_UnsupportedFontFormat, rSubType.GetEscapedName().c_str() ); } if ( pDescriptor ) { m_nWeight = static_cast(pDescriptor->GetDictionary().GetKeyAsLong( "FontWeight", 400L )); m_nItalicAngle = static_cast(pDescriptor->GetDictionary().GetKeyAsLong( "ItalicAngle", 0L )); m_dPdfAscent = pDescriptor->GetDictionary().GetKeyAsReal( "Ascent", 0.0 ); m_dPdfDescent = pDescriptor->GetDictionary().GetKeyAsReal( "Descent", 0.0 ); } else { m_nWeight = 400L; m_nItalicAngle = 0L; m_dPdfAscent = 0.0; m_dPdfDescent = 0.0; } if (m_matrix.size() == 0) { // Default FontMatrix for all font types: [0.001 0 0 0.001 0 0] m_matrix.push_back(0.001); m_matrix.push_back(0.0); m_matrix.push_back(0.0); m_matrix.push_back(0.001); m_matrix.push_back(0.0); m_matrix.push_back(0.0); } m_dAscent = m_dPdfAscent * m_matrix[3].GetReal(); m_dDescent = m_dPdfDescent * m_matrix[3].GetReal(); m_dLineSpacing = m_dAscent + m_dDescent; // Try to fine some sensible values m_dUnderlineThickness = 1.0; m_dUnderlinePosition = 0.0; m_dStrikeOutThickness = m_dUnderlinePosition; m_dStrikeOutPosition = m_dAscent / 2.0; m_bSymbol = false; // TODO } PdfFontMetricsObject::~PdfFontMetricsObject() { } const char* PdfFontMetricsObject::GetFontname() const { return m_sName.GetName().c_str(); } void PdfFontMetricsObject::GetBoundingBox( PdfArray & array ) const { array = m_bbox; } double PdfFontMetricsObject::CharWidth( unsigned char c ) const { if( c >= m_nFirst && c <= m_nLast && c - m_nFirst < static_cast(m_width.GetSize()) ) { double dWidth = m_width[c - m_nFirst].GetReal(); return (dWidth * m_matrix.front().GetReal() * this->GetFontSize() + this->GetFontCharSpace()) * this->GetFontScale() / 100.0; } if( m_missingWidth != NULL ) return m_missingWidth->GetReal (); else return m_dDefWidth; } double PdfFontMetricsObject::UnicodeCharWidth( unsigned short c ) const { if( c >= m_nFirst && c <= m_nLast && c - m_nFirst < static_cast(m_width.GetSize()) ) { double dWidth = m_width[c - m_nFirst].GetReal(); return (dWidth * m_matrix.front().GetReal() * this->GetFontSize() + this->GetFontCharSpace()) * this->GetFontScale() / 100.0; } if( m_missingWidth != NULL ) return m_missingWidth->GetReal (); else return m_dDefWidth; } void PdfFontMetricsObject::GetWidthArray( PdfVariant & var, unsigned int, unsigned int, const PdfEncoding* ) const { var = m_width; } double PdfFontMetricsObject::GetGlyphWidth( int ) const { // TODO return 0.0; // OC 13.08.2010 BugFix: Avoid microsoft compiler error } double PdfFontMetricsObject::GetGlyphWidth( const char* ) const { // TODO return 0.0; } long PdfFontMetricsObject::GetGlyphId( long ) const { // TODO return 0; // OC 13.08.2010 BugFix: Avoid microsoft compiler error } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfFontMetricsObject::GetLineSpacing() const { return m_dLineSpacing * this->GetFontSize(); } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfFontMetricsObject::GetUnderlinePosition() const { return m_dUnderlinePosition * this->GetFontSize(); } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfFontMetricsObject::GetStrikeOutPosition() const { return m_dStrikeOutPosition * this->GetFontSize(); } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfFontMetricsObject::GetUnderlineThickness() const { return m_dUnderlineThickness * this->GetFontSize(); } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfFontMetricsObject::GetStrikeoutThickness() const { return m_dStrikeOutThickness * this->GetFontSize(); } // ----------------------------------------------------- // // ----------------------------------------------------- const char* PdfFontMetricsObject::GetFontData() const { return NULL; } // ----------------------------------------------------- // // ----------------------------------------------------- pdf_long PdfFontMetricsObject::GetFontDataLen() const { return 0; } // ----------------------------------------------------- // // ----------------------------------------------------- unsigned int PdfFontMetricsObject::GetWeight() const { return m_nWeight; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfFontMetricsObject::GetAscent() const { return m_dAscent * this->GetFontSize(); } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfFontMetricsObject::GetPdfAscent() const { return m_dPdfAscent; } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfFontMetricsObject::GetDescent() const { return m_dDescent * this->GetFontSize(); } // ----------------------------------------------------- // // ----------------------------------------------------- double PdfFontMetricsObject::GetPdfDescent() const { return m_dPdfDescent; } // ----------------------------------------------------- // // ----------------------------------------------------- int PdfFontMetricsObject::GetItalicAngle() const { return m_nItalicAngle; } // ----------------------------------------------------- // // ----------------------------------------------------- bool PdfFontMetricsObject::IsSymbol() const { return m_bSymbol; } }; podofo-0.9.5/src/doc/PdfFontType1Base14.h0000664000175000017500000001040012344436402017610 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FONT_TYPE1_BASE14_H_ #define _PDF_FONT_TYPE1_BASE14_H_ #include "podofo/base/PdfDefines.h" #include "PdfFontSimple.h" namespace PoDoFo { /** A PdfFont implementation that can be used * draw with base14 type1 fonts into a PDF file. */ class PdfFontType1Base14 : public PdfFontSimple { public: /** Create a new Type1 font object. * * \param pMetrics pointer to a font metrics object. The font in the PDF * file will match this fontmetrics object. The metrics object is * deleted along with the font. * \param pEncoding the encoding of this font. The font will take ownership of this object * depending on pEncoding->IsAutoDelete() * \param pParent parent of the font object * */ PdfFontType1Base14( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfVecObjects* pParent ); // OC 13.08.2010 New: /** Create a new Type1 font object based on an existing PdfObject * \param pMetrics pointer to a font metrics object. The font in the PDF * file will match this fontmetrics object. The metrics object is * deleted along with the font. * \param pEncoding the encoding of this font. The font will take ownership of this object * depending on pEncoding->IsAutoDelete() * \param pObject an existing PdfObject */ PdfFontType1Base14( PdfFontMetrics* pMetrics, const PdfEncoding* const pEncoding, PdfObject* pObject ); ~PdfFontType1Base14(); protected: /** Embed the font file directly into the PDF file. * * \param pDescriptor font descriptor object */ virtual void EmbedFontFile( PdfObject* pDescriptor ); private: void InitBase14Font( PdfFontMetrics* pMetrics ); }; }; #endif // _PDF_FONT_TYPE1_BASE14_H_ podofo-0.9.5/src/doc/PdfPage.h0000664000175000017500000003061112262234754015706 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_PAGE_H_ #define _PDF_PAGE_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfArray.h" #include "podofo/base/PdfCanvas.h" #include "podofo/base/PdfRect.h" #include "PdfAnnotation.h" #include "PdfContents.h" #include "PdfElement.h" #include "PdfField.h" namespace PoDoFo { class PdfDocument; class PdfDictionary; class PdfVecObjects; typedef std::map TMapAnnotation; typedef TMapAnnotation::iterator TIMapAnnotation; typedef TMapAnnotation::const_iterator TCIMapAnnotation; /** PdfPage is one page in the pdf document. * It is possible to draw on a page using a PdfPainter object. * Every document needs at least one page. */ class PODOFO_DOC_API PdfPage : public PdfElement, public PdfCanvas { public: /** Create a new PdfPage object. * \param rSize a PdfRect specifying the size of the page (i.e the /MediaBox key) in PDF units * \param pParent add the page to this parent */ PdfPage( const PdfRect & rSize, PdfDocument* pParent ); /** Create a new PdfPage object. * \param rSize a PdfRect specifying the size of the page (i.e the /MediaBox key) in PDF units * \param pParent add the page to this parent */ PdfPage( const PdfRect & rSize, PdfVecObjects* pParent ); /** Create a PdfPage based on an existing PdfObject * \param pObject an existing PdfObject * \param listOfParents a list of PdfObjects that are * parents of this page and can be * queried for inherited attributes. * The last object in the list is the * most direct parent of this page. */ PdfPage( PdfObject* pObject, const std::deque & listOfParents ); virtual ~PdfPage(); /** Get the current page size in PDF Units * \returns a PdfRect containing the page size available for drawing */ inline virtual const PdfRect GetPageSize() const; // added by Petr P. Petrov 21 Febrary 2010 /** Set the current page width in PDF Units * * \returns true if successfull, false otherwise * */ bool SetPageWidth(int newWidth); // added by Petr P. Petrov 21 Febrary 2010 /** Set the current page height in PDF Units * * \returns true if successfull, false otherwise * */ bool SetPageHeight(int newHeight); /** Set the trimbox in PDF Units * \param rSize a PdfRect specifying the trimbox of the page (i.e the /TrimBox key) in PDF units */ void SetTrimBox( const PdfRect & rSize ); /** Page number inside of the document. The first page * has the number 1, the last page has the number * PdfPagesTree:GetTotalNumberOfPages() * * \returns the number of the page inside of the document * * \see PdfPagesTree:GetTotalNumberOfPages() */ unsigned int GetPageNumber() const; /** Creates a PdfRect with the page size as values which is needed to create a PdfPage object * from an enum which are defined for a few standard page sizes. * * \param ePageSize the page size you want * \param bLandscape create a landscape pagesize instead of portrait (by exchanging width and height) * \returns a PdfRect object which can be passed to the PdfPage constructor */ static PdfRect CreateStandardPageSize( const EPdfPageSize ePageSize, bool bLandscape = false ); /** Get access to the contents object of this page. * If you want to draw onto the page, you have to add * drawing commands to the stream of the Contents object. * \returns a contents object */ virtual PdfObject* GetContents() const; /** Get access an object that you can use to ADD drawing to. * If you want to draw onto the page, you have to add * drawing commands to the stream of the Contents object. * \returns a contents object */ virtual PdfObject* GetContentsForAppending() const; /** Get access to the resources object of this page. * This is most likely an internal object. * \returns a resources object */ inline virtual PdfObject* GetResources() const; /** Get the current MediaBox (physical page size) in PDF units. * \returns PdfRect the page box */ virtual const PdfRect GetMediaBox() const { return GetPageBox( "MediaBox" ); } /** Get the current CropBox (visible page size) in PDF units. * \returns PdfRect the page box */ virtual const PdfRect GetCropBox() const { return GetPageBox( "CropBox" ); } /** Get the current TrimBox (cut area) in PDF units. * \returns PdfRect the page box */ virtual const PdfRect GetTrimBox() const { return GetPageBox( "TrimBox" ); } /** Get the current BleedBox (extra area for printing purposes) in PDF units. * \returns PdfRect the page box */ virtual const PdfRect GetBleedBox() const { return GetPageBox( "BleedBox" ); } /** Get the current ArtBox in PDF units. * \returns PdfRect the page box */ virtual const PdfRect GetArtBox() const { return GetPageBox( "ArtBox" ); } /** Get the current page rotation (if any). * \returns int 0, 90, 180 or 270 */ virtual int GetRotation() const; /** Set the current page rotation. * \param iRotation Rotation to set to the page. Valid value are 0, 90, 180, 270. */ virtual void SetRotation(int nRotation); /** Get the number of annotations associated with this page * \ returns int number of annotations */ virtual int GetNumAnnots() const; /** Create a new annotation to this page. * \param eType the type of the annotation * \param rRect rectangle of the annotation on the page * * \returns the annotation object which is owned by the PdfPage */ PdfAnnotation* CreateAnnotation( EPdfAnnotation eType, const PdfRect & rRect ); /** Get the annotation with index index of the current page. * \param index the index of the annotation to retrieve * * \returns a annotation object. The annotation object is owned by the PdfPage. * * \see GetNumAnnots */ PdfAnnotation* GetAnnotation( int index ); /** Delete the annotation with index index from this page. * \param index the index of the annotation to delete * * \see GetNumAnnots */ void DeleteAnnotation( int index ); /** Delete the annotation object with reference ref from this page. * \param ref the reference of an annotation object of this page. * * \see GetNumAnnots */ void DeleteAnnotation( const PdfReference & ref ); /** * \returns the number of PdfFields on this page. */ int GetNumFields() const; /** Get a PdfField with a certain index. * \param index of the PdfField (must be smaller than GetNumFields() ) * * \see GetNumFields * * \returns a PdfField */ PdfField GetField( int index ); /** Get a PdfField with a certain index. * \param index of the PdfField (must be smaller than GetNumFields() ) * * \see GetNumFields * * \returns a constP dfField */ const PdfField GetField( int index ) const; /** Get an element from the pages resources dictionary, * using a type (category) and a key. * * \param rType the type of resource to fetch (e.g. /Font, or /XObject) * \param rKey the key of the resource * * \returns the object of the resource or NULL if it was not found */ PdfObject* GetFromResources( const PdfName & rType, const PdfName & rKey ); /** Method for getting a value that can be inherited * Possible names that can be inherited according to * the PDF specification are: Resources, MediaBox, CropBox and Rotate * * \returns PdfObject - the result of the key fetching or NULL */ inline const PdfObject* GetInheritedKey( const PdfName & rName ) const; PdfObject* GetOwnAnnotationsArray( bool bCreate, PdfDocument *pDocument); private: /** * Initialize a new page object. * m_pContents must be initialized before calling this! * * @param rSize page size */ void InitNewPage( const PdfRect & rSize ); /** * Create the internal PdfContents object. * Call this before accessing m_pContents as * the object is only created if needed. */ void CreateContents(); /** Get the bounds of a specified page box in PDF units. * This function is internal, since there are wrappers for all standard boxes * \returns PdfRect the page box */ const PdfRect GetPageBox( const char* inBox ) const; /** Method for getting a key value that could be inherited (such as the boxes, resources, etc.) * \returns PdfObject - the result of the key fetching or NULL */ const PdfObject* GetInheritedKeyFromObject( const char* inKey, const PdfObject* inObject ) const; /** Get the annotations array. * \param bCreate if true the annotations array is created * if it does not exist. * \returns the annotations array or NULL if none exists. */ PdfObject* GetAnnotationsArray( bool bCreate = false ) const; private: PdfContents* m_pContents; PdfObject* m_pResources; TMapAnnotation m_mapAnnotations; }; // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfObject* PdfPage::GetResources() const { return m_pResources; } // ----------------------------------------------------- // // ----------------------------------------------------- inline const PdfRect PdfPage::GetPageSize() const { return this->GetMediaBox(); } // ----------------------------------------------------- // // ----------------------------------------------------- inline const PdfObject* PdfPage::GetInheritedKey( const PdfName & rName ) const { return this->GetInheritedKeyFromObject( rName.GetName().c_str(), this->GetObject() ); } }; #endif // _PDF_PAGE_H_ podofo-0.9.5/src/doc/PdfDifferenceEncoding.cpp0000664000175000017500000021351512725063217021072 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfDifferenceEncoding.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfDictionary.h" #include "PdfFont.h" #include #include #include #include namespace PoDoFo { static struct { pdf_utf16be u; // in fact this might be little endian on LE systems const char *name; } nameToUnicodeTab[] = { {0x0021, "!"}, {0x0023, "#"}, {0x0024, "$"}, {0x0025, "%"}, {0x0026, "&"}, {0x0027, "'"}, {0x0028, "("}, {0x0029, ")"}, {0x002a, "*"}, {0x002b, "+"}, {0x002c, ","}, {0x002d, "-"}, {0x002e, "."}, {0x002f, "/"}, {0x0030, "0"}, {0x0031, "1"}, {0x0032, "2"}, {0x0033, "3"}, {0x0034, "4"}, {0x0035, "5"}, {0x0036, "6"}, {0x0037, "7"}, {0x0038, "8"}, {0x0039, "9"}, {0x003a, ":"}, {0x003b, ";"}, {0x003c, "<"}, {0x003d, "="}, {0x003e, ">"}, {0x003f, "?"}, {0x0040, "@"}, {0x0041, "A"}, {0x00c6, "AE"}, {0x01fc, "AEacute"}, {0x00c6, "AEsmall"}, {0x00c1, "Aacute"}, {0x00c1, "Aacutesmall"}, {0x0102, "Abreve"}, {0x00c2, "Acircumflex"}, {0x00c2, "Acircumflexsmall"}, {0xf6c9, "Acute"}, {0xf6c9, "Acutesmall"}, {0x00c4, "Adieresis"}, {0x00c4, "Adieresissmall"}, {0x00c0, "Agrave"}, {0x00c0, "Agravesmall"}, {0x0391, "Alpha"}, {0x0386, "Alphatonos"}, {0x0100, "Amacron"}, {0x0104, "Aogonek"}, {0x00c5, "Aring"}, {0x01fa, "Aringacute"}, {0x00c5, "Aringsmall"}, {0x0041, "Asmall"}, {0x00c3, "Atilde"}, {0x00c3, "Atildesmall"}, {0x0042, "B"}, {0x0392, "Beta"}, {0xf6f4, "Brevesmall"}, {0x0042, "Bsmall"}, {0x0043, "C"}, {0x0106, "Cacute"}, {0xf6ca, "Caron"}, {0xf6ca, "Caronsmall"}, {0x010c, "Ccaron"}, {0x00c7, "Ccedilla"}, {0x00c7, "Ccedillasmall"}, {0x0108, "Ccircumflex"}, {0x010a, "Cdotaccent"}, {0xf7b8, "Cedillasmall"}, {0x03a7, "Chi"}, {0xf6f6, "Circumflexsmall"}, {0x0043, "Csmall"}, {0x0044, "D"}, {0x010e, "Dcaron"}, {0x0110, "Dcroat"}, {0x2206, "Delta"}, {0xf6cb, "Dieresis"}, {0xf6cc, "DieresisAcute"}, {0xf6cd, "DieresisGrave"}, {0xf6cb, "Dieresissmall"}, {0xf6f7, "Dotaccentsmall"}, {0x0044, "Dsmall"}, {0x0045, "E"}, {0x00c9, "Eacute"}, {0x00c9, "Eacutesmall"}, {0x0114, "Ebreve"}, {0x011a, "Ecaron"}, {0x00ca, "Ecircumflex"}, {0x00ca, "Ecircumflexsmall"}, {0x00cb, "Edieresis"}, {0x00cb, "Edieresissmall"}, {0x0116, "Edotaccent"}, {0x00c8, "Egrave"}, {0x00c8, "Egravesmall"}, {0x0112, "Emacron"}, {0x014a, "Eng"}, {0x0118, "Eogonek"}, {0x0395, "Epsilon"}, {0x0388, "Epsilontonos"}, {0x0045, "Esmall"}, {0x0397, "Eta"}, {0x0389, "Etatonos"}, {0x00d0, "Eth"}, {0x00d0, "Ethsmall"}, {0x20ac, "Euro"}, {0x0046, "F"}, {0x0046, "Fsmall"}, {0x0047, "G"}, {0x0393, "Gamma"}, {0x011e, "Gbreve"}, {0x01e6, "Gcaron"}, {0x011c, "Gcircumflex"}, {0x0122, "Gcommaaccent"}, {0x0120, "Gdotaccent"}, {0xf6ce, "Grave"}, {0xf6ce, "Gravesmall"}, {0x0047, "Gsmall"}, {0x0048, "H"}, {0x25cf, "H18533"}, {0x25aa, "H18543"}, {0x25ab, "H18551"}, {0x25a1, "H22073"}, {0x0126, "Hbar"}, {0x0124, "Hcircumflex"}, {0x0048, "Hsmall"}, {0xf6cf, "Hungarumlaut"}, {0xf6cf, "Hungarumlautsmall"}, {0x0049, "I"}, {0x0132, "IJ"}, {0x00cd, "Iacute"}, {0x00cd, "Iacutesmall"}, {0x012c, "Ibreve"}, {0x00ce, "Icircumflex"}, {0x00ce, "Icircumflexsmall"}, {0x00cf, "Idieresis"}, {0x00cf, "Idieresissmall"}, {0x0130, "Idotaccent"}, {0x2111, "Ifraktur"}, {0x00cc, "Igrave"}, {0x00cc, "Igravesmall"}, {0x012a, "Imacron"}, {0x012e, "Iogonek"}, {0x0399, "Iota"}, {0x03aa, "Iotadieresis"}, {0x038a, "Iotatonos"}, {0x0049, "Ismall"}, {0x0128, "Itilde"}, {0x004a, "J"}, {0x0134, "Jcircumflex"}, {0x004a, "Jsmall"}, {0x004b, "K"}, {0x039a, "Kappa"}, {0x0136, "Kcommaaccent"}, {0x004b, "Ksmall"}, {0x004c, "L"}, {0xf6bf, "LL"}, {0x0139, "Lacute"}, {0x039b, "Lambda"}, {0x013d, "Lcaron"}, {0x013b, "Lcommaaccent"}, {0x013f, "Ldot"}, {0x0141, "Lslash"}, {0x0141, "Lslashsmall"}, {0x004c, "Lsmall"}, {0x004d, "M"}, {0xf6d0, "Macron"}, {0xf6d0, "Macronsmall"}, {0x004d, "Msmall"}, {0x039c, "Mu"}, {0x004e, "N"}, {0x0143, "Nacute"}, {0x0147, "Ncaron"}, {0x0145, "Ncommaaccent"}, {0x004e, "Nsmall"}, {0x00d1, "Ntilde"}, {0x00d1, "Ntildesmall"}, {0x039d, "Nu"}, {0x004f, "O"}, {0x0152, "OE"}, {0x0152, "OEsmall"}, {0x00d3, "Oacute"}, {0x00d3, "Oacutesmall"}, {0x014e, "Obreve"}, {0x00d4, "Ocircumflex"}, {0x00d4, "Ocircumflexsmall"}, {0x00d6, "Odieresis"}, {0x00d6, "Odieresissmall"}, {0xf6fb, "Ogoneksmall"}, {0x00d2, "Ograve"}, {0x00d2, "Ogravesmall"}, {0x01a0, "Ohorn"}, {0x0150, "Ohungarumlaut"}, {0x014c, "Omacron"}, {0x2126, "Omega"}, {0x038f, "Omegatonos"}, {0x039f, "Omicron"}, {0x038c, "Omicrontonos"}, {0x00d8, "Oslash"}, {0x01fe, "Oslashacute"}, {0x00d8, "Oslashsmall"}, {0x004f, "Osmall"}, {0x00d5, "Otilde"}, {0x00d5, "Otildesmall"}, {0x0050, "P"}, {0x03a6, "Phi"}, {0x03a0, "Pi"}, {0x03a8, "Psi"}, {0x0050, "Psmall"}, {0x0051, "Q"}, {0x0051, "Qsmall"}, {0x0052, "R"}, {0x0154, "Racute"}, {0x0158, "Rcaron"}, {0x0156, "Rcommaaccent"}, {0x211c, "Rfraktur"}, {0x03a1, "Rho"}, {0xf6fc, "Ringsmall"}, {0x0052, "Rsmall"}, {0x0053, "S"}, {0x250c, "SF010000"}, {0x2514, "SF020000"}, {0x2510, "SF030000"}, {0x2518, "SF040000"}, {0x253c, "SF050000"}, {0x252c, "SF060000"}, {0x2534, "SF070000"}, {0x251c, "SF080000"}, {0x2524, "SF090000"}, {0x2500, "SF100000"}, {0x2502, "SF110000"}, {0x2561, "SF190000"}, {0x2562, "SF200000"}, {0x2556, "SF210000"}, {0x2555, "SF220000"}, {0x2563, "SF230000"}, {0x2551, "SF240000"}, {0x2557, "SF250000"}, {0x255d, "SF260000"}, {0x255c, "SF270000"}, {0x255b, "SF280000"}, {0x255e, "SF360000"}, {0x255f, "SF370000"}, {0x255a, "SF380000"}, {0x2554, "SF390000"}, {0x2569, "SF400000"}, {0x2566, "SF410000"}, {0x2560, "SF420000"}, {0x2550, "SF430000"}, {0x256c, "SF440000"}, {0x2567, "SF450000"}, {0x2568, "SF460000"}, {0x2564, "SF470000"}, {0x2565, "SF480000"}, {0x2559, "SF490000"}, {0x2558, "SF500000"}, {0x2552, "SF510000"}, {0x2553, "SF520000"}, {0x256b, "SF530000"}, {0x256a, "SF540000"}, {0x015a, "Sacute"}, {0x0160, "Scaron"}, {0x0160, "Scaronsmall"}, {0x015e, "Scedilla"}, {0x015c, "Scircumflex"}, {0x0218, "Scommaaccent"}, {0x03a3, "Sigma"}, {0x0053, "Ssmall"}, {0x0054, "T"}, {0x03a4, "Tau"}, {0x0166, "Tbar"}, {0x0164, "Tcaron"}, {0x0162, "Tcommaaccent"}, {0x0398, "Theta"}, {0x00de, "Thorn"}, {0x00de, "Thornsmall"}, {0xf6fe, "Tildesmall"}, {0x0054, "Tsmall"}, {0x0055, "U"}, {0x00da, "Uacute"}, {0x00da, "Uacutesmall"}, {0x016c, "Ubreve"}, {0x00db, "Ucircumflex"}, {0x00db, "Ucircumflexsmall"}, {0x00dc, "Udieresis"}, {0x00dc, "Udieresissmall"}, {0x00d9, "Ugrave"}, {0x00d9, "Ugravesmall"}, {0x01af, "Uhorn"}, {0x0170, "Uhungarumlaut"}, {0x016a, "Umacron"}, {0x0172, "Uogonek"}, {0x03a5, "Upsilon"}, {0x03d2, "Upsilon1"}, {0x03ab, "Upsilondieresis"}, {0x038e, "Upsilontonos"}, {0x016e, "Uring"}, {0x0055, "Usmall"}, {0x0168, "Utilde"}, {0x0056, "V"}, {0x0056, "Vsmall"}, {0x0057, "W"}, {0x1e82, "Wacute"}, {0x0174, "Wcircumflex"}, {0x1e84, "Wdieresis"}, {0x1e80, "Wgrave"}, {0x0057, "Wsmall"}, {0x0058, "X"}, {0x039e, "Xi"}, {0x0058, "Xsmall"}, {0x0059, "Y"}, {0x00dd, "Yacute"}, {0x00dd, "Yacutesmall"}, {0x0176, "Ycircumflex"}, {0x0178, "Ydieresis"}, {0x0178, "Ydieresissmall"}, {0x1ef2, "Ygrave"}, {0x0059, "Ysmall"}, {0x005a, "Z"}, {0x0179, "Zacute"}, {0x017d, "Zcaron"}, {0x017d, "Zcaronsmall"}, {0x017b, "Zdotaccent"}, {0x0396, "Zeta"}, {0x005a, "Zsmall"}, {0x0022, "\""}, {0x005c, "\\"}, {0x005d, "]"}, {0x005e, "^"}, {0x005f, "_"}, {0x0060, "`"}, {0x0061, "a"}, {0x00e1, "aacute"}, {0x0103, "abreve"}, {0x00e2, "acircumflex"}, {0x00b4, "acute"}, {0x0301, "acutecomb"}, {0x00e4, "adieresis"}, {0x00e6, "ae"}, {0x01fd, "aeacute"}, {0x2015, "afii00208"}, {0x0410, "afii10017"}, {0x0411, "afii10018"}, {0x0412, "afii10019"}, {0x0413, "afii10020"}, {0x0414, "afii10021"}, {0x0415, "afii10022"}, {0x0401, "afii10023"}, {0x0416, "afii10024"}, {0x0417, "afii10025"}, {0x0418, "afii10026"}, {0x0419, "afii10027"}, {0x041a, "afii10028"}, {0x041b, "afii10029"}, {0x041c, "afii10030"}, {0x041d, "afii10031"}, {0x041e, "afii10032"}, {0x041f, "afii10033"}, {0x0420, "afii10034"}, {0x0421, "afii10035"}, {0x0422, "afii10036"}, {0x0423, "afii10037"}, {0x0424, "afii10038"}, {0x0425, "afii10039"}, {0x0426, "afii10040"}, {0x0427, "afii10041"}, {0x0428, "afii10042"}, {0x0429, "afii10043"}, {0x042a, "afii10044"}, {0x042b, "afii10045"}, {0x042c, "afii10046"}, {0x042d, "afii10047"}, {0x042e, "afii10048"}, {0x042f, "afii10049"}, {0x0490, "afii10050"}, {0x0402, "afii10051"}, {0x0403, "afii10052"}, {0x0404, "afii10053"}, {0x0405, "afii10054"}, {0x0406, "afii10055"}, {0x0407, "afii10056"}, {0x0408, "afii10057"}, {0x0409, "afii10058"}, {0x040a, "afii10059"}, {0x040b, "afii10060"}, {0x040c, "afii10061"}, {0x040e, "afii10062"}, {0xf6c4, "afii10063"}, {0xf6c5, "afii10064"}, {0x0430, "afii10065"}, {0x0431, "afii10066"}, {0x0432, "afii10067"}, {0x0433, "afii10068"}, {0x0434, "afii10069"}, {0x0435, "afii10070"}, {0x0451, "afii10071"}, {0x0436, "afii10072"}, {0x0437, "afii10073"}, {0x0438, "afii10074"}, {0x0439, "afii10075"}, {0x043a, "afii10076"}, {0x043b, "afii10077"}, {0x043c, "afii10078"}, {0x043d, "afii10079"}, {0x043e, "afii10080"}, {0x043f, "afii10081"}, {0x0440, "afii10082"}, {0x0441, "afii10083"}, {0x0442, "afii10084"}, {0x0443, "afii10085"}, {0x0444, "afii10086"}, {0x0445, "afii10087"}, {0x0446, "afii10088"}, {0x0447, "afii10089"}, {0x0448, "afii10090"}, {0x0449, "afii10091"}, {0x044a, "afii10092"}, {0x044b, "afii10093"}, {0x044c, "afii10094"}, {0x044d, "afii10095"}, {0x044e, "afii10096"}, {0x044f, "afii10097"}, {0x0491, "afii10098"}, {0x0452, "afii10099"}, {0x0453, "afii10100"}, {0x0454, "afii10101"}, {0x0455, "afii10102"}, {0x0456, "afii10103"}, {0x0457, "afii10104"}, {0x0458, "afii10105"}, {0x0459, "afii10106"}, {0x045a, "afii10107"}, {0x045b, "afii10108"}, {0x045c, "afii10109"}, {0x045e, "afii10110"}, {0x040f, "afii10145"}, {0x0462, "afii10146"}, {0x0472, "afii10147"}, {0x0474, "afii10148"}, {0xf6c6, "afii10192"}, {0x045f, "afii10193"}, {0x0463, "afii10194"}, {0x0473, "afii10195"}, {0x0475, "afii10196"}, {0xf6c7, "afii10831"}, {0xf6c8, "afii10832"}, {0x04d9, "afii10846"}, {0x200e, "afii299"}, {0x200f, "afii300"}, {0x200d, "afii301"}, {0x066a, "afii57381"}, {0x060c, "afii57388"}, {0x0660, "afii57392"}, {0x0661, "afii57393"}, {0x0662, "afii57394"}, {0x0663, "afii57395"}, {0x0664, "afii57396"}, {0x0665, "afii57397"}, {0x0666, "afii57398"}, {0x0667, "afii57399"}, {0x0668, "afii57400"}, {0x0669, "afii57401"}, {0x061b, "afii57403"}, {0x061f, "afii57407"}, {0x0621, "afii57409"}, {0x0622, "afii57410"}, {0x0623, "afii57411"}, {0x0624, "afii57412"}, {0x0625, "afii57413"}, {0x0626, "afii57414"}, {0x0627, "afii57415"}, {0x0628, "afii57416"}, {0x0629, "afii57417"}, {0x062a, "afii57418"}, {0x062b, "afii57419"}, {0x062c, "afii57420"}, {0x062d, "afii57421"}, {0x062e, "afii57422"}, {0x062f, "afii57423"}, {0x0630, "afii57424"}, {0x0631, "afii57425"}, {0x0632, "afii57426"}, {0x0633, "afii57427"}, {0x0634, "afii57428"}, {0x0635, "afii57429"}, {0x0636, "afii57430"}, {0x0637, "afii57431"}, {0x0638, "afii57432"}, {0x0639, "afii57433"}, {0x063a, "afii57434"}, {0x0640, "afii57440"}, {0x0641, "afii57441"}, {0x0642, "afii57442"}, {0x0643, "afii57443"}, {0x0644, "afii57444"}, {0x0645, "afii57445"}, {0x0646, "afii57446"}, {0x0648, "afii57448"}, {0x0649, "afii57449"}, {0x064a, "afii57450"}, {0x064b, "afii57451"}, {0x064c, "afii57452"}, {0x064d, "afii57453"}, {0x064e, "afii57454"}, {0x064f, "afii57455"}, {0x0650, "afii57456"}, {0x0651, "afii57457"}, {0x0652, "afii57458"}, {0x0647, "afii57470"}, {0x06a4, "afii57505"}, {0x067e, "afii57506"}, {0x0686, "afii57507"}, {0x0698, "afii57508"}, {0x06af, "afii57509"}, {0x0679, "afii57511"}, {0x0688, "afii57512"}, {0x0691, "afii57513"}, {0x06ba, "afii57514"}, {0x06d2, "afii57519"}, {0x06d5, "afii57534"}, {0x20aa, "afii57636"}, {0x05be, "afii57645"}, {0x05c3, "afii57658"}, {0x05d0, "afii57664"}, {0x05d1, "afii57665"}, {0x05d2, "afii57666"}, {0x05d3, "afii57667"}, {0x05d4, "afii57668"}, {0x05d5, "afii57669"}, {0x05d6, "afii57670"}, {0x05d7, "afii57671"}, {0x05d8, "afii57672"}, {0x05d9, "afii57673"}, {0x05da, "afii57674"}, {0x05db, "afii57675"}, {0x05dc, "afii57676"}, {0x05dd, "afii57677"}, {0x05de, "afii57678"}, {0x05df, "afii57679"}, {0x05e0, "afii57680"}, {0x05e1, "afii57681"}, {0x05e2, "afii57682"}, {0x05e3, "afii57683"}, {0x05e4, "afii57684"}, {0x05e5, "afii57685"}, {0x05e6, "afii57686"}, {0x05e7, "afii57687"}, {0x05e8, "afii57688"}, {0x05e9, "afii57689"}, {0x05ea, "afii57690"}, {0xfb2a, "afii57694"}, {0xfb2b, "afii57695"}, {0xfb4b, "afii57700"}, {0xfb1f, "afii57705"}, {0x05f0, "afii57716"}, {0x05f1, "afii57717"}, {0x05f2, "afii57718"}, {0xfb35, "afii57723"}, {0x05b4, "afii57793"}, {0x05b5, "afii57794"}, {0x05b6, "afii57795"}, {0x05bb, "afii57796"}, {0x05b8, "afii57797"}, {0x05b7, "afii57798"}, {0x05b0, "afii57799"}, {0x05b2, "afii57800"}, {0x05b1, "afii57801"}, {0x05b3, "afii57802"}, {0x05c2, "afii57803"}, {0x05c1, "afii57804"}, {0x05b9, "afii57806"}, {0x05bc, "afii57807"}, {0x05bd, "afii57839"}, {0x05bf, "afii57841"}, {0x05c0, "afii57842"}, {0x02bc, "afii57929"}, {0x2105, "afii61248"}, {0x2113, "afii61289"}, {0x2116, "afii61352"}, {0x202c, "afii61573"}, {0x202d, "afii61574"}, {0x202e, "afii61575"}, {0x200c, "afii61664"}, {0x066d, "afii63167"}, {0x02bd, "afii64937"}, {0x00e0, "agrave"}, {0x2135, "aleph"}, {0x03b1, "alpha"}, {0x03ac, "alphatonos"}, {0x0101, "amacron"}, {0x0026, "ampersand"}, {0x0026, "ampersandsmall"}, {0x2220, "angle"}, {0x2329, "angleleft"}, {0x232a, "angleright"}, {0x0387, "anoteleia"}, {0x0105, "aogonek"}, {0x2248, "approxequal"}, {0x00e5, "aring"}, {0x01fb, "aringacute"}, {0x2194, "arrowboth"}, {0x21d4, "arrowdblboth"}, {0x21d3, "arrowdbldown"}, {0x21d0, "arrowdblleft"}, {0x21d2, "arrowdblright"}, {0x21d1, "arrowdblup"}, {0x2193, "arrowdown"}, {0xf8e7, "arrowhorizex"}, {0x2190, "arrowleft"}, {0x2192, "arrowright"}, {0x2191, "arrowup"}, {0x2195, "arrowupdn"}, {0x21a8, "arrowupdnbse"}, {0xf8e6, "arrowvertex"}, {0x005e, "asciicircum"}, {0x007e, "asciitilde"}, {0x002a, "asterisk"}, {0x2217, "asteriskmath"}, {0xf6e9, "asuperior"}, {0x0040, "at"}, {0x00e3, "atilde"}, {0x0062, "b"}, {0x005c, "backslash"}, {0x007c, "bar"}, {0x03b2, "beta"}, {0x2588, "block"}, {0xf8f4, "braceex"}, {0x007b, "braceleft"}, {0xf8f3, "braceleftbt"}, {0xf8f2, "braceleftmid"}, {0xf8f1, "bracelefttp"}, {0x007d, "braceright"}, {0xf8fe, "bracerightbt"}, {0xf8fd, "bracerightmid"}, {0xf8fc, "bracerighttp"}, {0x005b, "bracketleft"}, {0xf8f0, "bracketleftbt"}, {0xf8ef, "bracketleftex"}, {0xf8ee, "bracketlefttp"}, {0x005d, "bracketright"}, {0xf8fb, "bracketrightbt"}, {0xf8fa, "bracketrightex"}, {0xf8f9, "bracketrighttp"}, {0x02d8, "breve"}, {0x00a6, "brokenbar"}, {0xf6ea, "bsuperior"}, {0x2022, "bullet"}, {0x0063, "c"}, {0x0107, "cacute"}, {0x02c7, "caron"}, {0x21b5, "carriagereturn"}, {0x010d, "ccaron"}, {0x00e7, "ccedilla"}, {0x0109, "ccircumflex"}, {0x010b, "cdotaccent"}, {0x00b8, "cedilla"}, {0x00a2, "cent"}, {0xf6df, "centinferior"}, {0x00a2, "centoldstyle"}, {0xf6e0, "centsuperior"}, {0x03c7, "chi"}, {0x25cb, "circle"}, {0x2297, "circlemultiply"}, {0x2295, "circleplus"}, {0x02c6, "circumflex"}, {0x2663, "club"}, {0x003a, "colon"}, {0x20a1, "colonmonetary"}, {0x002c, "comma"}, {0xf6c3, "commaaccent"}, {0xf6e1, "commainferior"}, {0xf6e2, "commasuperior"}, {0x2245, "congruent"}, {0x00a9, "copyright"}, {0x00a9, "copyrightsans"}, {0x00a9, "copyrightserif"}, {0x00a4, "currency"}, {0xf6d1, "cyrBreve"}, {0xf6d2, "cyrFlex"}, {0xf6d4, "cyrbreve"}, {0xf6d5, "cyrflex"}, {0x0064, "d"}, {0x2020, "dagger"}, {0x2021, "daggerdbl"}, {0xf6d3, "dblGrave"}, {0xf6d6, "dblgrave"}, {0x010f, "dcaron"}, {0x0111, "dcroat"}, {0x00b0, "degree"}, {0x03b4, "delta"}, {0x2666, "diamond"}, {0x00a8, "dieresis"}, {0xf6d7, "dieresisacute"}, {0xf6d8, "dieresisgrave"}, {0x0385, "dieresistonos"}, {0x00f7, "divide"}, {0x2593, "dkshade"}, {0x2584, "dnblock"}, {0x0024, "dollar"}, {0xf6e3, "dollarinferior"}, {0x0024, "dollaroldstyle"}, {0xf6e4, "dollarsuperior"}, {0x20ab, "dong"}, {0x02d9, "dotaccent"}, {0x0323, "dotbelowcomb"}, {0x0131, "dotlessi"}, {0xf6be, "dotlessj"}, {0x22c5, "dotmath"}, {0xf6eb, "dsuperior"}, {0x0065, "e"}, {0x00e9, "eacute"}, {0x0115, "ebreve"}, {0x011b, "ecaron"}, {0x00ea, "ecircumflex"}, {0x00eb, "edieresis"}, {0x0117, "edotaccent"}, {0x00e8, "egrave"}, {0x0038, "eight"}, {0x2088, "eightinferior"}, {0x0038, "eightoldstyle"}, {0x2078, "eightsuperior"}, {0x2208, "element"}, {0x2026, "ellipsis"}, {0x0113, "emacron"}, {0x2014, "emdash"}, {0x2205, "emptyset"}, {0x2013, "endash"}, {0x014b, "eng"}, {0x0119, "eogonek"}, {0x03b5, "epsilon"}, {0x03ad, "epsilontonos"}, {0x003d, "equal"}, {0x2261, "equivalence"}, {0x212e, "estimated"}, {0xf6ec, "esuperior"}, {0x03b7, "eta"}, {0x03ae, "etatonos"}, {0x00f0, "eth"}, {0x0021, "exclam"}, {0x203c, "exclamdbl"}, {0x00a1, "exclamdown"}, {0x00a1, "exclamdownsmall"}, {0x0021, "exclamleft"}, {0x0021, "exclamsmall"}, {0x2203, "existential"}, {0x0066, "f"}, {0xfb00, "ff"}, {0xfb03, "ffi"}, {0xfb04, "ffl"}, {0xfb01, "fi"}, {0xfb00, "f_f"}, {0xfb03, "f_f_i"}, {0xfb04, "f_f_l"}, {0xfb01, "f_i"}, {0x2640, "female"}, {0x2012, "figuredash"}, {0x25a0, "filledbox"}, {0x25ac, "filledrect"}, {0x0035, "five"}, {0x215d, "fiveeighths"}, {0x2085, "fiveinferior"}, {0x0035, "fiveoldstyle"}, {0x2075, "fivesuperior"}, {0xfb02, "fl"}, {0xfb02, "f_l"}, {0x0192, "florin"}, {0x0034, "four"}, {0x2084, "fourinferior"}, {0x0034, "fouroldstyle"}, {0x2074, "foursuperior"}, {0x2044, "fraction"}, {0x20a3, "franc"}, {0x0067, "g"}, {0x03b3, "gamma"}, {0x011f, "gbreve"}, {0x01e7, "gcaron"}, {0x011d, "gcircumflex"}, {0x0123, "gcommaaccent"}, {0x0121, "gdotaccent"}, {0x00df, "germandbls"}, {0x2207, "gradient"}, {0x0060, "grave"}, {0x0300, "gravecomb"}, {0x003e, "greater"}, {0x2265, "greaterequal"}, {0x00ab, "guillemotleft"}, {0x00bb, "guillemotright"}, {0x2039, "guilsinglleft"}, {0x203a, "guilsinglright"}, {0x0068, "h"}, {0x0127, "hbar"}, {0x0125, "hcircumflex"}, {0x2665, "heart"}, {0x0309, "hookabovecomb"}, {0x2302, "house"}, {0x02dd, "hungarumlaut"}, {0x002d, "hyphen"}, {0xf6e5, "hypheninferior"}, {0xf6e6, "hyphensuperior"}, {0x0069, "i"}, {0x00ed, "iacute"}, {0x012d, "ibreve"}, {0x00ee, "icircumflex"}, {0x00ef, "idieresis"}, {0x00ec, "igrave"}, {0x0133, "ij"}, {0x012b, "imacron"}, {0x221e, "infinity"}, {0x222b, "integral"}, {0x2321, "integralbt"}, {0xf8f5, "integralex"}, {0x2320, "integraltp"}, {0x2229, "intersection"}, {0x25d8, "invbullet"}, {0x25d9, "invcircle"}, {0x263b, "invsmileface"}, {0x012f, "iogonek"}, {0x03b9, "iota"}, {0x03ca, "iotadieresis"}, {0x0390, "iotadieresistonos"}, {0x03af, "iotatonos"}, {0xf6ed, "isuperior"}, {0x0129, "itilde"}, {0x006a, "j"}, {0x0135, "jcircumflex"}, {0x006b, "k"}, {0x03ba, "kappa"}, {0x0137, "kcommaaccent"}, {0x0138, "kgreenlandic"}, {0x006c, "l"}, {0x013a, "lacute"}, {0x03bb, "lambda"}, {0x013e, "lcaron"}, {0x013c, "lcommaaccent"}, {0x0140, "ldot"}, {0x003c, "less"}, {0x2264, "lessequal"}, {0x258c, "lfblock"}, {0x20a4, "lira"}, {0xf6c0, "ll"}, {0x2227, "logicaland"}, {0x00ac, "logicalnot"}, {0x2228, "logicalor"}, {0x017f, "longs"}, {0x25ca, "lozenge"}, {0x0142, "lslash"}, {0xf6ee, "lsuperior"}, {0x2591, "ltshade"}, {0x006d, "m"}, {0x00af, "macron"}, {0x2642, "male"}, {0x2212, "minus"}, {0x2032, "minute"}, {0xf6ef, "msuperior"}, {0x00b5, "mu"}, {0x00d7, "multiply"}, {0x266a, "musicalnote"}, {0x266b, "musicalnotedbl"}, {0x006e, "n"}, {0x0144, "nacute"}, {0x0149, "napostrophe"}, {0x00a0, "nbspace"}, {0x0148, "ncaron"}, {0x0146, "ncommaaccent"}, {0x0039, "nine"}, {0x2089, "nineinferior"}, {0x0039, "nineoldstyle"}, {0x2079, "ninesuperior"}, {0x00a0, "nonbreakingspace"}, {0x2209, "notelement"}, {0x2260, "notequal"}, {0x2284, "notsubset"}, {0x207f, "nsuperior"}, {0x00f1, "ntilde"}, {0x03bd, "nu"}, {0x0023, "numbersign"}, {0x006f, "o"}, {0x00f3, "oacute"}, {0x014f, "obreve"}, {0x00f4, "ocircumflex"}, {0x00f6, "odieresis"}, {0x0153, "oe"}, {0x02db, "ogonek"}, {0x00f2, "ograve"}, {0x01a1, "ohorn"}, {0x0151, "ohungarumlaut"}, {0x014d, "omacron"}, {0x03c9, "omega"}, {0x03d6, "omega1"}, {0x03ce, "omegatonos"}, {0x03bf, "omicron"}, {0x03cc, "omicrontonos"}, {0x0031, "one"}, {0x2024, "onedotenleader"}, {0x215b, "oneeighth"}, {0xf6dc, "onefitted"}, {0x00bd, "onehalf"}, {0x2081, "oneinferior"}, {0x0031, "oneoldstyle"}, {0x00bc, "onequarter"}, {0x00b9, "onesuperior"}, {0x2153, "onethird"}, {0x25e6, "openbullet"}, {0x00aa, "ordfeminine"}, {0x00ba, "ordmasculine"}, {0x221f, "orthogonal"}, {0x00f8, "oslash"}, {0x01ff, "oslashacute"}, {0xf6f0, "osuperior"}, {0x00f5, "otilde"}, {0x0070, "p"}, {0x00b6, "paragraph"}, {0x0028, "parenleft"}, {0xf8ed, "parenleftbt"}, {0xf8ec, "parenleftex"}, {0x208d, "parenleftinferior"}, {0x207d, "parenleftsuperior"}, {0xf8eb, "parenlefttp"}, {0x0029, "parenright"}, {0xf8f8, "parenrightbt"}, {0xf8f7, "parenrightex"}, {0x208e, "parenrightinferior"}, {0x207e, "parenrightsuperior"}, {0xf8f6, "parenrighttp"}, {0x2202, "partialdiff"}, {0x0025, "percent"}, {0x002e, "period"}, {0x00b7, "periodcentered"}, {0xf6e7, "periodinferior"}, {0xf6e8, "periodsuperior"}, {0x22a5, "perpendicular"}, {0x2030, "perthousand"}, {0x20a7, "peseta"}, {0x03c6, "phi"}, {0x03d5, "phi1"}, {0x03c0, "pi"}, {0x002b, "plus"}, {0x00b1, "plusminus"}, {0x211e, "prescription"}, {0x220f, "product"}, {0x2282, "propersubset"}, {0x2283, "propersuperset"}, {0x221d, "proportional"}, {0x03c8, "psi"}, {0x0071, "q"}, {0x003f, "question"}, {0x00bf, "questiondown"}, {0x00bf, "questiondownsmall"}, {0x003f, "questionsmall"}, {0x0022, "quotedbl"}, {0x201e, "quotedblbase"}, {0x201c, "quotedblleft"}, {0x201d, "quotedblright"}, {0x2018, "quoteleft"}, {0x201b, "quotereversed"}, {0x2019, "quoteright"}, {0x201a, "quotesinglbase"}, {0x0027, "quotesingle"}, {0x0072, "r"}, {0x0155, "racute"}, {0x221a, "radical"}, {0xf8e5, "radicalex"}, {0x0159, "rcaron"}, {0x0157, "rcommaaccent"}, {0x2286, "reflexsubset"}, {0x2287, "reflexsuperset"}, {0x00ae, "registered"}, {0x00ae, "registersans"}, {0x00ae, "registerserif"}, {0x2310, "revlogicalnot"}, {0x03c1, "rho"}, {0x02da, "ring"}, {0xf6f1, "rsuperior"}, {0x2590, "rtblock"}, {0xf6dd, "rupiah"}, {0x0073, "s"}, {0x015b, "sacute"}, {0x0161, "scaron"}, {0x015f, "scedilla"}, {0x015d, "scircumflex"}, {0x0219, "scommaaccent"}, {0x2033, "second"}, {0x00a7, "section"}, {0x003b, "semicolon"}, {0x0037, "seven"}, {0x215e, "seveneighths"}, {0x2087, "seveninferior"}, {0x0037, "sevenoldstyle"}, {0x2077, "sevensuperior"}, {0x2592, "shade"}, {0x03c3, "sigma"}, {0x03c2, "sigma1"}, {0x223c, "similar"}, {0x0036, "six"}, {0x2086, "sixinferior"}, {0x0036, "sixoldstyle"}, {0x2076, "sixsuperior"}, {0x002f, "slash"}, {0x263a, "smileface"}, {0x0020, "space"}, {0x2660, "spade"}, {0xf6f2, "ssuperior"}, {0x00a3, "sterling"}, {0x220b, "suchthat"}, {0x2211, "summation"}, {0x263c, "sun"}, {0x0074, "t"}, {0x03c4, "tau"}, {0x0167, "tbar"}, {0x0165, "tcaron"}, {0x0163, "tcommaaccent"}, {0x2234, "therefore"}, {0x03b8, "theta"}, {0x03d1, "theta1"}, {0x00fe, "thorn"}, {0x0033, "three"}, {0x215c, "threeeighths"}, {0x2083, "threeinferior"}, {0x0033, "threeoldstyle"}, {0x00be, "threequarters"}, {0xf6de, "threequartersemdash"}, {0x00b3, "threesuperior"}, {0x02dc, "tilde"}, {0x0303, "tildecomb"}, {0x0384, "tonos"}, {0x2122, "trademark"}, {0x2122, "trademarksans"}, {0x2122, "trademarkserif"}, {0x25bc, "triagdn"}, {0x25c4, "triaglf"}, {0x25ba, "triagrt"}, {0x25b2, "triagup"}, {0xf6f3, "tsuperior"}, {0x0032, "two"}, {0x2025, "twodotenleader"}, {0x2082, "twoinferior"}, {0x0032, "twooldstyle"}, {0x00b2, "twosuperior"}, {0x2154, "twothirds"}, {0x0075, "u"}, {0x00fa, "uacute"}, {0x016d, "ubreve"}, {0x00fb, "ucircumflex"}, {0x00fc, "udieresis"}, {0x00f9, "ugrave"}, {0x01b0, "uhorn"}, {0x0171, "uhungarumlaut"}, {0x016b, "umacron"}, {0x005f, "underscore"}, {0x2017, "underscoredbl"}, {0x222a, "union"}, {0x2200, "universal"}, {0x0173, "uogonek"}, {0x2580, "upblock"}, {0x03c5, "upsilon"}, {0x03cb, "upsilondieresis"}, {0x03b0, "upsilondieresistonos"}, {0x03cd, "upsilontonos"}, {0x016f, "uring"}, {0x0169, "utilde"}, {0x0076, "v"}, {0x0077, "w"}, {0x1e83, "wacute"}, {0x0175, "wcircumflex"}, {0x1e85, "wdieresis"}, {0x2118, "weierstrass"}, {0x1e81, "wgrave"}, {0x0078, "x"}, {0x03be, "xi"}, {0x0079, "y"}, {0x00fd, "yacute"}, {0x0177, "ycircumflex"}, {0x00ff, "ydieresis"}, {0x00a5, "yen"}, {0x1ef3, "ygrave"}, {0x007a, "z"}, {0x017a, "zacute"}, {0x017e, "zcaron"}, {0x017c, "zdotaccent"}, {0x0030, "zero"}, {0x2080, "zeroinferior"}, {0x0030, "zerooldstyle"}, {0x2070, "zerosuperior"}, {0x03b6, "zeta"}, {0x007b, "{"}, {0x007c, "|"}, {0x007d, "}"}, {0x007e, "~"}, { 0, NULL } }; static struct { pdf_utf16be u; const char *name; } UnicodeToNameTab[] = { {0x0000, ".notdef"}, {0x0020, "space"}, {0x0021, "exclam"}, {0x0022, "quotedbl"}, {0x0023, "numbersign"}, {0x0024, "dollar"}, {0x0025, "percent"}, {0x0026, "ampersand"}, {0x0027, "quotesingle"}, {0x0028, "parenleft"}, {0x0029, "parenright"}, {0x002A, "asterisk"}, {0x002B, "plus"}, {0x002C, "comma"}, {0x002D, "hyphen"}, {0x002E, "period"}, {0x002F, "slash"}, {0x0030, "zero"}, {0x0031, "one"}, {0x0032, "two"}, {0x0033, "three"}, {0x0034, "four"}, {0x0035, "five"}, {0x0036, "six"}, {0x0037, "seven"}, {0x0038, "eight"}, {0x0039, "nine"}, {0x003A, "colon"}, {0x003B, "semicolon"}, {0x003C, "less"}, {0x003D, "equal"}, {0x003E, "greater"}, {0x003F, "question"}, {0x0040, "at"}, {0x0041, "A"}, {0x0042, "B"}, {0x0043, "C"}, {0x0044, "D"}, {0x0045, "E"}, {0x0046, "F"}, {0x0047, "G"}, {0x0048, "H"}, {0x0049, "I"}, {0x004A, "J"}, {0x004B, "K"}, {0x004C, "L"}, {0x004D, "M"}, {0x004E, "N"}, {0x004F, "O"}, {0x0050, "P"}, {0x0051, "Q"}, {0x0052, "R"}, {0x0053, "S"}, {0x0054, "T"}, {0x0055, "U"}, {0x0056, "V"}, {0x0057, "W"}, {0x0058, "X"}, {0x0059, "Y"}, {0x005A, "Z"}, {0x005B, "bracketleft"}, {0x005C, "backslash"}, {0x005D, "bracketright"}, {0x005E, "asciicircum"}, {0x005F, "underscore"}, {0x0060, "grave"}, {0x0061, "a"}, {0x0062, "b"}, {0x0063, "c"}, {0x0064, "d"}, {0x0065, "e"}, {0x0066, "f"}, {0x0067, "g"}, {0x0068, "h"}, {0x0069, "i"}, {0x006A, "j"}, {0x006B, "k"}, {0x006C, "l"}, {0x006D, "m"}, {0x006E, "n"}, {0x006F, "o"}, {0x0070, "p"}, {0x0071, "q"}, {0x0072, "r"}, {0x0073, "s"}, {0x0074, "t"}, {0x0075, "u"}, {0x0076, "v"}, {0x0077, "w"}, {0x0078, "x"}, {0x0079, "y"}, {0x007A, "z"}, {0x007B, "braceleft"}, {0x007C, "bar"}, {0x007D, "braceright"}, {0x007E, "asciitilde"}, {0x00A0, "space"}, {0x00A1, "exclamdown"}, {0x00A2, "cent"}, {0x00A3, "sterling"}, {0x00A4, "currency"}, {0x00A5, "yen"}, {0x00A6, "brokenbar"}, {0x00A7, "section"}, {0x00A8, "dieresis"}, {0x00A9, "copyright"}, {0x00AA, "ordfeminine"}, {0x00AB, "guillemotleft"}, {0x00AC, "logicalnot"}, {0x00AD, "hyphen"}, {0x00AE, "registered"}, {0x00AF, "macron"}, {0x00B0, "degree"}, {0x00B1, "plusminus"}, {0x00B2, "twosuperior"}, {0x00B3, "threesuperior"}, {0x00B4, "acute"}, {0x00B5, "mu"}, {0x00B6, "paragraph"}, {0x00B7, "periodcentered"}, {0x00B8, "cedilla"}, {0x00B9, "onesuperior"}, {0x00BA, "ordmasculine"}, {0x00BB, "guillemotright"}, {0x00BC, "onequarter"}, {0x00BD, "onehalf"}, {0x00BE, "threequarters"}, {0x00BF, "questiondown"}, {0x00C0, "Agrave"}, {0x00C1, "Aacute"}, {0x00C2, "Acircumflex"}, {0x00C3, "Atilde"}, {0x00C4, "Adieresis"}, {0x00C5, "Aring"}, {0x00C6, "AE"}, {0x00C7, "Ccedilla"}, {0x00C8, "Egrave"}, {0x00C9, "Eacute"}, {0x00CA, "Ecircumflex"}, {0x00CB, "Edieresis"}, {0x00CC, "Igrave"}, {0x00CD, "Iacute"}, {0x00CE, "Icircumflex"}, {0x00CF, "Idieresis"}, {0x00D0, "Eth"}, {0x00D1, "Ntilde"}, {0x00D2, "Ograve"}, {0x00D3, "Oacute"}, {0x00D4, "Ocircumflex"}, {0x00D5, "Otilde"}, {0x00D6, "Odieresis"}, {0x00D7, "multiply"}, {0x00D8, "Oslash"}, {0x00D9, "Ugrave"}, {0x00DA, "Uacute"}, {0x00DB, "Ucircumflex"}, {0x00DC, "Udieresis"}, {0x00DD, "Yacute"}, {0x00DE, "Thorn"}, {0x00DF, "germandbls"}, {0x00E0, "agrave"}, {0x00E1, "aacute"}, {0x00E2, "acircumflex"}, {0x00E3, "atilde"}, {0x00E4, "adieresis"}, {0x00E5, "aring"}, {0x00E6, "ae"}, {0x00E7, "ccedilla"}, {0x00E8, "egrave"}, {0x00E9, "eacute"}, {0x00EA, "ecircumflex"}, {0x00EB, "edieresis"}, {0x00EC, "igrave"}, {0x00ED, "iacute"}, {0x00EE, "icircumflex"}, {0x00EF, "idieresis"}, {0x00F0, "eth"}, {0x00F1, "ntilde"}, {0x00F2, "ograve"}, {0x00F3, "oacute"}, {0x00F4, "ocircumflex"}, {0x00F5, "otilde"}, {0x00F6, "odieresis"}, {0x00F7, "divide"}, {0x00F8, "oslash"}, {0x00F9, "ugrave"}, {0x00FA, "uacute"}, {0x00FB, "ucircumflex"}, {0x00FC, "udieresis"}, {0x00FD, "yacute"}, {0x00FE, "thorn"}, {0x00FF, "ydieresis"}, {0x0100, "Amacron"}, {0x0101, "amacron"}, {0x0102, "Abreve"}, {0x0103, "abreve"}, {0x0104, "Aogonek"}, {0x0105, "aogonek"}, {0x0106, "Cacute"}, {0x0107, "cacute"}, {0x0108, "Ccircumflex"}, {0x0109, "ccircumflex"}, {0x010A, "Cdotaccent"}, {0x010B, "cdotaccent"}, {0x010C, "Ccaron"}, {0x010D, "ccaron"}, {0x010E, "Dcaron"}, {0x010F, "dcaron"}, {0x0110, "Dcroat"}, {0x0111, "dcroat"}, {0x0112, "Emacron"}, {0x0113, "emacron"}, {0x0114, "Ebreve"}, {0x0115, "ebreve"}, {0x0116, "Edotaccent"}, {0x0117, "edotaccent"}, {0x0118, "Eogonek"}, {0x0119, "eogonek"}, {0x011A, "Ecaron"}, {0x011B, "ecaron"}, {0x011C, "Gcircumflex"}, {0x011D, "gcircumflex"}, {0x011E, "Gbreve"}, {0x011F, "gbreve"}, {0x0120, "Gdotaccent"}, {0x0121, "gdotaccent"}, {0x0122, "Gcommaaccent"}, {0x0123, "gcommaaccent"}, {0x0124, "Hcircumflex"}, {0x0125, "hcircumflex"}, {0x0126, "Hbar"}, {0x0127, "hbar"}, {0x0128, "Itilde"}, {0x0129, "itilde"}, {0x012A, "Imacron"}, {0x012B, "imacron"}, {0x012C, "Ibreve"}, {0x012D, "ibreve"}, {0x012E, "Iogonek"}, {0x012F, "iogonek"}, {0x0130, "Idotaccent"}, {0x0131, "dotlessi"}, {0x0132, "IJ"}, {0x0133, "ij"}, {0x0134, "Jcircumflex"}, {0x0135, "jcircumflex"}, {0x0136, "Kcommaaccent"}, {0x0137, "kcommaaccent"}, {0x0138, "kgreenlandic"}, {0x0139, "Lacute"}, {0x013A, "lacute"}, {0x013B, "Lcommaaccent"}, {0x013C, "lcommaaccent"}, {0x013D, "Lcaron"}, {0x013E, "lcaron"}, {0x013F, "Ldot"}, {0x0140, "ldot"}, {0x0141, "Lslash"}, {0x0142, "lslash"}, {0x0143, "Nacute"}, {0x0144, "nacute"}, {0x0145, "Ncommaaccent"}, {0x0146, "ncommaaccent"}, {0x0147, "Ncaron"}, {0x0148, "ncaron"}, {0x0149, "napostrophe"}, {0x014A, "Eng"}, {0x014B, "eng"}, {0x014C, "Omacron"}, {0x014D, "omacron"}, {0x014E, "Obreve"}, {0x014F, "obreve"}, {0x0150, "Ohungarumlaut"}, {0x0151, "ohungarumlaut"}, {0x0152, "OE"}, {0x0153, "oe"}, {0x0154, "Racute"}, {0x0155, "racute"}, {0x0156, "Rcommaaccent"}, {0x0157, "rcommaaccent"}, {0x0158, "Rcaron"}, {0x0159, "rcaron"}, {0x015A, "Sacute"}, {0x015B, "sacute"}, {0x015C, "Scircumflex"}, {0x015D, "scircumflex"}, {0x015E, "Scedilla"}, {0x015F, "scedilla"}, {0x0160, "Scaron"}, {0x0161, "scaron"}, {0x0162, "Tcommaaccent"}, {0x0163, "tcommaaccent"}, {0x0164, "Tcaron"}, {0x0165, "tcaron"}, {0x0166, "Tbar"}, {0x0167, "tbar"}, {0x0168, "Utilde"}, {0x0169, "utilde"}, {0x016A, "Umacron"}, {0x016B, "umacron"}, {0x016C, "Ubreve"}, {0x016D, "ubreve"}, {0x016E, "Uring"}, {0x016F, "uring"}, {0x0170, "Uhungarumlaut"}, {0x0171, "uhungarumlaut"}, {0x0172, "Uogonek"}, {0x0173, "uogonek"}, {0x0174, "Wcircumflex"}, {0x0175, "wcircumflex"}, {0x0176, "Ycircumflex"}, {0x0177, "ycircumflex"}, {0x0178, "Ydieresis"}, {0x0179, "Zacute"}, {0x017A, "zacute"}, {0x017B, "Zdotaccent"}, {0x017C, "zdotaccent"}, {0x017D, "Zcaron"}, {0x017E, "zcaron"}, {0x017F, "longs"}, {0x0192, "florin"}, {0x01A0, "Ohorn"}, {0x01A1, "ohorn"}, {0x01AF, "Uhorn"}, {0x01B0, "uhorn"}, {0x01E6, "Gcaron"}, {0x01E7, "gcaron"}, {0x01FA, "Aringacute"}, {0x01FB, "aringacute"}, {0x01FC, "AEacute"}, {0x01FD, "aeacute"}, {0x01FE, "Oslashacute"}, {0x01FF, "oslashacute"}, {0x0218, "Scommaaccent"}, {0x0219, "scommaaccent"}, {0x021A, "Tcommaaccent"}, {0x021B, "tcommaaccent"}, {0x02BC, "afii57929"}, {0x02BD, "afii64937"}, {0x02C6, "circumflex"}, {0x02C7, "caron"}, {0x02C9, "macron"}, {0x02D8, "breve"}, {0x02D9, "dotaccent"}, {0x02DA, "ring"}, {0x02DB, "ogonek"}, {0x02DC, "tilde"}, {0x02DD, "hungarumlaut"}, {0x0300, "gravecomb"}, {0x0301, "acutecomb"}, {0x0303, "tildecomb"}, {0x0309, "hookabovecomb"}, {0x0323, "dotbelowcomb"}, {0x0384, "tonos"}, {0x0385, "dieresistonos"}, {0x0386, "Alphatonos"}, {0x0387, "anoteleia"}, {0x0388, "Epsilontonos"}, {0x0389, "Etatonos"}, {0x038A, "Iotatonos"}, {0x038C, "Omicrontonos"}, {0x038E, "Upsilontonos"}, {0x038F, "Omegatonos"}, {0x0390, "iotadieresistonos"}, {0x0391, "Alpha"}, {0x0392, "Beta"}, {0x0393, "Gamma"}, {0x0394, "Delta"}, {0x0395, "Epsilon"}, {0x0396, "Zeta"}, {0x0397, "Eta"}, {0x0398, "Theta"}, {0x0399, "Iota"}, {0x039A, "Kappa"}, {0x039B, "Lambda"}, {0x039C, "Mu"}, {0x039D, "Nu"}, {0x039E, "Xi"}, {0x039F, "Omicron"}, {0x03A0, "Pi"}, {0x03A1, "Rho"}, {0x03A3, "Sigma"}, {0x03A4, "Tau"}, {0x03A5, "Upsilon"}, {0x03A6, "Phi"}, {0x03A7, "Chi"}, {0x03A8, "Psi"}, {0x03A9, "Omega"}, {0x03AA, "Iotadieresis"}, {0x03AB, "Upsilondieresis"}, {0x03AC, "alphatonos"}, {0x03AD, "epsilontonos"}, {0x03AE, "etatonos"}, {0x03AF, "iotatonos"}, {0x03B0, "upsilondieresistonos"}, {0x03B1, "alpha"}, {0x03B2, "beta"}, {0x03B3, "gamma"}, {0x03B4, "delta"}, {0x03B5, "epsilon"}, {0x03B6, "zeta"}, {0x03B7, "eta"}, {0x03B8, "theta"}, {0x03B9, "iota"}, {0x03BA, "kappa"}, {0x03BB, "lambda"}, {0x03BC, "mu"}, {0x03BD, "nu"}, {0x03BE, "xi"}, {0x03BF, "omicron"}, {0x03C0, "pi"}, {0x03C1, "rho"}, {0x03C2, "sigma1"}, {0x03C3, "sigma"}, {0x03C4, "tau"}, {0x03C5, "upsilon"}, {0x03C6, "phi"}, {0x03C7, "chi"}, {0x03C8, "psi"}, {0x03C9, "omega"}, {0x03CA, "iotadieresis"}, {0x03CB, "upsilondieresis"}, {0x03CC, "omicrontonos"}, {0x03CD, "upsilontonos"}, {0x03CE, "omegatonos"}, {0x03D1, "theta1"}, {0x03D2, "Upsilon1"}, {0x03D5, "phi1"}, {0x03D6, "omega1"}, {0x0401, "afii10023"}, {0x0402, "afii10051"}, {0x0403, "afii10052"}, {0x0404, "afii10053"}, {0x0405, "afii10054"}, {0x0406, "afii10055"}, {0x0407, "afii10056"}, {0x0408, "afii10057"}, {0x0409, "afii10058"}, {0x040A, "afii10059"}, {0x040B, "afii10060"}, {0x040C, "afii10061"}, {0x040E, "afii10062"}, {0x040F, "afii10145"}, {0x0410, "afii10017"}, {0x0411, "afii10018"}, {0x0412, "afii10019"}, {0x0413, "afii10020"}, {0x0414, "afii10021"}, {0x0415, "afii10022"}, {0x0416, "afii10024"}, {0x0417, "afii10025"}, {0x0418, "afii10026"}, {0x0419, "afii10027"}, {0x041A, "afii10028"}, {0x041B, "afii10029"}, {0x041C, "afii10030"}, {0x041D, "afii10031"}, {0x041E, "afii10032"}, {0x041F, "afii10033"}, {0x0420, "afii10034"}, {0x0421, "afii10035"}, {0x0422, "afii10036"}, {0x0423, "afii10037"}, {0x0424, "afii10038"}, {0x0425, "afii10039"}, {0x0426, "afii10040"}, {0x0427, "afii10041"}, {0x0428, "afii10042"}, {0x0429, "afii10043"}, {0x042A, "afii10044"}, {0x042B, "afii10045"}, {0x042C, "afii10046"}, {0x042D, "afii10047"}, {0x042E, "afii10048"}, {0x042F, "afii10049"}, {0x0430, "afii10065"}, {0x0431, "afii10066"}, {0x0432, "afii10067"}, {0x0433, "afii10068"}, {0x0434, "afii10069"}, {0x0435, "afii10070"}, {0x0436, "afii10072"}, {0x0437, "afii10073"}, {0x0438, "afii10074"}, {0x0439, "afii10075"}, {0x043A, "afii10076"}, {0x043B, "afii10077"}, {0x043C, "afii10078"}, {0x043D, "afii10079"}, {0x043E, "afii10080"}, {0x043F, "afii10081"}, {0x0440, "afii10082"}, {0x0441, "afii10083"}, {0x0442, "afii10084"}, {0x0443, "afii10085"}, {0x0444, "afii10086"}, {0x0445, "afii10087"}, {0x0446, "afii10088"}, {0x0447, "afii10089"}, {0x0448, "afii10090"}, {0x0449, "afii10091"}, {0x044A, "afii10092"}, {0x044B, "afii10093"}, {0x044C, "afii10094"}, {0x044D, "afii10095"}, {0x044E, "afii10096"}, {0x044F, "afii10097"}, {0x0451, "afii10071"}, {0x0452, "afii10099"}, {0x0453, "afii10100"}, {0x0454, "afii10101"}, {0x0455, "afii10102"}, {0x0456, "afii10103"}, {0x0457, "afii10104"}, {0x0458, "afii10105"}, {0x0459, "afii10106"}, {0x045A, "afii10107"}, {0x045B, "afii10108"}, {0x045C, "afii10109"}, {0x045E, "afii10110"}, {0x045F, "afii10193"}, {0x0462, "afii10146"}, {0x0463, "afii10194"}, {0x0472, "afii10147"}, {0x0473, "afii10195"}, {0x0474, "afii10148"}, {0x0475, "afii10196"}, {0x0490, "afii10050"}, {0x0491, "afii10098"}, {0x04D9, "afii10846"}, {0x05B0, "afii57799"}, {0x05B1, "afii57801"}, {0x05B2, "afii57800"}, {0x05B3, "afii57802"}, {0x05B4, "afii57793"}, {0x05B5, "afii57794"}, {0x05B6, "afii57795"}, {0x05B7, "afii57798"}, {0x05B8, "afii57797"}, {0x05B9, "afii57806"}, {0x05BB, "afii57796"}, {0x05BC, "afii57807"}, {0x05BD, "afii57839"}, {0x05BE, "afii57645"}, {0x05BF, "afii57841"}, {0x05C0, "afii57842"}, {0x05C1, "afii57804"}, {0x05C2, "afii57803"}, {0x05C3, "afii57658"}, {0x05D0, "afii57664"}, {0x05D1, "afii57665"}, {0x05D2, "afii57666"}, {0x05D3, "afii57667"}, {0x05D4, "afii57668"}, {0x05D5, "afii57669"}, {0x05D6, "afii57670"}, {0x05D7, "afii57671"}, {0x05D8, "afii57672"}, {0x05D9, "afii57673"}, {0x05DA, "afii57674"}, {0x05DB, "afii57675"}, {0x05DC, "afii57676"}, {0x05DD, "afii57677"}, {0x05DE, "afii57678"}, {0x05DF, "afii57679"}, {0x05E0, "afii57680"}, {0x05E1, "afii57681"}, {0x05E2, "afii57682"}, {0x05E3, "afii57683"}, {0x05E4, "afii57684"}, {0x05E5, "afii57685"}, {0x05E6, "afii57686"}, {0x05E7, "afii57687"}, {0x05E8, "afii57688"}, {0x05E9, "afii57689"}, {0x05EA, "afii57690"}, {0x05F0, "afii57716"}, {0x05F1, "afii57717"}, {0x05F2, "afii57718"}, {0x060C, "afii57388"}, {0x061B, "afii57403"}, {0x061F, "afii57407"}, {0x0621, "afii57409"}, {0x0622, "afii57410"}, {0x0623, "afii57411"}, {0x0624, "afii57412"}, {0x0625, "afii57413"}, {0x0626, "afii57414"}, {0x0627, "afii57415"}, {0x0628, "afii57416"}, {0x0629, "afii57417"}, {0x062A, "afii57418"}, {0x062B, "afii57419"}, {0x062C, "afii57420"}, {0x062D, "afii57421"}, {0x062E, "afii57422"}, {0x062F, "afii57423"}, {0x0630, "afii57424"}, {0x0631, "afii57425"}, {0x0632, "afii57426"}, {0x0633, "afii57427"}, {0x0634, "afii57428"}, {0x0635, "afii57429"}, {0x0636, "afii57430"}, {0x0637, "afii57431"}, {0x0638, "afii57432"}, {0x0639, "afii57433"}, {0x063A, "afii57434"}, {0x0640, "afii57440"}, {0x0641, "afii57441"}, {0x0642, "afii57442"}, {0x0643, "afii57443"}, {0x0644, "afii57444"}, {0x0645, "afii57445"}, {0x0646, "afii57446"}, {0x0647, "afii57470"}, {0x0648, "afii57448"}, {0x0649, "afii57449"}, {0x064A, "afii57450"}, {0x064B, "afii57451"}, {0x064C, "afii57452"}, {0x064D, "afii57453"}, {0x064E, "afii57454"}, {0x064F, "afii57455"}, {0x0650, "afii57456"}, {0x0651, "afii57457"}, {0x0652, "afii57458"}, {0x0660, "afii57392"}, {0x0661, "afii57393"}, {0x0662, "afii57394"}, {0x0663, "afii57395"}, {0x0664, "afii57396"}, {0x0665, "afii57397"}, {0x0666, "afii57398"}, {0x0667, "afii57399"}, {0x0668, "afii57400"}, {0x0669, "afii57401"}, {0x066A, "afii57381"}, {0x066D, "afii63167"}, {0x0679, "afii57511"}, {0x067E, "afii57506"}, {0x0686, "afii57507"}, {0x0688, "afii57512"}, {0x0691, "afii57513"}, {0x0698, "afii57508"}, {0x06A4, "afii57505"}, {0x06AF, "afii57509"}, {0x06BA, "afii57514"}, {0x06D2, "afii57519"}, {0x06D5, "afii57534"}, {0x1E80, "Wgrave"}, {0x1E81, "wgrave"}, {0x1E82, "Wacute"}, {0x1E83, "wacute"}, {0x1E84, "Wdieresis"}, {0x1E85, "wdieresis"}, {0x1EF2, "Ygrave"}, {0x1EF3, "ygrave"}, {0x200C, "afii61664"}, {0x200D, "afii301"}, {0x200E, "afii299"}, {0x200F, "afii300"}, {0x2012, "figuredash"}, {0x2013, "endash"}, {0x2014, "emdash"}, {0x2015, "afii00208"}, {0x2017, "underscoredbl"}, {0x2018, "quoteleft"}, {0x2019, "quoteright"}, {0x201A, "quotesinglbase"}, {0x201B, "quotereversed"}, {0x201C, "quotedblleft"}, {0x201D, "quotedblright"}, {0x201E, "quotedblbase"}, {0x2020, "dagger"}, {0x2021, "daggerdbl"}, {0x2022, "bullet"}, {0x2024, "onedotenleader"}, {0x2025, "twodotenleader"}, {0x2026, "ellipsis"}, {0x202C, "afii61573"}, {0x202D, "afii61574"}, {0x202E, "afii61575"}, {0x2030, "perthousand"}, {0x2032, "minute"}, {0x2033, "second"}, {0x2039, "guilsinglleft"}, {0x203A, "guilsinglright"}, {0x203C, "exclamdbl"}, {0x2044, "fraction"}, {0x2070, "zerosuperior"}, {0x2074, "foursuperior"}, {0x2075, "fivesuperior"}, {0x2076, "sixsuperior"}, {0x2077, "sevensuperior"}, {0x2078, "eightsuperior"}, {0x2079, "ninesuperior"}, {0x207D, "parenleftsuperior"}, {0x207E, "parenrightsuperior"}, {0x207F, "nsuperior"}, {0x2080, "zeroinferior"}, {0x2081, "oneinferior"}, {0x2082, "twoinferior"}, {0x2083, "threeinferior"}, {0x2084, "fourinferior"}, {0x2085, "fiveinferior"}, {0x2086, "sixinferior"}, {0x2087, "seveninferior"}, {0x2088, "eightinferior"}, {0x2089, "nineinferior"}, {0x208D, "parenleftinferior"}, {0x208E, "parenrightinferior"}, {0x20A1, "colonmonetary"}, {0x20A3, "franc"}, {0x20A4, "lira"}, {0x20A7, "peseta"}, {0x20AA, "afii57636"}, {0x20AB, "dong"}, {0x20AC, "Euro"}, {0x2105, "afii61248"}, {0x2111, "Ifraktur"}, {0x2113, "afii61289"}, {0x2116, "afii61352"}, {0x2118, "weierstrass"}, {0x211C, "Rfraktur"}, {0x211E, "prescription"}, {0x2122, "trademark"}, {0x2126, "Omega"}, {0x212E, "estimated"}, {0x2135, "aleph"}, {0x2153, "onethird"}, {0x2154, "twothirds"}, {0x215B, "oneeighth"}, {0x215C, "threeeighths"}, {0x215D, "fiveeighths"}, {0x215E, "seveneighths"}, {0x2190, "arrowleft"}, {0x2191, "arrowup"}, {0x2192, "arrowright"}, {0x2193, "arrowdown"}, {0x2194, "arrowboth"}, {0x2195, "arrowupdn"}, {0x21A8, "arrowupdnbse"}, {0x21B5, "carriagereturn"}, {0x21D0, "arrowdblleft"}, {0x21D1, "arrowdblup"}, {0x21D2, "arrowdblright"}, {0x21D3, "arrowdbldown"}, {0x21D4, "arrowdblboth"}, {0x2200, "universal"}, {0x2202, "partialdiff"}, {0x2203, "existential"}, {0x2205, "emptyset"}, {0x2206, "Delta"}, {0x2207, "gradient"}, {0x2208, "element"}, {0x2209, "notelement"}, {0x220B, "suchthat"}, {0x220F, "product"}, {0x2211, "summation"}, {0x2212, "minus"}, {0x2215, "fraction"}, {0x2217, "asteriskmath"}, {0x2219, "periodcentered"}, {0x221A, "radical"}, {0x221D, "proportional"}, {0x221E, "infinity"}, {0x221F, "orthogonal"}, {0x2220, "angle"}, {0x2227, "logicaland"}, {0x2228, "logicalor"}, {0x2229, "intersection"}, {0x222A, "union"}, {0x222B, "integral"}, {0x2234, "therefore"}, {0x223C, "similar"}, {0x2245, "congruent"}, {0x2248, "approxequal"}, {0x2260, "notequal"}, {0x2261, "equivalence"}, {0x2264, "lessequal"}, {0x2265, "greaterequal"}, {0x2282, "propersubset"}, {0x2283, "propersuperset"}, {0x2284, "notsubset"}, {0x2286, "reflexsubset"}, {0x2287, "reflexsuperset"}, {0x2295, "circleplus"}, {0x2297, "circlemultiply"}, {0x22A5, "perpendicular"}, {0x22C5, "dotmath"}, {0x2302, "house"}, {0x2310, "revlogicalnot"}, {0x2320, "integraltp"}, {0x2321, "integralbt"}, {0x2329, "angleleft"}, {0x232A, "angleright"}, {0x2500, "SF100000"}, {0x2502, "SF110000"}, {0x250C, "SF010000"}, {0x2510, "SF030000"}, {0x2514, "SF020000"}, {0x2518, "SF040000"}, {0x251C, "SF080000"}, {0x2524, "SF090000"}, {0x252C, "SF060000"}, {0x2534, "SF070000"}, {0x253C, "SF050000"}, {0x2550, "SF430000"}, {0x2551, "SF240000"}, {0x2552, "SF510000"}, {0x2553, "SF520000"}, {0x2554, "SF390000"}, {0x2555, "SF220000"}, {0x2556, "SF210000"}, {0x2557, "SF250000"}, {0x2558, "SF500000"}, {0x2559, "SF490000"}, {0x255A, "SF380000"}, {0x255B, "SF280000"}, {0x255C, "SF270000"}, {0x255D, "SF260000"}, {0x255E, "SF360000"}, {0x255F, "SF370000"}, {0x2560, "SF420000"}, {0x2561, "SF190000"}, {0x2562, "SF200000"}, {0x2563, "SF230000"}, {0x2564, "SF470000"}, {0x2565, "SF480000"}, {0x2566, "SF410000"}, {0x2567, "SF450000"}, {0x2568, "SF460000"}, {0x2569, "SF400000"}, {0x256A, "SF540000"}, {0x256B, "SF530000"}, {0x256C, "SF440000"}, {0x2580, "upblock"}, {0x2584, "dnblock"}, {0x2588, "block"}, {0x258C, "lfblock"}, {0x2590, "rtblock"}, {0x2591, "ltshade"}, {0x2592, "shade"}, {0x2593, "dkshade"}, {0x25A0, "filledbox"}, {0x25A1, "H22073"}, {0x25AA, "H18543"}, {0x25AB, "H18551"}, {0x25AC, "filledrect"}, {0x25B2, "triagup"}, {0x25BA, "triagrt"}, {0x25BC, "triagdn"}, {0x25C4, "triaglf"}, {0x25CA, "lozenge"}, {0x25CB, "circle"}, {0x25CF, "H18533"}, {0x25D8, "invbullet"}, {0x25D9, "invcircle"}, {0x25E6, "openbullet"}, {0x263A, "smileface"}, {0x263B, "invsmileface"}, {0x263C, "sun"}, {0x2640, "female"}, {0x2642, "male"}, {0x2660, "spade"}, {0x2663, "club"}, {0x2665, "heart"}, {0x2666, "diamond"}, {0x266A, "musicalnote"}, {0x266B, "musicalnotedbl"}, {0xF6BE, "dotlessj"}, {0xF6BF, "LL"}, {0xF6C0, "ll"}, {0xF6C1, "Scedilla"}, {0xF6C2, "scedilla"}, {0xF6C3, "commaaccent"}, {0xF6C4, "afii10063"}, {0xF6C5, "afii10064"}, {0xF6C6, "afii10192"}, {0xF6C7, "afii10831"}, {0xF6C8, "afii10832"}, {0xF6C9, "Acute"}, {0xF6CA, "Caron"}, {0xF6CB, "Dieresis"}, {0xF6CC, "DieresisAcute"}, {0xF6CD, "DieresisGrave"}, {0xF6CE, "Grave"}, {0xF6CF, "Hungarumlaut"}, {0xF6D0, "Macron"}, {0xF6D1, "cyrBreve"}, {0xF6D2, "cyrFlex"}, {0xF6D3, "dblGrave"}, {0xF6D4, "cyrbreve"}, {0xF6D5, "cyrflex"}, {0xF6D6, "dblgrave"}, {0xF6D7, "dieresisacute"}, {0xF6D8, "dieresisgrave"}, {0xF6D9, "copyrightserif"}, {0xF6DA, "registerserif"}, {0xF6DB, "trademarkserif"}, {0xF6DC, "onefitted"}, {0xF6DD, "rupiah"}, {0xF6DE, "threequartersemdash"}, {0xF6DF, "centinferior"}, {0xF6E0, "centsuperior"}, {0xF6E1, "commainferior"}, {0xF6E2, "commasuperior"}, {0xF6E3, "dollarinferior"}, {0xF6E4, "dollarsuperior"}, {0xF6E5, "hypheninferior"}, {0xF6E6, "hyphensuperior"}, {0xF6E7, "periodinferior"}, {0xF6E8, "periodsuperior"}, {0xF6E9, "asuperior"}, {0xF6EA, "bsuperior"}, {0xF6EB, "dsuperior"}, {0xF6EC, "esuperior"}, {0xF6ED, "isuperior"}, {0xF6EE, "lsuperior"}, {0xF6EF, "msuperior"}, {0xF6F0, "osuperior"}, {0xF6F1, "rsuperior"}, {0xF6F2, "ssuperior"}, {0xF6F3, "tsuperior"}, {0xF6F4, "Brevesmall"}, {0xF6F5, "Caronsmall"}, {0xF6F6, "Circumflexsmall"}, {0xF6F7, "Dotaccentsmall"}, {0xF6F8, "Hungarumlautsmall"}, {0xF6F9, "Lslashsmall"}, {0xF6FA, "OEsmall"}, {0xF6FB, "Ogoneksmall"}, {0xF6FC, "Ringsmall"}, {0xF6FD, "Scaronsmall"}, {0xF6FE, "Tildesmall"}, {0xF6FF, "Zcaronsmall"}, {0xF721, "exclamsmall"}, {0xF724, "dollaroldstyle"}, {0xF726, "ampersandsmall"}, {0xF730, "zerooldstyle"}, {0xF731, "oneoldstyle"}, {0xF732, "twooldstyle"}, {0xF733, "threeoldstyle"}, {0xF734, "fouroldstyle"}, {0xF735, "fiveoldstyle"}, {0xF736, "sixoldstyle"}, {0xF737, "sevenoldstyle"}, {0xF738, "eightoldstyle"}, {0xF739, "nineoldstyle"}, {0xF73F, "questionsmall"}, {0xF760, "Gravesmall"}, {0xF761, "Asmall"}, {0xF762, "Bsmall"}, {0xF763, "Csmall"}, {0xF764, "Dsmall"}, {0xF765, "Esmall"}, {0xF766, "Fsmall"}, {0xF767, "Gsmall"}, {0xF768, "Hsmall"}, {0xF769, "Ismall"}, {0xF76A, "Jsmall"}, {0xF76B, "Ksmall"}, {0xF76C, "Lsmall"}, {0xF76D, "Msmall"}, {0xF76E, "Nsmall"}, {0xF76F, "Osmall"}, {0xF770, "Psmall"}, {0xF771, "Qsmall"}, {0xF772, "Rsmall"}, {0xF773, "Ssmall"}, {0xF774, "Tsmall"}, {0xF775, "Usmall"}, {0xF776, "Vsmall"}, {0xF777, "Wsmall"}, {0xF778, "Xsmall"}, {0xF779, "Ysmall"}, {0xF77A, "Zsmall"}, {0xF7A1, "exclamdownsmall"}, {0xF7A2, "centoldstyle"}, {0xF7A8, "Dieresissmall"}, {0xF7AF, "Macronsmall"}, {0xF7B4, "Acutesmall"}, {0xF7B8, "Cedillasmall"}, {0xF7BF, "questiondownsmall"}, {0xF7E0, "Agravesmall"}, {0xF7E1, "Aacutesmall"}, {0xF7E2, "Acircumflexsmall"}, {0xF7E3, "Atildesmall"}, {0xF7E4, "Adieresissmall"}, {0xF7E5, "Aringsmall"}, {0xF7E6, "AEsmall"}, {0xF7E7, "Ccedillasmall"}, {0xF7E8, "Egravesmall"}, {0xF7E9, "Eacutesmall"}, {0xF7EA, "Ecircumflexsmall"}, {0xF7EB, "Edieresissmall"}, {0xF7EC, "Igravesmall"}, {0xF7ED, "Iacutesmall"}, {0xF7EE, "Icircumflexsmall"}, {0xF7EF, "Idieresissmall"}, {0xF7F0, "Ethsmall"}, {0xF7F1, "Ntildesmall"}, {0xF7F2, "Ogravesmall"}, {0xF7F3, "Oacutesmall"}, {0xF7F4, "Ocircumflexsmall"}, {0xF7F5, "Otildesmall"}, {0xF7F6, "Odieresissmall"}, {0xF7F8, "Oslashsmall"}, {0xF7F9, "Ugravesmall"}, {0xF7FA, "Uacutesmall"}, {0xF7FB, "Ucircumflexsmall"}, {0xF7FC, "Udieresissmall"}, {0xF7FD, "Yacutesmall"}, {0xF7FE, "Thornsmall"}, {0xF7FF, "Ydieresissmall"}, {0xF8E5, "radicalex"}, {0xF8E6, "arrowvertex"}, {0xF8E7, "arrowhorizex"}, {0xF8E8, "registersans"}, {0xF8E9, "copyrightsans"}, {0xF8EA, "trademarksans"}, {0xF8EB, "parenlefttp"}, {0xF8EC, "parenleftex"}, {0xF8ED, "parenleftbt"}, {0xF8EE, "bracketlefttp"}, {0xF8EF, "bracketleftex"}, {0xF8F0, "bracketleftbt"}, {0xF8F1, "bracelefttp"}, {0xF8F2, "braceleftmid"}, {0xF8F3, "braceleftbt"}, {0xF8F4, "braceex"}, {0xF8F5, "integralex"}, {0xF8F6, "parenrighttp"}, {0xF8F7, "parenrightex"}, {0xF8F8, "parenrightbt"}, {0xF8F9, "bracketrighttp"}, {0xF8FA, "bracketrightex"}, {0xF8FB, "bracketrightbt"}, {0xF8FC, "bracerighttp"}, {0xF8FD, "bracerightmid"}, {0xF8FE, "bracerightbt"}, {0xFB00, "ff"}, {0xFB01, "fi"}, {0xFB02, "fl"}, {0xFB03, "ffi"}, {0xFB04, "ffl"}, {0xFB1F, "afii57705"}, {0xFB2A, "afii57694"}, {0xFB2B, "afii57695"}, {0xFB35, "afii57723"}, {0xFB4B, "afii57700"}, {0xFFFF, NULL} }; PdfEncodingDifference::PdfEncodingDifference() { } PdfEncodingDifference::PdfEncodingDifference( const PdfEncodingDifference & rhs ) { this->operator=( rhs ); } const PdfEncodingDifference & PdfEncodingDifference::operator=( const PdfEncodingDifference & rhs ) { m_vecDifferences = rhs.m_vecDifferences; return *this; } void PdfEncodingDifference::AddDifference( int nCode, pdf_utf16be unicodeValue ) { pdf_utf16be inCodePoint = unicodeValue; #ifdef PODOFO_IS_LITTLE_ENDIAN inCodePoint = ((inCodePoint & 0xff00) >> 8) | ((inCodePoint & 0xff) << 8); #endif // PODOFO_IS_LITTLE_ENDIAN this->AddDifference( nCode, unicodeValue, PdfDifferenceEncoding::UnicodeIDToName( inCodePoint ) ); } void PdfEncodingDifference::AddDifference( int nCode, pdf_utf16be unicodeValue, const PdfName & rName, bool bExplicitNames ) { if( nCode > 255 || nCode < 0 ) { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } TDifference dif; dif.nCode = nCode; dif.name = rName; // In type3 fonts, glyph names are explicit keys from the font's CharProcs // dictionary, therefore they have no meaning. // By setting unicodeValue to nCode, we keep PdfEncodingDifference::Contains // from calling PdfDifferenceEncoding::NameToUnicodeID, which would return 0 // after looking it up in the unicode tables. This allows us, provided the // font's encoding is unicode-compatible, to preserve the characters' codes // in the process. This seems to be Adobe Reader's behaviour as well. if (bExplicitNames) { #ifdef PODOFO_IS_LITTLE_ENDIAN dif.unicodeValue = ((nCode & 0xff00) >> 8) | ((nCode & 0xff) << 8); #else dif.unicodeValue = nCode; #endif // PODOFO_IS_LITTLE_ENDIAN } else { dif.unicodeValue = unicodeValue; } std::pair it = std::equal_range( m_vecDifferences.begin(), m_vecDifferences.end(), dif, DifferenceComparatorPredicate() ); if( it.first != it.second ) { // replace existing object *(it.first) = dif; } else { m_vecDifferences.insert( it.first, dif ); } } bool PdfEncodingDifference::Contains( int nCode, PdfName & rName, pdf_utf16be & rValue ) const { TDifference dif; dif.nCode = nCode; std::pair it = std::equal_range( const_cast(this)->m_vecDifferences.begin(), const_cast(this)->m_vecDifferences.end(), dif, DifferenceComparatorPredicate() ); if( it.first != it.second ) { rName = (*(it.first)).name; if( !(*(it.first)).unicodeValue ) // Field is not yet initialized, // initialize it now, so that we only // compute the value if it is needed. (*(it.first)).unicodeValue = PdfDifferenceEncoding::NameToUnicodeID( rName ); rValue = (*(it.first)).unicodeValue; return true; } return false; } bool PdfEncodingDifference::ContainsUnicodeValue( pdf_utf16be unicodeValue, char &rValue ) const { #ifdef PODOFO_IS_LITTLE_ENDIAN unicodeValue = ((unicodeValue & 0xff00) >> 8) | ((unicodeValue & 0xff) << 8); #endif // PODOFO_IS_LITTLE_ENDIAN TCIVecDifferences it, end = m_vecDifferences.end(); for (it = m_vecDifferences.begin(); it != end; it++) { pdf_utf16be uv = it->unicodeValue; if (uv == unicodeValue) { rValue = it->nCode; return true; } } return false; } void PdfEncodingDifference::ToArray( PdfArray & rArray ) { pdf_int64 nLastCode = -2; rArray.Clear(); TCIVecDifferences it = m_vecDifferences.begin(); while( it != m_vecDifferences.end() ) { if( (*it).nCode != nLastCode + 1 ) { nLastCode = (*it).nCode; rArray.push_back( nLastCode ); rArray.push_back( (*it).name ); } else { ++nLastCode; rArray.push_back( (*it).name ); } ++it; } } // ----------------------------------------------------- // PdfDifferenceEncoding // ----------------------------------------------------- PdfDifferenceEncoding::PdfDifferenceEncoding( const PdfEncodingDifference & rDifference, PdfDocument* pParent, bool bAutoDelete ) : PdfEncoding( 0x00, 0xff ), PdfElement( "Encoding", pParent ), m_differences( rDifference ), m_bAutoDelete( bAutoDelete ), m_baseEncoding( eBaseEncoding_Font ) { Init(); } PdfDifferenceEncoding::PdfDifferenceEncoding( const PdfEncodingDifference & rDifference, PdfVecObjects* pParent, bool bAutoDelete ) : PdfEncoding( 0x00, 0xff ), PdfElement( "Encoding", pParent ), m_differences( rDifference ), m_bAutoDelete( bAutoDelete ), m_baseEncoding( eBaseEncoding_Font ) { Init(); } PdfDifferenceEncoding::PdfDifferenceEncoding( const PdfEncodingDifference & rDifference, EBaseEncoding eBaseEncoding, PdfDocument* pParent, bool bAutoDelete ) : PdfEncoding( 0x00, 0xff ), PdfElement( "Encoding", pParent ), m_differences( rDifference ), m_bAutoDelete( bAutoDelete ), m_baseEncoding( eBaseEncoding ) { Init(); } PdfDifferenceEncoding::PdfDifferenceEncoding( const PdfEncodingDifference & rDifference, EBaseEncoding eBaseEncoding, PdfVecObjects* pParent, bool bAutoDelete ) : PdfEncoding( 0x00, 0xff ), PdfElement( "Encoding", pParent ), m_differences( rDifference ), m_bAutoDelete( bAutoDelete ), m_baseEncoding( eBaseEncoding ) { Init(); } PdfDifferenceEncoding::PdfDifferenceEncoding( PdfObject* pObject, bool bAutoDelete, bool bExplicitNames ) : PdfEncoding( 0x00, 0xff ), PdfElement( NULL, pObject ), m_bAutoDelete( bAutoDelete ) { CreateID(); m_baseEncoding = eBaseEncoding_WinAnsi; if( this->GetObject()->GetDictionary().HasKey( PdfName("BaseEncoding") ) ) { const PdfName & rBase = this->GetObject()->GetDictionary().GetKey( PdfName("BaseEncoding") )->GetName(); if( rBase == PdfName("WinAnsiEncoding") ) m_baseEncoding = eBaseEncoding_WinAnsi; else if( rBase == PdfName("MacRomanEncoding") ) m_baseEncoding = eBaseEncoding_MacRoman; else if( rBase == PdfName("MacExpertEncoding") ) m_baseEncoding = eBaseEncoding_MacExpert; } // Read the differences key if( this->GetObject()->GetDictionary().HasKey( PdfName("Differences") ) ) { const PdfArray & rDifferences = this->GetObject()->GetIndirectKey( PdfName("Differences") )->GetArray(); PdfArray::const_iterator it = rDifferences.begin(); pdf_int64 curCode = -1; while( it != rDifferences.end() ) { if( (*it).IsNumber() ) curCode = (*it).GetNumber(); else if( (*it).IsName() ) { m_differences.AddDifference( static_cast(curCode), 0, (*it).GetName(), bExplicitNames ); ++curCode; } ++it; } } } void PdfDifferenceEncoding::CreateID() { std::ostringstream oss; oss << "/DifferencesEncoding" << this->GetObject()->Reference().ObjectNumber() << "_" << this->GetObject()->Reference().GenerationNumber(); m_id = PdfName( oss.str() ); } void PdfDifferenceEncoding::Init() { CreateID(); switch( m_baseEncoding ) { case eBaseEncoding_WinAnsi: this->GetObject()->GetDictionary().AddKey( PdfName("BaseEncoding"), PdfName("WinAnsiEncoding") ); break; case eBaseEncoding_MacRoman: this->GetObject()->GetDictionary().AddKey( PdfName("BaseEncoding"), PdfName("MacRomanEncoding") ); break; case eBaseEncoding_MacExpert: this->GetObject()->GetDictionary().AddKey( PdfName("BaseEncoding"), PdfName("MacExpertEncoding") ); break; case eBaseEncoding_Font: default: break; } if( m_differences.GetCount() ) { PdfArray differences; m_differences.ToArray( differences ); this->GetObject()->GetDictionary().AddKey( PdfName("Differences"), differences ); } } void PdfDifferenceEncoding::AddToDictionary( PdfDictionary & rDictionary ) const { rDictionary.AddKey( PdfName("Encoding"), this->GetObject()->Reference() ); } pdf_utf16be PdfDifferenceEncoding::GetCharCode( int nIndex ) const { if( nIndex < this->GetFirstChar() || nIndex > this->GetLastChar() ) { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } PdfName name; pdf_utf16be value; if( m_differences.Contains( nIndex, name, value ) ) { return value; } else { const PdfEncoding* pEncoding = this->GetBaseEncoding(); return pEncoding->GetCharCode( nIndex ); } } pdf_utf16be PdfDifferenceEncoding::NameToUnicodeID( const PdfName & rName ) { const char* pszName = rName.GetName().c_str(); for( int i = 0; nameToUnicodeTab[i].name; ++i) { if ( strcmp( nameToUnicodeTab[i].name, pszName ) == 0 ) #ifdef PODOFO_IS_LITTLE_ENDIAN return ((nameToUnicodeTab[i].u & 0xff00) >> 8) | ((nameToUnicodeTab[i].u & 0xff) << 8); #else return nameToUnicodeTab[i].u; #endif // PODOFO_IS_LITTLE_ENDIAN } // if we get here, then we might be looking up an undefined codepoint // so try looking for our special format.. if( strncmp( "uni", pszName, 3 ) == 0 ) { pszName += 3; // remove "uni" size_t length = strlen( pszName ); // force base16 IF it's 4 characters line pdf_utf16be val = static_cast(strtol( pszName, NULL, (length == 4 ? 16 : 10) )); #ifdef PODOFO_IS_LITTLE_ENDIAN return val = ((val & 0xff00) >> 8) | ((val & 0xff) << 8); #else return val; #endif // PODOFO_IS_LITTLE_ENDIAN } return 0; } PdfName PdfDifferenceEncoding::UnicodeIDToName( pdf_utf16be inCodePoint ) { #ifdef PODOFO_IS_LITTLE_ENDIAN inCodePoint = ((inCodePoint & 0xff00) >> 8) | ((inCodePoint & 0xff) << 8); #endif // PODOFO_IS_LITTLE_ENDIAN int i; for( i = 0; UnicodeToNameTab[i].name; ++i) { if ( UnicodeToNameTab[i].u == inCodePoint ) return PdfName( UnicodeToNameTab[i].name ); } // if we can't find in the canonical list, look in the complete list for ( i = 0; nameToUnicodeTab[i].name; ++i) { if ( nameToUnicodeTab[i].u == inCodePoint ) return PdfName( UnicodeToNameTab[i].name ); } // if we get here, then we are looking up an undefined codepoint // so we'll just give it SOME name.. const int BUFFER_LEN = 8; char buffer[BUFFER_LEN]; snprintf( buffer, BUFFER_LEN, "uni%04x", inCodePoint ); return PdfName( buffer ); //return PdfName(".notdef"); } PdfString PdfDifferenceEncoding::ConvertToUnicode( const PdfString & rEncodedString, const PdfFont* pFont ) const { const PdfEncoding* pEncoding = GetBaseEncoding(); PdfString str = pEncoding->ConvertToUnicode( rEncodedString, pFont ); pdf_long lLen = str.GetCharacterLength(); pdf_utf16be* pszUtf16 = static_cast(podofo_calloc(lLen, sizeof(pdf_utf16be))); if( !pszUtf16 ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } memcpy( pszUtf16, str.GetUnicode(), lLen * sizeof(pdf_utf16be) ); for( pdf_long i=0;i> 8) | ((val & 0xff) << 8); #endif // PODOFO_IS_LITTLE_ENDIAN PdfName name; pdf_utf16be value; if( m_differences.Contains( static_cast(val), name, value ) ) pszUtf16[i] = value; } PdfString ret( pszUtf16, lLen ); podofo_free( pszUtf16 ); return ret; } PdfRefCountedBuffer PdfDifferenceEncoding::ConvertToEncoding( const PdfString & rString, const PdfFont* /*pFont*/ ) const { const PdfEncoding* pEncoding = GetBaseEncoding(); pdf_utf16be* pszUtf16 = NULL; pdf_long lLen = 0; if( rString.IsUnicode() ) { lLen = rString.GetCharacterLength(); if( !lLen ) return PdfRefCountedBuffer(); pszUtf16 = static_cast(podofo_calloc(lLen,sizeof(pdf_utf16be))); if( !pszUtf16 ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } memcpy( pszUtf16, rString.GetUnicode(), lLen * sizeof(pdf_utf16be) ); } else { // Only do a copy if we really have to PdfString str = rString.ToUnicode(); lLen = str.GetCharacterLength(); if( !lLen ) return PdfRefCountedBuffer(); pszUtf16 = static_cast(podofo_calloc(lLen,sizeof(pdf_utf16be))); if( !pszUtf16 ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } memcpy( pszUtf16, str.GetUnicode(), lLen * sizeof(pdf_utf16be) ); } char* pDest = static_cast(podofo_calloc( (lLen + 1), sizeof(char) )); if( !pDest ) { PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } char *pCur = pDest; long lNewLen = 0L; for( int i=0;i(pEncoding)->GetUnicodeCharCode(val); } if( *pCur) // ignore 0 characters, as they cannot be converted to the current encoding { ++pCur; ++lNewLen; } } *pCur = '\0'; PdfRefCountedBuffer cDest( lNewLen ); memcpy( cDest.GetBuffer(), pDest, lNewLen ); podofo_free( pDest ); podofo_free( pszUtf16 ); return cDest; } const PdfEncoding* PdfDifferenceEncoding::GetBaseEncoding() const { const PdfEncoding* pEncoding = NULL; switch( m_baseEncoding ) { case eBaseEncoding_WinAnsi: pEncoding = PdfEncodingFactory::GlobalWinAnsiEncodingInstance(); break; case eBaseEncoding_MacRoman: pEncoding = PdfEncodingFactory::GlobalMacRomanEncodingInstance(); break; case eBaseEncoding_MacExpert: case eBaseEncoding_Font: default: break; } if( !pEncoding ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } return pEncoding; } }; /* PoDoFo */ podofo-0.9.5/src/doc/PdfCMapEncoding.cpp0000664000175000017500000002306112715357362017661 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2011 by Dominik Seichter * * domseichter@web.de * * * * Pdf CMAP encoding by kalyan * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfCMapEncoding.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfEncodingFactory.h" #include "base/PdfObject.h" #include "base/PdfVariant.h" #include "base/PdfLocale.h" #include "base/PdfStream.h" #include "base/PdfContentsTokenizer.h" #include #include #include #include using namespace std; namespace PoDoFo { PdfCMapEncoding::PdfCMapEncoding (PdfObject * pObject, PdfObject * pToUnicode) : PdfEncoding(0x0000, 0xffff, pToUnicode), PdfElement(NULL, pObject), m_baseEncoding( eBaseEncoding_Font ) { if (pObject && pObject->HasStream()) { std::stack stkToken; pdf_uint16 loop = 0; char *streamBuffer; const char *streamToken = NULL; EPdfTokenType *streamTokenType = NULL; pdf_long streamBufferLen; bool in_begincidrange = 0; bool in_begincidchar = 0; pdf_uint16 range_entries = 0; pdf_uint16 char_entries = 0; pdf_uint16 inside_hex_string = 0; pdf_uint16 inside_array = 0; pdf_uint16 range_start = 0; pdf_uint16 range_end = 0; pdf_uint16 i = 0; pdf_utf16be firstvalue = 0; const PdfStream *CIDStreamdata = pObject->GetStream (); CIDStreamdata->GetFilteredCopy (&streamBuffer, &streamBufferLen); PdfContentsTokenizer streamTokenizer (streamBuffer, streamBufferLen); while (streamTokenizer.GetNextToken (streamToken, streamTokenType)) { stkToken.push (streamToken); if (strcmp (streamToken, ">") == 0) { if (inside_hex_string == 0) PODOFO_RAISE_ERROR_INFO(ePdfError_InvalidStream, "CMap Error, got > before <") else inside_hex_string = 0; i++; } if (strcmp (streamToken, "]") == 0) { if (inside_array == 0) PODOFO_RAISE_ERROR_INFO(ePdfError_InvalidStream, "CMap Error, got ] before [") else inside_array = 0; i++; } if (in_begincidrange == 1) { if (loop < range_entries) { if (inside_hex_string == 1) { pdf_utf16be num_value; std::stringstream ss; ss << std::hex << streamToken; ss >> num_value; if (i % 3 == 0) range_start = num_value; if (i % 3 == 1) { range_end = num_value; } if (i % 3 == 2) { for (int k = range_start; k <= range_end; k++) { m_cMap[k] = num_value; num_value++; } loop++; } } } } if (in_begincidchar == 1) { if (loop < char_entries) { if (inside_hex_string == 1) { pdf_utf16be num_value; std::stringstream ss; ss << std::hex << streamToken; ss >> num_value; if (i % 2 == 0) { firstvalue = num_value; } if (i % 2 == 1) { m_cMap[firstvalue] = num_value; } } } } if (strcmp (streamToken, "<") == 0) { inside_hex_string = 1; } if (strcmp (streamToken, "[") == 0) { inside_array = 1; } if (strcmp (streamToken, "begincidrange") == 0) { i = loop = 0; in_begincidrange = 1; stkToken.pop (); std::stringstream ss; ss << std::hex << stkToken.top (); ss >> range_entries; } if (strcmp (streamToken, "endcidrange") == 0) { in_begincidrange = 0; i = 0; } if (strcmp (streamToken, "begincidchar") == 0) { i = loop = 0; in_begincidchar = 1; stkToken.pop (); std::stringstream ss; ss << std::hex << stkToken.top (); ss >> char_entries; } if (strcmp (streamToken, "endcidchar") == 0) { in_begincidchar = 0; i = 0; } } podofo_free(streamBuffer); } } void PdfCMapEncoding::AddToDictionary(PdfDictionary &) const { } const PdfEncoding* PdfCMapEncoding::GetBaseEncoding() const { const PdfEncoding* pEncoding = NULL; switch( m_baseEncoding ) { case eBaseEncoding_WinAnsi: pEncoding = PdfEncodingFactory::GlobalWinAnsiEncodingInstance(); break; case eBaseEncoding_MacRoman: pEncoding = PdfEncodingFactory::GlobalMacRomanEncodingInstance(); break; case eBaseEncoding_MacExpert: case eBaseEncoding_Font: default: break; } if( !pEncoding ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } return pEncoding; } PdfString PdfCMapEncoding::ConvertToUnicode(const PdfString & rEncodedString, const PdfFont* pFont) const { if(m_bToUnicodeIsLoaded) { return PdfEncoding::ConvertToUnicode(rEncodedString, pFont); } else PODOFO_RAISE_ERROR( ePdfError_NotImplemented ); } PdfRefCountedBuffer PdfCMapEncoding::ConvertToEncoding( const PdfString & rString, const PdfFont* pFont ) const { if(m_bToUnicodeIsLoaded) { return PdfEncoding::ConvertToEncoding(rString, pFont); } else PODOFO_RAISE_ERROR( ePdfError_NotImplemented ); } bool PdfCMapEncoding::IsSingleByteEncoding() const { return false; } bool PdfCMapEncoding::IsAutoDelete() const { return true; } pdf_utf16be PdfCMapEncoding::GetCharCode( int nIndex ) const { if( nIndex < this->GetFirstChar() || nIndex > this->GetLastChar() ) { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } #ifdef PODOFO_IS_LITTLE_ENDIAN return ((nIndex & 0xff00) >> 8) | ((nIndex & 0xff) << 8); #else return static_cast(nIndex); #endif // PODOFO_IS_LITTLE_ENDIAN } const PdfName & PdfCMapEncoding::GetID() const { PODOFO_RAISE_ERROR( ePdfError_NotImplemented ); } }; podofo-0.9.5/src/doc/PdfFontFactoryBase14Data.h0000664000175000017500000032422112344436402021020 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_FONT_FACTORY_BASE14_DATA_H_ #define _PDF_FONT_FACTORY_BASE14_DATA_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfRect.h" #include "PdfFontMetricsBase14.h" /* * The following are the Base 14 fonts data copied from libharu. * - kaushik April 12 2010 */ namespace PoDoFo { struct PODOFO_CharData { pdf_int16 char_cd; pdf_uint16 unicode; pdf_int16 width; } ; static const PODOFO_CharData CHAR_DATA_COURIER[316] = { {32, 0x0020, 600}, {33, 0x0021, 600}, {34, 0x0022, 600}, {35, 0x0023, 600}, {36, 0x0024, 600}, {37, 0x0025, 600}, {38, 0x0026, 600}, {39, 0x2019, 600}, {40, 0x0028, 600}, {41, 0x0029, 600}, {42, 0x002A, 600}, {43, 0x002B, 600}, {44, 0x002C, 600}, {45, 0x002D, 600}, {46, 0x002E, 600}, {47, 0x002F, 600}, {48, 0x0030, 600}, {49, 0x0031, 600}, {50, 0x0032, 600}, {51, 0x0033, 600}, {52, 0x0034, 600}, {53, 0x0035, 600}, {54, 0x0036, 600}, {55, 0x0037, 600}, {56, 0x0038, 600}, {57, 0x0039, 600}, {58, 0x003A, 600}, {59, 0x003B, 600}, {60, 0x003C, 600}, {61, 0x003D, 600}, {62, 0x003E, 600}, {63, 0x003F, 600}, {64, 0x0040, 600}, {65, 0x0041, 600}, {66, 0x0042, 600}, {67, 0x0043, 600}, {68, 0x0044, 600}, {69, 0x0045, 600}, {70, 0x0046, 600}, {71, 0x0047, 600}, {72, 0x0048, 600}, {73, 0x0049, 600}, {74, 0x004A, 600}, {75, 0x004B, 600}, {76, 0x004C, 600}, {77, 0x004D, 600}, {78, 0x004E, 600}, {79, 0x004F, 600}, {80, 0x0050, 600}, {81, 0x0051, 600}, {82, 0x0052, 600}, {83, 0x0053, 600}, {84, 0x0054, 600}, {85, 0x0055, 600}, {86, 0x0056, 600}, {87, 0x0057, 600}, {88, 0x0058, 600}, {89, 0x0059, 600}, {90, 0x005A, 600}, {91, 0x005B, 600}, {92, 0x005C, 600}, {93, 0x005D, 600}, {94, 0x005E, 600}, {95, 0x005F, 600}, {96, 0x2018, 600}, {97, 0x0061, 600}, {98, 0x0062, 600}, {99, 0x0063, 600}, {100, 0x0064, 600}, {101, 0x0065, 600}, {102, 0x0066, 600}, {103, 0x0067, 600}, {104, 0x0068, 600}, {105, 0x0069, 600}, {106, 0x006A, 600}, {107, 0x006B, 600}, {108, 0x006C, 600}, {109, 0x006D, 600}, {110, 0x006E, 600}, {111, 0x006F, 600}, {112, 0x0070, 600}, {113, 0x0071, 600}, {114, 0x0072, 600}, {115, 0x0073, 600}, {116, 0x0074, 600}, {117, 0x0075, 600}, {118, 0x0076, 600}, {119, 0x0077, 600}, {120, 0x0078, 600}, {121, 0x0079, 600}, {122, 0x007A, 600}, {123, 0x007B, 600}, {124, 0x007C, 600}, {125, 0x007D, 600}, {126, 0x007E, 600}, {161, 0x00A1, 600}, {162, 0x00A2, 600}, {163, 0x00A3, 600}, {164, 0x2044, 600}, {165, 0x00A5, 600}, {166, 0x0192, 600}, {167, 0x00A7, 600}, {168, 0x00A4, 600}, {169, 0x0027, 600}, {170, 0x201C, 600}, {171, 0x00AB, 600}, {172, 0x2039, 600}, {173, 0x203A, 600}, {174, 0xFB01, 600}, {175, 0xFB02, 600}, {177, 0x2013, 600}, {178, 0x2020, 600}, {179, 0x2021, 600}, {180, 0x00B7, 600}, {182, 0x00B6, 600}, {183, 0x2022, 600}, {184, 0x201A, 600}, {185, 0x201E, 600}, {186, 0x201D, 600}, {187, 0x00BB, 600}, {188, 0x2026, 600}, {189, 0x2030, 600}, {191, 0x00BF, 600}, {193, 0x0060, 600}, {194, 0x00B4, 600}, {195, 0x02C6, 600}, {196, 0x02DC, 600}, {197, 0x00AF, 600}, {198, 0x02D8, 600}, {199, 0x02D9, 600}, {200, 0x00A8, 600}, {202, 0x02DA, 600}, {203, 0x00B8, 600}, {205, 0x02DD, 600}, {206, 0x02DB, 600}, {207, 0x02C7, 600}, {208, 0x2014, 600}, {225, 0x00C6, 600}, {227, 0x00AA, 600}, {232, 0x0141, 600}, {233, 0x00D8, 600}, {234, 0x0152, 600}, {235, 0x00BA, 600}, {241, 0x00E6, 600}, {245, 0x0131, 600}, {248, 0x0142, 600}, {249, 0x00F8, 600}, {250, 0x0153, 600}, {251, 0x00DF, 600}, {-1, 0x00CF, 600}, {-1, 0x00E9, 600}, {-1, 0x0103, 600}, {-1, 0x0171, 600}, {-1, 0x011B, 600}, {-1, 0x0178, 600}, {-1, 0x00F7, 600}, {-1, 0x00DD, 600}, {-1, 0x00C2, 600}, {-1, 0x00E1, 600}, {-1, 0x00DB, 600}, {-1, 0x00FD, 600}, {-1, 0x0219, 600}, {-1, 0x00EA, 600}, {-1, 0x016E, 600}, {-1, 0x00DC, 600}, {-1, 0x0105, 600}, {-1, 0x00DA, 600}, {-1, 0x0173, 600}, {-1, 0x00CB, 600}, {-1, 0x0110, 600}, {-1, 0xF6C3, 600}, {-1, 0x00A9, 600}, {-1, 0x0112, 600}, {-1, 0x010D, 600}, {-1, 0x00E5, 600}, {-1, 0x0145, 600}, {-1, 0x013A, 600}, {-1, 0x00E0, 600}, {-1, 0x0162, 600}, {-1, 0x0106, 600}, {-1, 0x00E3, 600}, {-1, 0x0116, 600}, {-1, 0x0161, 600}, {-1, 0x015F, 600}, {-1, 0x00ED, 600}, {-1, 0x25CA, 600}, {-1, 0x0158, 600}, {-1, 0x0122, 600}, {-1, 0x00FB, 600}, {-1, 0x00E2, 600}, {-1, 0x0100, 600}, {-1, 0x0159, 600}, {-1, 0x00E7, 600}, {-1, 0x017B, 600}, {-1, 0x00DE, 600}, {-1, 0x014C, 600}, {-1, 0x0154, 600}, {-1, 0x015A, 600}, {-1, 0x010F, 600}, {-1, 0x016A, 600}, {-1, 0x016F, 600}, {-1, 0x00B3, 600}, {-1, 0x00D2, 600}, {-1, 0x00C0, 600}, {-1, 0x0102, 600}, {-1, 0x00D7, 600}, {-1, 0x00FA, 600}, {-1, 0x0164, 600}, {-1, 0x2202, 600}, {-1, 0x00FF, 600}, {-1, 0x0143, 600}, {-1, 0x00EE, 600}, {-1, 0x00CA, 600}, {-1, 0x00E4, 600}, {-1, 0x00EB, 600}, {-1, 0x0107, 600}, {-1, 0x0144, 600}, {-1, 0x016B, 600}, {-1, 0x0147, 600}, {-1, 0x00CD, 600}, {-1, 0x00B1, 600}, {-1, 0x00A6, 600}, {-1, 0x00AE, 600}, {-1, 0x011E, 600}, {-1, 0x0130, 600}, {-1, 0x2211, 600}, {-1, 0x00C8, 600}, {-1, 0x0155, 600}, {-1, 0x014D, 600}, {-1, 0x0179, 600}, {-1, 0x017D, 600}, {-1, 0x2265, 600}, {-1, 0x00D0, 600}, {-1, 0x00C7, 600}, {-1, 0x013C, 600}, {-1, 0x0165, 600}, {-1, 0x0119, 600}, {-1, 0x0172, 600}, {-1, 0x00C1, 600}, {-1, 0x00C4, 600}, {-1, 0x00E8, 600}, {-1, 0x017A, 600}, {-1, 0x012F, 600}, {-1, 0x00D3, 600}, {-1, 0x00F3, 600}, {-1, 0x0101, 600}, {-1, 0x015B, 600}, {-1, 0x00EF, 600}, {-1, 0x00D4, 600}, {-1, 0x00D9, 600}, {-1, 0x0394, 600}, {-1, 0x00FE, 600}, {-1, 0x00B2, 600}, {-1, 0x00D6, 600}, {-1, 0x00B5, 600}, {-1, 0x00EC, 600}, {-1, 0x0151, 600}, {-1, 0x0118, 600}, {-1, 0x0111, 600}, {-1, 0x00BE, 600}, {-1, 0x015E, 600}, {-1, 0x013E, 600}, {-1, 0x0136, 600}, {-1, 0x0139, 600}, {-1, 0x2122, 600}, {-1, 0x0117, 600}, {-1, 0x00CC, 600}, {-1, 0x012A, 600}, {-1, 0x013D, 600}, {-1, 0x00BD, 600}, {-1, 0x2264, 600}, {-1, 0x00F4, 600}, {-1, 0x00F1, 600}, {-1, 0x0170, 600}, {-1, 0x00C9, 600}, {-1, 0x0113, 600}, {-1, 0x011F, 600}, {-1, 0x00BC, 600}, {-1, 0x0160, 600}, {-1, 0x0218, 600}, {-1, 0x0150, 600}, {-1, 0x00B0, 600}, {-1, 0x00F2, 600}, {-1, 0x010C, 600}, {-1, 0x00F9, 600}, {-1, 0x221A, 600}, {-1, 0x010E, 600}, {-1, 0x0157, 600}, {-1, 0x00D1, 600}, {-1, 0x00F5, 600}, {-1, 0x0156, 600}, {-1, 0x013B, 600}, {-1, 0x00C3, 600}, {-1, 0x0104, 600}, {-1, 0x00C5, 600}, {-1, 0x00D5, 600}, {-1, 0x017C, 600}, {-1, 0x011A, 600}, {-1, 0x012E, 600}, {-1, 0x0137, 600}, {-1, 0x2212, 600}, {-1, 0x00CE, 600}, {-1, 0x0148, 600}, {-1, 0x0163, 600}, {-1, 0x00AC, 600}, {-1, 0x00F6, 600}, {-1, 0x00FC, 600}, {-1, 0x2260, 600}, {-1, 0x0123, 600}, {-1, 0x00F0, 600}, {-1, 0x017E, 600}, {-1, 0x0146, 600}, {-1, 0x00B9, 600}, {-1, 0x012B, 600}, {-1, 0x20AC, 600}, {-1, 0xFFFF, 0} }; static const PODOFO_CharData CHAR_DATA_COURIER_BOLD[316] = { {32, 0x0020, 600}, {33, 0x0021, 600}, {34, 0x0022, 600}, {35, 0x0023, 600}, {36, 0x0024, 600}, {37, 0x0025, 600}, {38, 0x0026, 600}, {39, 0x2019, 600}, {40, 0x0028, 600}, {41, 0x0029, 600}, {42, 0x002A, 600}, {43, 0x002B, 600}, {44, 0x002C, 600}, {45, 0x002D, 600}, {46, 0x002E, 600}, {47, 0x002F, 600}, {48, 0x0030, 600}, {49, 0x0031, 600}, {50, 0x0032, 600}, {51, 0x0033, 600}, {52, 0x0034, 600}, {53, 0x0035, 600}, {54, 0x0036, 600}, {55, 0x0037, 600}, {56, 0x0038, 600}, {57, 0x0039, 600}, {58, 0x003A, 600}, {59, 0x003B, 600}, {60, 0x003C, 600}, {61, 0x003D, 600}, {62, 0x003E, 600}, {63, 0x003F, 600}, {64, 0x0040, 600}, {65, 0x0041, 600}, {66, 0x0042, 600}, {67, 0x0043, 600}, {68, 0x0044, 600}, {69, 0x0045, 600}, {70, 0x0046, 600}, {71, 0x0047, 600}, {72, 0x0048, 600}, {73, 0x0049, 600}, {74, 0x004A, 600}, {75, 0x004B, 600}, {76, 0x004C, 600}, {77, 0x004D, 600}, {78, 0x004E, 600}, {79, 0x004F, 600}, {80, 0x0050, 600}, {81, 0x0051, 600}, {82, 0x0052, 600}, {83, 0x0053, 600}, {84, 0x0054, 600}, {85, 0x0055, 600}, {86, 0x0056, 600}, {87, 0x0057, 600}, {88, 0x0058, 600}, {89, 0x0059, 600}, {90, 0x005A, 600}, {91, 0x005B, 600}, {92, 0x005C, 600}, {93, 0x005D, 600}, {94, 0x005E, 600}, {95, 0x005F, 600}, {96, 0x2018, 600}, {97, 0x0061, 600}, {98, 0x0062, 600}, {99, 0x0063, 600}, {100, 0x0064, 600}, {101, 0x0065, 600}, {102, 0x0066, 600}, {103, 0x0067, 600}, {104, 0x0068, 600}, {105, 0x0069, 600}, {106, 0x006A, 600}, {107, 0x006B, 600}, {108, 0x006C, 600}, {109, 0x006D, 600}, {110, 0x006E, 600}, {111, 0x006F, 600}, {112, 0x0070, 600}, {113, 0x0071, 600}, {114, 0x0072, 600}, {115, 0x0073, 600}, {116, 0x0074, 600}, {117, 0x0075, 600}, {118, 0x0076, 600}, {119, 0x0077, 600}, {120, 0x0078, 600}, {121, 0x0079, 600}, {122, 0x007A, 600}, {123, 0x007B, 600}, {124, 0x007C, 600}, {125, 0x007D, 600}, {126, 0x007E, 600}, {161, 0x00A1, 600}, {162, 0x00A2, 600}, {163, 0x00A3, 600}, {164, 0x2044, 600}, {165, 0x00A5, 600}, {166, 0x0192, 600}, {167, 0x00A7, 600}, {168, 0x00A4, 600}, {169, 0x0027, 600}, {170, 0x201C, 600}, {171, 0x00AB, 600}, {172, 0x2039, 600}, {173, 0x203A, 600}, {174, 0xFB01, 600}, {175, 0xFB02, 600}, {177, 0x2013, 600}, {178, 0x2020, 600}, {179, 0x2021, 600}, {180, 0x00B7, 600}, {182, 0x00B6, 600}, {183, 0x2022, 600}, {184, 0x201A, 600}, {185, 0x201E, 600}, {186, 0x201D, 600}, {187, 0x00BB, 600}, {188, 0x2026, 600}, {189, 0x2030, 600}, {191, 0x00BF, 600}, {193, 0x0060, 600}, {194, 0x00B4, 600}, {195, 0x02C6, 600}, {196, 0x02DC, 600}, {197, 0x00AF, 600}, {198, 0x02D8, 600}, {199, 0x02D9, 600}, {200, 0x00A8, 600}, {202, 0x02DA, 600}, {203, 0x00B8, 600}, {205, 0x02DD, 600}, {206, 0x02DB, 600}, {207, 0x02C7, 600}, {208, 0x2014, 600}, {225, 0x00C6, 600}, {227, 0x00AA, 600}, {232, 0x0141, 600}, {233, 0x00D8, 600}, {234, 0x0152, 600}, {235, 0x00BA, 600}, {241, 0x00E6, 600}, {245, 0x0131, 600}, {248, 0x0142, 600}, {249, 0x00F8, 600}, {250, 0x0153, 600}, {251, 0x00DF, 600}, {-1, 0x00CF, 600}, {-1, 0x00E9, 600}, {-1, 0x0103, 600}, {-1, 0x0171, 600}, {-1, 0x011B, 600}, {-1, 0x0178, 600}, {-1, 0x00F7, 600}, {-1, 0x00DD, 600}, {-1, 0x00C2, 600}, {-1, 0x00E1, 600}, {-1, 0x00DB, 600}, {-1, 0x00FD, 600}, {-1, 0x0219, 600}, {-1, 0x00EA, 600}, {-1, 0x016E, 600}, {-1, 0x00DC, 600}, {-1, 0x0105, 600}, {-1, 0x00DA, 600}, {-1, 0x0173, 600}, {-1, 0x00CB, 600}, {-1, 0x0110, 600}, {-1, 0xF6C3, 600}, {-1, 0x00A9, 600}, {-1, 0x0112, 600}, {-1, 0x010D, 600}, {-1, 0x00E5, 600}, {-1, 0x0145, 600}, {-1, 0x013A, 600}, {-1, 0x00E0, 600}, {-1, 0x0162, 600}, {-1, 0x0106, 600}, {-1, 0x00E3, 600}, {-1, 0x0116, 600}, {-1, 0x0161, 600}, {-1, 0x015F, 600}, {-1, 0x00ED, 600}, {-1, 0x25CA, 600}, {-1, 0x0158, 600}, {-1, 0x0122, 600}, {-1, 0x00FB, 600}, {-1, 0x00E2, 600}, {-1, 0x0100, 600}, {-1, 0x0159, 600}, {-1, 0x00E7, 600}, {-1, 0x017B, 600}, {-1, 0x00DE, 600}, {-1, 0x014C, 600}, {-1, 0x0154, 600}, {-1, 0x015A, 600}, {-1, 0x010F, 600}, {-1, 0x016A, 600}, {-1, 0x016F, 600}, {-1, 0x00B3, 600}, {-1, 0x00D2, 600}, {-1, 0x00C0, 600}, {-1, 0x0102, 600}, {-1, 0x00D7, 600}, {-1, 0x00FA, 600}, {-1, 0x0164, 600}, {-1, 0x2202, 600}, {-1, 0x00FF, 600}, {-1, 0x0143, 600}, {-1, 0x00EE, 600}, {-1, 0x00CA, 600}, {-1, 0x00E4, 600}, {-1, 0x00EB, 600}, {-1, 0x0107, 600}, {-1, 0x0144, 600}, {-1, 0x016B, 600}, {-1, 0x0147, 600}, {-1, 0x00CD, 600}, {-1, 0x00B1, 600}, {-1, 0x00A6, 600}, {-1, 0x00AE, 600}, {-1, 0x011E, 600}, {-1, 0x0130, 600}, {-1, 0x2211, 600}, {-1, 0x00C8, 600}, {-1, 0x0155, 600}, {-1, 0x014D, 600}, {-1, 0x0179, 600}, {-1, 0x017D, 600}, {-1, 0x2265, 600}, {-1, 0x00D0, 600}, {-1, 0x00C7, 600}, {-1, 0x013C, 600}, {-1, 0x0165, 600}, {-1, 0x0119, 600}, {-1, 0x0172, 600}, {-1, 0x00C1, 600}, {-1, 0x00C4, 600}, {-1, 0x00E8, 600}, {-1, 0x017A, 600}, {-1, 0x012F, 600}, {-1, 0x00D3, 600}, {-1, 0x00F3, 600}, {-1, 0x0101, 600}, {-1, 0x015B, 600}, {-1, 0x00EF, 600}, {-1, 0x00D4, 600}, {-1, 0x00D9, 600}, {-1, 0x0394, 600}, {-1, 0x00FE, 600}, {-1, 0x00B2, 600}, {-1, 0x00D6, 600}, {-1, 0x00B5, 600}, {-1, 0x00EC, 600}, {-1, 0x0151, 600}, {-1, 0x0118, 600}, {-1, 0x0111, 600}, {-1, 0x00BE, 600}, {-1, 0x015E, 600}, {-1, 0x013E, 600}, {-1, 0x0136, 600}, {-1, 0x0139, 600}, {-1, 0x2122, 600}, {-1, 0x0117, 600}, {-1, 0x00CC, 600}, {-1, 0x012A, 600}, {-1, 0x013D, 600}, {-1, 0x00BD, 600}, {-1, 0x2264, 600}, {-1, 0x00F4, 600}, {-1, 0x00F1, 600}, {-1, 0x0170, 600}, {-1, 0x00C9, 600}, {-1, 0x0113, 600}, {-1, 0x011F, 600}, {-1, 0x00BC, 600}, {-1, 0x0160, 600}, {-1, 0x0218, 600}, {-1, 0x0150, 600}, {-1, 0x00B0, 600}, {-1, 0x00F2, 600}, {-1, 0x010C, 600}, {-1, 0x00F9, 600}, {-1, 0x221A, 600}, {-1, 0x010E, 600}, {-1, 0x0157, 600}, {-1, 0x00D1, 600}, {-1, 0x00F5, 600}, {-1, 0x0156, 600}, {-1, 0x013B, 600}, {-1, 0x00C3, 600}, {-1, 0x0104, 600}, {-1, 0x00C5, 600}, {-1, 0x00D5, 600}, {-1, 0x017C, 600}, {-1, 0x011A, 600}, {-1, 0x012E, 600}, {-1, 0x0137, 600}, {-1, 0x2212, 600}, {-1, 0x00CE, 600}, {-1, 0x0148, 600}, {-1, 0x0163, 600}, {-1, 0x00AC, 600}, {-1, 0x00F6, 600}, {-1, 0x00FC, 600}, {-1, 0x2260, 600}, {-1, 0x0123, 600}, {-1, 0x00F0, 600}, {-1, 0x017E, 600}, {-1, 0x0146, 600}, {-1, 0x00B9, 600}, {-1, 0x012B, 600}, {-1, 0x20AC, 600}, {-1, 0xFFFF, 0} }; static const PODOFO_CharData CHAR_DATA_COURIER_BOLD_OBLIQUE[316] = { {32, 0x0020, 600}, {33, 0x0021, 600}, {34, 0x0022, 600}, {35, 0x0023, 600}, {36, 0x0024, 600}, {37, 0x0025, 600}, {38, 0x0026, 600}, {39, 0x2019, 600}, {40, 0x0028, 600}, {41, 0x0029, 600}, {42, 0x002A, 600}, {43, 0x002B, 600}, {44, 0x002C, 600}, {45, 0x002D, 600}, {46, 0x002E, 600}, {47, 0x002F, 600}, {48, 0x0030, 600}, {49, 0x0031, 600}, {50, 0x0032, 600}, {51, 0x0033, 600}, {52, 0x0034, 600}, {53, 0x0035, 600}, {54, 0x0036, 600}, {55, 0x0037, 600}, {56, 0x0038, 600}, {57, 0x0039, 600}, {58, 0x003A, 600}, {59, 0x003B, 600}, {60, 0x003C, 600}, {61, 0x003D, 600}, {62, 0x003E, 600}, {63, 0x003F, 600}, {64, 0x0040, 600}, {65, 0x0041, 600}, {66, 0x0042, 600}, {67, 0x0043, 600}, {68, 0x0044, 600}, {69, 0x0045, 600}, {70, 0x0046, 600}, {71, 0x0047, 600}, {72, 0x0048, 600}, {73, 0x0049, 600}, {74, 0x004A, 600}, {75, 0x004B, 600}, {76, 0x004C, 600}, {77, 0x004D, 600}, {78, 0x004E, 600}, {79, 0x004F, 600}, {80, 0x0050, 600}, {81, 0x0051, 600}, {82, 0x0052, 600}, {83, 0x0053, 600}, {84, 0x0054, 600}, {85, 0x0055, 600}, {86, 0x0056, 600}, {87, 0x0057, 600}, {88, 0x0058, 600}, {89, 0x0059, 600}, {90, 0x005A, 600}, {91, 0x005B, 600}, {92, 0x005C, 600}, {93, 0x005D, 600}, {94, 0x005E, 600}, {95, 0x005F, 600}, {96, 0x2018, 600}, {97, 0x0061, 600}, {98, 0x0062, 600}, {99, 0x0063, 600}, {100, 0x0064, 600}, {101, 0x0065, 600}, {102, 0x0066, 600}, {103, 0x0067, 600}, {104, 0x0068, 600}, {105, 0x0069, 600}, {106, 0x006A, 600}, {107, 0x006B, 600}, {108, 0x006C, 600}, {109, 0x006D, 600}, {110, 0x006E, 600}, {111, 0x006F, 600}, {112, 0x0070, 600}, {113, 0x0071, 600}, {114, 0x0072, 600}, {115, 0x0073, 600}, {116, 0x0074, 600}, {117, 0x0075, 600}, {118, 0x0076, 600}, {119, 0x0077, 600}, {120, 0x0078, 600}, {121, 0x0079, 600}, {122, 0x007A, 600}, {123, 0x007B, 600}, {124, 0x007C, 600}, {125, 0x007D, 600}, {126, 0x007E, 600}, {161, 0x00A1, 600}, {162, 0x00A2, 600}, {163, 0x00A3, 600}, {164, 0x2044, 600}, {165, 0x00A5, 600}, {166, 0x0192, 600}, {167, 0x00A7, 600}, {168, 0x00A4, 600}, {169, 0x0027, 600}, {170, 0x201C, 600}, {171, 0x00AB, 600}, {172, 0x2039, 600}, {173, 0x203A, 600}, {174, 0xFB01, 600}, {175, 0xFB02, 600}, {177, 0x2013, 600}, {178, 0x2020, 600}, {179, 0x2021, 600}, {180, 0x00B7, 600}, {182, 0x00B6, 600}, {183, 0x2022, 600}, {184, 0x201A, 600}, {185, 0x201E, 600}, {186, 0x201D, 600}, {187, 0x00BB, 600}, {188, 0x2026, 600}, {189, 0x2030, 600}, {191, 0x00BF, 600}, {193, 0x0060, 600}, {194, 0x00B4, 600}, {195, 0x02C6, 600}, {196, 0x02DC, 600}, {197, 0x00AF, 600}, {198, 0x02D8, 600}, {199, 0x02D9, 600}, {200, 0x00A8, 600}, {202, 0x02DA, 600}, {203, 0x00B8, 600}, {205, 0x02DD, 600}, {206, 0x02DB, 600}, {207, 0x02C7, 600}, {208, 0x2014, 600}, {225, 0x00C6, 600}, {227, 0x00AA, 600}, {232, 0x0141, 600}, {233, 0x00D8, 600}, {234, 0x0152, 600}, {235, 0x00BA, 600}, {241, 0x00E6, 600}, {245, 0x0131, 600}, {248, 0x0142, 600}, {249, 0x00F8, 600}, {250, 0x0153, 600}, {251, 0x00DF, 600}, {-1, 0x00CF, 600}, {-1, 0x00E9, 600}, {-1, 0x0103, 600}, {-1, 0x0171, 600}, {-1, 0x011B, 600}, {-1, 0x0178, 600}, {-1, 0x00F7, 600}, {-1, 0x00DD, 600}, {-1, 0x00C2, 600}, {-1, 0x00E1, 600}, {-1, 0x00DB, 600}, {-1, 0x00FD, 600}, {-1, 0x0219, 600}, {-1, 0x00EA, 600}, {-1, 0x016E, 600}, {-1, 0x00DC, 600}, {-1, 0x0105, 600}, {-1, 0x00DA, 600}, {-1, 0x0173, 600}, {-1, 0x00CB, 600}, {-1, 0x0110, 600}, {-1, 0xF6C3, 600}, {-1, 0x00A9, 600}, {-1, 0x0112, 600}, {-1, 0x010D, 600}, {-1, 0x00E5, 600}, {-1, 0x0145, 600}, {-1, 0x013A, 600}, {-1, 0x00E0, 600}, {-1, 0x0162, 600}, {-1, 0x0106, 600}, {-1, 0x00E3, 600}, {-1, 0x0116, 600}, {-1, 0x0161, 600}, {-1, 0x015F, 600}, {-1, 0x00ED, 600}, {-1, 0x25CA, 600}, {-1, 0x0158, 600}, {-1, 0x0122, 600}, {-1, 0x00FB, 600}, {-1, 0x00E2, 600}, {-1, 0x0100, 600}, {-1, 0x0159, 600}, {-1, 0x00E7, 600}, {-1, 0x017B, 600}, {-1, 0x00DE, 600}, {-1, 0x014C, 600}, {-1, 0x0154, 600}, {-1, 0x015A, 600}, {-1, 0x010F, 600}, {-1, 0x016A, 600}, {-1, 0x016F, 600}, {-1, 0x00B3, 600}, {-1, 0x00D2, 600}, {-1, 0x00C0, 600}, {-1, 0x0102, 600}, {-1, 0x00D7, 600}, {-1, 0x00FA, 600}, {-1, 0x0164, 600}, {-1, 0x2202, 600}, {-1, 0x00FF, 600}, {-1, 0x0143, 600}, {-1, 0x00EE, 600}, {-1, 0x00CA, 600}, {-1, 0x00E4, 600}, {-1, 0x00EB, 600}, {-1, 0x0107, 600}, {-1, 0x0144, 600}, {-1, 0x016B, 600}, {-1, 0x0147, 600}, {-1, 0x00CD, 600}, {-1, 0x00B1, 600}, {-1, 0x00A6, 600}, {-1, 0x00AE, 600}, {-1, 0x011E, 600}, {-1, 0x0130, 600}, {-1, 0x2211, 600}, {-1, 0x00C8, 600}, {-1, 0x0155, 600}, {-1, 0x014D, 600}, {-1, 0x0179, 600}, {-1, 0x017D, 600}, {-1, 0x2265, 600}, {-1, 0x00D0, 600}, {-1, 0x00C7, 600}, {-1, 0x013C, 600}, {-1, 0x0165, 600}, {-1, 0x0119, 600}, {-1, 0x0172, 600}, {-1, 0x00C1, 600}, {-1, 0x00C4, 600}, {-1, 0x00E8, 600}, {-1, 0x017A, 600}, {-1, 0x012F, 600}, {-1, 0x00D3, 600}, {-1, 0x00F3, 600}, {-1, 0x0101, 600}, {-1, 0x015B, 600}, {-1, 0x00EF, 600}, {-1, 0x00D4, 600}, {-1, 0x00D9, 600}, {-1, 0x0394, 600}, {-1, 0x00FE, 600}, {-1, 0x00B2, 600}, {-1, 0x00D6, 600}, {-1, 0x00B5, 600}, {-1, 0x00EC, 600}, {-1, 0x0151, 600}, {-1, 0x0118, 600}, {-1, 0x0111, 600}, {-1, 0x00BE, 600}, {-1, 0x015E, 600}, {-1, 0x013E, 600}, {-1, 0x0136, 600}, {-1, 0x0139, 600}, {-1, 0x2122, 600}, {-1, 0x0117, 600}, {-1, 0x00CC, 600}, {-1, 0x012A, 600}, {-1, 0x013D, 600}, {-1, 0x00BD, 600}, {-1, 0x2264, 600}, {-1, 0x00F4, 600}, {-1, 0x00F1, 600}, {-1, 0x0170, 600}, {-1, 0x00C9, 600}, {-1, 0x0113, 600}, {-1, 0x011F, 600}, {-1, 0x00BC, 600}, {-1, 0x0160, 600}, {-1, 0x0218, 600}, {-1, 0x0150, 600}, {-1, 0x00B0, 600}, {-1, 0x00F2, 600}, {-1, 0x010C, 600}, {-1, 0x00F9, 600}, {-1, 0x221A, 600}, {-1, 0x010E, 600}, {-1, 0x0157, 600}, {-1, 0x00D1, 600}, {-1, 0x00F5, 600}, {-1, 0x0156, 600}, {-1, 0x013B, 600}, {-1, 0x00C3, 600}, {-1, 0x0104, 600}, {-1, 0x00C5, 600}, {-1, 0x00D5, 600}, {-1, 0x017C, 600}, {-1, 0x011A, 600}, {-1, 0x012E, 600}, {-1, 0x0137, 600}, {-1, 0x2212, 600}, {-1, 0x00CE, 600}, {-1, 0x0148, 600}, {-1, 0x0163, 600}, {-1, 0x00AC, 600}, {-1, 0x00F6, 600}, {-1, 0x00FC, 600}, {-1, 0x2260, 600}, {-1, 0x0123, 600}, {-1, 0x00F0, 600}, {-1, 0x017E, 600}, {-1, 0x0146, 600}, {-1, 0x00B9, 600}, {-1, 0x012B, 600}, {-1, 0x20AC, 600}, {-1, 0xFFFF, 0} }; static const PODOFO_CharData CHAR_DATA_COURIER_OBLIQUE[316] = { {32, 0x0020, 600}, {33, 0x0021, 600}, {34, 0x0022, 600}, {35, 0x0023, 600}, {36, 0x0024, 600}, {37, 0x0025, 600}, {38, 0x0026, 600}, {39, 0x2019, 600}, {40, 0x0028, 600}, {41, 0x0029, 600}, {42, 0x002A, 600}, {43, 0x002B, 600}, {44, 0x002C, 600}, {45, 0x002D, 600}, {46, 0x002E, 600}, {47, 0x002F, 600}, {48, 0x0030, 600}, {49, 0x0031, 600}, {50, 0x0032, 600}, {51, 0x0033, 600}, {52, 0x0034, 600}, {53, 0x0035, 600}, {54, 0x0036, 600}, {55, 0x0037, 600}, {56, 0x0038, 600}, {57, 0x0039, 600}, {58, 0x003A, 600}, {59, 0x003B, 600}, {60, 0x003C, 600}, {61, 0x003D, 600}, {62, 0x003E, 600}, {63, 0x003F, 600}, {64, 0x0040, 600}, {65, 0x0041, 600}, {66, 0x0042, 600}, {67, 0x0043, 600}, {68, 0x0044, 600}, {69, 0x0045, 600}, {70, 0x0046, 600}, {71, 0x0047, 600}, {72, 0x0048, 600}, {73, 0x0049, 600}, {74, 0x004A, 600}, {75, 0x004B, 600}, {76, 0x004C, 600}, {77, 0x004D, 600}, {78, 0x004E, 600}, {79, 0x004F, 600}, {80, 0x0050, 600}, {81, 0x0051, 600}, {82, 0x0052, 600}, {83, 0x0053, 600}, {84, 0x0054, 600}, {85, 0x0055, 600}, {86, 0x0056, 600}, {87, 0x0057, 600}, {88, 0x0058, 600}, {89, 0x0059, 600}, {90, 0x005A, 600}, {91, 0x005B, 600}, {92, 0x005C, 600}, {93, 0x005D, 600}, {94, 0x005E, 600}, {95, 0x005F, 600}, {96, 0x2018, 600}, {97, 0x0061, 600}, {98, 0x0062, 600}, {99, 0x0063, 600}, {100, 0x0064, 600}, {101, 0x0065, 600}, {102, 0x0066, 600}, {103, 0x0067, 600}, {104, 0x0068, 600}, {105, 0x0069, 600}, {106, 0x006A, 600}, {107, 0x006B, 600}, {108, 0x006C, 600}, {109, 0x006D, 600}, {110, 0x006E, 600}, {111, 0x006F, 600}, {112, 0x0070, 600}, {113, 0x0071, 600}, {114, 0x0072, 600}, {115, 0x0073, 600}, {116, 0x0074, 600}, {117, 0x0075, 600}, {118, 0x0076, 600}, {119, 0x0077, 600}, {120, 0x0078, 600}, {121, 0x0079, 600}, {122, 0x007A, 600}, {123, 0x007B, 600}, {124, 0x007C, 600}, {125, 0x007D, 600}, {126, 0x007E, 600}, {161, 0x00A1, 600}, {162, 0x00A2, 600}, {163, 0x00A3, 600}, {164, 0x2044, 600}, {165, 0x00A5, 600}, {166, 0x0192, 600}, {167, 0x00A7, 600}, {168, 0x00A4, 600}, {169, 0x0027, 600}, {170, 0x201C, 600}, {171, 0x00AB, 600}, {172, 0x2039, 600}, {173, 0x203A, 600}, {174, 0xFB01, 600}, {175, 0xFB02, 600}, {177, 0x2013, 600}, {178, 0x2020, 600}, {179, 0x2021, 600}, {180, 0x00B7, 600}, {182, 0x00B6, 600}, {183, 0x2022, 600}, {184, 0x201A, 600}, {185, 0x201E, 600}, {186, 0x201D, 600}, {187, 0x00BB, 600}, {188, 0x2026, 600}, {189, 0x2030, 600}, {191, 0x00BF, 600}, {193, 0x0060, 600}, {194, 0x00B4, 600}, {195, 0x02C6, 600}, {196, 0x02DC, 600}, {197, 0x00AF, 600}, {198, 0x02D8, 600}, {199, 0x02D9, 600}, {200, 0x00A8, 600}, {202, 0x02DA, 600}, {203, 0x00B8, 600}, {205, 0x02DD, 600}, {206, 0x02DB, 600}, {207, 0x02C7, 600}, {208, 0x2014, 600}, {225, 0x00C6, 600}, {227, 0x00AA, 600}, {232, 0x0141, 600}, {233, 0x00D8, 600}, {234, 0x0152, 600}, {235, 0x00BA, 600}, {241, 0x00E6, 600}, {245, 0x0131, 600}, {248, 0x0142, 600}, {249, 0x00F8, 600}, {250, 0x0153, 600}, {251, 0x00DF, 600}, {-1, 0x00CF, 600}, {-1, 0x00E9, 600}, {-1, 0x0103, 600}, {-1, 0x0171, 600}, {-1, 0x011B, 600}, {-1, 0x0178, 600}, {-1, 0x00F7, 600}, {-1, 0x00DD, 600}, {-1, 0x00C2, 600}, {-1, 0x00E1, 600}, {-1, 0x00DB, 600}, {-1, 0x00FD, 600}, {-1, 0x0219, 600}, {-1, 0x00EA, 600}, {-1, 0x016E, 600}, {-1, 0x00DC, 600}, {-1, 0x0105, 600}, {-1, 0x00DA, 600}, {-1, 0x0173, 600}, {-1, 0x00CB, 600}, {-1, 0x0110, 600}, {-1, 0xF6C3, 600}, {-1, 0x00A9, 600}, {-1, 0x0112, 600}, {-1, 0x010D, 600}, {-1, 0x00E5, 600}, {-1, 0x0145, 600}, {-1, 0x013A, 600}, {-1, 0x00E0, 600}, {-1, 0x0162, 600}, {-1, 0x0106, 600}, {-1, 0x00E3, 600}, {-1, 0x0116, 600}, {-1, 0x0161, 600}, {-1, 0x015F, 600}, {-1, 0x00ED, 600}, {-1, 0x25CA, 600}, {-1, 0x0158, 600}, {-1, 0x0122, 600}, {-1, 0x00FB, 600}, {-1, 0x00E2, 600}, {-1, 0x0100, 600}, {-1, 0x0159, 600}, {-1, 0x00E7, 600}, {-1, 0x017B, 600}, {-1, 0x00DE, 600}, {-1, 0x014C, 600}, {-1, 0x0154, 600}, {-1, 0x015A, 600}, {-1, 0x010F, 600}, {-1, 0x016A, 600}, {-1, 0x016F, 600}, {-1, 0x00B3, 600}, {-1, 0x00D2, 600}, {-1, 0x00C0, 600}, {-1, 0x0102, 600}, {-1, 0x00D7, 600}, {-1, 0x00FA, 600}, {-1, 0x0164, 600}, {-1, 0x2202, 600}, {-1, 0x00FF, 600}, {-1, 0x0143, 600}, {-1, 0x00EE, 600}, {-1, 0x00CA, 600}, {-1, 0x00E4, 600}, {-1, 0x00EB, 600}, {-1, 0x0107, 600}, {-1, 0x0144, 600}, {-1, 0x016B, 600}, {-1, 0x0147, 600}, {-1, 0x00CD, 600}, {-1, 0x00B1, 600}, {-1, 0x00A6, 600}, {-1, 0x00AE, 600}, {-1, 0x011E, 600}, {-1, 0x0130, 600}, {-1, 0x2211, 600}, {-1, 0x00C8, 600}, {-1, 0x0155, 600}, {-1, 0x014D, 600}, {-1, 0x0179, 600}, {-1, 0x017D, 600}, {-1, 0x2265, 600}, {-1, 0x00D0, 600}, {-1, 0x00C7, 600}, {-1, 0x013C, 600}, {-1, 0x0165, 600}, {-1, 0x0119, 600}, {-1, 0x0172, 600}, {-1, 0x00C1, 600}, {-1, 0x00C4, 600}, {-1, 0x00E8, 600}, {-1, 0x017A, 600}, {-1, 0x012F, 600}, {-1, 0x00D3, 600}, {-1, 0x00F3, 600}, {-1, 0x0101, 600}, {-1, 0x015B, 600}, {-1, 0x00EF, 600}, {-1, 0x00D4, 600}, {-1, 0x00D9, 600}, {-1, 0x0394, 600}, {-1, 0x00FE, 600}, {-1, 0x00B2, 600}, {-1, 0x00D6, 600}, {-1, 0x00B5, 600}, {-1, 0x00EC, 600}, {-1, 0x0151, 600}, {-1, 0x0118, 600}, {-1, 0x0111, 600}, {-1, 0x00BE, 600}, {-1, 0x015E, 600}, {-1, 0x013E, 600}, {-1, 0x0136, 600}, {-1, 0x0139, 600}, {-1, 0x2122, 600}, {-1, 0x0117, 600}, {-1, 0x00CC, 600}, {-1, 0x012A, 600}, {-1, 0x013D, 600}, {-1, 0x00BD, 600}, {-1, 0x2264, 600}, {-1, 0x00F4, 600}, {-1, 0x00F1, 600}, {-1, 0x0170, 600}, {-1, 0x00C9, 600}, {-1, 0x0113, 600}, {-1, 0x011F, 600}, {-1, 0x00BC, 600}, {-1, 0x0160, 600}, {-1, 0x0218, 600}, {-1, 0x0150, 600}, {-1, 0x00B0, 600}, {-1, 0x00F2, 600}, {-1, 0x010C, 600}, {-1, 0x00F9, 600}, {-1, 0x221A, 600}, {-1, 0x010E, 600}, {-1, 0x0157, 600}, {-1, 0x00D1, 600}, {-1, 0x00F5, 600}, {-1, 0x0156, 600}, {-1, 0x013B, 600}, {-1, 0x00C3, 600}, {-1, 0x0104, 600}, {-1, 0x00C5, 600}, {-1, 0x00D5, 600}, {-1, 0x017C, 600}, {-1, 0x011A, 600}, {-1, 0x012E, 600}, {-1, 0x0137, 600}, {-1, 0x2212, 600}, {-1, 0x00CE, 600}, {-1, 0x0148, 600}, {-1, 0x0163, 600}, {-1, 0x00AC, 600}, {-1, 0x00F6, 600}, {-1, 0x00FC, 600}, {-1, 0x2260, 600}, {-1, 0x0123, 600}, {-1, 0x00F0, 600}, {-1, 0x017E, 600}, {-1, 0x0146, 600}, {-1, 0x00B9, 600}, {-1, 0x012B, 600}, {-1, 0x20AC, 600}, {-1, 0xFFFF, 0} }; static const PODOFO_CharData CHAR_DATA_HELVETICA[316] = { {32, 0x0020, 278}, {33, 0x0021, 278}, {34, 0x0022, 355}, {35, 0x0023, 556}, {36, 0x0024, 556}, {37, 0x0025, 889}, {38, 0x0026, 667}, {39, 0x2019, 222}, {40, 0x0028, 333}, {41, 0x0029, 333}, {42, 0x002A, 389}, {43, 0x002B, 584}, {44, 0x002C, 278}, {45, 0x002D, 333}, {46, 0x002E, 278}, {47, 0x002F, 278}, {48, 0x0030, 556}, {49, 0x0031, 556}, {50, 0x0032, 556}, {51, 0x0033, 556}, {52, 0x0034, 556}, {53, 0x0035, 556}, {54, 0x0036, 556}, {55, 0x0037, 556}, {56, 0x0038, 556}, {57, 0x0039, 556}, {58, 0x003A, 278}, {59, 0x003B, 278}, {60, 0x003C, 584}, {61, 0x003D, 584}, {62, 0x003E, 584}, {63, 0x003F, 556}, {64, 0x0040, 1015}, {65, 0x0041, 667}, {66, 0x0042, 667}, {67, 0x0043, 722}, {68, 0x0044, 722}, {69, 0x0045, 667}, {70, 0x0046, 611}, {71, 0x0047, 778}, {72, 0x0048, 722}, {73, 0x0049, 278}, {74, 0x004A, 500}, {75, 0x004B, 667}, {76, 0x004C, 556}, {77, 0x004D, 833}, {78, 0x004E, 722}, {79, 0x004F, 778}, {80, 0x0050, 667}, {81, 0x0051, 778}, {82, 0x0052, 722}, {83, 0x0053, 667}, {84, 0x0054, 611}, {85, 0x0055, 722}, {86, 0x0056, 667}, {87, 0x0057, 944}, {88, 0x0058, 667}, {89, 0x0059, 667}, {90, 0x005A, 611}, {91, 0x005B, 278}, {92, 0x005C, 278}, {93, 0x005D, 278}, {94, 0x005E, 469}, {95, 0x005F, 556}, {96, 0x2018, 222}, {97, 0x0061, 556}, {98, 0x0062, 556}, {99, 0x0063, 500}, {100, 0x0064, 556}, {101, 0x0065, 556}, {102, 0x0066, 278}, {103, 0x0067, 556}, {104, 0x0068, 556}, {105, 0x0069, 222}, {106, 0x006A, 222}, {107, 0x006B, 500}, {108, 0x006C, 222}, {109, 0x006D, 833}, {110, 0x006E, 556}, {111, 0x006F, 556}, {112, 0x0070, 556}, {113, 0x0071, 556}, {114, 0x0072, 333}, {115, 0x0073, 500}, {116, 0x0074, 278}, {117, 0x0075, 556}, {118, 0x0076, 500}, {119, 0x0077, 722}, {120, 0x0078, 500}, {121, 0x0079, 500}, {122, 0x007A, 500}, {123, 0x007B, 334}, {124, 0x007C, 260}, {125, 0x007D, 334}, {126, 0x007E, 584}, {161, 0x00A1, 333}, {162, 0x00A2, 556}, {163, 0x00A3, 556}, {164, 0x2044, 167}, {165, 0x00A5, 556}, {166, 0x0192, 556}, {167, 0x00A7, 556}, {168, 0x00A4, 556}, {169, 0x0027, 191}, {170, 0x201C, 333}, {171, 0x00AB, 556}, {172, 0x2039, 333}, {173, 0x203A, 333}, {174, 0xFB01, 500}, {175, 0xFB02, 500}, {177, 0x2013, 556}, {178, 0x2020, 556}, {179, 0x2021, 556}, {180, 0x00B7, 278}, {182, 0x00B6, 537}, {183, 0x2022, 350}, {184, 0x201A, 222}, {185, 0x201E, 333}, {186, 0x201D, 333}, {187, 0x00BB, 556}, {188, 0x2026, 1000}, {189, 0x2030, 1000}, {191, 0x00BF, 611}, {193, 0x0060, 333}, {194, 0x00B4, 333}, {195, 0x02C6, 333}, {196, 0x02DC, 333}, {197, 0x00AF, 333}, {198, 0x02D8, 333}, {199, 0x02D9, 333}, {200, 0x00A8, 333}, {202, 0x02DA, 333}, {203, 0x00B8, 333}, {205, 0x02DD, 333}, {206, 0x02DB, 333}, {207, 0x02C7, 333}, {208, 0x2014, 1000}, {225, 0x00C6, 1000}, {227, 0x00AA, 370}, {232, 0x0141, 556}, {233, 0x00D8, 778}, {234, 0x0152, 1000}, {235, 0x00BA, 365}, {241, 0x00E6, 889}, {245, 0x0131, 278}, {248, 0x0142, 222}, {249, 0x00F8, 611}, {250, 0x0153, 944}, {251, 0x00DF, 611}, {-1, 0x00CF, 278}, {-1, 0x00E9, 556}, {-1, 0x0103, 556}, {-1, 0x0171, 556}, {-1, 0x011B, 556}, {-1, 0x0178, 667}, {-1, 0x00F7, 584}, {-1, 0x00DD, 667}, {-1, 0x00C2, 667}, {-1, 0x00E1, 556}, {-1, 0x00DB, 722}, {-1, 0x00FD, 500}, {-1, 0x0219, 500}, {-1, 0x00EA, 556}, {-1, 0x016E, 722}, {-1, 0x00DC, 722}, {-1, 0x0105, 556}, {-1, 0x00DA, 722}, {-1, 0x0173, 556}, {-1, 0x00CB, 667}, {-1, 0x0110, 722}, {-1, 0xF6C3, 250}, {-1, 0x00A9, 737}, {-1, 0x0112, 667}, {-1, 0x010D, 500}, {-1, 0x00E5, 556}, {-1, 0x0145, 722}, {-1, 0x013A, 222}, {-1, 0x00E0, 556}, {-1, 0x0162, 611}, {-1, 0x0106, 722}, {-1, 0x00E3, 556}, {-1, 0x0116, 667}, {-1, 0x0161, 500}, {-1, 0x015F, 500}, {-1, 0x00ED, 278}, {-1, 0x25CA, 471}, {-1, 0x0158, 722}, {-1, 0x0122, 778}, {-1, 0x00FB, 556}, {-1, 0x00E2, 556}, {-1, 0x0100, 667}, {-1, 0x0159, 333}, {-1, 0x00E7, 500}, {-1, 0x017B, 611}, {-1, 0x00DE, 667}, {-1, 0x014C, 778}, {-1, 0x0154, 722}, {-1, 0x015A, 667}, {-1, 0x010F, 643}, {-1, 0x016A, 722}, {-1, 0x016F, 556}, {-1, 0x00B3, 333}, {-1, 0x00D2, 778}, {-1, 0x00C0, 667}, {-1, 0x0102, 667}, {-1, 0x00D7, 584}, {-1, 0x00FA, 556}, {-1, 0x0164, 611}, {-1, 0x2202, 476}, {-1, 0x00FF, 500}, {-1, 0x0143, 722}, {-1, 0x00EE, 278}, {-1, 0x00CA, 667}, {-1, 0x00E4, 556}, {-1, 0x00EB, 556}, {-1, 0x0107, 500}, {-1, 0x0144, 556}, {-1, 0x016B, 556}, {-1, 0x0147, 722}, {-1, 0x00CD, 278}, {-1, 0x00B1, 584}, {-1, 0x00A6, 260}, {-1, 0x00AE, 737}, {-1, 0x011E, 778}, {-1, 0x0130, 278}, {-1, 0x2211, 600}, {-1, 0x00C8, 667}, {-1, 0x0155, 333}, {-1, 0x014D, 556}, {-1, 0x0179, 611}, {-1, 0x017D, 611}, {-1, 0x2265, 549}, {-1, 0x00D0, 722}, {-1, 0x00C7, 722}, {-1, 0x013C, 222}, {-1, 0x0165, 316}, {-1, 0x0119, 556}, {-1, 0x0172, 722}, {-1, 0x00C1, 667}, {-1, 0x00C4, 667}, {-1, 0x00E8, 556}, {-1, 0x017A, 500}, {-1, 0x012F, 222}, {-1, 0x00D3, 778}, {-1, 0x00F3, 556}, {-1, 0x0101, 556}, {-1, 0x015B, 500}, {-1, 0x00EF, 278}, {-1, 0x00D4, 778}, {-1, 0x00D9, 722}, {-1, 0x0394, 612}, {-1, 0x00FE, 556}, {-1, 0x00B2, 333}, {-1, 0x00D6, 778}, {-1, 0x00B5, 556}, {-1, 0x00EC, 278}, {-1, 0x0151, 556}, {-1, 0x0118, 667}, {-1, 0x0111, 556}, {-1, 0x00BE, 834}, {-1, 0x015E, 667}, {-1, 0x013E, 299}, {-1, 0x0136, 667}, {-1, 0x0139, 556}, {-1, 0x2122, 1000}, {-1, 0x0117, 556}, {-1, 0x00CC, 278}, {-1, 0x012A, 278}, {-1, 0x013D, 556}, {-1, 0x00BD, 834}, {-1, 0x2264, 549}, {-1, 0x00F4, 556}, {-1, 0x00F1, 556}, {-1, 0x0170, 722}, {-1, 0x00C9, 667}, {-1, 0x0113, 556}, {-1, 0x011F, 556}, {-1, 0x00BC, 834}, {-1, 0x0160, 667}, {-1, 0x0218, 667}, {-1, 0x0150, 778}, {-1, 0x00B0, 400}, {-1, 0x00F2, 556}, {-1, 0x010C, 722}, {-1, 0x00F9, 556}, {-1, 0x221A, 453}, {-1, 0x010E, 722}, {-1, 0x0157, 333}, {-1, 0x00D1, 722}, {-1, 0x00F5, 556}, {-1, 0x0156, 722}, {-1, 0x013B, 556}, {-1, 0x00C3, 667}, {-1, 0x0104, 667}, {-1, 0x00C5, 667}, {-1, 0x00D5, 778}, {-1, 0x017C, 500}, {-1, 0x011A, 667}, {-1, 0x012E, 278}, {-1, 0x0137, 500}, {-1, 0x2212, 584}, {-1, 0x00CE, 278}, {-1, 0x0148, 556}, {-1, 0x0163, 278}, {-1, 0x00AC, 584}, {-1, 0x00F6, 556}, {-1, 0x00FC, 556}, {-1, 0x2260, 549}, {-1, 0x0123, 556}, {-1, 0x00F0, 556}, {-1, 0x017E, 500}, {-1, 0x0146, 556}, {-1, 0x00B9, 333}, {-1, 0x012B, 278}, {-1, 0x20AC, 556}, {-1, 0xFFFF, 0} }; static const PODOFO_CharData CHAR_DATA_HELVETICA_BOLD[316] = { {32, 0x0020, 278}, {33, 0x0021, 333}, {34, 0x0022, 474}, {35, 0x0023, 556}, {36, 0x0024, 556}, {37, 0x0025, 889}, {38, 0x0026, 722}, {39, 0x2019, 278}, {40, 0x0028, 333}, {41, 0x0029, 333}, {42, 0x002A, 389}, {43, 0x002B, 584}, {44, 0x002C, 278}, {45, 0x002D, 333}, {46, 0x002E, 278}, {47, 0x002F, 278}, {48, 0x0030, 556}, {49, 0x0031, 556}, {50, 0x0032, 556}, {51, 0x0033, 556}, {52, 0x0034, 556}, {53, 0x0035, 556}, {54, 0x0036, 556}, {55, 0x0037, 556}, {56, 0x0038, 556}, {57, 0x0039, 556}, {58, 0x003A, 333}, {59, 0x003B, 333}, {60, 0x003C, 584}, {61, 0x003D, 584}, {62, 0x003E, 584}, {63, 0x003F, 611}, {64, 0x0040, 975}, {65, 0x0041, 722}, {66, 0x0042, 722}, {67, 0x0043, 722}, {68, 0x0044, 722}, {69, 0x0045, 667}, {70, 0x0046, 611}, {71, 0x0047, 778}, {72, 0x0048, 722}, {73, 0x0049, 278}, {74, 0x004A, 556}, {75, 0x004B, 722}, {76, 0x004C, 611}, {77, 0x004D, 833}, {78, 0x004E, 722}, {79, 0x004F, 778}, {80, 0x0050, 667}, {81, 0x0051, 778}, {82, 0x0052, 722}, {83, 0x0053, 667}, {84, 0x0054, 611}, {85, 0x0055, 722}, {86, 0x0056, 667}, {87, 0x0057, 944}, {88, 0x0058, 667}, {89, 0x0059, 667}, {90, 0x005A, 611}, {91, 0x005B, 333}, {92, 0x005C, 278}, {93, 0x005D, 333}, {94, 0x005E, 584}, {95, 0x005F, 556}, {96, 0x2018, 278}, {97, 0x0061, 556}, {98, 0x0062, 611}, {99, 0x0063, 556}, {100, 0x0064, 611}, {101, 0x0065, 556}, {102, 0x0066, 333}, {103, 0x0067, 611}, {104, 0x0068, 611}, {105, 0x0069, 278}, {106, 0x006A, 278}, {107, 0x006B, 556}, {108, 0x006C, 278}, {109, 0x006D, 889}, {110, 0x006E, 611}, {111, 0x006F, 611}, {112, 0x0070, 611}, {113, 0x0071, 611}, {114, 0x0072, 389}, {115, 0x0073, 556}, {116, 0x0074, 333}, {117, 0x0075, 611}, {118, 0x0076, 556}, {119, 0x0077, 778}, {120, 0x0078, 556}, {121, 0x0079, 556}, {122, 0x007A, 500}, {123, 0x007B, 389}, {124, 0x007C, 280}, {125, 0x007D, 389}, {126, 0x007E, 584}, {161, 0x00A1, 333}, {162, 0x00A2, 556}, {163, 0x00A3, 556}, {164, 0x2044, 167}, {165, 0x00A5, 556}, {166, 0x0192, 556}, {167, 0x00A7, 556}, {168, 0x00A4, 556}, {169, 0x0027, 238}, {170, 0x201C, 500}, {171, 0x00AB, 556}, {172, 0x2039, 333}, {173, 0x203A, 333}, {174, 0xFB01, 611}, {175, 0xFB02, 611}, {177, 0x2013, 556}, {178, 0x2020, 556}, {179, 0x2021, 556}, {180, 0x00B7, 278}, {182, 0x00B6, 556}, {183, 0x2022, 350}, {184, 0x201A, 278}, {185, 0x201E, 500}, {186, 0x201D, 500}, {187, 0x00BB, 556}, {188, 0x2026, 1000}, {189, 0x2030, 1000}, {191, 0x00BF, 611}, {193, 0x0060, 333}, {194, 0x00B4, 333}, {195, 0x02C6, 333}, {196, 0x02DC, 333}, {197, 0x00AF, 333}, {198, 0x02D8, 333}, {199, 0x02D9, 333}, {200, 0x00A8, 333}, {202, 0x02DA, 333}, {203, 0x00B8, 333}, {205, 0x02DD, 333}, {206, 0x02DB, 333}, {207, 0x02C7, 333}, {208, 0x2014, 1000}, {225, 0x00C6, 1000}, {227, 0x00AA, 370}, {232, 0x0141, 611}, {233, 0x00D8, 778}, {234, 0x0152, 1000}, {235, 0x00BA, 365}, {241, 0x00E6, 889}, {245, 0x0131, 278}, {248, 0x0142, 278}, {249, 0x00F8, 611}, {250, 0x0153, 944}, {251, 0x00DF, 611}, {-1, 0x00CF, 278}, {-1, 0x00E9, 556}, {-1, 0x0103, 556}, {-1, 0x0171, 611}, {-1, 0x011B, 556}, {-1, 0x0178, 667}, {-1, 0x00F7, 584}, {-1, 0x00DD, 667}, {-1, 0x00C2, 722}, {-1, 0x00E1, 556}, {-1, 0x00DB, 722}, {-1, 0x00FD, 556}, {-1, 0x0219, 556}, {-1, 0x00EA, 556}, {-1, 0x016E, 722}, {-1, 0x00DC, 722}, {-1, 0x0105, 556}, {-1, 0x00DA, 722}, {-1, 0x0173, 611}, {-1, 0x00CB, 667}, {-1, 0x0110, 722}, {-1, 0xF6C3, 250}, {-1, 0x00A9, 737}, {-1, 0x0112, 667}, {-1, 0x010D, 556}, {-1, 0x00E5, 556}, {-1, 0x0145, 722}, {-1, 0x013A, 278}, {-1, 0x00E0, 556}, {-1, 0x0162, 611}, {-1, 0x0106, 722}, {-1, 0x00E3, 556}, {-1, 0x0116, 667}, {-1, 0x0161, 556}, {-1, 0x015F, 556}, {-1, 0x00ED, 278}, {-1, 0x25CA, 494}, {-1, 0x0158, 722}, {-1, 0x0122, 778}, {-1, 0x00FB, 611}, {-1, 0x00E2, 556}, {-1, 0x0100, 722}, {-1, 0x0159, 389}, {-1, 0x00E7, 556}, {-1, 0x017B, 611}, {-1, 0x00DE, 667}, {-1, 0x014C, 778}, {-1, 0x0154, 722}, {-1, 0x015A, 667}, {-1, 0x010F, 743}, {-1, 0x016A, 722}, {-1, 0x016F, 611}, {-1, 0x00B3, 333}, {-1, 0x00D2, 778}, {-1, 0x00C0, 722}, {-1, 0x0102, 722}, {-1, 0x00D7, 584}, {-1, 0x00FA, 611}, {-1, 0x0164, 611}, {-1, 0x2202, 494}, {-1, 0x00FF, 556}, {-1, 0x0143, 722}, {-1, 0x00EE, 278}, {-1, 0x00CA, 667}, {-1, 0x00E4, 556}, {-1, 0x00EB, 556}, {-1, 0x0107, 556}, {-1, 0x0144, 611}, {-1, 0x016B, 611}, {-1, 0x0147, 722}, {-1, 0x00CD, 278}, {-1, 0x00B1, 584}, {-1, 0x00A6, 280}, {-1, 0x00AE, 737}, {-1, 0x011E, 778}, {-1, 0x0130, 278}, {-1, 0x2211, 600}, {-1, 0x00C8, 667}, {-1, 0x0155, 389}, {-1, 0x014D, 611}, {-1, 0x0179, 611}, {-1, 0x017D, 611}, {-1, 0x2265, 549}, {-1, 0x00D0, 722}, {-1, 0x00C7, 722}, {-1, 0x013C, 278}, {-1, 0x0165, 389}, {-1, 0x0119, 556}, {-1, 0x0172, 722}, {-1, 0x00C1, 722}, {-1, 0x00C4, 722}, {-1, 0x00E8, 556}, {-1, 0x017A, 500}, {-1, 0x012F, 278}, {-1, 0x00D3, 778}, {-1, 0x00F3, 611}, {-1, 0x0101, 556}, {-1, 0x015B, 556}, {-1, 0x00EF, 278}, {-1, 0x00D4, 778}, {-1, 0x00D9, 722}, {-1, 0x0394, 612}, {-1, 0x00FE, 611}, {-1, 0x00B2, 333}, {-1, 0x00D6, 778}, {-1, 0x00B5, 611}, {-1, 0x00EC, 278}, {-1, 0x0151, 611}, {-1, 0x0118, 667}, {-1, 0x0111, 611}, {-1, 0x00BE, 834}, {-1, 0x015E, 667}, {-1, 0x013E, 400}, {-1, 0x0136, 722}, {-1, 0x0139, 611}, {-1, 0x2122, 1000}, {-1, 0x0117, 556}, {-1, 0x00CC, 278}, {-1, 0x012A, 278}, {-1, 0x013D, 611}, {-1, 0x00BD, 834}, {-1, 0x2264, 549}, {-1, 0x00F4, 611}, {-1, 0x00F1, 611}, {-1, 0x0170, 722}, {-1, 0x00C9, 667}, {-1, 0x0113, 556}, {-1, 0x011F, 611}, {-1, 0x00BC, 834}, {-1, 0x0160, 667}, {-1, 0x0218, 667}, {-1, 0x0150, 778}, {-1, 0x00B0, 400}, {-1, 0x00F2, 611}, {-1, 0x010C, 722}, {-1, 0x00F9, 611}, {-1, 0x221A, 549}, {-1, 0x010E, 722}, {-1, 0x0157, 389}, {-1, 0x00D1, 722}, {-1, 0x00F5, 611}, {-1, 0x0156, 722}, {-1, 0x013B, 611}, {-1, 0x00C3, 722}, {-1, 0x0104, 722}, {-1, 0x00C5, 722}, {-1, 0x00D5, 778}, {-1, 0x017C, 500}, {-1, 0x011A, 667}, {-1, 0x012E, 278}, {-1, 0x0137, 556}, {-1, 0x2212, 584}, {-1, 0x00CE, 278}, {-1, 0x0148, 611}, {-1, 0x0163, 333}, {-1, 0x00AC, 584}, {-1, 0x00F6, 611}, {-1, 0x00FC, 611}, {-1, 0x2260, 549}, {-1, 0x0123, 611}, {-1, 0x00F0, 611}, {-1, 0x017E, 500}, {-1, 0x0146, 611}, {-1, 0x00B9, 333}, {-1, 0x012B, 278}, {-1, 0x20AC, 556}, {-1, 0xFFFF, 0} }; static const PODOFO_CharData CHAR_DATA_HELVETICA_BOLD_OBLIQUE[316] = { {32, 0x0020, 278}, {33, 0x0021, 333}, {34, 0x0022, 474}, {35, 0x0023, 556}, {36, 0x0024, 556}, {37, 0x0025, 889}, {38, 0x0026, 722}, {39, 0x2019, 278}, {40, 0x0028, 333}, {41, 0x0029, 333}, {42, 0x002A, 389}, {43, 0x002B, 584}, {44, 0x002C, 278}, {45, 0x002D, 333}, {46, 0x002E, 278}, {47, 0x002F, 278}, {48, 0x0030, 556}, {49, 0x0031, 556}, {50, 0x0032, 556}, {51, 0x0033, 556}, {52, 0x0034, 556}, {53, 0x0035, 556}, {54, 0x0036, 556}, {55, 0x0037, 556}, {56, 0x0038, 556}, {57, 0x0039, 556}, {58, 0x003A, 333}, {59, 0x003B, 333}, {60, 0x003C, 584}, {61, 0x003D, 584}, {62, 0x003E, 584}, {63, 0x003F, 611}, {64, 0x0040, 975}, {65, 0x0041, 722}, {66, 0x0042, 722}, {67, 0x0043, 722}, {68, 0x0044, 722}, {69, 0x0045, 667}, {70, 0x0046, 611}, {71, 0x0047, 778}, {72, 0x0048, 722}, {73, 0x0049, 278}, {74, 0x004A, 556}, {75, 0x004B, 722}, {76, 0x004C, 611}, {77, 0x004D, 833}, {78, 0x004E, 722}, {79, 0x004F, 778}, {80, 0x0050, 667}, {81, 0x0051, 778}, {82, 0x0052, 722}, {83, 0x0053, 667}, {84, 0x0054, 611}, {85, 0x0055, 722}, {86, 0x0056, 667}, {87, 0x0057, 944}, {88, 0x0058, 667}, {89, 0x0059, 667}, {90, 0x005A, 611}, {91, 0x005B, 333}, {92, 0x005C, 278}, {93, 0x005D, 333}, {94, 0x005E, 584}, {95, 0x005F, 556}, {96, 0x2018, 278}, {97, 0x0061, 556}, {98, 0x0062, 611}, {99, 0x0063, 556}, {100, 0x0064, 611}, {101, 0x0065, 556}, {102, 0x0066, 333}, {103, 0x0067, 611}, {104, 0x0068, 611}, {105, 0x0069, 278}, {106, 0x006A, 278}, {107, 0x006B, 556}, {108, 0x006C, 278}, {109, 0x006D, 889}, {110, 0x006E, 611}, {111, 0x006F, 611}, {112, 0x0070, 611}, {113, 0x0071, 611}, {114, 0x0072, 389}, {115, 0x0073, 556}, {116, 0x0074, 333}, {117, 0x0075, 611}, {118, 0x0076, 556}, {119, 0x0077, 778}, {120, 0x0078, 556}, {121, 0x0079, 556}, {122, 0x007A, 500}, {123, 0x007B, 389}, {124, 0x007C, 280}, {125, 0x007D, 389}, {126, 0x007E, 584}, {161, 0x00A1, 333}, {162, 0x00A2, 556}, {163, 0x00A3, 556}, {164, 0x2044, 167}, {165, 0x00A5, 556}, {166, 0x0192, 556}, {167, 0x00A7, 556}, {168, 0x00A4, 556}, {169, 0x0027, 238}, {170, 0x201C, 500}, {171, 0x00AB, 556}, {172, 0x2039, 333}, {173, 0x203A, 333}, {174, 0xFB01, 611}, {175, 0xFB02, 611}, {177, 0x2013, 556}, {178, 0x2020, 556}, {179, 0x2021, 556}, {180, 0x00B7, 278}, {182, 0x00B6, 556}, {183, 0x2022, 350}, {184, 0x201A, 278}, {185, 0x201E, 500}, {186, 0x201D, 500}, {187, 0x00BB, 556}, {188, 0x2026, 1000}, {189, 0x2030, 1000}, {191, 0x00BF, 611}, {193, 0x0060, 333}, {194, 0x00B4, 333}, {195, 0x02C6, 333}, {196, 0x02DC, 333}, {197, 0x00AF, 333}, {198, 0x02D8, 333}, {199, 0x02D9, 333}, {200, 0x00A8, 333}, {202, 0x02DA, 333}, {203, 0x00B8, 333}, {205, 0x02DD, 333}, {206, 0x02DB, 333}, {207, 0x02C7, 333}, {208, 0x2014, 1000}, {225, 0x00C6, 1000}, {227, 0x00AA, 370}, {232, 0x0141, 611}, {233, 0x00D8, 778}, {234, 0x0152, 1000}, {235, 0x00BA, 365}, {241, 0x00E6, 889}, {245, 0x0131, 278}, {248, 0x0142, 278}, {249, 0x00F8, 611}, {250, 0x0153, 944}, {251, 0x00DF, 611}, {-1, 0x00CF, 278}, {-1, 0x00E9, 556}, {-1, 0x0103, 556}, {-1, 0x0171, 611}, {-1, 0x011B, 556}, {-1, 0x0178, 667}, {-1, 0x00F7, 584}, {-1, 0x00DD, 667}, {-1, 0x00C2, 722}, {-1, 0x00E1, 556}, {-1, 0x00DB, 722}, {-1, 0x00FD, 556}, {-1, 0x0219, 556}, {-1, 0x00EA, 556}, {-1, 0x016E, 722}, {-1, 0x00DC, 722}, {-1, 0x0105, 556}, {-1, 0x00DA, 722}, {-1, 0x0173, 611}, {-1, 0x00CB, 667}, {-1, 0x0110, 722}, {-1, 0xF6C3, 250}, {-1, 0x00A9, 737}, {-1, 0x0112, 667}, {-1, 0x010D, 556}, {-1, 0x00E5, 556}, {-1, 0x0145, 722}, {-1, 0x013A, 278}, {-1, 0x00E0, 556}, {-1, 0x0162, 611}, {-1, 0x0106, 722}, {-1, 0x00E3, 556}, {-1, 0x0116, 667}, {-1, 0x0161, 556}, {-1, 0x015F, 556}, {-1, 0x00ED, 278}, {-1, 0x25CA, 494}, {-1, 0x0158, 722}, {-1, 0x0122, 778}, {-1, 0x00FB, 611}, {-1, 0x00E2, 556}, {-1, 0x0100, 722}, {-1, 0x0159, 389}, {-1, 0x00E7, 556}, {-1, 0x017B, 611}, {-1, 0x00DE, 667}, {-1, 0x014C, 778}, {-1, 0x0154, 722}, {-1, 0x015A, 667}, {-1, 0x010F, 743}, {-1, 0x016A, 722}, {-1, 0x016F, 611}, {-1, 0x00B3, 333}, {-1, 0x00D2, 778}, {-1, 0x00C0, 722}, {-1, 0x0102, 722}, {-1, 0x00D7, 584}, {-1, 0x00FA, 611}, {-1, 0x0164, 611}, {-1, 0x2202, 494}, {-1, 0x00FF, 556}, {-1, 0x0143, 722}, {-1, 0x00EE, 278}, {-1, 0x00CA, 667}, {-1, 0x00E4, 556}, {-1, 0x00EB, 556}, {-1, 0x0107, 556}, {-1, 0x0144, 611}, {-1, 0x016B, 611}, {-1, 0x0147, 722}, {-1, 0x00CD, 278}, {-1, 0x00B1, 584}, {-1, 0x00A6, 280}, {-1, 0x00AE, 737}, {-1, 0x011E, 778}, {-1, 0x0130, 278}, {-1, 0x2211, 600}, {-1, 0x00C8, 667}, {-1, 0x0155, 389}, {-1, 0x014D, 611}, {-1, 0x0179, 611}, {-1, 0x017D, 611}, {-1, 0x2265, 549}, {-1, 0x00D0, 722}, {-1, 0x00C7, 722}, {-1, 0x013C, 278}, {-1, 0x0165, 389}, {-1, 0x0119, 556}, {-1, 0x0172, 722}, {-1, 0x00C1, 722}, {-1, 0x00C4, 722}, {-1, 0x00E8, 556}, {-1, 0x017A, 500}, {-1, 0x012F, 278}, {-1, 0x00D3, 778}, {-1, 0x00F3, 611}, {-1, 0x0101, 556}, {-1, 0x015B, 556}, {-1, 0x00EF, 278}, {-1, 0x00D4, 778}, {-1, 0x00D9, 722}, {-1, 0x0394, 612}, {-1, 0x00FE, 611}, {-1, 0x00B2, 333}, {-1, 0x00D6, 778}, {-1, 0x00B5, 611}, {-1, 0x00EC, 278}, {-1, 0x0151, 611}, {-1, 0x0118, 667}, {-1, 0x0111, 611}, {-1, 0x00BE, 834}, {-1, 0x015E, 667}, {-1, 0x013E, 400}, {-1, 0x0136, 722}, {-1, 0x0139, 611}, {-1, 0x2122, 1000}, {-1, 0x0117, 556}, {-1, 0x00CC, 278}, {-1, 0x012A, 278}, {-1, 0x013D, 611}, {-1, 0x00BD, 834}, {-1, 0x2264, 549}, {-1, 0x00F4, 611}, {-1, 0x00F1, 611}, {-1, 0x0170, 722}, {-1, 0x00C9, 667}, {-1, 0x0113, 556}, {-1, 0x011F, 611}, {-1, 0x00BC, 834}, {-1, 0x0160, 667}, {-1, 0x0218, 667}, {-1, 0x0150, 778}, {-1, 0x00B0, 400}, {-1, 0x00F2, 611}, {-1, 0x010C, 722}, {-1, 0x00F9, 611}, {-1, 0x221A, 549}, {-1, 0x010E, 722}, {-1, 0x0157, 389}, {-1, 0x00D1, 722}, {-1, 0x00F5, 611}, {-1, 0x0156, 722}, {-1, 0x013B, 611}, {-1, 0x00C3, 722}, {-1, 0x0104, 722}, {-1, 0x00C5, 722}, {-1, 0x00D5, 778}, {-1, 0x017C, 500}, {-1, 0x011A, 667}, {-1, 0x012E, 278}, {-1, 0x0137, 556}, {-1, 0x2212, 584}, {-1, 0x00CE, 278}, {-1, 0x0148, 611}, {-1, 0x0163, 333}, {-1, 0x00AC, 584}, {-1, 0x00F6, 611}, {-1, 0x00FC, 611}, {-1, 0x2260, 549}, {-1, 0x0123, 611}, {-1, 0x00F0, 611}, {-1, 0x017E, 500}, {-1, 0x0146, 611}, {-1, 0x00B9, 333}, {-1, 0x012B, 278}, {-1, 0x20AC, 556}, {-1, 0xFFFF, 0} }; static const PODOFO_CharData CHAR_DATA_HELVETICA_OBLIQUE[316] = { {32, 0x0020, 278}, {33, 0x0021, 278}, {34, 0x0022, 355}, {35, 0x0023, 556}, {36, 0x0024, 556}, {37, 0x0025, 889}, {38, 0x0026, 667}, {39, 0x2019, 222}, {40, 0x0028, 333}, {41, 0x0029, 333}, {42, 0x002A, 389}, {43, 0x002B, 584}, {44, 0x002C, 278}, {45, 0x002D, 333}, {46, 0x002E, 278}, {47, 0x002F, 278}, {48, 0x0030, 556}, {49, 0x0031, 556}, {50, 0x0032, 556}, {51, 0x0033, 556}, {52, 0x0034, 556}, {53, 0x0035, 556}, {54, 0x0036, 556}, {55, 0x0037, 556}, {56, 0x0038, 556}, {57, 0x0039, 556}, {58, 0x003A, 278}, {59, 0x003B, 278}, {60, 0x003C, 584}, {61, 0x003D, 584}, {62, 0x003E, 584}, {63, 0x003F, 556}, {64, 0x0040, 1015}, {65, 0x0041, 667}, {66, 0x0042, 667}, {67, 0x0043, 722}, {68, 0x0044, 722}, {69, 0x0045, 667}, {70, 0x0046, 611}, {71, 0x0047, 778}, {72, 0x0048, 722}, {73, 0x0049, 278}, {74, 0x004A, 500}, {75, 0x004B, 667}, {76, 0x004C, 556}, {77, 0x004D, 833}, {78, 0x004E, 722}, {79, 0x004F, 778}, {80, 0x0050, 667}, {81, 0x0051, 778}, {82, 0x0052, 722}, {83, 0x0053, 667}, {84, 0x0054, 611}, {85, 0x0055, 722}, {86, 0x0056, 667}, {87, 0x0057, 944}, {88, 0x0058, 667}, {89, 0x0059, 667}, {90, 0x005A, 611}, {91, 0x005B, 278}, {92, 0x005C, 278}, {93, 0x005D, 278}, {94, 0x005E, 469}, {95, 0x005F, 556}, {96, 0x2018, 222}, {97, 0x0061, 556}, {98, 0x0062, 556}, {99, 0x0063, 500}, {100, 0x0064, 556}, {101, 0x0065, 556}, {102, 0x0066, 278}, {103, 0x0067, 556}, {104, 0x0068, 556}, {105, 0x0069, 222}, {106, 0x006A, 222}, {107, 0x006B, 500}, {108, 0x006C, 222}, {109, 0x006D, 833}, {110, 0x006E, 556}, {111, 0x006F, 556}, {112, 0x0070, 556}, {113, 0x0071, 556}, {114, 0x0072, 333}, {115, 0x0073, 500}, {116, 0x0074, 278}, {117, 0x0075, 556}, {118, 0x0076, 500}, {119, 0x0077, 722}, {120, 0x0078, 500}, {121, 0x0079, 500}, {122, 0x007A, 500}, {123, 0x007B, 334}, {124, 0x007C, 260}, {125, 0x007D, 334}, {126, 0x007E, 584}, {161, 0x00A1, 333}, {162, 0x00A2, 556}, {163, 0x00A3, 556}, {164, 0x2044, 167}, {165, 0x00A5, 556}, {166, 0x0192, 556}, {167, 0x00A7, 556}, {168, 0x00A4, 556}, {169, 0x0027, 191}, {170, 0x201C, 333}, {171, 0x00AB, 556}, {172, 0x2039, 333}, {173, 0x203A, 333}, {174, 0xFB01, 500}, {175, 0xFB02, 500}, {177, 0x2013, 556}, {178, 0x2020, 556}, {179, 0x2021, 556}, {180, 0x00B7, 278}, {182, 0x00B6, 537}, {183, 0x2022, 350}, {184, 0x201A, 222}, {185, 0x201E, 333}, {186, 0x201D, 333}, {187, 0x00BB, 556}, {188, 0x2026, 1000}, {189, 0x2030, 1000}, {191, 0x00BF, 611}, {193, 0x0060, 333}, {194, 0x00B4, 333}, {195, 0x02C6, 333}, {196, 0x02DC, 333}, {197, 0x00AF, 333}, {198, 0x02D8, 333}, {199, 0x02D9, 333}, {200, 0x00A8, 333}, {202, 0x02DA, 333}, {203, 0x00B8, 333}, {205, 0x02DD, 333}, {206, 0x02DB, 333}, {207, 0x02C7, 333}, {208, 0x2014, 1000}, {225, 0x00C6, 1000}, {227, 0x00AA, 370}, {232, 0x0141, 556}, {233, 0x00D8, 778}, {234, 0x0152, 1000}, {235, 0x00BA, 365}, {241, 0x00E6, 889}, {245, 0x0131, 278}, {248, 0x0142, 222}, {249, 0x00F8, 611}, {250, 0x0153, 944}, {251, 0x00DF, 611}, {-1, 0x00CF, 278}, {-1, 0x00E9, 556}, {-1, 0x0103, 556}, {-1, 0x0171, 556}, {-1, 0x011B, 556}, {-1, 0x0178, 667}, {-1, 0x00F7, 584}, {-1, 0x00DD, 667}, {-1, 0x00C2, 667}, {-1, 0x00E1, 556}, {-1, 0x00DB, 722}, {-1, 0x00FD, 500}, {-1, 0x0219, 500}, {-1, 0x00EA, 556}, {-1, 0x016E, 722}, {-1, 0x00DC, 722}, {-1, 0x0105, 556}, {-1, 0x00DA, 722}, {-1, 0x0173, 556}, {-1, 0x00CB, 667}, {-1, 0x0110, 722}, {-1, 0xF6C3, 250}, {-1, 0x00A9, 737}, {-1, 0x0112, 667}, {-1, 0x010D, 500}, {-1, 0x00E5, 556}, {-1, 0x0145, 722}, {-1, 0x013A, 222}, {-1, 0x00E0, 556}, {-1, 0x0162, 611}, {-1, 0x0106, 722}, {-1, 0x00E3, 556}, {-1, 0x0116, 667}, {-1, 0x0161, 500}, {-1, 0x015F, 500}, {-1, 0x00ED, 278}, {-1, 0x25CA, 471}, {-1, 0x0158, 722}, {-1, 0x0122, 778}, {-1, 0x00FB, 556}, {-1, 0x00E2, 556}, {-1, 0x0100, 667}, {-1, 0x0159, 333}, {-1, 0x00E7, 500}, {-1, 0x017B, 611}, {-1, 0x00DE, 667}, {-1, 0x014C, 778}, {-1, 0x0154, 722}, {-1, 0x015A, 667}, {-1, 0x010F, 643}, {-1, 0x016A, 722}, {-1, 0x016F, 556}, {-1, 0x00B3, 333}, {-1, 0x00D2, 778}, {-1, 0x00C0, 667}, {-1, 0x0102, 667}, {-1, 0x00D7, 584}, {-1, 0x00FA, 556}, {-1, 0x0164, 611}, {-1, 0x2202, 476}, {-1, 0x00FF, 500}, {-1, 0x0143, 722}, {-1, 0x00EE, 278}, {-1, 0x00CA, 667}, {-1, 0x00E4, 556}, {-1, 0x00EB, 556}, {-1, 0x0107, 500}, {-1, 0x0144, 556}, {-1, 0x016B, 556}, {-1, 0x0147, 722}, {-1, 0x00CD, 278}, {-1, 0x00B1, 584}, {-1, 0x00A6, 260}, {-1, 0x00AE, 737}, {-1, 0x011E, 778}, {-1, 0x0130, 278}, {-1, 0x2211, 600}, {-1, 0x00C8, 667}, {-1, 0x0155, 333}, {-1, 0x014D, 556}, {-1, 0x0179, 611}, {-1, 0x017D, 611}, {-1, 0x2265, 549}, {-1, 0x00D0, 722}, {-1, 0x00C7, 722}, {-1, 0x013C, 222}, {-1, 0x0165, 316}, {-1, 0x0119, 556}, {-1, 0x0172, 722}, {-1, 0x00C1, 667}, {-1, 0x00C4, 667}, {-1, 0x00E8, 556}, {-1, 0x017A, 500}, {-1, 0x012F, 222}, {-1, 0x00D3, 778}, {-1, 0x00F3, 556}, {-1, 0x0101, 556}, {-1, 0x015B, 500}, {-1, 0x00EF, 278}, {-1, 0x00D4, 778}, {-1, 0x00D9, 722}, {-1, 0x0394, 612}, {-1, 0x00FE, 556}, {-1, 0x00B2, 333}, {-1, 0x00D6, 778}, {-1, 0x00B5, 556}, {-1, 0x00EC, 278}, {-1, 0x0151, 556}, {-1, 0x0118, 667}, {-1, 0x0111, 556}, {-1, 0x00BE, 834}, {-1, 0x015E, 667}, {-1, 0x013E, 299}, {-1, 0x0136, 667}, {-1, 0x0139, 556}, {-1, 0x2122, 1000}, {-1, 0x0117, 556}, {-1, 0x00CC, 278}, {-1, 0x012A, 278}, {-1, 0x013D, 556}, {-1, 0x00BD, 834}, {-1, 0x2264, 549}, {-1, 0x00F4, 556}, {-1, 0x00F1, 556}, {-1, 0x0170, 722}, {-1, 0x00C9, 667}, {-1, 0x0113, 556}, {-1, 0x011F, 556}, {-1, 0x00BC, 834}, {-1, 0x0160, 667}, {-1, 0x0218, 667}, {-1, 0x0150, 778}, {-1, 0x00B0, 400}, {-1, 0x00F2, 556}, {-1, 0x010C, 722}, {-1, 0x00F9, 556}, {-1, 0x221A, 453}, {-1, 0x010E, 722}, {-1, 0x0157, 333}, {-1, 0x00D1, 722}, {-1, 0x00F5, 556}, {-1, 0x0156, 722}, {-1, 0x013B, 556}, {-1, 0x00C3, 667}, {-1, 0x0104, 667}, {-1, 0x00C5, 667}, {-1, 0x00D5, 778}, {-1, 0x017C, 500}, {-1, 0x011A, 667}, {-1, 0x012E, 278}, {-1, 0x0137, 500}, {-1, 0x2212, 584}, {-1, 0x00CE, 278}, {-1, 0x0148, 556}, {-1, 0x0163, 278}, {-1, 0x00AC, 584}, {-1, 0x00F6, 556}, {-1, 0x00FC, 556}, {-1, 0x2260, 549}, {-1, 0x0123, 556}, {-1, 0x00F0, 556}, {-1, 0x017E, 500}, {-1, 0x0146, 556}, {-1, 0x00B9, 333}, {-1, 0x012B, 278}, {-1, 0x20AC, 556}, {-1, 0xFFFF, 0} }; static const PODOFO_CharData CHAR_DATA_TIMES_ROMAN[316] = { {32, 0x0020, 250}, {33, 0x0021, 333}, {34, 0x0022, 408}, {35, 0x0023, 500}, {36, 0x0024, 500}, {37, 0x0025, 833}, {38, 0x0026, 778}, {39, 0x2019, 333}, {40, 0x0028, 333}, {41, 0x0029, 333}, {42, 0x002A, 500}, {43, 0x002B, 564}, {44, 0x002C, 250}, {45, 0x002D, 333}, {46, 0x002E, 250}, {47, 0x002F, 278}, {48, 0x0030, 500}, {49, 0x0031, 500}, {50, 0x0032, 500}, {51, 0x0033, 500}, {52, 0x0034, 500}, {53, 0x0035, 500}, {54, 0x0036, 500}, {55, 0x0037, 500}, {56, 0x0038, 500}, {57, 0x0039, 500}, {58, 0x003A, 278}, {59, 0x003B, 278}, {60, 0x003C, 564}, {61, 0x003D, 564}, {62, 0x003E, 564}, {63, 0x003F, 444}, {64, 0x0040, 921}, {65, 0x0041, 722}, {66, 0x0042, 667}, {67, 0x0043, 667}, {68, 0x0044, 722}, {69, 0x0045, 611}, {70, 0x0046, 556}, {71, 0x0047, 722}, {72, 0x0048, 722}, {73, 0x0049, 333}, {74, 0x004A, 389}, {75, 0x004B, 722}, {76, 0x004C, 611}, {77, 0x004D, 889}, {78, 0x004E, 722}, {79, 0x004F, 722}, {80, 0x0050, 556}, {81, 0x0051, 722}, {82, 0x0052, 667}, {83, 0x0053, 556}, {84, 0x0054, 611}, {85, 0x0055, 722}, {86, 0x0056, 722}, {87, 0x0057, 944}, {88, 0x0058, 722}, {89, 0x0059, 722}, {90, 0x005A, 611}, {91, 0x005B, 333}, {92, 0x005C, 278}, {93, 0x005D, 333}, {94, 0x005E, 469}, {95, 0x005F, 500}, {96, 0x2018, 333}, {97, 0x0061, 444}, {98, 0x0062, 500}, {99, 0x0063, 444}, {100, 0x0064, 500}, {101, 0x0065, 444}, {102, 0x0066, 333}, {103, 0x0067, 500}, {104, 0x0068, 500}, {105, 0x0069, 278}, {106, 0x006A, 278}, {107, 0x006B, 500}, {108, 0x006C, 278}, {109, 0x006D, 778}, {110, 0x006E, 500}, {111, 0x006F, 500}, {112, 0x0070, 500}, {113, 0x0071, 500}, {114, 0x0072, 333}, {115, 0x0073, 389}, {116, 0x0074, 278}, {117, 0x0075, 500}, {118, 0x0076, 500}, {119, 0x0077, 722}, {120, 0x0078, 500}, {121, 0x0079, 500}, {122, 0x007A, 444}, {123, 0x007B, 480}, {124, 0x007C, 200}, {125, 0x007D, 480}, {126, 0x007E, 541}, {161, 0x00A1, 333}, {162, 0x00A2, 500}, {163, 0x00A3, 500}, {164, 0x2044, 167}, {165, 0x00A5, 500}, {166, 0x0192, 500}, {167, 0x00A7, 500}, {168, 0x00A4, 500}, {169, 0x0027, 180}, {170, 0x201C, 444}, {171, 0x00AB, 500}, {172, 0x2039, 333}, {173, 0x203A, 333}, {174, 0xFB01, 556}, {175, 0xFB02, 556}, {177, 0x2013, 500}, {178, 0x2020, 500}, {179, 0x2021, 500}, {180, 0x00B7, 250}, {182, 0x00B6, 453}, {183, 0x2022, 350}, {184, 0x201A, 333}, {185, 0x201E, 444}, {186, 0x201D, 444}, {187, 0x00BB, 500}, {188, 0x2026, 1000}, {189, 0x2030, 1000}, {191, 0x00BF, 444}, {193, 0x0060, 333}, {194, 0x00B4, 333}, {195, 0x02C6, 333}, {196, 0x02DC, 333}, {197, 0x00AF, 333}, {198, 0x02D8, 333}, {199, 0x02D9, 333}, {200, 0x00A8, 333}, {202, 0x02DA, 333}, {203, 0x00B8, 333}, {205, 0x02DD, 333}, {206, 0x02DB, 333}, {207, 0x02C7, 333}, {208, 0x2014, 1000}, {225, 0x00C6, 889}, {227, 0x00AA, 276}, {232, 0x0141, 611}, {233, 0x00D8, 722}, {234, 0x0152, 889}, {235, 0x00BA, 310}, {241, 0x00E6, 667}, {245, 0x0131, 278}, {248, 0x0142, 278}, {249, 0x00F8, 500}, {250, 0x0153, 722}, {251, 0x00DF, 500}, {-1, 0x00CF, 333}, {-1, 0x00E9, 444}, {-1, 0x0103, 444}, {-1, 0x0171, 500}, {-1, 0x011B, 444}, {-1, 0x0178, 722}, {-1, 0x00F7, 564}, {-1, 0x00DD, 722}, {-1, 0x00C2, 722}, {-1, 0x00E1, 444}, {-1, 0x00DB, 722}, {-1, 0x00FD, 500}, {-1, 0x0219, 389}, {-1, 0x00EA, 444}, {-1, 0x016E, 722}, {-1, 0x00DC, 722}, {-1, 0x0105, 444}, {-1, 0x00DA, 722}, {-1, 0x0173, 500}, {-1, 0x00CB, 611}, {-1, 0x0110, 722}, {-1, 0xF6C3, 250}, {-1, 0x00A9, 760}, {-1, 0x0112, 611}, {-1, 0x010D, 444}, {-1, 0x00E5, 444}, {-1, 0x0145, 722}, {-1, 0x013A, 278}, {-1, 0x00E0, 444}, {-1, 0x0162, 611}, {-1, 0x0106, 667}, {-1, 0x00E3, 444}, {-1, 0x0116, 611}, {-1, 0x0161, 389}, {-1, 0x015F, 389}, {-1, 0x00ED, 278}, {-1, 0x25CA, 471}, {-1, 0x0158, 667}, {-1, 0x0122, 722}, {-1, 0x00FB, 500}, {-1, 0x00E2, 444}, {-1, 0x0100, 722}, {-1, 0x0159, 333}, {-1, 0x00E7, 444}, {-1, 0x017B, 611}, {-1, 0x00DE, 556}, {-1, 0x014C, 722}, {-1, 0x0154, 667}, {-1, 0x015A, 556}, {-1, 0x010F, 588}, {-1, 0x016A, 722}, {-1, 0x016F, 500}, {-1, 0x00B3, 300}, {-1, 0x00D2, 722}, {-1, 0x00C0, 722}, {-1, 0x0102, 722}, {-1, 0x00D7, 564}, {-1, 0x00FA, 500}, {-1, 0x0164, 611}, {-1, 0x2202, 476}, {-1, 0x00FF, 500}, {-1, 0x0143, 722}, {-1, 0x00EE, 278}, {-1, 0x00CA, 611}, {-1, 0x00E4, 444}, {-1, 0x00EB, 444}, {-1, 0x0107, 444}, {-1, 0x0144, 500}, {-1, 0x016B, 500}, {-1, 0x0147, 722}, {-1, 0x00CD, 333}, {-1, 0x00B1, 564}, {-1, 0x00A6, 200}, {-1, 0x00AE, 760}, {-1, 0x011E, 722}, {-1, 0x0130, 333}, {-1, 0x2211, 600}, {-1, 0x00C8, 611}, {-1, 0x0155, 333}, {-1, 0x014D, 500}, {-1, 0x0179, 611}, {-1, 0x017D, 611}, {-1, 0x2265, 549}, {-1, 0x00D0, 722}, {-1, 0x00C7, 667}, {-1, 0x013C, 278}, {-1, 0x0165, 326}, {-1, 0x0119, 444}, {-1, 0x0172, 722}, {-1, 0x00C1, 722}, {-1, 0x00C4, 722}, {-1, 0x00E8, 444}, {-1, 0x017A, 444}, {-1, 0x012F, 278}, {-1, 0x00D3, 722}, {-1, 0x00F3, 500}, {-1, 0x0101, 444}, {-1, 0x015B, 389}, {-1, 0x00EF, 278}, {-1, 0x00D4, 722}, {-1, 0x00D9, 722}, {-1, 0x0394, 612}, {-1, 0x00FE, 500}, {-1, 0x00B2, 300}, {-1, 0x00D6, 722}, {-1, 0x00B5, 500}, {-1, 0x00EC, 278}, {-1, 0x0151, 500}, {-1, 0x0118, 611}, {-1, 0x0111, 500}, {-1, 0x00BE, 750}, {-1, 0x015E, 556}, {-1, 0x013E, 344}, {-1, 0x0136, 722}, {-1, 0x0139, 611}, {-1, 0x2122, 980}, {-1, 0x0117, 444}, {-1, 0x00CC, 333}, {-1, 0x012A, 333}, {-1, 0x013D, 611}, {-1, 0x00BD, 750}, {-1, 0x2264, 549}, {-1, 0x00F4, 500}, {-1, 0x00F1, 500}, {-1, 0x0170, 722}, {-1, 0x00C9, 611}, {-1, 0x0113, 444}, {-1, 0x011F, 500}, {-1, 0x00BC, 750}, {-1, 0x0160, 556}, {-1, 0x0218, 556}, {-1, 0x0150, 722}, {-1, 0x00B0, 400}, {-1, 0x00F2, 500}, {-1, 0x010C, 667}, {-1, 0x00F9, 500}, {-1, 0x221A, 453}, {-1, 0x010E, 722}, {-1, 0x0157, 333}, {-1, 0x00D1, 722}, {-1, 0x00F5, 500}, {-1, 0x0156, 667}, {-1, 0x013B, 611}, {-1, 0x00C3, 722}, {-1, 0x0104, 722}, {-1, 0x00C5, 722}, {-1, 0x00D5, 722}, {-1, 0x017C, 444}, {-1, 0x011A, 611}, {-1, 0x012E, 333}, {-1, 0x0137, 500}, {-1, 0x2212, 564}, {-1, 0x00CE, 333}, {-1, 0x0148, 500}, {-1, 0x0163, 278}, {-1, 0x00AC, 564}, {-1, 0x00F6, 500}, {-1, 0x00FC, 500}, {-1, 0x2260, 549}, {-1, 0x0123, 500}, {-1, 0x00F0, 500}, {-1, 0x017E, 444}, {-1, 0x0146, 500}, {-1, 0x00B9, 300}, {-1, 0x012B, 278}, {-1, 0x20AC, 500}, {-1, 0xFFFF, 0} }; static const PODOFO_CharData CHAR_DATA_TIMES_BOLD[316] = { {32, 0x0020, 250}, {33, 0x0021, 333}, {34, 0x0022, 555}, {35, 0x0023, 500}, {36, 0x0024, 500}, {37, 0x0025, 1000}, {38, 0x0026, 833}, {39, 0x2019, 333}, {40, 0x0028, 333}, {41, 0x0029, 333}, {42, 0x002A, 500}, {43, 0x002B, 570}, {44, 0x002C, 250}, {45, 0x002D, 333}, {46, 0x002E, 250}, {47, 0x002F, 278}, {48, 0x0030, 500}, {49, 0x0031, 500}, {50, 0x0032, 500}, {51, 0x0033, 500}, {52, 0x0034, 500}, {53, 0x0035, 500}, {54, 0x0036, 500}, {55, 0x0037, 500}, {56, 0x0038, 500}, {57, 0x0039, 500}, {58, 0x003A, 333}, {59, 0x003B, 333}, {60, 0x003C, 570}, {61, 0x003D, 570}, {62, 0x003E, 570}, {63, 0x003F, 500}, {64, 0x0040, 930}, {65, 0x0041, 722}, {66, 0x0042, 667}, {67, 0x0043, 722}, {68, 0x0044, 722}, {69, 0x0045, 667}, {70, 0x0046, 611}, {71, 0x0047, 778}, {72, 0x0048, 778}, {73, 0x0049, 389}, {74, 0x004A, 500}, {75, 0x004B, 778}, {76, 0x004C, 667}, {77, 0x004D, 944}, {78, 0x004E, 722}, {79, 0x004F, 778}, {80, 0x0050, 611}, {81, 0x0051, 778}, {82, 0x0052, 722}, {83, 0x0053, 556}, {84, 0x0054, 667}, {85, 0x0055, 722}, {86, 0x0056, 722}, {87, 0x0057, 1000}, {88, 0x0058, 722}, {89, 0x0059, 722}, {90, 0x005A, 667}, {91, 0x005B, 333}, {92, 0x005C, 278}, {93, 0x005D, 333}, {94, 0x005E, 581}, {95, 0x005F, 500}, {96, 0x2018, 333}, {97, 0x0061, 500}, {98, 0x0062, 556}, {99, 0x0063, 444}, {100, 0x0064, 556}, {101, 0x0065, 444}, {102, 0x0066, 333}, {103, 0x0067, 500}, {104, 0x0068, 556}, {105, 0x0069, 278}, {106, 0x006A, 333}, {107, 0x006B, 556}, {108, 0x006C, 278}, {109, 0x006D, 833}, {110, 0x006E, 556}, {111, 0x006F, 500}, {112, 0x0070, 556}, {113, 0x0071, 556}, {114, 0x0072, 444}, {115, 0x0073, 389}, {116, 0x0074, 333}, {117, 0x0075, 556}, {118, 0x0076, 500}, {119, 0x0077, 722}, {120, 0x0078, 500}, {121, 0x0079, 500}, {122, 0x007A, 444}, {123, 0x007B, 394}, {124, 0x007C, 220}, {125, 0x007D, 394}, {126, 0x007E, 520}, {161, 0x00A1, 333}, {162, 0x00A2, 500}, {163, 0x00A3, 500}, {164, 0x2044, 167}, {165, 0x00A5, 500}, {166, 0x0192, 500}, {167, 0x00A7, 500}, {168, 0x00A4, 500}, {169, 0x0027, 278}, {170, 0x201C, 500}, {171, 0x00AB, 500}, {172, 0x2039, 333}, {173, 0x203A, 333}, {174, 0xFB01, 556}, {175, 0xFB02, 556}, {177, 0x2013, 500}, {178, 0x2020, 500}, {179, 0x2021, 500}, {180, 0x00B7, 250}, {182, 0x00B6, 540}, {183, 0x2022, 350}, {184, 0x201A, 333}, {185, 0x201E, 500}, {186, 0x201D, 500}, {187, 0x00BB, 500}, {188, 0x2026, 1000}, {189, 0x2030, 1000}, {191, 0x00BF, 500}, {193, 0x0060, 333}, {194, 0x00B4, 333}, {195, 0x02C6, 333}, {196, 0x02DC, 333}, {197, 0x00AF, 333}, {198, 0x02D8, 333}, {199, 0x02D9, 333}, {200, 0x00A8, 333}, {202, 0x02DA, 333}, {203, 0x00B8, 333}, {205, 0x02DD, 333}, {206, 0x02DB, 333}, {207, 0x02C7, 333}, {208, 0x2014, 1000}, {225, 0x00C6, 1000}, {227, 0x00AA, 300}, {232, 0x0141, 667}, {233, 0x00D8, 778}, {234, 0x0152, 1000}, {235, 0x00BA, 330}, {241, 0x00E6, 722}, {245, 0x0131, 278}, {248, 0x0142, 278}, {249, 0x00F8, 500}, {250, 0x0153, 722}, {251, 0x00DF, 556}, {-1, 0x00CF, 389}, {-1, 0x00E9, 444}, {-1, 0x0103, 500}, {-1, 0x0171, 556}, {-1, 0x011B, 444}, {-1, 0x0178, 722}, {-1, 0x00F7, 570}, {-1, 0x00DD, 722}, {-1, 0x00C2, 722}, {-1, 0x00E1, 500}, {-1, 0x00DB, 722}, {-1, 0x00FD, 500}, {-1, 0x0219, 389}, {-1, 0x00EA, 444}, {-1, 0x016E, 722}, {-1, 0x00DC, 722}, {-1, 0x0105, 500}, {-1, 0x00DA, 722}, {-1, 0x0173, 556}, {-1, 0x00CB, 667}, {-1, 0x0110, 722}, {-1, 0xF6C3, 250}, {-1, 0x00A9, 747}, {-1, 0x0112, 667}, {-1, 0x010D, 444}, {-1, 0x00E5, 500}, {-1, 0x0145, 722}, {-1, 0x013A, 278}, {-1, 0x00E0, 500}, {-1, 0x0162, 667}, {-1, 0x0106, 722}, {-1, 0x00E3, 500}, {-1, 0x0116, 667}, {-1, 0x0161, 389}, {-1, 0x015F, 389}, {-1, 0x00ED, 278}, {-1, 0x25CA, 494}, {-1, 0x0158, 722}, {-1, 0x0122, 778}, {-1, 0x00FB, 556}, {-1, 0x00E2, 500}, {-1, 0x0100, 722}, {-1, 0x0159, 444}, {-1, 0x00E7, 444}, {-1, 0x017B, 667}, {-1, 0x00DE, 611}, {-1, 0x014C, 778}, {-1, 0x0154, 722}, {-1, 0x015A, 556}, {-1, 0x010F, 672}, {-1, 0x016A, 722}, {-1, 0x016F, 556}, {-1, 0x00B3, 300}, {-1, 0x00D2, 778}, {-1, 0x00C0, 722}, {-1, 0x0102, 722}, {-1, 0x00D7, 570}, {-1, 0x00FA, 556}, {-1, 0x0164, 667}, {-1, 0x2202, 494}, {-1, 0x00FF, 500}, {-1, 0x0143, 722}, {-1, 0x00EE, 278}, {-1, 0x00CA, 667}, {-1, 0x00E4, 500}, {-1, 0x00EB, 444}, {-1, 0x0107, 444}, {-1, 0x0144, 556}, {-1, 0x016B, 556}, {-1, 0x0147, 722}, {-1, 0x00CD, 389}, {-1, 0x00B1, 570}, {-1, 0x00A6, 220}, {-1, 0x00AE, 747}, {-1, 0x011E, 778}, {-1, 0x0130, 389}, {-1, 0x2211, 600}, {-1, 0x00C8, 667}, {-1, 0x0155, 444}, {-1, 0x014D, 500}, {-1, 0x0179, 667}, {-1, 0x017D, 667}, {-1, 0x2265, 549}, {-1, 0x00D0, 722}, {-1, 0x00C7, 722}, {-1, 0x013C, 278}, {-1, 0x0165, 416}, {-1, 0x0119, 444}, {-1, 0x0172, 722}, {-1, 0x00C1, 722}, {-1, 0x00C4, 722}, {-1, 0x00E8, 444}, {-1, 0x017A, 444}, {-1, 0x012F, 278}, {-1, 0x00D3, 778}, {-1, 0x00F3, 500}, {-1, 0x0101, 500}, {-1, 0x015B, 389}, {-1, 0x00EF, 278}, {-1, 0x00D4, 778}, {-1, 0x00D9, 722}, {-1, 0x0394, 612}, {-1, 0x00FE, 556}, {-1, 0x00B2, 300}, {-1, 0x00D6, 778}, {-1, 0x00B5, 556}, {-1, 0x00EC, 278}, {-1, 0x0151, 500}, {-1, 0x0118, 667}, {-1, 0x0111, 556}, {-1, 0x00BE, 750}, {-1, 0x015E, 556}, {-1, 0x013E, 394}, {-1, 0x0136, 778}, {-1, 0x0139, 667}, {-1, 0x2122, 1000}, {-1, 0x0117, 444}, {-1, 0x00CC, 389}, {-1, 0x012A, 389}, {-1, 0x013D, 667}, {-1, 0x00BD, 750}, {-1, 0x2264, 549}, {-1, 0x00F4, 500}, {-1, 0x00F1, 556}, {-1, 0x0170, 722}, {-1, 0x00C9, 667}, {-1, 0x0113, 444}, {-1, 0x011F, 500}, {-1, 0x00BC, 750}, {-1, 0x0160, 556}, {-1, 0x0218, 556}, {-1, 0x0150, 778}, {-1, 0x00B0, 400}, {-1, 0x00F2, 500}, {-1, 0x010C, 722}, {-1, 0x00F9, 556}, {-1, 0x221A, 549}, {-1, 0x010E, 722}, {-1, 0x0157, 444}, {-1, 0x00D1, 722}, {-1, 0x00F5, 500}, {-1, 0x0156, 722}, {-1, 0x013B, 667}, {-1, 0x00C3, 722}, {-1, 0x0104, 722}, {-1, 0x00C5, 722}, {-1, 0x00D5, 778}, {-1, 0x017C, 444}, {-1, 0x011A, 667}, {-1, 0x012E, 389}, {-1, 0x0137, 556}, {-1, 0x2212, 570}, {-1, 0x00CE, 389}, {-1, 0x0148, 556}, {-1, 0x0163, 333}, {-1, 0x00AC, 570}, {-1, 0x00F6, 500}, {-1, 0x00FC, 556}, {-1, 0x2260, 549}, {-1, 0x0123, 500}, {-1, 0x00F0, 500}, {-1, 0x017E, 444}, {-1, 0x0146, 556}, {-1, 0x00B9, 300}, {-1, 0x012B, 278}, {-1, 0x20AC, 500}, {-1, 0xFFFF, 0} }; static const PODOFO_CharData CHAR_DATA_TIMES_BOLD_ITALIC[316] = { {32, 0x0020, 250}, {33, 0x0021, 389}, {34, 0x0022, 555}, {35, 0x0023, 500}, {36, 0x0024, 500}, {37, 0x0025, 833}, {38, 0x0026, 778}, {39, 0x2019, 333}, {40, 0x0028, 333}, {41, 0x0029, 333}, {42, 0x002A, 500}, {43, 0x002B, 570}, {44, 0x002C, 250}, {45, 0x002D, 333}, {46, 0x002E, 250}, {47, 0x002F, 278}, {48, 0x0030, 500}, {49, 0x0031, 500}, {50, 0x0032, 500}, {51, 0x0033, 500}, {52, 0x0034, 500}, {53, 0x0035, 500}, {54, 0x0036, 500}, {55, 0x0037, 500}, {56, 0x0038, 500}, {57, 0x0039, 500}, {58, 0x003A, 333}, {59, 0x003B, 333}, {60, 0x003C, 570}, {61, 0x003D, 570}, {62, 0x003E, 570}, {63, 0x003F, 500}, {64, 0x0040, 832}, {65, 0x0041, 667}, {66, 0x0042, 667}, {67, 0x0043, 667}, {68, 0x0044, 722}, {69, 0x0045, 667}, {70, 0x0046, 667}, {71, 0x0047, 722}, {72, 0x0048, 778}, {73, 0x0049, 389}, {74, 0x004A, 500}, {75, 0x004B, 667}, {76, 0x004C, 611}, {77, 0x004D, 889}, {78, 0x004E, 722}, {79, 0x004F, 722}, {80, 0x0050, 611}, {81, 0x0051, 722}, {82, 0x0052, 667}, {83, 0x0053, 556}, {84, 0x0054, 611}, {85, 0x0055, 722}, {86, 0x0056, 667}, {87, 0x0057, 889}, {88, 0x0058, 667}, {89, 0x0059, 611}, {90, 0x005A, 611}, {91, 0x005B, 333}, {92, 0x005C, 278}, {93, 0x005D, 333}, {94, 0x005E, 570}, {95, 0x005F, 500}, {96, 0x2018, 333}, {97, 0x0061, 500}, {98, 0x0062, 500}, {99, 0x0063, 444}, {100, 0x0064, 500}, {101, 0x0065, 444}, {102, 0x0066, 333}, {103, 0x0067, 500}, {104, 0x0068, 556}, {105, 0x0069, 278}, {106, 0x006A, 278}, {107, 0x006B, 500}, {108, 0x006C, 278}, {109, 0x006D, 778}, {110, 0x006E, 556}, {111, 0x006F, 500}, {112, 0x0070, 500}, {113, 0x0071, 500}, {114, 0x0072, 389}, {115, 0x0073, 389}, {116, 0x0074, 278}, {117, 0x0075, 556}, {118, 0x0076, 444}, {119, 0x0077, 667}, {120, 0x0078, 500}, {121, 0x0079, 444}, {122, 0x007A, 389}, {123, 0x007B, 348}, {124, 0x007C, 220}, {125, 0x007D, 348}, {126, 0x007E, 570}, {161, 0x00A1, 389}, {162, 0x00A2, 500}, {163, 0x00A3, 500}, {164, 0x2044, 167}, {165, 0x00A5, 500}, {166, 0x0192, 500}, {167, 0x00A7, 500}, {168, 0x00A4, 500}, {169, 0x0027, 278}, {170, 0x201C, 500}, {171, 0x00AB, 500}, {172, 0x2039, 333}, {173, 0x203A, 333}, {174, 0xFB01, 556}, {175, 0xFB02, 556}, {177, 0x2013, 500}, {178, 0x2020, 500}, {179, 0x2021, 500}, {180, 0x00B7, 250}, {182, 0x00B6, 500}, {183, 0x2022, 350}, {184, 0x201A, 333}, {185, 0x201E, 500}, {186, 0x201D, 500}, {187, 0x00BB, 500}, {188, 0x2026, 1000}, {189, 0x2030, 1000}, {191, 0x00BF, 500}, {193, 0x0060, 333}, {194, 0x00B4, 333}, {195, 0x02C6, 333}, {196, 0x02DC, 333}, {197, 0x00AF, 333}, {198, 0x02D8, 333}, {199, 0x02D9, 333}, {200, 0x00A8, 333}, {202, 0x02DA, 333}, {203, 0x00B8, 333}, {205, 0x02DD, 333}, {206, 0x02DB, 333}, {207, 0x02C7, 333}, {208, 0x2014, 1000}, {225, 0x00C6, 944}, {227, 0x00AA, 266}, {232, 0x0141, 611}, {233, 0x00D8, 722}, {234, 0x0152, 944}, {235, 0x00BA, 300}, {241, 0x00E6, 722}, {245, 0x0131, 278}, {248, 0x0142, 278}, {249, 0x00F8, 500}, {250, 0x0153, 722}, {251, 0x00DF, 500}, {-1, 0x00CF, 389}, {-1, 0x00E9, 444}, {-1, 0x0103, 500}, {-1, 0x0171, 556}, {-1, 0x011B, 444}, {-1, 0x0178, 611}, {-1, 0x00F7, 570}, {-1, 0x00DD, 611}, {-1, 0x00C2, 667}, {-1, 0x00E1, 500}, {-1, 0x00DB, 722}, {-1, 0x00FD, 444}, {-1, 0x0219, 389}, {-1, 0x00EA, 444}, {-1, 0x016E, 722}, {-1, 0x00DC, 722}, {-1, 0x0105, 500}, {-1, 0x00DA, 722}, {-1, 0x0173, 556}, {-1, 0x00CB, 667}, {-1, 0x0110, 722}, {-1, 0xF6C3, 250}, {-1, 0x00A9, 747}, {-1, 0x0112, 667}, {-1, 0x010D, 444}, {-1, 0x00E5, 500}, {-1, 0x0145, 722}, {-1, 0x013A, 278}, {-1, 0x00E0, 500}, {-1, 0x0162, 611}, {-1, 0x0106, 667}, {-1, 0x00E3, 500}, {-1, 0x0116, 667}, {-1, 0x0161, 389}, {-1, 0x015F, 389}, {-1, 0x00ED, 278}, {-1, 0x25CA, 494}, {-1, 0x0158, 667}, {-1, 0x0122, 722}, {-1, 0x00FB, 556}, {-1, 0x00E2, 500}, {-1, 0x0100, 667}, {-1, 0x0159, 389}, {-1, 0x00E7, 444}, {-1, 0x017B, 611}, {-1, 0x00DE, 611}, {-1, 0x014C, 722}, {-1, 0x0154, 667}, {-1, 0x015A, 556}, {-1, 0x010F, 608}, {-1, 0x016A, 722}, {-1, 0x016F, 556}, {-1, 0x00B3, 300}, {-1, 0x00D2, 722}, {-1, 0x00C0, 667}, {-1, 0x0102, 667}, {-1, 0x00D7, 570}, {-1, 0x00FA, 556}, {-1, 0x0164, 611}, {-1, 0x2202, 494}, {-1, 0x00FF, 444}, {-1, 0x0143, 722}, {-1, 0x00EE, 278}, {-1, 0x00CA, 667}, {-1, 0x00E4, 500}, {-1, 0x00EB, 444}, {-1, 0x0107, 444}, {-1, 0x0144, 556}, {-1, 0x016B, 556}, {-1, 0x0147, 722}, {-1, 0x00CD, 389}, {-1, 0x00B1, 570}, {-1, 0x00A6, 220}, {-1, 0x00AE, 747}, {-1, 0x011E, 722}, {-1, 0x0130, 389}, {-1, 0x2211, 600}, {-1, 0x00C8, 667}, {-1, 0x0155, 389}, {-1, 0x014D, 500}, {-1, 0x0179, 611}, {-1, 0x017D, 611}, {-1, 0x2265, 549}, {-1, 0x00D0, 722}, {-1, 0x00C7, 667}, {-1, 0x013C, 278}, {-1, 0x0165, 366}, {-1, 0x0119, 444}, {-1, 0x0172, 722}, {-1, 0x00C1, 667}, {-1, 0x00C4, 667}, {-1, 0x00E8, 444}, {-1, 0x017A, 389}, {-1, 0x012F, 278}, {-1, 0x00D3, 722}, {-1, 0x00F3, 500}, {-1, 0x0101, 500}, {-1, 0x015B, 389}, {-1, 0x00EF, 278}, {-1, 0x00D4, 722}, {-1, 0x00D9, 722}, {-1, 0x0394, 612}, {-1, 0x00FE, 500}, {-1, 0x00B2, 300}, {-1, 0x00D6, 722}, {-1, 0x00B5, 576}, {-1, 0x00EC, 278}, {-1, 0x0151, 500}, {-1, 0x0118, 667}, {-1, 0x0111, 500}, {-1, 0x00BE, 750}, {-1, 0x015E, 556}, {-1, 0x013E, 382}, {-1, 0x0136, 667}, {-1, 0x0139, 611}, {-1, 0x2122, 1000}, {-1, 0x0117, 444}, {-1, 0x00CC, 389}, {-1, 0x012A, 389}, {-1, 0x013D, 611}, {-1, 0x00BD, 750}, {-1, 0x2264, 549}, {-1, 0x00F4, 500}, {-1, 0x00F1, 556}, {-1, 0x0170, 722}, {-1, 0x00C9, 667}, {-1, 0x0113, 444}, {-1, 0x011F, 500}, {-1, 0x00BC, 750}, {-1, 0x0160, 556}, {-1, 0x0218, 556}, {-1, 0x0150, 722}, {-1, 0x00B0, 400}, {-1, 0x00F2, 500}, {-1, 0x010C, 667}, {-1, 0x00F9, 556}, {-1, 0x221A, 549}, {-1, 0x010E, 722}, {-1, 0x0157, 389}, {-1, 0x00D1, 722}, {-1, 0x00F5, 500}, {-1, 0x0156, 667}, {-1, 0x013B, 611}, {-1, 0x00C3, 667}, {-1, 0x0104, 667}, {-1, 0x00C5, 667}, {-1, 0x00D5, 722}, {-1, 0x017C, 389}, {-1, 0x011A, 667}, {-1, 0x012E, 389}, {-1, 0x0137, 500}, {-1, 0x2212, 606}, {-1, 0x00CE, 389}, {-1, 0x0148, 556}, {-1, 0x0163, 278}, {-1, 0x00AC, 606}, {-1, 0x00F6, 500}, {-1, 0x00FC, 556}, {-1, 0x2260, 549}, {-1, 0x0123, 500}, {-1, 0x00F0, 500}, {-1, 0x017E, 389}, {-1, 0x0146, 556}, {-1, 0x00B9, 300}, {-1, 0x012B, 278}, {-1, 0x20AC, 500}, {-1, 0xFFFF, 0} }; static const PODOFO_CharData CHAR_DATA_TIMES_ITALIC[316] = { {32, 0x0020, 250}, {33, 0x0021, 333}, {34, 0x0022, 420}, {35, 0x0023, 500}, {36, 0x0024, 500}, {37, 0x0025, 833}, {38, 0x0026, 778}, {39, 0x2019, 333}, {40, 0x0028, 333}, {41, 0x0029, 333}, {42, 0x002A, 500}, {43, 0x002B, 675}, {44, 0x002C, 250}, {45, 0x002D, 333}, {46, 0x002E, 250}, {47, 0x002F, 278}, {48, 0x0030, 500}, {49, 0x0031, 500}, {50, 0x0032, 500}, {51, 0x0033, 500}, {52, 0x0034, 500}, {53, 0x0035, 500}, {54, 0x0036, 500}, {55, 0x0037, 500}, {56, 0x0038, 500}, {57, 0x0039, 500}, {58, 0x003A, 333}, {59, 0x003B, 333}, {60, 0x003C, 675}, {61, 0x003D, 675}, {62, 0x003E, 675}, {63, 0x003F, 500}, {64, 0x0040, 920}, {65, 0x0041, 611}, {66, 0x0042, 611}, {67, 0x0043, 667}, {68, 0x0044, 722}, {69, 0x0045, 611}, {70, 0x0046, 611}, {71, 0x0047, 722}, {72, 0x0048, 722}, {73, 0x0049, 333}, {74, 0x004A, 444}, {75, 0x004B, 667}, {76, 0x004C, 556}, {77, 0x004D, 833}, {78, 0x004E, 667}, {79, 0x004F, 722}, {80, 0x0050, 611}, {81, 0x0051, 722}, {82, 0x0052, 611}, {83, 0x0053, 500}, {84, 0x0054, 556}, {85, 0x0055, 722}, {86, 0x0056, 611}, {87, 0x0057, 833}, {88, 0x0058, 611}, {89, 0x0059, 556}, {90, 0x005A, 556}, {91, 0x005B, 389}, {92, 0x005C, 278}, {93, 0x005D, 389}, {94, 0x005E, 422}, {95, 0x005F, 500}, {96, 0x2018, 333}, {97, 0x0061, 500}, {98, 0x0062, 500}, {99, 0x0063, 444}, {100, 0x0064, 500}, {101, 0x0065, 444}, {102, 0x0066, 278}, {103, 0x0067, 500}, {104, 0x0068, 500}, {105, 0x0069, 278}, {106, 0x006A, 278}, {107, 0x006B, 444}, {108, 0x006C, 278}, {109, 0x006D, 722}, {110, 0x006E, 500}, {111, 0x006F, 500}, {112, 0x0070, 500}, {113, 0x0071, 500}, {114, 0x0072, 389}, {115, 0x0073, 389}, {116, 0x0074, 278}, {117, 0x0075, 500}, {118, 0x0076, 444}, {119, 0x0077, 667}, {120, 0x0078, 444}, {121, 0x0079, 444}, {122, 0x007A, 389}, {123, 0x007B, 400}, {124, 0x007C, 275}, {125, 0x007D, 400}, {126, 0x007E, 541}, {161, 0x00A1, 389}, {162, 0x00A2, 500}, {163, 0x00A3, 500}, {164, 0x2044, 167}, {165, 0x00A5, 500}, {166, 0x0192, 500}, {167, 0x00A7, 500}, {168, 0x00A4, 500}, {169, 0x0027, 214}, {170, 0x201C, 556}, {171, 0x00AB, 500}, {172, 0x2039, 333}, {173, 0x203A, 333}, {174, 0xFB01, 500}, {175, 0xFB02, 500}, {177, 0x2013, 500}, {178, 0x2020, 500}, {179, 0x2021, 500}, {180, 0x00B7, 250}, {182, 0x00B6, 523}, {183, 0x2022, 350}, {184, 0x201A, 333}, {185, 0x201E, 556}, {186, 0x201D, 556}, {187, 0x00BB, 500}, {188, 0x2026, 889}, {189, 0x2030, 1000}, {191, 0x00BF, 500}, {193, 0x0060, 333}, {194, 0x00B4, 333}, {195, 0x02C6, 333}, {196, 0x02DC, 333}, {197, 0x00AF, 333}, {198, 0x02D8, 333}, {199, 0x02D9, 333}, {200, 0x00A8, 333}, {202, 0x02DA, 333}, {203, 0x00B8, 333}, {205, 0x02DD, 333}, {206, 0x02DB, 333}, {207, 0x02C7, 333}, {208, 0x2014, 889}, {225, 0x00C6, 889}, {227, 0x00AA, 276}, {232, 0x0141, 556}, {233, 0x00D8, 722}, {234, 0x0152, 944}, {235, 0x00BA, 310}, {241, 0x00E6, 667}, {245, 0x0131, 278}, {248, 0x0142, 278}, {249, 0x00F8, 500}, {250, 0x0153, 667}, {251, 0x00DF, 500}, {-1, 0x00CF, 333}, {-1, 0x00E9, 444}, {-1, 0x0103, 500}, {-1, 0x0171, 500}, {-1, 0x011B, 444}, {-1, 0x0178, 556}, {-1, 0x00F7, 675}, {-1, 0x00DD, 556}, {-1, 0x00C2, 611}, {-1, 0x00E1, 500}, {-1, 0x00DB, 722}, {-1, 0x00FD, 444}, {-1, 0x0219, 389}, {-1, 0x00EA, 444}, {-1, 0x016E, 722}, {-1, 0x00DC, 722}, {-1, 0x0105, 500}, {-1, 0x00DA, 722}, {-1, 0x0173, 500}, {-1, 0x00CB, 611}, {-1, 0x0110, 722}, {-1, 0xF6C3, 250}, {-1, 0x00A9, 760}, {-1, 0x0112, 611}, {-1, 0x010D, 444}, {-1, 0x00E5, 500}, {-1, 0x0145, 667}, {-1, 0x013A, 278}, {-1, 0x00E0, 500}, {-1, 0x0162, 556}, {-1, 0x0106, 667}, {-1, 0x00E3, 500}, {-1, 0x0116, 611}, {-1, 0x0161, 389}, {-1, 0x015F, 389}, {-1, 0x00ED, 278}, {-1, 0x25CA, 471}, {-1, 0x0158, 611}, {-1, 0x0122, 722}, {-1, 0x00FB, 500}, {-1, 0x00E2, 500}, {-1, 0x0100, 611}, {-1, 0x0159, 389}, {-1, 0x00E7, 444}, {-1, 0x017B, 556}, {-1, 0x00DE, 611}, {-1, 0x014C, 722}, {-1, 0x0154, 611}, {-1, 0x015A, 500}, {-1, 0x010F, 544}, {-1, 0x016A, 722}, {-1, 0x016F, 500}, {-1, 0x00B3, 300}, {-1, 0x00D2, 722}, {-1, 0x00C0, 611}, {-1, 0x0102, 611}, {-1, 0x00D7, 675}, {-1, 0x00FA, 500}, {-1, 0x0164, 556}, {-1, 0x2202, 476}, {-1, 0x00FF, 444}, {-1, 0x0143, 667}, {-1, 0x00EE, 278}, {-1, 0x00CA, 611}, {-1, 0x00E4, 500}, {-1, 0x00EB, 444}, {-1, 0x0107, 444}, {-1, 0x0144, 500}, {-1, 0x016B, 500}, {-1, 0x0147, 667}, {-1, 0x00CD, 333}, {-1, 0x00B1, 675}, {-1, 0x00A6, 275}, {-1, 0x00AE, 760}, {-1, 0x011E, 722}, {-1, 0x0130, 333}, {-1, 0x2211, 600}, {-1, 0x00C8, 611}, {-1, 0x0155, 389}, {-1, 0x014D, 500}, {-1, 0x0179, 556}, {-1, 0x017D, 556}, {-1, 0x2265, 549}, {-1, 0x00D0, 722}, {-1, 0x00C7, 667}, {-1, 0x013C, 278}, {-1, 0x0165, 300}, {-1, 0x0119, 444}, {-1, 0x0172, 722}, {-1, 0x00C1, 611}, {-1, 0x00C4, 611}, {-1, 0x00E8, 444}, {-1, 0x017A, 389}, {-1, 0x012F, 278}, {-1, 0x00D3, 722}, {-1, 0x00F3, 500}, {-1, 0x0101, 500}, {-1, 0x015B, 389}, {-1, 0x00EF, 278}, {-1, 0x00D4, 722}, {-1, 0x00D9, 722}, {-1, 0x0394, 612}, {-1, 0x00FE, 500}, {-1, 0x00B2, 300}, {-1, 0x00D6, 722}, {-1, 0x00B5, 500}, {-1, 0x00EC, 278}, {-1, 0x0151, 500}, {-1, 0x0118, 611}, {-1, 0x0111, 500}, {-1, 0x00BE, 750}, {-1, 0x015E, 500}, {-1, 0x013E, 300}, {-1, 0x0136, 667}, {-1, 0x0139, 556}, {-1, 0x2122, 980}, {-1, 0x0117, 444}, {-1, 0x00CC, 333}, {-1, 0x012A, 333}, {-1, 0x013D, 611}, {-1, 0x00BD, 750}, {-1, 0x2264, 549}, {-1, 0x00F4, 500}, {-1, 0x00F1, 500}, {-1, 0x0170, 722}, {-1, 0x00C9, 611}, {-1, 0x0113, 444}, {-1, 0x011F, 500}, {-1, 0x00BC, 750}, {-1, 0x0160, 500}, {-1, 0x0218, 500}, {-1, 0x0150, 722}, {-1, 0x00B0, 400}, {-1, 0x00F2, 500}, {-1, 0x010C, 667}, {-1, 0x00F9, 500}, {-1, 0x221A, 453}, {-1, 0x010E, 722}, {-1, 0x0157, 389}, {-1, 0x00D1, 667}, {-1, 0x00F5, 500}, {-1, 0x0156, 611}, {-1, 0x013B, 556}, {-1, 0x00C3, 611}, {-1, 0x0104, 611}, {-1, 0x00C5, 611}, {-1, 0x00D5, 722}, {-1, 0x017C, 389}, {-1, 0x011A, 611}, {-1, 0x012E, 333}, {-1, 0x0137, 444}, {-1, 0x2212, 675}, {-1, 0x00CE, 333}, {-1, 0x0148, 500}, {-1, 0x0163, 278}, {-1, 0x00AC, 675}, {-1, 0x00F6, 500}, {-1, 0x00FC, 500}, {-1, 0x2260, 549}, {-1, 0x0123, 500}, {-1, 0x00F0, 500}, {-1, 0x017E, 389}, {-1, 0x0146, 500}, {-1, 0x00B9, 300}, {-1, 0x012B, 278}, {-1, 0x20AC, 500}, {-1, 0xFFFF, 0} }; static const PODOFO_CharData CHAR_DATA_ZAPF_DINGBATS[203] = { {32, 0x0020, 278}, {33, 0x0021, 974}, {34, 0x0022, 961}, {35, 0x0023, 974}, {36, 0x0024, 980}, {37, 0x0025, 719}, {38, 0x0026, 789}, {39, 0x0027, 790}, {40, 0x0028, 791}, {41, 0x0029, 690}, {42, 0x002A, 960}, {43, 0x002B, 939}, {44, 0x002C, 549}, {45, 0x002D, 855}, {46, 0x002E, 911}, {47, 0x002F, 933}, {48, 0x0030, 911}, {49, 0x0031, 945}, {50, 0x0032, 974}, {51, 0x0033, 755}, {52, 0x0034, 846}, {53, 0x0035, 762}, {54, 0x0036, 761}, {55, 0x0037, 571}, {56, 0x0038, 677}, {57, 0x0039, 763}, {58, 0x003A, 760}, {59, 0x003B, 759}, {60, 0x003C, 754}, {61, 0x003D, 494}, {62, 0x003E, 552}, {63, 0x003F, 537}, {64, 0x0040, 577}, {65, 0x0041, 692}, {66, 0x0042, 786}, {67, 0x0043, 788}, {68, 0x0044, 788}, {69, 0x0045, 790}, {70, 0x0046, 793}, {71, 0x0047, 794}, {72, 0x0048, 816}, {73, 0x0049, 823}, {74, 0x004A, 789}, {75, 0x004B, 841}, {76, 0x004C, 823}, {77, 0x004D, 833}, {78, 0x004E, 816}, {79, 0x004F, 831}, {80, 0x0050, 923}, {81, 0x0051, 744}, {82, 0x0052, 723}, {83, 0x0053, 749}, {84, 0x0054, 790}, {85, 0x0055, 792}, {86, 0x0056, 695}, {87, 0x0057, 776}, {88, 0x0058, 768}, {89, 0x0059, 792}, {90, 0x005A, 759}, {91, 0x005B, 707}, {92, 0x005C, 708}, {93, 0x005D, 682}, {94, 0x005E, 701}, {95, 0x005F, 826}, {96, 0x0060, 815}, {97, 0x0061, 789}, {98, 0x0062, 789}, {99, 0x0063, 707}, {100, 0x0064, 687}, {101, 0x0065, 696}, {102, 0x0066, 689}, {103, 0x0067, 786}, {104, 0x0068, 787}, {105, 0x0069, 713}, {106, 0x006A, 791}, {107, 0x006B, 785}, {108, 0x006C, 791}, {109, 0x006D, 873}, {110, 0x006E, 761}, {111, 0x006F, 762}, {112, 0x0070, 762}, {113, 0x0071, 759}, {114, 0x0072, 759}, {115, 0x0073, 892}, {116, 0x0074, 892}, {117, 0x0075, 788}, {118, 0x0076, 784}, {119, 0x0077, 438}, {120, 0x0078, 138}, {121, 0x0079, 277}, {122, 0x007A, 415}, {123, 0x007B, 392}, {124, 0x007C, 392}, {125, 0x007D, 668}, {126, 0x007E, 668}, {128, 0x0080, 390}, {129, 0x0081, 390}, {130, 0x0082, 317}, {131, 0x0083, 317}, {132, 0x0084, 276}, {133, 0x0085, 276}, {134, 0x0086, 509}, {135, 0x0087, 509}, {136, 0x0088, 410}, {137, 0x0089, 410}, {138, 0x008A, 234}, {139, 0x008B, 234}, {140, 0x008C, 334}, {141, 0x008D, 334}, {161, 0x00A1, 732}, {162, 0x00A2, 544}, {163, 0x00A3, 544}, {164, 0x00A4, 910}, {165, 0x00A5, 667}, {166, 0x00A6, 760}, {167, 0x00A7, 760}, {168, 0x00A8, 776}, {169, 0x00A9, 595}, {170, 0x00AA, 694}, {171, 0x00AB, 626}, {172, 0x00AC, 788}, {173, 0x00AD, 788}, {174, 0x00AE, 788}, {175, 0x00AF, 788}, {176, 0x00B0, 788}, {177, 0x00B1, 788}, {178, 0x00B2, 788}, {179, 0x00B3, 788}, {180, 0x00B4, 788}, {181, 0x00B5, 788}, {182, 0x00B6, 788}, {183, 0x00B7, 788}, {184, 0x00B8, 788}, {185, 0x00B9, 788}, {186, 0x00BA, 788}, {187, 0x00BB, 788}, {188, 0x00BC, 788}, {189, 0x00BD, 788}, {190, 0x00BE, 788}, {191, 0x00BF, 788}, {192, 0x00C0, 788}, {193, 0x00C1, 788}, {194, 0x00C2, 788}, {195, 0x00C3, 788}, {196, 0x00C4, 788}, {197, 0x00C5, 788}, {198, 0x00C6, 788}, {199, 0x00C7, 788}, {200, 0x00C8, 788}, {201, 0x00C9, 788}, {202, 0x00CA, 788}, {203, 0x00CB, 788}, {204, 0x00CC, 788}, {205, 0x00CD, 788}, {206, 0x00CE, 788}, {207, 0x00CF, 788}, {208, 0x00D0, 788}, {209, 0x00D1, 788}, {210, 0x00D2, 788}, {211, 0x00D3, 788}, {212, 0x00D4, 894}, {213, 0x00D5, 838}, {214, 0x00D6, 1016}, {215, 0x00D7, 458}, {216, 0x00D8, 748}, {217, 0x00D9, 924}, {218, 0x00DA, 748}, {219, 0x00DB, 918}, {220, 0x00DC, 927}, {221, 0x00DD, 928}, {222, 0x00DE, 928}, {223, 0x00DF, 834}, {224, 0x00E0, 873}, {225, 0x00E1, 828}, {226, 0x00E2, 924}, {227, 0x00E3, 924}, {228, 0x00E4, 917}, {229, 0x00E5, 930}, {230, 0x00E6, 931}, {231, 0x00E7, 463}, {232, 0x00E8, 883}, {233, 0x00E9, 836}, {234, 0x00EA, 836}, {235, 0x00EB, 867}, {236, 0x00EC, 867}, {237, 0x00ED, 696}, {238, 0x00EE, 696}, {239, 0x00EF, 874}, {241, 0x00F1, 874}, {242, 0x00F2, 760}, {243, 0x00F3, 946}, {244, 0x00F4, 771}, {245, 0x00F5, 865}, {246, 0x00F6, 771}, {247, 0x00F7, 888}, {248, 0x00F8, 967}, {249, 0x00F9, 888}, {250, 0x00FA, 831}, {251, 0x00FB, 873}, {252, 0x00FC, 927}, {253, 0x00FD, 970}, {254, 0x00FE, 918}, {-1, 0xFFFF, 0} }; static const PODOFO_CharData CHAR_DATA_SYMBOL[190] = { {32, 0x0020, 250}, {33, 0x0021, 333}, {34, 0x0022, 713}, {35, 0x0023, 500}, {36, 0x0024, 549}, {37, 0x0025, 833}, {38, 0x0026, 778}, {39, 0x0027, 439}, {40, 0x0028, 333}, {41, 0x0029, 333}, {42, 0x002A, 500}, {43, 0x002B, 549}, {44, 0x002C, 250}, {45, 0x002D, 549}, {46, 0x002E, 250}, {47, 0x002F, 278}, {48, 0x0030, 500}, {49, 0x0031, 500}, {50, 0x0032, 500}, {51, 0x0033, 500}, {52, 0x0034, 500}, {53, 0x0035, 500}, {54, 0x0036, 500}, {55, 0x0037, 500}, {56, 0x0038, 500}, {57, 0x0039, 500}, {58, 0x003A, 278}, {59, 0x003B, 278}, {60, 0x003C, 549}, {61, 0x003D, 549}, {62, 0x003E, 549}, {63, 0x003F, 444}, {64, 0x0040, 549}, {65, 0x0041, 722}, {66, 0x0042, 667}, {67, 0x0043, 722}, {68, 0x0044, 612}, {69, 0x0045, 611}, {70, 0x0046, 763}, {71, 0x0047, 603}, {72, 0x0048, 722}, {73, 0x0049, 333}, {74, 0x004A, 631}, {75, 0x004B, 722}, {76, 0x004C, 686}, {77, 0x004D, 889}, {78, 0x004E, 722}, {79, 0x004F, 722}, {80, 0x0050, 768}, {81, 0x0051, 741}, {82, 0x0052, 556}, {83, 0x0053, 592}, {84, 0x0054, 611}, {85, 0x0055, 690}, {86, 0x0056, 439}, {87, 0x0057, 768}, {88, 0x0058, 645}, {89, 0x0059, 795}, {90, 0x005A, 611}, {91, 0x005B, 333}, {92, 0x005C, 863}, {93, 0x005D, 333}, {94, 0x005E, 658}, {95, 0x005F, 500}, {96, 0x0060, 500}, {97, 0x0061, 631}, {98, 0x0062, 549}, {99, 0x0063, 549}, {100, 0x0064, 494}, {101, 0x0065, 439}, {102, 0x0066, 521}, {103, 0x0067, 411}, {104, 0x0068, 603}, {105, 0x0069, 329}, {106, 0x006A, 603}, {107, 0x006B, 549}, {108, 0x006C, 549}, {109, 0x006D, 576}, {110, 0x006E, 521}, {111, 0x006F, 549}, {112, 0x0070, 549}, {113, 0x0071, 521}, {114, 0x0072, 549}, {115, 0x0073, 603}, {116, 0x0074, 439}, {117, 0x0075, 576}, {118, 0x0076, 713}, {119, 0x0077, 686}, {120, 0x0078, 493}, {121, 0x0079, 686}, {122, 0x007A, 494}, {123, 0x007B, 480}, {124, 0x007C, 200}, {125, 0x007D, 480}, {126, 0x007E, 549}, {160, 0x00A0, 750}, {161, 0x00A1, 620}, {162, 0x00A2, 247}, {163, 0x00A3, 549}, {164, 0x00A4, 167}, {165, 0x00A5, 713}, {166, 0x00A6, 500}, {167, 0x00A7, 753}, {168, 0x00A8, 753}, {169, 0x00A9, 753}, {170, 0x00AA, 753}, {171, 0x00AB, 1042}, {172, 0x00AC, 987}, {173, 0x00AD, 603}, {174, 0x00AE, 987}, {175, 0x00AF, 603}, {176, 0x00B0, 400}, {177, 0x00B1, 549}, {178, 0x00B2, 411}, {179, 0x00B3, 549}, {180, 0x00B4, 549}, {181, 0x00B5, 713}, {182, 0x00B6, 494}, {183, 0x00B7, 460}, {184, 0x00B8, 549}, {185, 0x00B9, 549}, {186, 0x00BA, 549}, {187, 0x00BB, 549}, {188, 0x00BC, 1000}, {189, 0x00BD, 603}, {190, 0x00BE, 1000}, {191, 0x00BF, 658}, {192, 0x00C0, 823}, {193, 0x00C1, 686}, {194, 0x00C2, 795}, {195, 0x00C3, 987}, {196, 0x00C4, 768}, {197, 0x00C5, 768}, {198, 0x00C6, 823}, {199, 0x00C7, 768}, {200, 0x00C8, 768}, {201, 0x00C9, 713}, {202, 0x00CA, 713}, {203, 0x00CB, 713}, {204, 0x00CC, 713}, {205, 0x00CD, 713}, {206, 0x00CE, 713}, {207, 0x00CF, 713}, {208, 0x00D0, 768}, {209, 0x00D1, 713}, {210, 0x00D2, 790}, {211, 0x00D3, 790}, {212, 0x00D4, 890}, {213, 0x00D5, 823}, {214, 0x00D6, 549}, {215, 0x00D7, 250}, {216, 0x00D8, 713}, {217, 0x00D9, 603}, {218, 0x00DA, 603}, {219, 0x00DB, 1042}, {220, 0x00DC, 987}, {221, 0x00DD, 603}, {222, 0x00DE, 987}, {223, 0x00DF, 603}, {224, 0x00E0, 494}, {225, 0x00E1, 329}, {226, 0x00E2, 790}, {227, 0x00E3, 790}, {228, 0x00E4, 786}, {229, 0x00E5, 713}, {230, 0x00E6, 384}, {231, 0x00E7, 384}, {232, 0x00E8, 384}, {233, 0x00E9, 384}, {234, 0x00EA, 384}, {235, 0x00EB, 384}, {236, 0x00EC, 494}, {237, 0x00ED, 494}, {238, 0x00EE, 494}, {239, 0x00EF, 494}, {241, 0x00F1, 329}, {242, 0x00F2, 274}, {243, 0x00F3, 686}, {244, 0x00F4, 686}, {245, 0x00F5, 686}, {246, 0x00F6, 384}, {247, 0x00F7, 384}, {248, 0x00F8, 384}, {249, 0x00F9, 384}, {250, 0x00FA, 384}, {251, 0x00FB, 384}, {252, 0x00FC, 494}, {253, 0x00FD, 494}, {254, 0x00FE, 494}, {-1, 0xFFFF, 0} }; #define PODOFO_HPDF_FONT_COURIER "Courier" #define PODOFO_HPDF_FONT_COURIER_BOLD "Courier-Bold" #define PODOFO_HPDF_FONT_COURIER_OBLIQUE "Courier-Oblique" #define PODOFO_HPDF_FONT_COURIER_BOLD_OBLIQUE "Courier-BoldOblique" #define PODOFO_HPDF_FONT_HELVETICA "Helvetica" #define PODOFO_HPDF_FONT_HELVETICA_BOLD "Helvetica-Bold" #define PODOFO_HPDF_FONT_HELVETICA_OBLIQUE "Helvetica-Oblique" #define PODOFO_HPDF_FONT_HELVETICA_BOLD_OBLIQUE "Helvetica-BoldOblique" #define PODOFO_HPDF_FONT_TIMES_ROMAN "Times-Roman" #define PODOFO_HPDF_FONT_TIMES_BOLD "Times-Bold" #define PODOFO_HPDF_FONT_TIMES_ITALIC "Times-Italic" #define PODOFO_HPDF_FONT_TIMES_BOLD_ITALIC "Times-BoldItalic" #define PODOFO_HPDF_FONT_SYMBOL "Symbol" #define PODOFO_HPDF_FONT_ZAPF_DINGBATS "ZapfDingbats" const int PODOFO_TRUE=1; const int PODOFO_FALSE=0; /* static const PdfFontMetricsBase14Rec PODOFO_BUILTIN_FONTS[] = { { PODOFO_HPDF_FONT_COURIER, CHAR_DATA_COURIER, PODOFO_FALSE, 629, -157, 426, 562, {-23, -250, 715, 805} }, { PODOFO_HPDF_FONT_COURIER_BOLD, CHAR_DATA_COURIER_BOLD, PODOFO_FALSE, 629, -157, 439, 562, {-113, -250, 749, 801} }, { PODOFO_HPDF_FONT_COURIER_OBLIQUE, CHAR_DATA_COURIER_OBLIQUE, PODOFO_FALSE, 629, -157, 426, 562, {-27, -250, 849, 805} }, { PODOFO_HPDF_FONT_COURIER_BOLD_OBLIQUE, CHAR_DATA_COURIER_BOLD_OBLIQUE, PODOFO_FALSE, 629, -157, 439, 562, {-57, -250, 869, 801} }, { PODOFO_HPDF_FONT_HELVETICA, CHAR_DATA_HELVETICA, PODOFO_FALSE, 718, -207, 523, 718, {-166, -225, 1000, 931} }, { PODOFO_HPDF_FONT_HELVETICA_BOLD, CHAR_DATA_HELVETICA_BOLD, PODOFO_FALSE, 718, -207, 532, 718, {-170, -228, 1003, 962} }, { PODOFO_HPDF_FONT_HELVETICA_OBLIQUE, CHAR_DATA_HELVETICA_OBLIQUE, PODOFO_FALSE, 718, -207, 532, 718, {-170, -225, 1116, 931} }, { PODOFO_HPDF_FONT_HELVETICA_BOLD_OBLIQUE, CHAR_DATA_HELVETICA_BOLD_OBLIQUE, PODOFO_FALSE, 718, -207, 532, 718, {-174, -228, 1114, 962} }, { PODOFO_HPDF_FONT_TIMES_ROMAN, CHAR_DATA_TIMES_ROMAN, PODOFO_FALSE, 683, -217, 450, 662, {-168, -218, 1000, 898} }, { PODOFO_HPDF_FONT_TIMES_BOLD, CHAR_DATA_TIMES_BOLD, PODOFO_FALSE, 683, -217, 461, 676, {-168, -218, 1000, 935} }, { PODOFO_HPDF_FONT_TIMES_ITALIC, CHAR_DATA_TIMES_ITALIC, PODOFO_FALSE, 683, -217, 441, 653, {-169, -217, 1010, 883} }, { PODOFO_HPDF_FONT_TIMES_BOLD_ITALIC, CHAR_DATA_TIMES_BOLD_ITALIC, PODOFO_FALSE, 683, -217, 462, 669, {-200, -218, 996, 921} }, { PODOFO_HPDF_FONT_SYMBOL, CHAR_DATA_SYMBOL, PODOFO_TRUE, 0, 0, 0, 0, {-180, -293, 1090, 1010} }, { PODOFO_HPDF_FONT_ZAPF_DINGBATS, CHAR_DATA_ZAPF_DINGBATS, PODOFO_TRUE, 0, 0, 0, 0, {-1, -143, 981, 820} }, { NULL, NULL, PODOFO_FALSE, 0, 0, 0, 0, {0, 0, 0, 0} }, }; */ static PdfFontMetricsBase14 PODOFO_BUILTIN_FONTS[] = { PdfFontMetricsBase14(PODOFO_HPDF_FONT_COURIER, CHAR_DATA_COURIER, PODOFO_FALSE, 629, -157, 426, 562, PdfRect(-23, -250, 715, 805) ), PdfFontMetricsBase14( PODOFO_HPDF_FONT_COURIER_BOLD, CHAR_DATA_COURIER_BOLD, PODOFO_FALSE, 629, -157, 439, 562, PdfRect(-113, -250, 749, 801) ), PdfFontMetricsBase14( PODOFO_HPDF_FONT_COURIER_OBLIQUE, CHAR_DATA_COURIER_OBLIQUE, PODOFO_FALSE, 629, -157, 426, 562, PdfRect(-27, -250, 849, 805) ), PdfFontMetricsBase14( PODOFO_HPDF_FONT_COURIER_BOLD_OBLIQUE, CHAR_DATA_COURIER_BOLD_OBLIQUE, PODOFO_FALSE, 629, -157, 439, 562, PdfRect(-57, -250, 869, 801) ), PdfFontMetricsBase14( PODOFO_HPDF_FONT_HELVETICA, CHAR_DATA_HELVETICA, PODOFO_FALSE, 718, -207, 523, 718, PdfRect(-166, -225, 1000, 931) ), PdfFontMetricsBase14( PODOFO_HPDF_FONT_HELVETICA_BOLD, CHAR_DATA_HELVETICA_BOLD, PODOFO_FALSE, 718, -207, 532, 718, PdfRect(-170, -228, 1003, 962) ), PdfFontMetricsBase14( PODOFO_HPDF_FONT_HELVETICA_OBLIQUE, CHAR_DATA_HELVETICA_OBLIQUE, PODOFO_FALSE, 718, -207, 532, 718, PdfRect(-170, -225, 1116, 931) ), PdfFontMetricsBase14( PODOFO_HPDF_FONT_HELVETICA_BOLD_OBLIQUE, CHAR_DATA_HELVETICA_BOLD_OBLIQUE, PODOFO_FALSE, 718, -207, 532, 718, PdfRect(-174, -228, 1114, 962) ), PdfFontMetricsBase14( PODOFO_HPDF_FONT_TIMES_ROMAN, CHAR_DATA_TIMES_ROMAN, PODOFO_FALSE, 683, -217, 450, 662, PdfRect(-168, -218, 1000, 898) ), PdfFontMetricsBase14( PODOFO_HPDF_FONT_TIMES_BOLD, CHAR_DATA_TIMES_BOLD, PODOFO_FALSE, 683, -217, 461, 676, PdfRect(-168, -218, 1000, 935) ), PdfFontMetricsBase14( PODOFO_HPDF_FONT_TIMES_ITALIC, CHAR_DATA_TIMES_ITALIC, PODOFO_FALSE, 683, -217, 441, 653, PdfRect(-169, -217, 1010, 883) ), PdfFontMetricsBase14( PODOFO_HPDF_FONT_TIMES_BOLD_ITALIC, CHAR_DATA_TIMES_BOLD_ITALIC, PODOFO_FALSE, 683, -217, 462, 669, PdfRect(-200, -218, 996, 921) ), PdfFontMetricsBase14( PODOFO_HPDF_FONT_SYMBOL, CHAR_DATA_SYMBOL, PODOFO_TRUE, 683, -217, 462, 669, /* 0, 0, 0, 0, */ PdfRect(-180, -293, 1090, 1010) ), PdfFontMetricsBase14( PODOFO_HPDF_FONT_ZAPF_DINGBATS, CHAR_DATA_ZAPF_DINGBATS, PODOFO_TRUE, 683, -217, 462, 669, /* 0, 0, 0, 0, */ PdfRect(-1, -143, 981, 820) ), PdfFontMetricsBase14( NULL, NULL, PODOFO_FALSE, 0, 0, 0, 0, PdfRect(0, 0, 0, 0) ), }; }; #endif // _PDF_FONT_FACTORY_BASE14_DATA_H_ podofo-0.9.5/src/doc/PdfPagesTree.h0000664000175000017500000003111712347310502016701 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_PAGES_TREE_H_ #define _PDF_PAGES_TREE_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfArray.h" #include "PdfElement.h" #include "PdfPagesTreeCache.h" namespace PoDoFo { class PdfObject; class PdfPage; class PdfRect; enum EPdfPageInsertionPoint { ePdfPageInsertionPoint_InsertBeforeFirstPage = -1, ePdfPageInsertionPoint_InsertLastPage = -2, ePdfPageInsertionPoint_InsertAllPages = -3, ePdfPageInsertionPoint_InsertOddPagesOnly = -4, ePdfPageInsertionPoint_InsertEvenPagesOnly = -5 }; /** Class for managing the tree of Pages in a PDF document * Don't use this class directly. Use PdfDocument instead. * * \see PdfDocument */ class PODOFO_DOC_API PdfPagesTree : public PdfElement { typedef std::deque< PdfObject* > PdfObjectList; public: /** Construct a new PdfPagesTree */ PdfPagesTree( PdfVecObjects* pParent ); /** Construct a PdfPagesTree from the root /Pages object * \param pPagesRoot pointer to page tree dictionary */ PdfPagesTree( PdfObject* pPagesRoot ); /** Close/down destruct a PdfPagesTree */ virtual ~PdfPagesTree(); /** Return the number of pages in the entire tree * \returns number of pages */ int GetTotalNumberOfPages() const; /** Return a PdfPage for the specified Page index * The returned page is owned by the pages tree and * deleted along with it. * * \param nIndex page index, 0-based * \returns a pointer to the requested page */ PdfPage* GetPage( int nIndex ); /** Return a PdfPage for the specified Page reference. * The returned page is owned by the pages tree and * deleted along with it. * * \param ref the reference of the pages object * \returns a pointer to the requested page */ PdfPage* GetPage( const PdfReference & ref ); /** Inserts an existing page object into the internal page tree. * after the specified page number * * \param nAfterPageIndex an integer specifying after what page * - may be one of the special values from EPdfPageInsertionPoint. * Pages are 0 based. * * \param pPage musst be a PdfObject with type /Page */ void InsertPage( int nAfterPageIndex, PdfObject* pPage ); /** Inserts an existing page object into the internal page tree. * after the specified page number * * \param nAfterPageIndex an integer specifying after what page * - may be one of the special values from EPdfPageInsertionPoint. * Pages are 0 based. * \param pPage a PdfPage to be inserted, the PdfPage will not get owned by the PdfPagesTree */ void InsertPage( int nAfterPageIndex, PdfPage* pPage ); /** Inserts a vector of page objects at once into the internal page tree * after the specified page index (zero based index) * * \param nAfterPageIndex a zero based integer index specifying after what page to insert * - you need to pass ePdfPageInsertionPoint_InsertBeforeFirstPage if you want to insert before the first page. * * \param vecPages must be a vector of PdfObjects with type /Page */ void InsertPages( int nAfterPageIndex, const std::vector& vecPages ); /** Creates a new page object and inserts it into the internal * page tree. * The returned page is owned by the pages tree and will get deleted along * with it! * * \param rSize a PdfRect specifying the size of the page (i.e the /MediaBox key) in PDF units * \returns a pointer to a PdfPage object */ PdfPage* CreatePage( const PdfRect & rSize ); /** Creates several new page objects and inserts them into the internal * page tree. * The new pages are owned by the pages tree and will get deleted along * with it! * Note: this function will attach all new pages onto the same page node * which can cause the tree to be unbalanced if * * \param vecSizes a vector of PdfRect specifying the size of each of the pages to create (i.e the /MediaBox key) in PDF units */ void CreatePages( const std::vector& vecSizes ); /** Creates a new page object and inserts it at index atIndex. * The returned page is owned by the pages tree and will get deleted along * with it! * * \param rSize a PdfRect specifying the size of the page (i.e the /MediaBox key) in PDF units * \param atIndex index where to insert the new page (0-based) * \returns a pointer to a PdfPage object */ PdfPage* InsertPage( const PdfRect & rSize, int atIndex); /** Delete the specified page object from the internal pages tree. * It does NOT remove any PdfObjects from memory - just the reference from the tree * * \param inPageNumber the page number (0-based) to be removed * * The PdfPage object refering to this page will be deleted by this call! * Empty page nodes will also be deleted. * * \see PdfMemDocument::DeletePages */ void DeletePage( int inPageNumber ); /** * Clear internal cache of PdfPage objects. * All references to PdfPage object will become invalid * when calling this method. All PdfPages will be deleted. * * You normally will never have to call this method. * It is only useful if one modified the page nodes * of the pagestree manually. * */ inline void ClearCache(); private: PdfPagesTree(); // don't allow construction from nothing! PdfObject* GetPageNode( int nPageNum, PdfObject* pParent, PdfObjectList & rLstParents ); PdfObject* GetPageNodeFromArray( int nPageNum, const PdfArray & rKidsArray, PdfObjectList & rLstParents ); int GetChildCount( const PdfObject* pNode ) const; /** * Test if a PdfObject is a page node * @return true if PdfObject is a page node */ bool IsTypePage( const PdfObject* pObject ) const; /** * Test if a PdfObject is a pages node * @return true if PdfObject is a pages node */ bool IsTypePages( const PdfObject* pObject ) const; /** * Find the position of pPageObj in the kids array of pPageParent * * @returns the index in the kids array or -1 if pPageObj is no child of pPageParent */ int GetPosInKids( PdfObject* pPageObj, PdfObject* pPageParent ); /** Private method for adjusting the page count in a tree */ int ChangePagesCount( PdfObject* inPageObj, int inDelta ); /** * Insert a page object into a pages node * * @param pNode the pages node whete pPage is to be inserted * @param rlstParents list of all (future) parent pages nodes in the pages tree * of pPage * @param nIndex index where pPage is to be inserted in pNode's kids array * @param pPage the page object which is to be inserted */ void InsertPageIntoNode( PdfObject* pNode, const PdfObjectList & rlstParents, int nIndex, PdfObject* pPage ); /** * Insert a vector of page objects into a pages node * Same as InsertPageIntoNode except that it allows for adding multiple pages at one time * Note that adding many pages onto the same node will create an unbalanced page tree * * @param pNode the pages node whete pPage is to be inserted * @param rlstParents list of all (future) parent pages nodes in the pages tree * of pPage * @param nIndex index where pPage is to be inserted in pNode's kids array * @param vecPages a vector of the page objects which are to be inserted */ void InsertPagesIntoNode( PdfObject* pParent, const PdfObjectList & rlstParents, int nIndex, const std::vector& vecPages ); /** * Delete a page object from a pages node * * @param pNode which is the direct parent of pPage and where the page must be deleted * @param rlstParents list of all parent pages nodes in the pages tree * of pPage * @param nIndex index where pPage is to be deleted in pNode's kids array * @param pPage the page object which is to be deleted */ void DeletePageFromNode( PdfObject* pNode, const PdfObjectList & rlstParents, int nIndex, PdfObject* pPage ); /** * Delete a single page node or page object from the kids array of pParent * * @param pParent the parent of the page node which is deleted * @param nIndex index to remove from the kids array of pParent */ void DeletePageNode( PdfObject* pParent, int nIndex ); /** * Tests if a page node is emtpy * * @returns true if Count of page is 0 or the Kids array is empty */ bool IsEmptyPageNode( PdfObject* pPageNode ); /** Private method for actually traversing the /Pages tree * * \param rListOfParents all parents of the page node will be added to this lists, * so that the PdfPage can later access inherited attributes */ /* PdfObject* GetPageNode( int nPageNum, PdfObject* pPagesObject, std::deque & rListOfParents ); */ /** Private method for actually traversing the /Pages tree * This method directly traverses the tree and does no * optimization for nodes with only one element like GetPageNode does. * * \param rListOfParents all parents of the page node will be added to this lists, * so that the PdfPage can later access inherited attributes */ /* PdfObject* GetPageNodeFromTree( int nPageNum, const PdfArray & kidsArray, std::deque & rListOfParents ); */ /** Private method to access the Root of the tree using a logical name */ PdfObject* GetRoot() { return this->GetObject(); } const PdfObject* GetRoot() const { return this->GetObject(); } private: PdfPagesTreeCache m_cache; }; // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfPagesTree::ClearCache() { m_cache.ClearCache(); } }; #endif // _PDF_PAGES_TREE_H_ podofo-0.9.5/src/doc/PdfField.cpp0000664000175000017500000007767413032763134016427 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #include "PdfField.h" #include "base/PdfDefinesPrivate.h" #include "base/PdfArray.h" #include "base/PdfDictionary.h" #include "PdfAcroForm.h" #include "PdfDocument.h" #include "PdfPainter.h" #include "PdfPage.h" #include "PdfStreamedDocument.h" #include "PdfXObject.h" #include namespace PoDoFo { PdfField::PdfField( EPdfField eField, PdfAnnotation* pWidget, PdfAcroForm* pParent ) : m_pObject( pWidget->GetObject() ), m_pWidget( pWidget ), m_eField( eField ) { Init( pParent ); } PdfField::PdfField( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfAcroForm* pParent ) : m_eField( eField ) { m_pWidget = pPage->CreateAnnotation( ePdfAnnotation_Widget, rRect ); m_pObject = m_pWidget->GetObject(); Init( pParent ); } PdfField::PdfField( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc ) : m_eField( eField ) { m_pWidget = pPage->CreateAnnotation( ePdfAnnotation_Widget, rRect ); m_pObject = m_pWidget->GetObject(); Init( pDoc->GetAcroForm() ); } PdfField::PdfField( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfStreamedDocument* pDoc ) : m_eField( eField ) { m_pWidget = pPage->CreateAnnotation( ePdfAnnotation_Widget, rRect ); m_pObject = m_pWidget->GetObject(); Init( pDoc->GetAcroForm() ); } PdfField::PdfField( EPdfField eField, PdfAnnotation* pWidget, PdfAcroForm* pParent, PdfDocument* pDoc) : m_pObject( pWidget->GetObject() ), m_pWidget( pWidget ), m_eField( eField ) { Init( pParent ); PdfObject* pFields = pParent->GetObject()->GetDictionary().GetKey( PdfName("Fields") ); if( pFields && pFields->IsReference()) { PdfObject *pRefFld = pDoc->GetObjects()->GetObject(pFields->GetReference()); if(pRefFld) pRefFld->GetArray().push_back( m_pObject->Reference() ); } } PdfField::PdfField( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc, bool bAppearanceNone) : m_eField( eField ) { m_pWidget = pPage->CreateAnnotation( ePdfAnnotation_Widget, rRect ); m_pObject = m_pWidget->GetObject(); Init( pDoc->GetAcroForm(true, bAppearanceNone ? ePdfAcroFormDefaultAppearance_None : ePdfAcroFormDefaultAppearance_BlackText12pt )); } PdfField::PdfField( const PdfField & rhs ) : m_pObject( NULL ), m_pWidget( NULL ), m_eField( ePdfField_Unknown ) { this->operator=( rhs ); } void PdfField::Init( PdfAcroForm* pParent ) { // Insert into the parents kids array PdfObject* pFields = pParent->GetObject()->GetDictionary().GetKey( PdfName("Fields") ); if( pFields ) { if(!pFields->IsReference() ) { pFields->GetArray().push_back( m_pObject->Reference() ); } } else { PODOFO_RAISE_ERROR( ePdfError_NoObject ); } switch( m_eField ) { case ePdfField_PushButton: case ePdfField_CheckBox: case ePdfField_RadioButton: m_pObject->GetDictionary().AddKey( PdfName("FT"), PdfName("Btn") ); break; case ePdfField_TextField: m_pObject->GetDictionary().AddKey( PdfName("FT"), PdfName("Tx") ); break; case ePdfField_ComboBox: case ePdfField_ListBox: m_pObject->GetDictionary().AddKey( PdfName("FT"), PdfName("Ch") ); break; case ePdfField_Signature: m_pObject->GetDictionary().AddKey( PdfName("FT"), PdfName("Sig") ); break; case ePdfField_Unknown: default: { PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } break; } // Create a unique fieldname, because Acrobat Reader crashes if the field has no field name std::ostringstream out; PdfLocaleImbue(out); out << "podofo_field_" << m_pObject->Reference().ObjectNumber(); } PdfField::PdfField( PdfObject* pObject, PdfAnnotation* pWidget ) : m_pObject( pObject ), m_pWidget( pWidget ), m_eField( ePdfField_Unknown ) { // ISO 32000:2008, Section 12.7.3.1, Table 220, Page #432. const PdfObject *pFT = m_pObject->GetDictionary().GetKey(PdfName("FT") ); if (!pFT && m_pObject->GetDictionary().HasKey( PdfName ("Parent") ) ) { const PdfObject *pTemp = m_pObject->GetIndirectKey ( PdfName("Parent") ); if (!pTemp) { PODOFO_RAISE_ERROR (ePdfError_InvalidDataType); } pFT = pTemp->GetDictionary().GetKey( PdfName ("FT") ); } if (!pFT) { PODOFO_RAISE_ERROR (ePdfError_NoObject); } const PdfName fieldType = pFT->GetName(); if( fieldType == PdfName("Btn") ) { PdfButton button( *this ); if( button.IsPushButton() ) m_eField = ePdfField_PushButton; else if( button.IsCheckBox() ) m_eField = ePdfField_CheckBox; else if (button.IsRadioButton() ) m_eField = ePdfField_RadioButton; } else if( fieldType == PdfName("Tx") ) m_eField = ePdfField_TextField; else if( fieldType == PdfName("Ch") ) { PdfListField listField( *this ); m_eField = listField.IsComboBox() ? ePdfField_ComboBox : ePdfField_ListBox; } else if( fieldType == PdfName("Sig") ) m_eField = ePdfField_Signature; } PdfObject* PdfField::GetAppearanceCharacteristics( bool bCreate ) const { PdfObject* pMK = NULL; if( !m_pObject->GetDictionary().HasKey( PdfName("MK") ) && bCreate ) { PdfDictionary dictionary; const_cast(this)->m_pObject->GetDictionary().AddKey( PdfName("MK"), dictionary ); } pMK = m_pObject->GetDictionary().GetKey( PdfName("MK") ); return pMK; } void PdfField::SetFieldFlag( long lValue, bool bSet ) { pdf_int64 lCur = 0; if( m_pObject->GetDictionary().HasKey( PdfName("Ff") ) ) lCur = m_pObject->GetDictionary().GetKey( PdfName("Ff") )->GetNumber(); if( bSet ) lCur |= lValue; else { if( (lCur & lValue) == lValue ) lCur ^= lValue; } m_pObject->GetDictionary().AddKey( PdfName("Ff"), lCur ); } bool PdfField::GetFieldFlag( long lValue, bool bDefault ) const { pdf_int64 lCur = 0; if( m_pObject->GetDictionary().HasKey( PdfName("Ff") ) ) { lCur = m_pObject->GetDictionary().GetKey( PdfName("Ff") )->GetNumber(); return (lCur & lValue) == lValue; } return bDefault; } void PdfField::SetHighlightingMode( EPdfHighlightingMode eMode ) { PdfName value; switch( eMode ) { case ePdfHighlightingMode_None: value = PdfName("N"); break; case ePdfHighlightingMode_Invert: value = PdfName("I"); break; case ePdfHighlightingMode_InvertOutline: value = PdfName("O"); break; case ePdfHighlightingMode_Push: value = PdfName("P"); break; case ePdfHighlightingMode_Unknown: default: PODOFO_RAISE_ERROR( ePdfError_InvalidName ); break; } m_pObject->GetDictionary().AddKey( PdfName("H"), value ); } EPdfHighlightingMode PdfField::GetHighlightingMode() const { EPdfHighlightingMode eMode = ePdfHighlightingMode_Invert; if( m_pObject->GetDictionary().HasKey( PdfName("H") ) ) { PdfName value = m_pObject->GetDictionary().GetKey( PdfName("H") )->GetName(); if( value == PdfName("N") ) return ePdfHighlightingMode_None; else if( value == PdfName("I") ) return ePdfHighlightingMode_Invert; else if( value == PdfName("O") ) return ePdfHighlightingMode_InvertOutline; else if( value == PdfName("P") ) return ePdfHighlightingMode_Push; } return eMode; } void PdfField::SetBorderColorTransparent() { PdfArray array; PdfObject* pMK = this->GetAppearanceCharacteristics( true ); pMK->GetDictionary().AddKey( PdfName("BC"), array ); } void PdfField::SetBorderColor( double dGray ) { PdfArray array; array.push_back( dGray ); PdfObject* pMK = this->GetAppearanceCharacteristics( true ); pMK->GetDictionary().AddKey( PdfName("BC"), array ); } void PdfField::SetBorderColor( double dRed, double dGreen, double dBlue ) { PdfArray array; array.push_back( dRed ); array.push_back( dGreen ); array.push_back( dBlue ); PdfObject* pMK = this->GetAppearanceCharacteristics( true ); pMK->GetDictionary().AddKey( PdfName("BC"), array ); } void PdfField::SetBorderColor( double dCyan, double dMagenta, double dYellow, double dBlack ) { PdfArray array; array.push_back( dCyan ); array.push_back( dMagenta ); array.push_back( dYellow ); array.push_back( dBlack ); PdfObject* pMK = this->GetAppearanceCharacteristics( true ); pMK->GetDictionary().AddKey( PdfName("BC"), array ); } void PdfField::SetBackgroundColorTransparent() { PdfArray array; PdfObject* pMK = this->GetAppearanceCharacteristics( true ); pMK->GetDictionary().AddKey( PdfName("BG"), array ); } void PdfField::SetBackgroundColor( double dGray ) { PdfArray array; array.push_back( dGray ); PdfObject* pMK = this->GetAppearanceCharacteristics( true ); pMK->GetDictionary().AddKey( PdfName("BG"), array ); } void PdfField::SetBackgroundColor( double dRed, double dGreen, double dBlue ) { PdfArray array; array.push_back( dRed ); array.push_back( dGreen ); array.push_back( dBlue ); PdfObject* pMK = this->GetAppearanceCharacteristics( true ); pMK->GetDictionary().AddKey( PdfName("BG"), array ); } void PdfField::SetBackgroundColor( double dCyan, double dMagenta, double dYellow, double dBlack ) { PdfArray array; array.push_back( dCyan ); array.push_back( dMagenta ); array.push_back( dYellow ); array.push_back( dBlack ); PdfObject* pMK = this->GetAppearanceCharacteristics( true ); pMK->GetDictionary().AddKey( PdfName("BG"), array ); } void PdfField::SetFieldName( const PdfString & rsName ) { m_pObject->GetDictionary().AddKey( PdfName("T"), rsName ); } PdfString PdfField::GetFieldName() const { if( m_pObject->GetDictionary().HasKey( PdfName("T" ) ) ) return m_pObject->GetDictionary().GetKey( PdfName("T" ) )->GetString(); return PdfString::StringNull; } void PdfField::SetAlternateName( const PdfString & rsName ) { m_pObject->GetDictionary().AddKey( PdfName("TU"), rsName ); } PdfString PdfField::GetAlternateName() const { if( m_pObject->GetDictionary().HasKey( PdfName("TU" ) ) ) return m_pObject->GetDictionary().GetKey( PdfName("TU" ) )->GetString(); return PdfString::StringNull; } void PdfField::SetMappingName( const PdfString & rsName ) { m_pObject->GetDictionary().AddKey( PdfName("TM"), rsName ); } PdfString PdfField::GetMappingName() const { if( m_pObject->GetDictionary().HasKey( PdfName("TM" ) ) ) return m_pObject->GetDictionary().GetKey( PdfName("TM" ) )->GetString(); return PdfString::StringNull; } void PdfField::AddAlternativeAction( const PdfName & rsName, const PdfAction & rAction ) { if( !m_pObject->GetDictionary().HasKey( PdfName("AA") ) ) m_pObject->GetDictionary().AddKey( PdfName("AA"), PdfDictionary() ); PdfObject* pAA = m_pObject->GetDictionary().GetKey( PdfName("AA") ); pAA->GetDictionary().AddKey( rsName, rAction.GetObject()->Reference() ); } ///////////////////////////////////////////////////////////////////////////// PdfButton::PdfButton( EPdfField eField, PdfAnnotation* pWidget, PdfAcroForm* pParent ) : PdfField( eField, pWidget, pParent ) { } PdfButton::PdfButton( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfAcroForm* pParent ) : PdfField( eField, pPage, rRect, pParent ) { } PdfButton::PdfButton( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc ) : PdfField( eField, pPage, rRect, pDoc ) { } PdfButton::PdfButton( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfStreamedDocument* pDoc ) : PdfField( eField, pPage, rRect, pDoc ) { } PdfButton::PdfButton( const PdfField & rhs ) : PdfField( rhs ) { } void PdfButton::SetCaption( const PdfString & rsText ) { PdfObject* pMK = this->GetAppearanceCharacteristics( true ); pMK->GetDictionary().AddKey( PdfName("CA"), rsText ); } const PdfString PdfButton::GetCaption() const { PdfObject* pMK = this->GetAppearanceCharacteristics( false ); if( pMK && pMK->GetDictionary().HasKey( PdfName("CA") ) ) return pMK->GetDictionary().GetKey( PdfName("CA") )->GetString(); return PdfString::StringNull; } ///////////////////////////////////////////////////////////////////////////// PdfPushButton::PdfPushButton( PdfAnnotation* pWidget, PdfAcroForm* pParent ) : PdfButton( ePdfField_PushButton, pWidget, pParent ) { Init(); } PdfPushButton::PdfPushButton( PdfPage* pPage, const PdfRect & rRect, PdfAcroForm* pParent ) : PdfButton( ePdfField_PushButton, pPage, rRect, pParent ) { Init(); } PdfPushButton::PdfPushButton( PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc ) : PdfButton( ePdfField_PushButton, pPage, rRect, pDoc ) { Init(); } PdfPushButton::PdfPushButton( PdfPage* pPage, const PdfRect & rRect, PdfStreamedDocument* pDoc ) : PdfButton( ePdfField_PushButton, pPage, rRect, pDoc ) { Init(); } PdfPushButton::PdfPushButton( const PdfField & rhs ) : PdfButton( rhs ) { if( this->GetType() != ePdfField_CheckBox ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Field cannot be converted into a PdfPushButton" ); } } void PdfPushButton::Init() { // make a push button this->SetFieldFlag( static_cast(ePdfButton_PushButton), true ); //m_pWidget->SetFlags( 4 ); /* m_pObject->GetDictionary().AddKey( PdfName("H"), PdfName("I") ); if( !m_pWidget->HasAppearanceStream() ) { // Create the default appearance stream PdfRect rect( 0.0, 0.0, m_pWidget->GetRect().GetWidth(), m_pWidget->GetRect().GetHeight() ); PdfXObject xObjOff( rect, m_pObject->GetOwner() ); PdfXObject xObjYes( rect, m_pObject->GetOwner() ); PdfPainter painter; painter.SetPage( &xObjOff ); painter.SetColor( 0.5, 0.5, 0.5 ); painter.FillRect( 0, xObjOff.GetPageSize().GetHeight(), xObjOff.GetPageSize().GetWidth(), xObjOff.GetPageSize().GetHeight() ); painter.FinishPage(); painter.SetPage( &xObjYes ); painter.SetColor( 1.0, 0.0, 0.0 ); painter.FillRect( 0, xObjYes.GetPageSize().GetHeight(), xObjYes.GetPageSize().GetWidth(), xObjYes.GetPageSize().GetHeight() ); painter.FinishPage(); PdfDictionary dict; PdfDictionary internal; internal.AddKey( "On", xObjYes.GetObject()->Reference() ); internal.AddKey( "Off", xObjOff.GetObject()->Reference() ); dict.AddKey( "N", internal ); m_pWidget->GetObject()->GetDictionary().AddKey( "AP", dict ); m_pWidget->GetObject()->GetDictionary().AddKey( "AS", PdfName("Off") ); //pWidget->SetAppearanceStream( &xObj ); } */ } void PdfPushButton::SetRolloverCaption( const PdfString & rsText ) { PdfObject* pMK = this->GetAppearanceCharacteristics( true ); pMK->GetDictionary().AddKey( PdfName("RC"), rsText ); } const PdfString PdfPushButton::GetRolloverCaption() const { PdfObject* pMK = this->GetAppearanceCharacteristics( false ); if( pMK && pMK->GetDictionary().HasKey( PdfName("RC") ) ) return pMK->GetDictionary().GetKey( PdfName("RC") )->GetString(); return PdfString::StringNull; } void PdfPushButton::SetAlternateCaption( const PdfString & rsText ) { PdfObject* pMK = this->GetAppearanceCharacteristics( true ); pMK->GetDictionary().AddKey( PdfName("AC"), rsText ); } const PdfString PdfPushButton::GetAlternateCaption() const { PdfObject* pMK = this->GetAppearanceCharacteristics( false ); if( pMK && pMK->GetDictionary().HasKey( PdfName("AC") ) ) return pMK->GetDictionary().GetKey( PdfName("AC") )->GetString(); return PdfString::StringNull; } ///////////////////////////////////////////////////////////////////////////// PdfCheckBox::PdfCheckBox( PdfAnnotation* pWidget, PdfAcroForm* pParent ) : PdfButton( ePdfField_CheckBox, pWidget, pParent ) { Init(); } PdfCheckBox::PdfCheckBox( PdfPage* pPage, const PdfRect & rRect, PdfAcroForm* pParent ) : PdfButton( ePdfField_CheckBox, pPage, rRect, pParent ) { Init(); } PdfCheckBox::PdfCheckBox( PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc ) : PdfButton( ePdfField_CheckBox, pPage, rRect, pDoc ) { Init(); } PdfCheckBox::PdfCheckBox( PdfPage* pPage, const PdfRect & rRect, PdfStreamedDocument* pDoc ) : PdfButton( ePdfField_CheckBox, pPage, rRect, pDoc ) { Init(); } PdfCheckBox::PdfCheckBox( const PdfField & rhs ) : PdfButton( rhs ) { if( this->GetType() != ePdfField_CheckBox ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Field cannot be converted into a PdfCheckBox" ); } } void PdfCheckBox::Init() { double dWidth = PDF_MIN( m_pWidget->GetRect().GetWidth(), m_pWidget->GetRect().GetHeight() ) * 0.1; dWidth = PDF_MAX( dWidth, 1.0 ); // Date: 20/10/2007 // Prashanth Udupa. // We expect PDF3DWidgetStyle to provide appearence streams. So we can comment this here. /*if( !m_pWidget->HasAppearanceStream() ) { // Create the default appearance stream PdfRect rect( 0.0, 0.0, m_pWidget->GetRect().GetWidth(), m_pWidget->GetRect().GetHeight() ); PdfXObject xObjOff( rect, m_pObject->GetOwner() ); PdfXObject xObjYes( rect, m_pObject->GetOwner() ); PdfPainter painter; painter.SetPage( &xObjOff ); painter.SetColor( 1.0, 1.0, 1.0 ); painter.FillRect( 0, xObjOff.GetPageSize().GetHeight(), xObjOff.GetPageSize().GetWidth(), xObjOff.GetPageSize().GetHeight() ); painter.SetColor( 0.0, 0.0, 0.0 ); painter.SetStrokeWidth( dWidth ); painter.DrawRect( 0.0, m_pWidget->GetRect().GetHeight(), m_pWidget->GetRect().GetWidth(), m_pWidget->GetRect().GetHeight() ); painter.FinishPage(); painter.SetPage( &xObjYes ); painter.SetColor( 1.0, 1.0, 1.0 ); painter.FillRect( 0, xObjYes.GetPageSize().GetHeight(), xObjYes.GetPageSize().GetWidth(), xObjYes.GetPageSize().GetHeight() ); painter.SetColor( 0.0, 0.0, 0.0 ); painter.SetStrokeWidth( dWidth ); painter.DrawLine( 0.0, 0.0, m_pWidget->GetRect().GetWidth(), m_pWidget->GetRect().GetHeight() ); painter.DrawLine( 0.0, m_pWidget->GetRect().GetHeight(), m_pWidget->GetRect().GetWidth(), 0.0 ); painter.DrawRect( 0.0, m_pWidget->GetRect().GetHeight(), m_pWidget->GetRect().GetWidth(), m_pWidget->GetRect().GetHeight() ); painter.FinishPage(); this->SetAppearanceChecked( xObjYes ); this->SetAppearanceUnchecked( xObjOff ); this->SetChecked( false ); }*/ } void PdfCheckBox::AddAppearanceStream( const PdfName & rName, const PdfReference & rReference ) { if( !m_pObject->GetDictionary().HasKey( PdfName("AP") ) ) m_pObject->GetDictionary().AddKey( PdfName("AP"), PdfDictionary() ); if( !m_pObject->GetDictionary().GetKey( PdfName("AP") )->GetDictionary().HasKey( PdfName("N") ) ) m_pObject->GetDictionary().GetKey( PdfName("AP") )->GetDictionary().AddKey( PdfName("N"), PdfDictionary() ); m_pObject->GetDictionary().GetKey( PdfName("AP") )-> GetDictionary().GetKey( PdfName("N") )->GetDictionary().AddKey( rName, rReference ); } void PdfCheckBox::SetAppearanceChecked( const PdfXObject & rXObject ) { this->AddAppearanceStream( PdfName("Yes"), rXObject.GetObject()->Reference() ); } void PdfCheckBox::SetAppearanceUnchecked( const PdfXObject & rXObject ) { this->AddAppearanceStream( PdfName("Off"), rXObject.GetObject()->Reference() ); } void PdfCheckBox::SetChecked( bool bChecked ) { m_pObject->GetDictionary().AddKey( PdfName("V"), (bChecked ? PdfName("Yes") : PdfName("Off")) ); m_pObject->GetDictionary().AddKey( PdfName("AS"), (bChecked ? PdfName("Yes") : PdfName("Off")) ); } bool PdfCheckBox::IsChecked() const { PdfDictionary dic = m_pObject->GetDictionary(); if (dic.HasKey(PdfName("V"))) { PdfName name = dic.GetKey( PdfName("V") )->GetName(); return (name == PdfName("Yes") || name == PdfName("On")); } else if (dic.HasKey(PdfName("AS"))) { PdfName name = dic.GetKey( PdfName("AS") )->GetName(); return (name == PdfName("Yes") || name == PdfName("On")); } return false; } ///////////////////////////////////////////////////////////////////////////// PdfTextField::PdfTextField( PdfAnnotation* pWidget, PdfAcroForm* pParent ) : PdfField( ePdfField_TextField, pWidget, pParent ) { Init(); } PdfTextField::PdfTextField( PdfPage* pPage, const PdfRect & rRect, PdfAcroForm* pParent ) : PdfField( ePdfField_TextField, pPage, rRect, pParent ) { Init(); } PdfTextField::PdfTextField( PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc ) : PdfField( ePdfField_TextField, pPage, rRect, pDoc ) { Init(); } PdfTextField::PdfTextField( PdfPage* pPage, const PdfRect & rRect, PdfStreamedDocument* pDoc ) : PdfField( ePdfField_TextField, pPage, rRect, pDoc ) { Init(); } PdfTextField::PdfTextField( const PdfField & rhs ) : PdfField( rhs ) { if( this->GetType() != ePdfField_TextField ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Field cannot be converted into a PdfTextField" ); } } void PdfTextField::Init() { if( !m_pObject->GetDictionary().HasKey( PdfName("DS") ) ) m_pObject->GetDictionary().AddKey( PdfName("DS"), PdfString("font: 12pt Helvetica") ); } void PdfTextField::SetText( const PdfString & rsText ) { PdfName key = this->IsRichText() ? PdfName("RV") : PdfName("V"); // if rsText is longer than maxlen, truncate it pdf_long nMax = this->GetMaxLen(); if( nMax != -1 && rsText.GetLength() > nMax ) m_pObject->GetDictionary().AddKey( key, PdfString( rsText.GetString(), nMax ) ); else m_pObject->GetDictionary().AddKey( key, rsText ); } PdfString PdfTextField::GetText() const { PdfName key = this->IsRichText() ? PdfName("RV") : PdfName("V"); PdfString str; if( m_pObject->GetDictionary().HasKey( key ) ) str = m_pObject->GetDictionary().GetKey( key )->GetString(); return str; } void PdfTextField::SetMaxLen( pdf_long nMaxLen ) { m_pObject->GetDictionary().AddKey( PdfName("MaxLen"), static_cast(nMaxLen) ); } pdf_long PdfTextField::GetMaxLen() const { return static_cast(m_pObject->GetDictionary().HasKey( PdfName("MaxLen") ) ? m_pObject->GetDictionary().GetKey( PdfName("MaxLen") )->GetNumber() : -1); } ///////////////////////////////////////////////////////////////////////////// PdfListField::PdfListField( EPdfField eField, PdfAnnotation* pWidget, PdfAcroForm* pParent ) : PdfField( eField, pWidget, pParent ) { } PdfListField::PdfListField( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfAcroForm* pParent ) : PdfField( eField, pPage, rRect, pParent ) { } PdfListField::PdfListField( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc ) : PdfField( eField, pPage, rRect, pDoc ) { } PdfListField::PdfListField( EPdfField eField, PdfPage* pPage, const PdfRect & rRect, PdfStreamedDocument* pDoc ) : PdfField( eField, pPage, rRect, pDoc ) { } PdfListField::PdfListField( const PdfField & rhs ) : PdfField( rhs ) { } void PdfListField::InsertItem( const PdfString & rsValue, const PdfString & rsDisplayName ) { PdfVariant var; PdfArray opt; if( rsDisplayName == PdfString::StringNull ) var = rsValue; else { PdfArray array; array.push_back( rsValue ); array.push_back( rsDisplayName ); var = array; } if( m_pObject->GetDictionary().HasKey( PdfName("Opt") ) ) opt = m_pObject->GetDictionary().GetKey( PdfName("Opt") )->GetArray(); // TODO: Sorting opt.push_back( var ); m_pObject->GetDictionary().AddKey( PdfName("Opt"), opt ); /* m_pObject->GetDictionary().AddKey( PdfName("V"), rsValue ); PdfArray array; array.push_back( 0L ); m_pObject->GetDictionary().AddKey( PdfName("I"), array ); */ } void PdfListField::RemoveItem( int nIndex ) { PdfArray opt; if( m_pObject->GetDictionary().HasKey( PdfName("Opt") ) ) opt = m_pObject->GetDictionary().GetKey( PdfName("Opt") )->GetArray(); if( nIndex < 0 || nIndex > static_cast(opt.size()) ) { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } opt.erase( opt.begin() + nIndex ); m_pObject->GetDictionary().AddKey( PdfName("Opt"), opt ); } const PdfString PdfListField::GetItem( int nIndex ) const { PdfArray opt; if( m_pObject->GetDictionary().HasKey( PdfName("Opt") ) ) opt = m_pObject->GetDictionary().GetKey( PdfName("Opt") )->GetArray(); if( nIndex < 0 || nIndex > static_cast(opt.size()) ) { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } PdfVariant var = opt[nIndex]; if( var.IsArray() ) { if( var.GetArray().size() < 2 ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } else return var.GetArray()[0].GetString(); } return var.GetString(); } const PdfString PdfListField::GetItemDisplayText( int nIndex ) const { PdfArray opt; if( m_pObject->GetDictionary().HasKey( PdfName("Opt") ) ) opt = m_pObject->GetDictionary().GetKey( PdfName("Opt") )->GetArray(); if( nIndex < 0 || nIndex > static_cast(opt.size()) ) { PODOFO_RAISE_ERROR( ePdfError_ValueOutOfRange ); } PdfVariant var = opt[nIndex]; if( var.IsArray() ) { if( var.GetArray().size() < 2 ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } else return var.GetArray()[1].GetString(); } return var.GetString(); } size_t PdfListField::GetItemCount() const { PdfArray opt; if( m_pObject->GetDictionary().HasKey( PdfName("Opt") ) ) opt = m_pObject->GetDictionary().GetKey( PdfName("Opt") )->GetArray(); return opt.size(); } void PdfListField::SetSelectedItem( int nIndex ) { PdfString selected = this->GetItem( nIndex ); m_pObject->GetDictionary().AddKey( PdfName("V"), selected ); } int PdfListField::GetSelectedItem() const { if( m_pObject->GetDictionary().HasKey( PdfName("V") ) ) { PdfObject* pValue = m_pObject->GetDictionary().GetKey( PdfName("V") ); if( pValue->IsString() || pValue->IsHexString() ) { PdfString value = pValue->GetString(); for( int i=0;i(this->GetItemCount());i++ ) { if( this->GetItem( i ) == value ) return i; } } } return -1; } ///////////////////////////////////////////////////////////////////////////// PdfComboBox::PdfComboBox( PdfAnnotation* pWidget, PdfAcroForm* pParent ) : PdfListField( ePdfField_ComboBox, pWidget, pParent ) { this->SetFieldFlag( static_cast(ePdfListField_Combo), true ); m_pWidget->SetBorderStyle( 0.0, 0.0, 1.0 ); } PdfComboBox::PdfComboBox( PdfPage* pPage, const PdfRect & rRect, PdfAcroForm* pParent ) : PdfListField( ePdfField_ComboBox, pPage, rRect, pParent ) { this->SetFieldFlag( static_cast(ePdfListField_Combo), true ); m_pWidget->SetBorderStyle( 0.0, 0.0, 1.0 ); } PdfComboBox::PdfComboBox( PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc ) : PdfListField( ePdfField_ComboBox, pPage, rRect, pDoc ) { this->SetFieldFlag( static_cast(ePdfListField_Combo), true ); m_pWidget->SetBorderStyle( 0.0, 0.0, 1.0 ); } PdfComboBox::PdfComboBox( PdfPage* pPage, const PdfRect & rRect, PdfStreamedDocument* pDoc ) : PdfListField( ePdfField_ComboBox, pPage, rRect, pDoc ) { this->SetFieldFlag( static_cast(ePdfListField_Combo), true ); m_pWidget->SetBorderStyle( 0.0, 0.0, 1.0 ); } PdfComboBox::PdfComboBox( const PdfField & rhs ) : PdfListField( rhs ) { if( this->GetType() != ePdfField_ComboBox ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Field cannot be converted into a PdfTextField" ); } } ///////////////////////////////////////////////////////////////////////////// PdfListBox::PdfListBox( PdfAnnotation* pWidget, PdfAcroForm* pParent ) : PdfListField( ePdfField_ListBox, pWidget, pParent ) { this->SetFieldFlag( static_cast(ePdfListField_Combo), false ); m_pWidget->SetBorderStyle( 0.0, 0.0, 1.0 ); } PdfListBox::PdfListBox( PdfPage* pPage, const PdfRect & rRect, PdfAcroForm* pParent ) : PdfListField( ePdfField_ListBox, pPage, rRect, pParent ) { this->SetFieldFlag( static_cast(ePdfListField_Combo), false ); m_pWidget->SetBorderStyle( 0.0, 0.0, 1.0 ); } PdfListBox::PdfListBox( PdfPage* pPage, const PdfRect & rRect, PdfDocument* pDoc ) : PdfListField( ePdfField_ListBox, pPage, rRect, pDoc ) { this->SetFieldFlag( static_cast(ePdfListField_Combo), false ); m_pWidget->SetBorderStyle( 0.0, 0.0, 1.0 ); } PdfListBox::PdfListBox( PdfPage* pPage, const PdfRect & rRect, PdfStreamedDocument* pDoc ) : PdfListField( ePdfField_ListBox, pPage, rRect, pDoc ) { this->SetFieldFlag( static_cast(ePdfListField_Combo), false ); m_pWidget->SetBorderStyle( 0.0, 0.0, 1.0 ); } PdfListBox::PdfListBox( const PdfField & rhs ) : PdfListField( rhs ) { if( this->GetType() != ePdfField_ListBox ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, "Field cannot be converted into a PdfTextField" ); } } }; podofo-0.9.5/src/doc/PdfDocument.h0000664000175000017500000007502213013650710016602 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * In addition, as a special exception, the copyright holders give * * permission to link the code of portions of this program with the * * OpenSSL library under certain conditions as described in each * * individual source file, and distribute linked combinations * * including the two. * * You must obey the GNU General Public License in all respects * * for all of the code used other than OpenSSL. If you modify * * file(s) with this exception, you may extend this exception to your * * version of the file(s), but you are not obligated to do so. If you * * do not wish to do so, delete this exception statement from your * * version. If you delete this exception statement from all source * * files in the program, then also delete it here. * ***************************************************************************/ #ifndef _PDF_DOCUMENT_H_ #define _PDF_DOCUMENT_H_ #include "podofo/base/PdfDefines.h" #include "podofo/base/PdfObject.h" #include "podofo/base/PdfParser.h" #include "podofo/base/PdfWriter.h" #include "PdfAcroForm.h" #include "PdfFontCache.h" #include "PdfInfo.h" namespace PoDoFo { class PdfDestination; class PdfDictionary; class PdfFileSpec; class PdfFont; class PdfFontConfigWrapper; class PdfInfo; class PdfMemDocument; class PdfNamesTree; class PdfOutlines; class PdfPage; class PdfPagesTree; class PdfRect; class PdfXObject; /** PdfDocument is the core interface for working with PDF documents. * * PdfDocument provides easy access to the individual pages * in the PDF file and to certain special dictionaries. * * PdfDocument cannot be used directly. * Use PdfMemDocument whenever you want to change the object structure * of a PDF file. * * When you are only creating PDF files, please use PdfStreamedDocument * which is usually faster for creating PDFs. * * \see PdfStreamedDocument * \see PdfMemDocument */ class PODOFO_DOC_API PdfDocument { friend class PdfElement; public: /** Close down/destruct the PdfDocument */ virtual ~PdfDocument(); /** Get the write mode used for writing the PDF * \returns the write mode */ virtual EPdfWriteMode GetWriteMode() const = 0; /** Get the PDF version of the document * \returns EPdfVersion version of the pdf document */ virtual EPdfVersion GetPdfVersion() const = 0; /** Returns whether this PDF document is linearized, aka * web-optimized * \returns true if the PDF document is linearized */ virtual bool IsLinearized() const = 0; /** Get access to the internal Info dictionary * You can set the author, title etc. of the * document using the info dictionary. * * \returns the info dictionary */ PdfInfo* GetInfo() const { return m_pInfo; } /** Get access to the Outlines (Bookmarks) dictionary * The returned outlines object is owned by the PdfDocument. * * \param bCreate create the object if it does not exist (ePdfCreateObject) * or return NULL if it does not exist * \returns the Outlines/Bookmarks dictionary */ PdfOutlines* GetOutlines( bool bCreate = ePdfCreateObject ); /** Get access to the Names dictionary (where all the named objects are stored) * The returned PdfNamesTree object is owned by the PdfDocument. * * \param bCreate create the object if it does not exist (ePdfCreateObject) * or return NULL if it does not exist * \returns the Names dictionary */ PdfNamesTree* GetNamesTree( bool bCreate = ePdfCreateObject ); /** Get access to the AcroForm dictionary * * \param bCreate create the object if it does not exist (ePdfCreateObject) * or return NULL if it does not exist * \param eDefaultAppearance specifies if a default appearence shall be created * * \returns PdfObject the AcroForm dictionary */ PdfAcroForm* GetAcroForm( bool bCreate = ePdfCreateObject, EPdfAcroFormDefaulAppearance eDefaultAppearance = ePdfAcroFormDefaultAppearance_BlackText12pt); /** Get access to the pages tree. * Better use the GetPage() and CreatePage() methods. * \returns the PdfPagesTree of this document. */ inline PdfPagesTree* GetPagesTree() const; /** Get the total number of pages in a document * \returns int number of pages */ int GetPageCount() const; /** Get the PdfPage for a specific page in a document * The returned page is owned by the PdfDocument * and will get deleted along with it! * * \param nIndex which page (0-based) * \returns a pointer to a PdfPage for the requested page. * The returned object is owned by the PdfDocument. */ PdfPage* GetPage( int nIndex ) const; /** Creates a PdfFont object * \param pszFontName name of the font as it is known to the system * \param bSymbolCharset whether to use the symbol charset, rather than unicode charset * \param pEncoding the encoding of the font. The font will not take ownership of this object. * \param eFontCreationFlags special flag to specify how fonts should be created * \param bEmbedd specifies whether this font should be embedded in the PDF file. * Embedding fonts is usually a good idea. * * \returns PdfFont* a pointer to a new PdfFont object. * The returned object is owned by the PdfDocument. */ PdfFont* CreateFont( const char* pszFontName, bool bSymbolCharset = false, const PdfEncoding * const pEncoding = PdfEncodingFactory::GlobalWinAnsiEncodingInstance(), PdfFontCache::EFontCreationFlags eFontCreationFlags = PdfFontCache::eFontCreationFlags_AutoSelectBase14, bool bEmbedd = true ); /** Creates a PdfFont object * \param pszFontName name of the font as it is known to the system * \param bBold if true search for a bold font * \param bItalic if true search for an italic font * \param bSymbolCharset whether to use the symbol charset, rather than unicode charset * \param pEncoding the encoding of the font. The font will not take ownership of this object. * \param eFontCreationFlags special flag to specify how fonts should be created * \param bEmbedd specifies whether this font should be embedded in the PDF file. * Embedding fonts is usually a good idea. * \param pszFileName path to a valid font file * * \returns PdfFont* a pointer to a new PdfFont object. */ PdfFont* CreateFont( const char* pszFontName, bool bBold, bool bItalic, bool bSymbolCharset = false, const PdfEncoding * const pEncoding = PdfEncodingFactory::GlobalWinAnsiEncodingInstance(), PdfFontCache::EFontCreationFlags eFontCreationFlags = PdfFontCache::eFontCreationFlags_AutoSelectBase14, bool bEmbedd = true, const char* pszFileName = NULL ); #ifdef _WIN32 /** Creates a PdfFont object * \param pszFontName name of the font as it is known to the system * \param bSymbolCharset whether to use the symbol charset, rather than unicode charset * \param pEncoding the encoding of the font. The font will not take ownership of this object. * \param bEmbedd specifies whether this font should be embedded in the PDF file. * Embedding fonts is usually a good idea. * * \returns PdfFont* a pointer to a new PdfFont object. * The returned object is owned by the PdfDocument. * * This is an overloaded member function to allow working * with unicode characters. On Unix/Unix-like systems you can also pass * UTF-8 to the const char* overload. */ PdfFont* CreateFont( const wchar_t* pszFontName, bool bSymbolCharset = false, const PdfEncoding * const pEncoding = PdfEncodingFactory::GlobalWinAnsiEncodingInstance(), bool bEmbedd = true ); /** Creates a PdfFont object * \param pszFontName name of the font as it is known to the system * \param bBold if true search for a bold font * \param bItalic if true search for an italic font * \param bSymbolCharset whether to use symbol charset, rather than unicode charset * \param pEncoding the encoding of the font. The font will not take ownership of this object. * \param bEmbedd specifies whether this font should be embedded in the PDF file. * Embedding fonts is usually a good idea. * \param optional: pszFileName path to a valid font file * * \returns PdfFont* a pointer to a new PdfFont object. * * This is an overloaded member function to allow working * with unicode characters. On Unix/Unix-like systems you can also pass * UTF-8 to the const char* overload. */ PdfFont* CreateFont( const wchar_t* pszFontName, bool bBold, bool bItalic, bool bSymbolCharset = false, const PdfEncoding * const pEncoding = PdfEncodingFactory::GlobalWinAnsiEncodingInstance(), bool bEmbedd = true); PdfFont* CreateFont( const LOGFONTA &logFont, const PdfEncoding * const pEncoding = PdfEncodingFactory::GlobalWinAnsiEncodingInstance(), bool bEmbedd = true ); PdfFont* CreateFont( const LOGFONTW &logFont, const PdfEncoding * const pEncoding = PdfEncodingFactory::GlobalWinAnsiEncodingInstance(), bool bEmbedd = true ); #endif // _WIN32 /** Creates a PdfFont object * \param face a valid freetype font handle (will be free()'d by PoDoFo) * \param bSymbolCharset whether to use the symbol charset, rather than unicode charset * \param pEncoding the encoding of the font. The font will not take ownership of this object. * \param bEmbedd specifies whether this font should be embedded in the PDF file. * Embedding fonts is usually a good idea. * \returns PdfFont* a pointer to a new PdfFont object. * The returned object is owned by the PdfDocument. */ PdfFont* CreateFont( FT_Face face, bool bSymbolCharset = false, const PdfEncoding * const pEncoding = PdfEncodingFactory::GlobalWinAnsiEncodingInstance(), bool bEmbedd = true ); /** Creates a duplicate Type1 PdfFont with a new ID * \param pFont is the existing font * \param pszSuffix Suffix to add to font ID * The returned object is owned by the PdfDocument. * * TODO: DS: Make this generic so that it will work * for any font type! */ PdfFont* CreateDuplicateFontType1( PdfFont * pFont, const char * pszSuffix ); /** Creates a font subset which contains only a few characters and is embedded. * * THIS WORKS ONLY FOR TTF FONTS! * * \param pszFontName name of the font as it is known to the system * \param bBold if true search for a bold font * \param bItalic if true search for an italic font * \param bSymbolCharset whether to use the symbol charset, rather than unicode charset * \param pEncoding the encoding of the font. The font will not take ownership of this object. * \param pszFileName optional path of a font file which should be used * * \returns PdfFont* a pointer to a new PdfFont object. */ PdfFont* CreateFontSubset( const char* pszFontName, bool bBold, bool bItalic, bool bSymbolCharset = false, const PdfEncoding * const pEncoding = PdfEncodingFactory::GlobalWinAnsiEncodingInstance(), const char* pszFileName = NULL); #ifdef _WIN32 /** Creates a font subset which contains only a few characters and is embedded. * * THIS WORKS ONLY FOR TTF FONTS! * * \param pszFontName name of the font as it is known to the system * \param bBold if true search for a bold font * \param bItalic if true search for an italic font * \param bSymbolCharset whether to use the symbol charset, rather than unicode charset * \param pEncoding the encoding of the font. The font will not take ownership of this object. * * \returns PdfFont* a pointer to a new PdfFont object. * * This is an overloaded member function to allow working * with unicode characters. On Unix systems/Unix-like you can also pass * UTF-8 to the const char* overload. */ PdfFont* CreateFontSubset( const wchar_t* pszFontName, bool bBold, bool bItalic, bool bSymbolCharset = false, const PdfEncoding * const = PdfEncodingFactory::GlobalWinAnsiEncodingInstance() ); #endif // _WIN32 // Peter Petrov 26 April 2008 /** Returns the font library from font cache * * \returns the internal handle to the freetype library */ inline FT_Library GetFontLibrary() const; /** Embeds all pending subset fonts, is automatically done on Write(). * Just call explicitly in case the PdfDocument is needed as PdfXObject. * */ void EmbedSubsetFonts(); /** Creates a new page object and inserts it into the internal * page tree. * The returned page is owned by the PdfDocument * and will get deleted along with it! * * \param rSize a PdfRect specifying the size of the page (i.e the /MediaBox key) in 1/1000th mm * \returns a pointer to a PdfPage object */ PdfPage* CreatePage( const PdfRect & rSize ); /** Creates several new page objects and inserts them into the internal * page tree. * The created pages are owned by the PdfDocument * and will get deleted along with it! * * \param vecSizes a vector of PdfRect instances specifying the size of the pages (i.e the /MediaBox key) in PDF Units */ void CreatePages( const std::vector& vecSizes ); /** Creates a new page object and inserts it at index atIndex. * The returned page is owned by the pages tree and will get deleted along * with it! * * \param rSize a PdfRect specifying the size of the page (i.e the /MediaBox key) in PDF units * \param atIndex index where to insert the new page (0-based) * \returns a pointer to a PdfPage object */ PdfPage* InsertPage( const PdfRect & rSize, int atIndex); /** Appends another PdfDocument to this document. * \param rDoc the document to append * \param bAppendAll specifies whether pages and outlines are appended too * \returns this document */ const PdfDocument & Append( const PdfMemDocument & rDoc, bool bAppendAll = true ); /** Inserts existing page from another PdfMemDocument to this document. * \param rDoc the document to append from * \param nPageIndex index of page to append (0-based), from rDoc * \param nAtIndex index at which to add the page in this document * \returns this document */ const PdfDocument &InsertExistingPageAt( const PdfMemDocument & rDoc, int nPageIndex, int nAtIndex); /** Fill an existing empty PdfXObject from a page of another document. * This will append the other document to this one. * \param pXObj pointer to the PdfXObject * \param rDoc the document to embed into the PdfXObject * \param nPage number of page to embed into the PdfXObject * \param bUseTrimBox if true try to use page's TrimBox for size of PdfXObject * \returns the bounding box */ PdfRect FillXObjectFromDocumentPage( PdfXObject * pXObj, const PdfMemDocument & rDoc, int nPage, bool bUseTrimBox ); /** Fill an existing empty PdfXObject from an existing page from the current document. * If you need a page from another document use FillXObjectFromDocumentPage(), or * append the document manually. * \param pXObj pointer to the PdfXObject * \param nPage number of page to embed into the PdfXObject * \param bUseTrimBox if true try to use page's TrimBox for size of PdfXObject * \returns the bounding box */ PdfRect FillXObjectFromExistingPage( PdfXObject * pXObj, int nPage, bool bUseTrimBox ); /** Fill an existing empty PdfXObject from an existing page pointer from the current document. * This is the implementation for FillXObjectFromDocumentPage() and FillXObjectFromExistingPage(), * you should use those directly instead of this. * \param pXObj pointer to the PdfXObject * \param pPage pointer to the page to embed into PdfXObject * \param bUseTrimBox if true try to use page's TrimBox for size of PdfXObject * \returns the bounding box */ PdfRect FillXObjectFromPage( PdfXObject * pXObj, const PdfPage * pPage, bool bUseTrimBox, unsigned int difference ); /** Attach a file to the document. * \param rFileSpec a file specification */ void AttachFile( const PdfFileSpec & rFileSpec ); /** Get an attached file's filespec. * \param rName the name of the attachment * \return the file specification object if the file exists, NULL otherwise * The file specification object is not owned by the document and must be deleted by the caller */ PdfFileSpec* GetAttachment( const PdfString & rName ); /** Adds a PdfDestination into the global Names tree * with the specified name, optionally replacing one of the same name. * \param rDest the destination to be assigned * \param rsName the name for the destination */ void AddNamedDestination( const PdfDestination& rDest, const PdfString & rsName ); /** Sets the opening mode for a document. * \param inMode which mode to set */ void SetPageMode( EPdfPageMode inMode ); /** Gets the opening mode for a document. * \returns which mode is set */ EPdfPageMode GetPageMode( void ) const; /** Sets the opening mode for a document to be in full screen. */ void SetUseFullScreen( void ); /** Sets the page layout for a document. */ void SetPageLayout( EPdfPageLayout inLayout ); /** Set the document's Viewer Preferences: * Hide the toolbar in the viewer. */ void SetHideToolbar( void ); /** Set the document's Viewer Preferences: * Hide the menubar in the viewer. */ void SetHideMenubar( void ); /** Set the document's Viewer Preferences: * Show only the documents contents and no control * elements such as buttons and scrollbars in the viewer. */ void SetHideWindowUI( void ); /** Set the document's Viewer Preferences: * Fit the document in the viewer's window. */ void SetFitWindow( void ); /** Set the document's Viewer Preferences: * Center the document in the viewer's window. */ void SetCenterWindow( void ); /** Set the document's Viewer Preferences: * Display the title from the document information * in the title of the viewer. * * \see SetTitle */ void SetDisplayDocTitle( void ); /** Set the document's Viewer Preferences: * Set the default print scaling of the document. * * TODO: DS use an enum here! */ void SetPrintScaling( PdfName& inScalingType ); /** Set the document's Viewer Preferences: * Set the base URI of the document. * * TODO: DS document value! */ void SetBaseURI( const std::string& inBaseURI ); /** Set the document's Viewer Preferences: * Set the language of the document. */ void SetLanguage( const std::string& inLanguage ); /** Set the document's Viewer Preferences: Set the document's binding direction. */ void SetBindingDirection( PdfName& inDirection ); /** Checks if printing this document is allowed. * Every PDF-consuming application has to adhere to this value! * * \returns true if you are allowed to print this document * * \see PdfEncrypt to set own document permissions. */ virtual bool IsPrintAllowed() const = 0; /** Checks if modifying this document (besides annotations, form fields or substituting pages) is allowed. * Every PDF-consuming application has to adhere to this value! * * \returns true if you are allowed to modfiy this document * * \see PdfEncrypt to set own document permissions. */ virtual bool IsEditAllowed() const = 0; /** Checks if text and graphics extraction is allowed. * Every PDF-consuming application has to adhere to this value! * * \returns true if you are allowed to extract text and graphics from this document * * \see PdfEncrypt to set own document permissions. */ virtual bool IsCopyAllowed() const = 0; /** Checks if it is allowed to add or modify annotations or form fields. * Every PDF-consuming application has to adhere to this value! * * \returns true if you are allowed to add or modify annotations or form fields * * \see PdfEncrypt to set own document permissions. */ virtual bool IsEditNotesAllowed() const = 0; /** Checks if it is allowed to fill in existing form or signature fields. * Every PDF-consuming application has to adhere to this value! * * \returns true if you are allowed to fill in existing form or signature fields * * \see PdfEncrypt to set own document permissions. */ virtual bool IsFillAndSignAllowed() const = 0; /** Checks if it is allowed to extract text and graphics to support users with disabilities. * Every PDF-consuming application has to adhere to this value! * * \returns true if you are allowed to extract text and graphics to support users with disabilities * * \see PdfEncrypt to set own document permissions. */ virtual bool IsAccessibilityAllowed() const = 0; /** Checks if it is allowed to insert, create, rotate, or delete pages or add bookmarks. * Every PDF-consuming application has to adhere to this value! * * \returns true if you are allowed to insert, create, rotate, or delete pages or add bookmarks * * \see PdfEncrypt to set own document permissions. */ virtual bool IsDocAssemblyAllowed() const = 0; /** Checks if it is allowed to print a high quality version of this document * Every PDF-consuming application has to adhere to this value! * * \returns true if you are allowed to print a high quality version of this document * * \see PdfEncrypt to set own document permissions. */ virtual bool IsHighPrintAllowed() const = 0; // Peter Petrov 26 April 2008 /** Get access to the internal vector of objects * or root object. * * \returns the vector of objects */ inline PdfVecObjects* GetObjects(); // Peter Petrov 26 April 2008 /** Get access to the internal vector of objects * or root object. * * \returns the vector of objects */ inline const PdfVecObjects* GetObjects() const; /** * Set wrapper for the fontconfig library. * Useful to avoid initializing Fontconfig multiple times. * * This setter can be called until first use of Fontconfig * as the library is initialized at first use. */ inline void SetFontConfigWrapper(const PdfFontConfigWrapper & rFontConfig); protected: /** Construct a new (empty) PdfDocument * \param bEmpty if true NO default objects (such as catalog) are created. */ PdfDocument( bool bEmpty = false ); /** Set the info object containing meta information. * Deletes any old info object. * * @param pInfo the new info object (will be owned by PdfDocument) */ void SetInfo( PdfInfo* pInfo ); /** Get access to the internal Catalog dictionary * or root object. * * \returns PdfObject the documents catalog */ inline PdfObject* GetCatalog(); /** Get access to the internal Catalog dictionary * or root object. * * \returns PdfObject the documents catalog */ inline const PdfObject* GetCatalog() const; /** Set the catalog of this PdfDocument * deleting the old one. * * \param pObject the new catalog object * It will be owned by PdfDocument. */ inline void SetCatalog( PdfObject* pObject ); /** Get access to the internal trailer dictionary * or root object. * * \returns PdfObject the documents catalog */ inline PdfObject* GetTrailer(); /** Get access to the internal trailer dictionary * or root object. * * \returns PdfObject the documents catalog */ inline const PdfObject* GetTrailer() const; /** Set the trailer of this PdfDocument * deleting the old one. * * @param pObject the new trailer object * It will be owned by PdfDocument. */ void SetTrailer( PdfObject* pObject ); /** Get a dictionary from the catalog dictionary by its name. * \param pszName will be converted into a PdfName * \returns the dictionary if it was found or NULL */ PdfObject* GetNamedObjectFromCatalog( const char* pszName ) const; /** Internal method for initializing the pages tree for this document */ void InitPagesTree(); /** Recursively changes every PdfReference in the PdfObject and in any child * that is either an PdfArray or a direct object. * The reference is changed so that difference is added to the object number * of the reference. * \param pObject object to change * \param difference add this value to every reference that is encountered */ void FixObjectReferences( PdfObject* pObject, int difference ); /** Low-level APIs for setting a viewer preference. * \param whichPref the dictionary key to set * \param valueObj the object to be set */ void SetViewerPreference( const PdfName& whichPref, const PdfObject & valueObj ); /** Low-level APIs for setting a viewer preference. * Convenience overload. * \param whichPref the dictionary key to set * \param inValue the object to be set */ void SetViewerPreference( const PdfName& whichPref, bool inValue ); /** Clear all internal variables * and reset PdfDocument to an intial state. */ void Clear(); protected: PdfFontCache m_fontCache; PdfObject* m_pTrailer; PdfObject* m_pCatalog; PdfInfo* m_pInfo; PdfPagesTree* m_pPagesTree; PdfAcroForm* m_pAcroForms; private: // Prevent use of copy constructor and assignment operator. These methods // should never be referenced (given that code referencing them outside // PdfDocument won't compile), and calling them will result in a link error // as they're not defined. explicit PdfDocument(const PdfDocument&); PdfDocument& operator=(const PdfDocument&); PdfVecObjects m_vecObjects; PdfOutlines* m_pOutlines; PdfNamesTree* m_pNamesTree; }; // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfPagesTree* PdfDocument::GetPagesTree() const { return m_pPagesTree; } // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfObject* PdfDocument::GetCatalog() { return m_pCatalog; } // ----------------------------------------------------- // // ----------------------------------------------------- inline const PdfObject* PdfDocument::GetCatalog() const { return m_pCatalog; } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfDocument::SetCatalog( PdfObject* pObject ) { m_pCatalog = pObject; // m_pCatalog does not need to // be reowned as it should // alread by part of m_vecObjects } // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfObject* PdfDocument::GetTrailer() { return m_pTrailer; } // ----------------------------------------------------- // // ----------------------------------------------------- inline const PdfObject* PdfDocument::GetTrailer() const { return m_pTrailer; } // ----------------------------------------------------- // // ----------------------------------------------------- inline PdfVecObjects* PdfDocument::GetObjects() { return &m_vecObjects; } // ----------------------------------------------------- // // ----------------------------------------------------- inline const PdfVecObjects* PdfDocument::GetObjects() const { return &m_vecObjects; } // Peter Petrov 26 April 2008 // ----------------------------------------------------- // // ----------------------------------------------------- inline FT_Library PdfDocument::GetFontLibrary() const { return this->m_fontCache.GetFontLibrary(); } // ----------------------------------------------------- // // ----------------------------------------------------- inline void PdfDocument::SetFontConfigWrapper(const PdfFontConfigWrapper & rFontConfig) { m_fontCache.SetFontConfigWrapper(rFontConfig); } }; #endif // _PDF_DOCUMENT_H_ podofo-0.9.5/src/libpodofo.pc.in0000664000175000017500000000046712770003133016363 0ustar dominikdominikprefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} libdir=${exec_prefix}/@LIBDIRNAME@ includedir=${prefix}/include/podofo Name: @CMAKE_PROJECT_NAME@ Description: A C++ library to work with the PDF file format Version: @PODOFO_VERSION@ Libs: -L${libdir} -lpodofo-@PODOFO_VERSION_MAJOR@ Cflags: -I${includedir} podofo-0.9.5/tools/0000775000175000017500000000000013044451161014022 5ustar dominikdominikpodofo-0.9.5/tools/podofomerge/0000775000175000017500000000000013044451161016330 5ustar dominikdominikpodofo-0.9.5/tools/podofomerge/CMakeLists.txt0000664000175000017500000000043210517314571021074 0ustar dominikdominikADD_EXECUTABLE(podofomerge podofomerge.cpp) TARGET_LINK_LIBRARIES(podofomerge ${PODOFO_LIB}) SET_TARGET_PROPERTIES(podofomerge PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(podofomerge ${PODOFO_DEPEND_TARGET}) INSTALL(TARGETS podofomerge RUNTIME DESTINATION "bin") podofo-0.9.5/tools/podofomerge/podofomerge.cpp0000664000175000017500000000704311474750735021364 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2006 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include using namespace PoDoFo; #ifdef _HAVE_CONFIG #include #endif // _HAVE_CONFIG void print_help() { printf("Usage: podofomerge [inputfile1] [inputfile2] [outputfile]\n\n"); printf("\nPoDoFo Version: %s\n\n", PODOFO_VERSION_STRING); } void merge( const char* pszInput1, const char* pszInput2, const char* pszOutput ) { printf("Reading file: %s\n", pszInput1 ); PdfMemDocument input1( pszInput1 ); printf("Reading file: %s\n", pszInput2 ); PdfMemDocument input2( pszInput2 ); // #define TEST_ONLY_SOME_PAGES #ifdef TEST_ONLY_SOME_PAGES input1.InsertPages( input2, 1, 2 ); #else printf("Appending %i pages on a document with %i pages.\n", input2.GetPageCount(), input1.GetPageCount() ); input1.Append( input2 ); #endif // we are going to bookmark the insertions // using destinations - also adding each as a NamedDest /* PdfDestination p1Dest( input1.GetPage(0) ); input1.AddNamedDestination( p1Dest, std::string("Input1") ); PdfOutlines* bMarks = input1.GetOutlines(); PdfOutlineItem* bmRoot = bMarks->CreateRoot( "Merged Document" ); PdfOutlineItem* child1 = bmRoot->CreateChild( pszInput1, p1Dest ); PdfDestination p2Dest( input1.GetPage(pgCount) ); input1.AddNamedDestination( p2Dest, std::string("Input2") ); child1->CreateNext( pszInput2, p2Dest ); */ #ifdef TEST_FULL_SCREEN input1.SetUseFullScreen(); #else input1.SetPageMode( ePdfPageModeUseBookmarks ); input1.SetHideToolbar(); input1.SetPageLayout( ePdfPageLayoutTwoColumnLeft ); #endif printf("Writing file: %s\n", pszOutput ); input1.Write( pszOutput ); } int main( int argc, char* argv[] ) { char* pszInput1; char* pszInput2; char* pszOutput; if( argc != 4 ) { print_help(); exit( -1 ); } pszInput1 = argv[1]; pszInput2 = argv[2]; pszOutput = argv[3]; try { merge( pszInput1, pszInput2, pszOutput ); } catch( PdfError & e ) { fprintf( stderr, "Error %i occurred!\n", e.GetError() ); e.PrintErrorMsg(); return e.GetError(); } return 0; } podofo-0.9.5/tools/podofomerge/podofomerge.vcproj0000664000175000017500000000671710475170454022106 0ustar dominikdominik podofo-0.9.5/tools/podofogc/0000775000175000017500000000000013044451161015622 5ustar dominikdominikpodofo-0.9.5/tools/podofogc/CMakeLists.txt0000664000175000017500000000041111515123365020361 0ustar dominikdominikADD_EXECUTABLE(podofogc podofogc.cpp) TARGET_LINK_LIBRARIES(podofogc ${PODOFO_LIB}) SET_TARGET_PROPERTIES(podofogc PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(podofogc ${PODOFO_DEPEND_TARGET}) INSTALL(TARGETS podofogc RUNTIME DESTINATION "bin") podofo-0.9.5/tools/podofogc/podofogc.cpp0000664000175000017500000000674213013650710020134 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Ian Ashley * * Ian Ashley * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include using namespace std; using namespace PoDoFo; int main (int argc, char *argv[]) { PdfError::EnableLogging(true); PdfError::EnableDebug(true); PdfVecObjects objects; PdfParser parser( &objects ); objects.SetAutoDelete( true ); if( argc != 3 ) { cerr << "Usage: podofogc \n" << " Performs garbage collection on a PDF file.\n" << " All objects that are not reachable from within\n" << " the trailer are deleted.\n" << flush; return 0; } try { cerr << "Parsing " << argv[1] << " ... (this might take a while)" << flush; bool bIncorrectPw = false; std::string pw; do { try { if( !bIncorrectPw ) parser.ParseFile( argv[1], false ); else parser.SetPassword( pw ); bIncorrectPw = false; } catch( PdfError & e ) { if( e.GetError() == ePdfError_InvalidPassword ) { cout << endl << "Password :"; std::getline( cin, pw ); cout << endl; // try to continue with the new password bIncorrectPw = true; } else throw e; } } while( bIncorrectPw ); cerr << " done" << endl; cerr << "Writing..." << flush; PdfWriter writer( &parser ); writer.SetPdfVersion( parser.GetPdfVersion() ); if( parser.GetEncrypted() ) { writer.SetEncrypted( *(parser.GetEncrypt()) ); } writer.Write( argv[2] ); cerr << " done" << endl; } catch( PdfError & e ) { e.PrintErrorMsg(); return e.GetError(); } cerr << "Parsed and wrote successfully" << endl; return EXIT_SUCCESS; } podofo-0.9.5/tools/podofoencrypt/0000775000175000017500000000000013044451161016715 5ustar dominikdominikpodofo-0.9.5/tools/podofoencrypt/CMakeLists.txt0000664000175000017500000000044610657347120021467 0ustar dominikdominikADD_EXECUTABLE(podofoencrypt podofoencrypt.cpp) TARGET_LINK_LIBRARIES(podofoencrypt ${PODOFO_LIB}) SET_TARGET_PROPERTIES(podofoencrypt PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(podofoencrypt ${PODOFO_DEPEND_TARGET}) INSTALL(TARGETS podofoencrypt RUNTIME DESTINATION "bin") podofo-0.9.5/tools/podofoencrypt/podofoencrypt.cpp0000664000175000017500000002140312774756031022331 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include using namespace PoDoFo; #include #include #ifdef _HAVE_CONFIG #include #endif // _HAVE_CONFIG void encrypt( const char* pszInput, const char* pszOutput, const std::string & userPass, const std::string & ownerPass, const PdfEncrypt::EPdfEncryptAlgorithm eAlgorithm, const int nPermissions ) { PdfVecObjects objects; PdfParser parser( &objects ); objects.SetAutoDelete( true ); parser.ParseFile( pszInput ); PdfEncrypt::EPdfKeyLength eKeyLength; EPdfVersion eVersion; switch( eAlgorithm ) { #ifndef OPENSSL_NO_RC4 case PdfEncrypt::ePdfEncryptAlgorithm_RC4V1: eKeyLength = PdfEncrypt::ePdfKeyLength_40; eVersion = ePdfVersion_1_3; break; #endif // OPENSSL_NO_RC4 #ifdef PODOFO_HAVE_LIBIDN case PdfEncrypt::ePdfEncryptAlgorithm_AESV3:; eKeyLength = PdfEncrypt::ePdfKeyLength_256; eVersion = ePdfVersion_1_7; break; #endif // PODOFO_HAVE_LIBIDN #ifndef OPENSSL_NO_RC4 case PdfEncrypt::ePdfEncryptAlgorithm_RC4V2: #endif // OPENSSL_NO_RC4 case PdfEncrypt::ePdfEncryptAlgorithm_AESV2: default: eKeyLength = PdfEncrypt::ePdfKeyLength_128; eVersion = ePdfVersion_1_5; break; } PdfWriter writer( &parser ); PdfEncrypt *encrypt = PdfEncrypt::CreatePdfEncrypt( userPass, ownerPass, nPermissions, eAlgorithm, eKeyLength ); writer.SetPdfVersion( eVersion ); writer.SetEncrypted( *encrypt ); writer.Write( pszOutput ); delete encrypt; } void print_help() { printf("Usage: podofoencrypt [--rc4v1] [--rc4v2] [--aesv2] [--aesv3] [-u ]\n"); printf(" -o \n\n"); printf(" This tool encrypts an existing PDF file.\n\n"); printf(" --help Display this help text\n"); printf(" Algorithm:\n"); printf(" --rc4v1 Use rc4v1 encryption\n"); printf(" --rc4v2 Use rc4v2 encryption (Default value)\n"); printf(" --aesv2 Use aes-128 encryption\n"); printf(" --aesv3 Use aes-256 encryption\n"); printf(" Passwords:\n"); printf(" -u An optional userpassword\n"); printf(" -o The required owner password\n"); printf(" Permissions:\n"); printf(" --print Allow printing the document\n"); printf(" --edit Allow modifying the document besides annotations, form fields or chaning pages\n"); printf(" --copy Allow text and graphic extraction\n"); printf(" --editnotes Add or modify text annoations or form fields (if ePdfPermissions_Edit is set also allow to create interactive form fields including signature)\n"); printf(" --fillandsign Fill in existing form or signature fields\n"); printf(" --accessible Extract text and graphics to support user with disabillities\n"); printf(" --assemble Assemble the document: insert, create, rotate delete pages or add bookmarks\n"); printf(" --highprint Print a high resolution version of the document\n"); printf("\n\n"); } int main( int argc, char* argv[] ) { const char* pszInput = NULL; const char* pszOutput = NULL; PdfEncrypt::EPdfEncryptAlgorithm eAlgorithm = PdfEncrypt::ePdfEncryptAlgorithm_AESV2; int nPerm = 0; std::string userPass; std::string ownerPass; if( argc < 3 ) { print_help(); exit( -1 ); } // Parse the commandline options for( int i=1;i #include #include #include #include #include #include #include #include "DeleteOperation.h" #include "MoveOperation.h" using namespace PoDoFo; #ifdef _HAVE_CONFIG #include #endif // _HAVE_CONFIG class BadConversion : public std::runtime_error { public: BadConversion(const std::string& s) : std::runtime_error(s) { } }; void print_help() { printf("Usage: podofopages [inputfile] [outputfile]\n"); printf("Options:\n"); printf("\t--delete NUMBER\n"); printf("\tDeletes the page NUMBER (number is 0-based)\n"); printf("\tThe page will not really be deleted from the PDF.\n"); printf("\tIt is only removed from the so called pagestree and\n"); printf("\ttherefore invisible. The content of the page can still\n"); printf("\tbe retrieved from the document though.\n\n"); printf("\t--move FROM TO\n"); printf("\tMoves a page FROM TO in the document (FROM and TO are 0-based)\n\n"); printf("\nPoDoFo Version: %s\n\n", PODOFO_VERSION_STRING); } void work(const char* pszInput, const char* pszOutput, std::vector & rvecOperations) { std::cout << "Input file: " << pszInput << std::endl; std::cout << "Output file: " << pszOutput << std::endl; PdfMemDocument doc(pszInput); int total = rvecOperations.size(); int i = 1; std::vector::iterator it = rvecOperations.begin(); while( it != rvecOperations.end() ) { std::string msg = (*it)->ToString(); std::cout << "Operation " << i << " of " << total << ": " << msg; (*it)->Perform( doc ); ++it; ++i; } std::cout << "Operations done. Writing PDF to disk." << std::endl; doc.Write( pszOutput ); std::cout << "Done." << std::endl; } double convertToInt(const std::string& s) { std::istringstream i(s); int x; if (!(i >> x)) throw BadConversion("convertToInt(\"" + s + "\")"); return x; } int main( int argc, char* argv[] ) { char* pszInput = NULL; char* pszOutput = NULL; if( argc < 3 ) { print_help(); exit( -1 ); } // Fill operations vector std::vector vecOperations; for( int i=1; i < argc; i++ ) { std::string argument = argv[i]; if( argument == "--delete" || argument == "-delete" ) { int page = static_cast(convertToInt( std::string(argv[i+1]) )); vecOperations.push_back( new DeleteOperation( page ) ); ++i; } else if( argument == "--move" || argument == "-move" ) { int from = static_cast(convertToInt( std::string(argv[i+1]) )); int to = static_cast(convertToInt( std::string(argv[i+2]) )); vecOperations.push_back( new MoveOperation( from, to ) ); ++i; ++i; } else { if( pszInput == NULL ) { pszInput = argv[i]; } else if( pszOutput == NULL ) { pszOutput = argv[i]; } else { std::cerr << "Ignoring unknown argument: " << argument << std::endl; } } } if( !pszInput ) { std::cerr << "Please specify an input file." << std::endl; exit( -2 ); } if( !pszOutput ) { std::cerr << "Please specify an output file." << std::endl; exit( -3 ); } if( std::string(pszInput) == std::string(pszOutput) ) { std::cerr << "Input and outpuf file must point to different files." << std::endl; exit( -4 ); } try { work( pszInput, pszOutput, vecOperations ); } catch( PdfError & e ) { std::cerr << "Error: An error " << e.GetError() << " ocurred." << std::endl; e.PrintErrorMsg(); return e.GetError(); } catch( std::runtime_error & re ) { std::cerr << "Error: An error " << re.what() << " ocurred." << std::endl; return -1; } // Delete operations vectore std::vector::iterator it = vecOperations.begin(); while( it != vecOperations.end() ) { delete (*it); ++it; } return 0; } podofo-0.9.5/tools/podofopages/DeleteOperation.h0000664000175000017500000000353211201067720021564 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2009 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef __DELETE_OPERATION__H__ #define __DELETE_OPERATION__H__ #include "Operation.h" namespace PoDoFo { class PdfDocument; } class DeleteOperation : public Operation { public: DeleteOperation( int nPage ); virtual ~DeleteOperation() { } virtual void Perform( PoDoFo::PdfDocument & rDoc ); virtual std::string ToString() const; private: int m_nPage; }; #endif // __DELETE_OPERATION__H__ podofo-0.9.5/tools/podofopages/DeleteOperation.cpp0000664000175000017500000000351311201067720022116 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2009 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "DeleteOperation.h" #include DeleteOperation::DeleteOperation( int nPage ) : m_nPage( nPage ) { } void DeleteOperation::Perform( PoDoFo::PdfDocument & rDoc ) { rDoc.GetPagesTree()->DeletePage( m_nPage ); } std::string DeleteOperation::ToString() const { std::ostringstream oss; oss << "Deleting page: " << m_nPage << "." << std::endl; return oss.str(); } podofo-0.9.5/tools/podofopages/Operation.h0000664000175000017500000000350311201067720020437 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2009 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef __OPERATION__H__ #define __OPERATION__H__ #include namespace PoDoFo { class PdfDocument; } /** * Abstract base class for all operations * the podofopages can perform. * */ class Operation { public: virtual ~Operation() { } virtual void Perform( PoDoFo::PdfDocument & rDoc ) = 0; virtual std::string ToString() const = 0; }; #endif // __OPERATION__H__ podofo-0.9.5/tools/podofopages/MoveOperation.h0000664000175000017500000000355011201067720021270 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2009 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef __MOVE_OPERATION__H__ #define __MOVE_OPERATION__H__ #include "Operation.h" namespace PoDoFo { class PdfDocument; } class MoveOperation : public Operation { public: MoveOperation( int nFrom, int nTo ); virtual ~MoveOperation() { } virtual void Perform( PoDoFo::PdfDocument & rDoc ); virtual std::string ToString() const; private: int m_nFrom; int m_nTo; }; #endif // __MOVE_OPERATION__H__ podofo-0.9.5/tools/podofopages/MoveOperation.cpp0000664000175000017500000000425711201067720021630 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2009 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "MoveOperation.h" #include MoveOperation::MoveOperation( int nFrom, int nTo ) : m_nFrom( nFrom ), m_nTo( nTo ) { } void MoveOperation::Perform( PoDoFo::PdfDocument & rDoc ) { PoDoFo::PdfPagesTree* pTree = rDoc.GetPagesTree(); PoDoFo::PdfPage* pPage = pTree->GetPage( m_nFrom ); int from = m_nFrom; pTree->InsertPage( m_nTo, pPage ); if( m_nTo < from ) { // If we inserted the page before the old // position we have to increment the from position from++; } pTree->DeletePage( from ); } std::string MoveOperation::ToString() const { std::ostringstream oss; oss << "Moving page " << m_nFrom << " to " << m_nTo << "." << std::endl; return oss.str(); } podofo-0.9.5/tools/podofoimg2pdf/0000775000175000017500000000000013044451161016561 5ustar dominikdominikpodofo-0.9.5/tools/podofoimg2pdf/CMakeLists.txt0000664000175000017500000000047111331602263021321 0ustar dominikdominikADD_EXECUTABLE(podofoimg2pdf podofoimg2pdf.cpp ImageConverter.cpp) TARGET_LINK_LIBRARIES(podofoimg2pdf ${PODOFO_LIB}) SET_TARGET_PROPERTIES(podofoimg2pdf PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(podofoimg2pdf ${PODOFO_DEPEND_TARGET}) INSTALL(TARGETS podofoimg2pdf RUNTIME DESTINATION "bin") podofo-0.9.5/tools/podofoimg2pdf/ImageConverter.cpp0000664000175000017500000000565711331602263022212 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "ImageConverter.h" #include ImageConverter::ImageConverter() : m_bUseImageSize( false ) { } ImageConverter::~ImageConverter() { } void ImageConverter::Work() { PoDoFo::PdfMemDocument document; std::vector::const_iterator it = m_vecImages.begin(); PoDoFo::PdfRect size = PoDoFo::PdfPage::CreateStandardPageSize( PoDoFo::ePdfPageSize_A4, false ); PoDoFo::PdfPainter painter; double dScaleX = 1.0; double dScaleY = 1.0; double dScale = 1.0; while( it != m_vecImages.end() ) { PoDoFo::PdfPage* pPage; PoDoFo::PdfImage image( &document ); image.LoadFromFile( (*it).c_str() ); if( m_bUseImageSize ) { size = PoDoFo::PdfRect( 0.0, 0.0, image.GetWidth(), image.GetHeight() ); } pPage = document.CreatePage( size ); dScaleX = size.GetWidth() / image.GetWidth(); dScaleY = size.GetHeight() / image.GetHeight(); dScale = PoDoFo::PDF_MIN( dScaleX, dScaleY ); painter.SetPage( pPage ); if( dScale < 1.0 ) { painter.DrawImage( 0.0, 0.0, &image, dScale, dScale ); } else { // Center Image double dX = (size.GetWidth() - image.GetWidth())/2.0; double dY = (size.GetHeight() - image.GetHeight())/2.0; painter.DrawImage( dX, dY, &image ); } painter.FinishPage(); ++it; } document.Write( m_sOutputFilename.c_str() ); } podofo-0.9.5/tools/podofoimg2pdf/podofoimg2pdf.cpp0000664000175000017500000000633411373224054022034 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #ifdef _HAVE_CONFIG #include #endif // _HAVE_CONFIG #include "ImageConverter.h" #include void print_help() { printf("Usage: podofoimg2pdf [output.pdf] [-useimgsize] [image1 image2 image3 ...]\n\n"); printf("Options:\n"); printf(" -useimgsize Use the imagesize as page size, instead of A4\n"); printf("\nPoDoFo Version: %s\n\n", PODOFO_VERSION_STRING); printf("\n"); printf("This tool will combine any number of images into a single PDF.\n"); printf("This is useful to create a document from scanned images.\n"); printf("Large pages will be scaled to fit the page and imags smaller\n"); printf("than the defined page size, will be centered.\n"); printf("\n"); printf("Supported image formats:\n"); const char** ppszFormats = PoDoFo::PdfImage::GetSupportedFormats(); while( *ppszFormats ) { printf("\t%s\n", *ppszFormats ); ++ppszFormats; } printf("\n"); } int main( int argc, char* argv[] ) { char* pszOutput; if( argc < 3 ) { print_help(); exit( -1 ); } pszOutput = argv[1]; printf("Output filename: %s\n", pszOutput); ImageConverter converter; converter.SetOutputFilename( pszOutput ); for( int i=2;i #include class ImageConverter { public: ImageConverter(); ~ImageConverter(); inline void SetOutputFilename( const char* pszFilename ) { m_sOutputFilename = pszFilename; } inline void AddImage( const char* pszImage ) { m_vecImages.push_back( std::string(pszImage) ); } inline void SetUseImageSize( bool bImageSize ) { m_bUseImageSize = bImageSize; } void Work(); private: std::vector m_vecImages; std::string m_sOutputFilename; bool m_bUseImageSize; }; podofo-0.9.5/tools/podofocountpages/0000775000175000017500000000000013044451161017401 5ustar dominikdominikpodofo-0.9.5/tools/podofocountpages/CMakeLists.txt0000664000175000017500000000046311217372575022157 0ustar dominikdominikADD_EXECUTABLE(podofocountpages countpages.cpp) TARGET_LINK_LIBRARIES(podofocountpages ${PODOFO_LIB}) SET_TARGET_PROPERTIES(podofocountpages PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(podofocountpages ${PODOFO_DEPEND_TARGET}) INSTALL(TARGETS podofocountpages RUNTIME DESTINATION "bin") podofo-0.9.5/tools/podofocountpages/countpages.cpp0000664000175000017500000000642111306221052022251 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2009 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include using namespace PoDoFo; #ifdef _HAVE_CONFIG #include #endif // _HAVE_CONFIG void print_help() { printf("Usage: podofocountpages [-s] [-t] file1.pdf ... \n\n"); printf(" This tool counts the pages in a PDF file.\n"); printf(" -s will enable the short format, which ommites\n"); printf(" printing of the filename in the output.\n"); printf(" -t print the total sum of all pages.\n"); printf("\nPoDoFo Version: %s\n\n", PODOFO_VERSION_STRING); } int count_pages( const char* pszFilename, const bool & bShortFormat ) { PdfMemDocument document; document.Load( pszFilename ); int nPages = document.GetPageCount(); if( bShortFormat ) printf("%i\n", nPages ); else printf("%s:\t%i\n", pszFilename, nPages ); return nPages; } int main( int argc, char* argv[] ) { PdfError::EnableDebug( false ); if( argc <= 1 ) { print_help(); exit( -1 ); } try { bool bTotal = false; bool bShortFormat = false; int sum = 0; for(int i=1;i podofo-0.9.5/tools/podofotxt2pdf/CMakeLists.txt0000664000175000017500000000044610517314571021375 0ustar dominikdominikADD_EXECUTABLE(podofotxt2pdf podofotxt2pdf.cpp) TARGET_LINK_LIBRARIES(podofotxt2pdf ${PODOFO_LIB}) SET_TARGET_PROPERTIES(podofotxt2pdf PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(podofotxt2pdf ${PODOFO_DEPEND_TARGET}) INSTALL(TARGETS podofotxt2pdf RUNTIME DESTINATION "bin") podofo-0.9.5/tools/podofotxt2pdf/podofotxt2pdf.cpp0000664000175000017500000001450113013650710022130 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include using namespace PoDoFo; #ifdef _HAVE_CONFIG #include #endif // _HAVE_CONFIG #define BORDER_TOP 10000 * CONVERSION_CONSTANT #define BORDER_LEFT 10000 * CONVERSION_CONSTANT #define FONT_SIZE 12.0 #define DEFAULT_FONT "Arial" void print_help() { printf("Usage: podofotxt2pdf [inputfile] [outputfile]\n\n"); printf("Optional parameters:\n"); printf("\t-fontname [name]\t Use the font [name]\n"); printf("\t-utf8\t that specifies that the input text\n"); printf("\t\tis UTF8 encoded instead of Windows ANSI encoding.\n"); printf("\nPoDoFo Version: %s\n\n", PODOFO_VERSION_STRING); } void draw( char* pszBuffer, PdfDocument* pDocument, bool bUtf8, const char* pszFontName ) { PdfPage* pPage; PdfPainter painter; PdfFont* pFont; PdfRect size; const PdfEncoding* pEncoding; double dX = BORDER_LEFT; double dY = BORDER_TOP; char* pszStart = pszBuffer; if( bUtf8 ) { pEncoding = new PdfIdentityEncoding(); } else { pEncoding = PdfEncodingFactory::GlobalWinAnsiEncodingInstance(); } size = PdfPage::CreateStandardPageSize( ePdfPageSize_A4 ); pFont = pDocument->CreateFont( pszFontName, false, pEncoding ); pPage = pDocument->CreatePage( size ); dY = size.GetHeight() - dY; if( !pFont ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } pFont->SetFontSize( FONT_SIZE ); painter.SetPage( pPage ); painter.SetFont( pFont ); while( *pszBuffer ) { if( *pszBuffer == '\n' ) { if( bUtf8 ) { painter.DrawText( dX, dY, PdfString( reinterpret_cast(pszStart), pszBuffer-pszStart ) ); } else { painter.DrawText( dX, dY, pszStart, pszBuffer-pszStart ); } pszStart = (++pszBuffer); dY -= pFont->GetFontMetrics()->GetLineSpacing(); if( dY < BORDER_TOP ) { pPage = pDocument->CreatePage( size ); painter.SetPage( pPage ); dY = size.GetHeight() - dY; } } else ++pszBuffer; } painter.FinishPage(); } void init( const char* pszInput, const char* pszOutput, bool bUtf8, const char* pszFontName ) { FILE* hFile; PdfStreamedDocument doc( pszOutput ); char* pszBuf; long lSize; hFile = fopen( pszInput, "rb" ); // read it as binary if we are going to compare sizes! if( !hFile ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } if( fseek( hFile, 0x00, SEEK_END ) == -1 ) { fclose( hFile ); PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to seek to the end of the file" ); } lSize = ftell( hFile ); if( lSize == -1 ) { fclose( hFile ); PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to read size of the file" ); } pszBuf = static_cast(malloc( sizeof( char ) * (lSize+1) )); fseek( hFile, 0x00, SEEK_SET ); if( !pszBuf ) { fclose( hFile ); PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } // read the whole file into memory at once. // this not very efficient, but as this is // a library demonstration I do not care. // If anyone wants to improve this: Go for it! if( static_cast( fread( pszBuf, sizeof(char), lSize, hFile ) ) != lSize ) { free( pszBuf ); fclose( hFile ); PODOFO_RAISE_ERROR( ePdfError_UnexpectedEOF ); } fclose( hFile ); pszBuf[lSize] = '\0'; draw( pszBuf, &doc, bUtf8, pszFontName ); doc.GetInfo()->SetCreator( PdfString("podofotxt2pdf") ); doc.GetInfo()->SetTitle( PdfString("Converted to PDF from a text file") ); doc.Close(); free( pszBuf ); } int main( int argc, char* argv[] ) { const char* pszInput = NULL; const char* pszOutput = NULL; const char* pszFontName = DEFAULT_FONT; bool bUtf8 = false; if( argc < 3 ) { print_help(); exit( -1 ); } for(int i=1;i, (C) 2008 // // Copyright: See COPYING file that comes with this distribution // // #include "impositionplan.h" #include #include #include #include #include #include #include using std::ostringstream; using std::map; using std::vector; using std::string; using std::ifstream; using std::istream; using std::ostream; using std::endl; using std::runtime_error; #ifdef _WIN32 #ifdef max #undef max #endif // max #ifdef min #undef min #endif // min #endif // _WIN32 #include //XXX namespace PoDoFo { namespace Impose { PageRecord::PageRecord ( int s,int d,double r, double tx, double ty, int du ) : sourcePage ( s ), destPage ( d ), rotate ( r ), transX ( tx ), transY ( ty ), duplicateOf( du ) { }; PageRecord::PageRecord ( ) : sourcePage ( 0 ), destPage ( 0 ), rotate ( 0 ), transX ( 0 ), transY ( 0 ), duplicateOf( 0 ) {}; void PageRecord::load ( const std::string& buffer, const std::map& vars ) { int blen ( buffer.length() ); std::vector tokens; std::string ts; for ( int i ( 0 ); i < blen; ++i ) { char ci ( buffer.at ( i ) ); if ( ci == ' ' ) continue; else if ( ci == ';' ) { tokens.push_back ( ts ); ts.clear(); continue; } ts += ci; } if ( tokens.size() != 5 ) { sourcePage = destPage = 0; // will return false for isValid() std::cerr<<"INVALID_RECORD("<< tokens.size() <<") "<(calc ( tokens.at ( 0 ) , vars)); destPage = static_cast(calc ( tokens.at ( 1 ) , vars)); if ( ( sourcePage < 1 ) || ( destPage < 1 ) ) { sourcePage = destPage = 0; } rotate = calc ( tokens.at ( 2 ) , vars); transX = calc ( tokens.at ( 3 ) , vars); transY = calc ( tokens.at ( 4 ) , vars); std::cerr<<" "<& vars) { // std::cerr<< s; std::vector tokens; int tlen ( s.length() ); std::string ts; for ( int i ( 0 ); i < tlen; ++i ) { char ci ( s.at ( i ) ); // if ( ci == 0x20 || ci == 0x9 )// skip spaces and horizontal tabs // continue; if ( ( ci == '+' ) || ( ci == '-' ) || ( ci == '*' ) || ( ci == '/' ) || ( ci == '%' ) || ( ci == '|' ) || ( ci == '"' ) || ( ci == '(' ) || ( ci == ')' ) ) { // commit current string if ( ts.length() > 0 ) { std::map::const_iterator vit = vars.find ( ts ); if ( vit != vars.end() ) { // std::cerr<<"A Found "<second <second, vars ) ) ); } else { // std::cerr<<"A Not Found "< 32 ) { ts += ci; } // else // std::cerr<<"Wrong char : "<< ci < 0 ) { std::map::const_iterator vit2 = vars.find ( ts ); if ( vit2 != vars.end() ) { // std::cerr<second , vars) ) ); } else { // if((ts.length() > 0) && (ts[0] == '$')) // { // std::cerr<::iterator i(PoDoFoImpose::vars.begin());i != PoDoFoImpose::vars.end(); ++i) // { // // std::cerr<<"VA \""<< i->first << "\" => " <<(i->first == ts ? "True" : "False") <first.length(); ++c) // { // std::cerr<< i->first[c]<<"/"; // } // std::cerr< values; std::vector ops; ops.push_back ( "+" ); for ( unsigned int vi = 0; vi < t.size(); ++vi ) { if ( t.at ( vi ) == "(" ) { std::vector tokens; int cdeep ( 0 ); // std::cerr<<"("; for ( ++vi ; vi < t.size(); ++vi ) { // std::cerr<> \""< ( ret ) % static_cast ( values.at ( vi ) ); } else if ( ops.at ( vi ) == "|" ) // Stands for max(a,b), easier than true condition, allow to filter division by 0 ret = std::max ( ret , values.at ( vi ) ); else if ( ops.at ( vi ) == "\"" ) // Stands for min(a,b) ret = std::min ( ret , values.at ( vi ) ); // std::cerr< "<, (C) 2008 // // Copyright: See COPYING file that comes with this distribution // // #include "planreader_legacy.h" #ifdef PODOFO_HAVE_LUA #include "planreader_lua.h" #endif // PODOFO_HAVE_LUA #include #include #include #include #include #include using std::ostringstream; using std::map; using std::vector; using std::string; using std::ifstream; using std::istream; using std::ostream; using std::endl; using std::runtime_error; #include //XXX#define MAX_SOURCE_PAGES 5000 #define MAX_RECORD_SIZE 2048 int PlanReader_Legacy::sortLoop(std::vector& memfile, int numline) { // std::cerr<<"===================================== "<::iterator dit(localvars.begin());dit!=localvars.end();++dit) // { // std::cerr<<"R "<first<<" = "<second< storedvars = I->vars; int startAt(numline); std::string buffer( memfile.at(numline) ); int blen = buffer.length(); std::string iterN; int a(1); char ca(0); for(;a increments; std::string tvar; std::string tinc; ++a; bool varside(true); for(;avars.find(tvar) != I->vars.end()) { // std::cerr<< "I " << tvar <<" = "<< tinc <( tvar, std::atof(tinc.c_str()))); } tvar.clear(); tinc.clear(); if(ca == ';') varside = true; else break; } else if(ca == '+') { varside = false; continue; } else { if(varside) tvar += ca; else tinc += ca; } } int endOfloopBlock(numline + 1); int openLoop(0); for(unsigned int bolb2 = (numline + 1); bolb2 < memfile.size();++bolb2) { // std::cerr<<"| "<< memfile.at ( bolb2 ) <<" |"<') { if(openLoop == 0) break; else --openLoop; } else endOfloopBlock = bolb2 + 1; } int maxIter(PoDoFo::Impose::PageRecord::calc(iterN, I->vars)); for(int iter(0); iter < maxIter ; ++iter ) { if(iter != 0) { // we set the vars std::map::iterator vit; for(vit = increments.begin(); vit != increments.end() ; ++vit) { I->vars[vit->first] = PoDoFo::Impose::Util::dToStr( std::atof(I->vars[vit->first].c_str()) + vit->second ); } } for(int subi(numline + 1);subi < endOfloopBlock ; ++subi) { // std::cerr<< subi <<"/"<< endOfloopBlock <<" - "<vars ) ; if(!p.isValid() || p.sourcePage > I->sourceVars.PageCount) { // std::cerr<< "Error p("<<(p.isValid()?"valid":"invalid")<<") "<< p.sourcePage <sourcePage == p.sourcePage) // { // isDup = true; // break; // } // } // if ( isDup ) // { // p.duplicateOf = p.sourcePage; // } I->push_back ( p ); } } } // numline = endOfloopBlock; // std::cerr<<"EOL"<vars = storedvars; // std::cerr<<"------------------------------------- "< memfile; do { in.getline ( cbuffer, MAX_RECORD_SIZE ); blen = in.gcount() ; std::string buffer ( cbuffer, blen ); #ifdef PODOFO_HAVE_LUA // This was "supposed" to be a legacy file, but if it starts // with two dashes, it must be a lua file, so process it accordingly: if (buffer.substr(0,2) == "--") { in.close(); PlanReader_Lua(plan, Imp); return; } #endif // PODOFO_HAVE_LUA if ( blen < 2 ) // Nothing continue; PoDoFo::Impose::Util::trimmed_str(buffer); if(buffer.length() < 2) continue; else if ( buffer.at ( 0 ) == '#' ) // Comment continue; else { memfile.push_back(buffer); // std::cerr<vars[std::string("$PagesCount")] = PoDoFo::Impose::Util::iToStr( I->sourceVars.PageCount ); I->vars[std::string("$SourceWidth")] = PoDoFo::Impose::Util::dToStr( I->sourceVars.PageWidth ); I->vars[std::string("$SourceHeight")] = PoDoFo::Impose::Util::dToStr( I->sourceVars.PageHeight ); /// END OF PROVIDED for( unsigned int numline = 0; numline < memfile.size() ; ++numline) { std::string buffer( memfile.at(numline) ); if ( buffer.at ( 0 ) == '$' ) // Variable { int sepPos ( buffer.find_first_of ( '=' ) ); std::string key(buffer.substr ( 0,sepPos )); std::string value(buffer.substr ( sepPos + 1 )); { I->vars[key] = value; } } else if( buffer.at ( 0 ) == '<' ) // Loop - experimental { numline += sortLoop( memfile , numline ); } else // Record? We hope! { PoDoFo::Impose::PageRecord p; p.load ( buffer, I->vars ) ; if(!p.isValid() || p.sourcePage > I->sourceVars.PageCount) continue; // maxPageDest = std::max ( maxPageDest, p.destPage ); // if ( pagesIndex.find ( p.sourcePage ) != pagesIndex.end() ) // { // p.duplicateOf = p.sourcePage; // } I->push_back ( p ); } } /// REQUIRED if ( I->vars.find("$PageWidth") == I->vars.end() ) throw runtime_error ( "$PageWidth not set" ); if (I->vars.find("$PageHeight") == I->vars.end() ) throw runtime_error ( "$PageHeight not set" ); I->setDestWidth( PoDoFo::Impose::PageRecord::calc( I->vars["$PageWidth"] , I->vars) ); I->setDestHeight( PoDoFo::Impose::PageRecord::calc( I->vars["$PageHeight"] , I->vars)); /// END OF REQUIRED /// SUPPORTED if ( I->vars.find("$ScaleFactor") != I->vars.end() ) I->setScale( PoDoFo::Impose::PageRecord::calc( I->vars["$ScaleFactor"] , I->vars)); /// END OF SUPPORTED } podofo-0.9.5/tools/podofoimpose/CMakeLists.txt0000664000175000017500000000110411075542173021267 0ustar dominikdominik# PoDoFoImpose SET(impose_srcs podofoimpose.cpp pdftranslator.cpp impositionplan.cpp planreader_legacy.cpp ) SET(impose_extra_libs) IF(LUA_FOUND) SET(impose_extra_libs ${LUA_LIBRARIES}) SET(impose_srcs ${impose_srcs} planreader_lua.cpp) ENDIF(LUA_FOUND) ADD_EXECUTABLE(podofoimpose ${impose_srcs} ) TARGET_LINK_LIBRARIES(podofoimpose ${PODOFO_LIB} ${impose_extra_libs} ) SET_TARGET_PROPERTIES(podofoimpose PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(podofoimpose ${PODOFO_DEPEND_TARGET}) INSTALL(TARGETS podofoimpose RUNTIME DESTINATION "bin") podofo-0.9.5/tools/podofoimpose/plans/0000775000175000017500000000000013044451161017642 5ustar dominikdominikpodofo-0.9.5/tools/podofoimpose/plans/lua/0000775000175000017500000000000013044451161020423 5ustar dominikdominikpodofo-0.9.5/tools/podofoimpose/plans/lua/In4.plan0000664000175000017500000000132611133352773021741 0ustar dominikdominik-- In4 - imposé sur un A4 présentement PageWidth = 595.27559 PageHeight = 841.88976 sw = SourceWidth sh = SourceHeight xoffset = (PageWidth - (2*sw)) / 2; yoffset = (PageHeight - (2*sh)) / 2; print("xo",xoffset ); print("yo",yoffset ); -- sw = sw + xoffset; -- sh = sh + yoffset; i = 0 while i < PageCount do F = i/8 PushRecord(i+ 8,F+ 1, 0, 0, yoffset ) PushRecord(i+ 1,F+ 1, 0, sw, yoffset ) PushRecord(i+ 4,F+ 1, 180, 2*sw, 2*(sh+yoffset) ) PushRecord(i+ 5,F+ 1, 180, sw, 2*(sh+yoffset) ) PushRecord( i+ 2, F+ 2, 0, 0, yoffset ) PushRecord( i+ 7, F+ 2, 0, sw, yoffset ) PushRecord( i+ 6, F+ 2, 180, 2*sw, 2*(sh+yoffset) ) PushRecord( i+ 3, F+ 2, 180, sw, 2*(sh+yoffset) ) i = i + 8 end podofo-0.9.5/tools/podofoimpose/plans/lua/Booklet-A4-duplex.plan0000664000175000017500000001454411577110115024447 0ustar dominikdominik---lua ---imposition plan : Generic Booklet -- A4 paper -- 210 x 297 --- ---It is said generic as it will try to determine ---automatically how to fit the booklet onto A4 ---paper sheets, scaling pages if necessary. ---it is well suited for office documents for ---which you do not care too much about resulting ---imposition artefacts since it manages to save ---paper! --- -- print("Booklet") -- We output a booklet on A4 paper -- 210 x 297 -- Interface notes ..... ---- Evidently PageCount, SourceWidth, and SourceHeight are ---- passed to us from the C++ program when we are called. ---- Evidently we are required to provide values for ---- PageWidth, PageHeight, and Scale ... which are used by ---- the C++ program after we return. Scale defaults to 1. ---- ---- Note that these Page-related names are unfortunate, ---- because they do *not* correspond to the pages as defined ---- by the source, or to the pages in the final booklet. ---- Really PageHeight should be called SheetHeight and ---- PageWidth should be called SheetWidth or something ---- like that. ---- ---- Note that we calculate our offsets and margins in ----_real_ units, not scaled units. That is significant ---- PushRecord will scale its arguments, so we will need -----to descale the offsets in the call to PushRecord. -- Useful units, measured in local units (i.e. postscript points): inch = 72 mm = inch / 25.4 PageWidth = 210*mm PageHeight = 297*mm -- Turn on TopMode if you want to print the top side of each sheet -- Turn on BottomMode if you want to print the bottm side of each sheet -- Turn on TopMode and BottomMode if you want both, as for a duplex printer TopMode = 1 BottomMode = 1 -- Turn on BoStack if your non-duplex printer has the property -- that the first thing printed winds up at the bottom of the -- stack, face up. BoStack = 0 print("PageCount",PageCount) -- Note that we need to distinguish ---- the hw margins need to keep the printer happy ---- the /added/ margins we need to apply here. -- Worst case is when the source -- material bleeds right to the edge of its bounding box. -- Conversely, if the source material has a lot of margin -- already built into it, we may not need any /extra/ margin -- at all, and we could set UsableHeight = PageHeight here. -- Similarly if Ydelta/2 is larger than the hwBottomMargin -- we shouldn't need to add any /add/ margin. hwTopMargin = 0.1*inch hwBottomMargin = 0.5*inch hwLeftMargin = 0.1*inch hwRightMargin = 0.1*inch srcMargin = 0 addTopMargin = math.max(0, hwTopMargin - srcMargin) addBottomMargin = math.max(0, hwBottomMargin - srcMargin) addLeftMargin = math.max(0, hwLeftMargin - srcMargin) addRightMargin = math.max(0, hwRightMargin - srcMargin) -- When calculating wiggle room, assume paper will be used -- symmetrically. This is a nontrivial assumption, since -- e.g. we could use a paper cutter to chop off one edge -- and not the other ... but that would be beyond the -- scope of this analysis. Symmetry means that if we -- apply a margin to the recto page, we must apply the -- same margin to the verso page, even if the hardware -- would not require it. Hence the factors of 2 here: UsableHeight = PageHeight - 2*addTopMargin - 2*addBottomMargin UsableWidth = PageWidth - 2*addLeftMargin - 2*addRightMargin if(SourceWidth <= SourceHeight) then Scale = math.min(UsableHeight / (2*SourceWidth), UsableWidth / SourceHeight) rot = 90 Ywiggle = 0.5 * math.max(0, UsableHeight - 2*SourceWidth*Scale) Xwiggle = math.max(0, UsableWidth - SourceHeight*Scale) fudge = addTopMargin + 2*(addBottomMargin + Ywiggle) -- Apply a factor of /2 to Xwiggle here, -- because we want centering -- (not flush to right of sheet, i.e. bottom of page): -- Do not apply corresponding factor to Ywiggle, because -- we do want flush to top of sheet, i.e. right of page: xof = addLeftMargin + SourceHeight*Scale + Xwiggle/2 yofRtop = SourceWidth*Scale + fudge yofRbot = SourceWidth*Scale + fudge yofVtop = addBottomMargin + Ywiggle yofVbot = addBottomMargin + Ywiggle else Scale = math.min(UsableHeight / (2*SourceHeight), UsableWidth / SourceWidth) rot = 0 Ywiggle = 0.5 * math.max(0, UsableHeight - 2*SourceHeight*Scale) Xwiggle = math.max(0, UsableWidth - SourceWidth*Scale) fudge = addTopMargin + 2*(addBottomMargin + Ywiggle) xof = addLeftMargin + Xwiggle/2 yofRtop = SourceHeight*Scale + fudge yofRbot = SourceHeight*Scale + fudge yofVtop = addBottomMargin + Ywiggle yofVbot = addBottomMargin + Ywiggle end do rest = PageCount % 4 totp = PageCount if rest ~= 0 then totp = totp + ( 4 - rest) end -- "inc" counts input pages skipped as well as pages actually used: inc = 0 -- "outc" counts output pages: outc = 0; count = 0 imax = totp/4 middle = totp/2 while count < imax do -- We assume that podofoimpose will discard invalid records -- such as those with source page greater than PageCount -- print(totp, inc, outc, rot, xof, yofRtop, yofVtop, yofRbot, yofVbot) -- Top of sheet: (8 1) ... (6 3) if TopMode ~= 0 then -- We did all the interesting calculations in real units (above). -- We convert to nasty descaled units at the last moment: PushRecord(totp - inc, outc + 1, rot, xof/Scale, yofVtop/Scale) PushRecord(inc + 1, outc + 1, rot, xof/Scale, yofRtop/Scale) outc = outc + 1 end -- Bottom of sheet: if BottomMode ~= 0 then if BoStack ~= 0 then -- Reversed bottom: (4 5) ... (2 7) PushRecord(middle - inc, outc + 1, rot, xof/Scale, yofVbot/Scale) PushRecord(middle + 1 + inc, outc + 1, rot, xof/Scale, yofRbot/Scale) else -- Normal bottom: (2 7) ... (4 5) PushRecord(inc + 2, outc + 1, rot, xof/Scale, yofVbot/Scale) PushRecord(totp-(inc + 1), outc + 1, rot, xof/Scale, yofRbot/Scale) end outc = outc + 1 end count = count + 1 inc = inc + 2 end end podofo-0.9.5/tools/podofoimpose/plans/lua/Booklet-USletter-bottom.plan0000664000175000017500000001457211577110115025756 0ustar dominikdominik---lua ---imposition plan : Generic Booklet -- US letter paper -- 8.5 x 11 --- ---It is said generic as it will try to determine ---automatically how to fit the booklet onto US letter ---paper sheets, scaling pages if necessary. ---it is well suited for office documents for ---which you do not care too much about resulting ---imposition artefacts since it manages to save ---paper! --- -- print("Booklet") -- We output a booklet on US letter paper -- 8.5 x 11 -- Interface notes ..... ---- Evidently PageCount, SourceWidth, and SourceHeight are ---- passed to us from the C++ program when we are called. ---- Evidently we are required to provide values for ---- PageWidth, PageHeight, and Scale ... which are used by ---- the C++ program after we return. Scale defaults to 1. ---- ---- Note that these Page-related names are unfortunate, ---- because they do *not* correspond to the pages as defined ---- by the source, or to the pages in the final booklet. ---- Really PageHeight should be called SheetHeight and ---- PageWidth should be called SheetWidth or something ---- like that. ---- ---- Note that we calculate our offsets and margins in ----_real_ units, not scaled units. That is significant ---- PushRecord will scale its arguments, so we will need -----to descale the offsets in the call to PushRecord. -- Useful units, measured in local units (i.e. postscript points): inch = 72 mm = inch / 25.4 PageWidth = 8.5*inch PageHeight = 11*inch -- Turn on TopMode if you want to print the top side of each sheet -- Turn on BottomMode if you want to print the bottm side of each sheet -- Turn on TopMode and BottomMode if you want both, as for a duplex printer TopMode = 1 BottomMode = 1 -- Turn on BoStack if your non-duplex printer has the property -- that the first thing printed winds up at the bottom of the -- stack, face up. BoStack = 1 print("PageCount",PageCount) -- Note that we need to distinguish ---- the hw margins need to keep the printer happy ---- the /added/ margins we need to apply here. -- Worst case is when the source -- material bleeds right to the edge of its bounding box. -- Conversely, if the source material has a lot of margin -- already built into it, we may not need any /extra/ margin -- at all, and we could set UsableHeight = PageHeight here. -- Similarly if Ydelta/2 is larger than the hwBottomMargin -- we shouldn't need to add any /add/ margin. hwTopMargin = 0.1*inch hwBottomMargin = 0.5*inch hwLeftMargin = 0.1*inch hwRightMargin = 0.1*inch srcMargin = 0 addTopMargin = math.max(0, hwTopMargin - srcMargin) addBottomMargin = math.max(0, hwBottomMargin - srcMargin) addLeftMargin = math.max(0, hwLeftMargin - srcMargin) addRightMargin = math.max(0, hwRightMargin - srcMargin) -- When calculating wiggle room, assume paper will be used -- symmetrically. This is a nontrivial assumption, since -- e.g. we could use a paper cutter to chop off one edge -- and not the other ... but that would be beyond the -- scope of this analysis. Symmetry means that if we -- apply a margin to the recto page, we must apply the -- same margin to the verso page, even if the hardware -- would not require it. Hence the factors of 2 here: UsableHeight = PageHeight - 2*addTopMargin - 2*addBottomMargin UsableWidth = PageWidth - 2*addLeftMargin - 2*addRightMargin if(SourceWidth <= SourceHeight) then Scale = math.min(UsableHeight / (2*SourceWidth), UsableWidth / SourceHeight) rot = 90 Ywiggle = 0.5 * math.max(0, UsableHeight - 2*SourceWidth*Scale) Xwiggle = math.max(0, UsableWidth - SourceHeight*Scale) fudge = addTopMargin + 2*(addBottomMargin + Ywiggle) -- Apply a factor of /2 to Xwiggle here, -- because we want centering -- (not flush to right of sheet, i.e. bottom of page): -- Do not apply corresponding factor to Ywiggle, because -- we do want flush to top of sheet, i.e. right of page: xof = addLeftMargin + SourceHeight*Scale + Xwiggle/2 yofRtop = SourceWidth*Scale + fudge yofRbot = SourceWidth*Scale + fudge yofVtop = addBottomMargin + Ywiggle yofVbot = addBottomMargin + Ywiggle else Scale = math.min(UsableHeight / (2*SourceHeight), UsableWidth / SourceWidth) rot = 0 Ywiggle = 0.5 * math.max(0, UsableHeight - 2*SourceHeight*Scale) Xwiggle = math.max(0, UsableWidth - SourceWidth*Scale) fudge = addTopMargin + 2*(addBottomMargin + Ywiggle) xof = addLeftMargin + Xwiggle/2 yofRtop = SourceHeight*Scale + fudge yofRbot = SourceHeight*Scale + fudge yofVtop = addBottomMargin + Ywiggle yofVbot = addBottomMargin + Ywiggle end do rest = PageCount % 4 totp = PageCount if rest ~= 0 then totp = totp + ( 4 - rest) end -- "inc" counts input pages skipped as well as pages actually used: inc = 0 -- "outc" counts output pages: outc = 0; count = 0 imax = totp/4 middle = totp/2 while count < imax do -- We assume that podofoimpose will discard invalid records -- such as those with source page greater than PageCount -- print(totp, inc, outc, rot, xof, yofRtop, yofVtop, yofRbot, yofVbot) -- Top of sheet: (8 1) ... (6 3) if TopMode ~= 0 then -- We did all the interesting calculations in real units (above). -- We convert to nasty descaled units at the last moment: PushRecord(totp - inc, outc + 1, rot, xof/Scale, yofVtop/Scale) PushRecord(inc + 1, outc + 1, rot, xof/Scale, yofRtop/Scale) outc = outc + 1 end -- Bottom of sheet: if BottomMode ~= 0 then if BoStack ~= 0 then -- Reversed bottom: (4 5) ... (2 7) PushRecord(middle - inc, outc + 1, rot, xof/Scale, yofVbot/Scale) PushRecord(middle + 1 + inc, outc + 1, rot, xof/Scale, yofRbot/Scale) else -- Normal bottom: (2 7) ... (4 5) PushRecord(inc + 2, outc + 1, rot, xof/Scale, yofVbot/Scale) PushRecord(totp-(inc + 1), outc + 1, rot, xof/Scale, yofRbot/Scale) end outc = outc + 1 end count = count + 1 inc = inc + 2 end end podofo-0.9.5/tools/podofoimpose/plans/lua/Booklet-USlegal-duplex.plan0000664000175000017500000001456711577110115025544 0ustar dominikdominik---lua ---imposition plan : Generic Booklet -- US legal paper -- 8.5 x 14 --- ---It is said generic as it will try to determine ---automatically how to fit the booklet onto US legal ---paper sheets, scaling pages if necessary. ---it is well suited for office documents for ---which you do not care too much about resulting ---imposition artefacts since it manages to save ---paper! --- -- print("Booklet") -- We output a booklet on US legal paper -- 8.5 x 14 -- Interface notes ..... ---- Evidently PageCount, SourceWidth, and SourceHeight are ---- passed to us from the C++ program when we are called. ---- Evidently we are required to provide values for ---- PageWidth, PageHeight, and Scale ... which are used by ---- the C++ program after we return. Scale defaults to 1. ---- ---- Note that these Page-related names are unfortunate, ---- because they do *not* correspond to the pages as defined ---- by the source, or to the pages in the final booklet. ---- Really PageHeight should be called SheetHeight and ---- PageWidth should be called SheetWidth or something ---- like that. ---- ---- Note that we calculate our offsets and margins in ----_real_ units, not scaled units. That is significant ---- PushRecord will scale its arguments, so we will need -----to descale the offsets in the call to PushRecord. -- Useful units, measured in local units (i.e. postscript points): inch = 72 mm = inch / 25.4 PageWidth = 8.5*inch PageHeight = 14*inch -- Turn on TopMode if you want to print the top side of each sheet -- Turn on BottomMode if you want to print the bottm side of each sheet -- Turn on TopMode and BottomMode if you want both, as for a duplex printer TopMode = 1 BottomMode = 1 -- Turn on BoStack if your non-duplex printer has the property -- that the first thing printed winds up at the bottom of the -- stack, face up. BoStack = 0 print("PageCount",PageCount) -- Note that we need to distinguish ---- the hw margins need to keep the printer happy ---- the /added/ margins we need to apply here. -- Worst case is when the source -- material bleeds right to the edge of its bounding box. -- Conversely, if the source material has a lot of margin -- already built into it, we may not need any /extra/ margin -- at all, and we could set UsableHeight = PageHeight here. -- Similarly if Ydelta/2 is larger than the hwBottomMargin -- we shouldn't need to add any /add/ margin. hwTopMargin = 0.1*inch hwBottomMargin = 0.5*inch hwLeftMargin = 0.1*inch hwRightMargin = 0.1*inch srcMargin = 0 addTopMargin = math.max(0, hwTopMargin - srcMargin) addBottomMargin = math.max(0, hwBottomMargin - srcMargin) addLeftMargin = math.max(0, hwLeftMargin - srcMargin) addRightMargin = math.max(0, hwRightMargin - srcMargin) -- When calculating wiggle room, assume paper will be used -- symmetrically. This is a nontrivial assumption, since -- e.g. we could use a paper cutter to chop off one edge -- and not the other ... but that would be beyond the -- scope of this analysis. Symmetry means that if we -- apply a margin to the recto page, we must apply the -- same margin to the verso page, even if the hardware -- would not require it. Hence the factors of 2 here: UsableHeight = PageHeight - 2*addTopMargin - 2*addBottomMargin UsableWidth = PageWidth - 2*addLeftMargin - 2*addRightMargin if(SourceWidth <= SourceHeight) then Scale = math.min(UsableHeight / (2*SourceWidth), UsableWidth / SourceHeight) rot = 90 Ywiggle = 0.5 * math.max(0, UsableHeight - 2*SourceWidth*Scale) Xwiggle = math.max(0, UsableWidth - SourceHeight*Scale) fudge = addTopMargin + 2*(addBottomMargin + Ywiggle) -- Apply a factor of /2 to Xwiggle here, -- because we want centering -- (not flush to right of sheet, i.e. bottom of page): -- Do not apply corresponding factor to Ywiggle, because -- we do want flush to top of sheet, i.e. right of page: xof = addLeftMargin + SourceHeight*Scale + Xwiggle/2 yofRtop = SourceWidth*Scale + fudge yofRbot = SourceWidth*Scale + fudge yofVtop = addBottomMargin + Ywiggle yofVbot = addBottomMargin + Ywiggle else Scale = math.min(UsableHeight / (2*SourceHeight), UsableWidth / SourceWidth) rot = 0 Ywiggle = 0.5 * math.max(0, UsableHeight - 2*SourceHeight*Scale) Xwiggle = math.max(0, UsableWidth - SourceWidth*Scale) fudge = addTopMargin + 2*(addBottomMargin + Ywiggle) xof = addLeftMargin + Xwiggle/2 yofRtop = SourceHeight*Scale + fudge yofRbot = SourceHeight*Scale + fudge yofVtop = addBottomMargin + Ywiggle yofVbot = addBottomMargin + Ywiggle end do rest = PageCount % 4 totp = PageCount if rest ~= 0 then totp = totp + ( 4 - rest) end -- "inc" counts input pages skipped as well as pages actually used: inc = 0 -- "outc" counts output pages: outc = 0; count = 0 imax = totp/4 middle = totp/2 while count < imax do -- We assume that podofoimpose will discard invalid records -- such as those with source page greater than PageCount -- print(totp, inc, outc, rot, xof, yofRtop, yofVtop, yofRbot, yofVbot) -- Top of sheet: (8 1) ... (6 3) if TopMode ~= 0 then -- We did all the interesting calculations in real units (above). -- We convert to nasty descaled units at the last moment: PushRecord(totp - inc, outc + 1, rot, xof/Scale, yofVtop/Scale) PushRecord(inc + 1, outc + 1, rot, xof/Scale, yofRtop/Scale) outc = outc + 1 end -- Bottom of sheet: if BottomMode ~= 0 then if BoStack ~= 0 then -- Reversed bottom: (4 5) ... (2 7) PushRecord(middle - inc, outc + 1, rot, xof/Scale, yofVbot/Scale) PushRecord(middle + 1 + inc, outc + 1, rot, xof/Scale, yofRbot/Scale) else -- Normal bottom: (2 7) ... (4 5) PushRecord(inc + 2, outc + 1, rot, xof/Scale, yofVbot/Scale) PushRecord(totp-(inc + 1), outc + 1, rot, xof/Scale, yofRbot/Scale) end outc = outc + 1 end count = count + 1 inc = inc + 2 end end podofo-0.9.5/tools/podofoimpose/plans/lua/Booklet-USletter-top.plan0000664000175000017500000001457211577110115025254 0ustar dominikdominik---lua ---imposition plan : Generic Booklet -- US letter paper -- 8.5 x 11 --- ---It is said generic as it will try to determine ---automatically how to fit the booklet onto US letter ---paper sheets, scaling pages if necessary. ---it is well suited for office documents for ---which you do not care too much about resulting ---imposition artefacts since it manages to save ---paper! --- -- print("Booklet") -- We output a booklet on US letter paper -- 8.5 x 11 -- Interface notes ..... ---- Evidently PageCount, SourceWidth, and SourceHeight are ---- passed to us from the C++ program when we are called. ---- Evidently we are required to provide values for ---- PageWidth, PageHeight, and Scale ... which are used by ---- the C++ program after we return. Scale defaults to 1. ---- ---- Note that these Page-related names are unfortunate, ---- because they do *not* correspond to the pages as defined ---- by the source, or to the pages in the final booklet. ---- Really PageHeight should be called SheetHeight and ---- PageWidth should be called SheetWidth or something ---- like that. ---- ---- Note that we calculate our offsets and margins in ----_real_ units, not scaled units. That is significant ---- PushRecord will scale its arguments, so we will need -----to descale the offsets in the call to PushRecord. -- Useful units, measured in local units (i.e. postscript points): inch = 72 mm = inch / 25.4 PageWidth = 8.5*inch PageHeight = 11*inch -- Turn on TopMode if you want to print the top side of each sheet -- Turn on BottomMode if you want to print the bottm side of each sheet -- Turn on TopMode and BottomMode if you want both, as for a duplex printer TopMode = 1 BottomMode = 1 -- Turn on BoStack if your non-duplex printer has the property -- that the first thing printed winds up at the bottom of the -- stack, face up. BoStack = 1 print("PageCount",PageCount) -- Note that we need to distinguish ---- the hw margins need to keep the printer happy ---- the /added/ margins we need to apply here. -- Worst case is when the source -- material bleeds right to the edge of its bounding box. -- Conversely, if the source material has a lot of margin -- already built into it, we may not need any /extra/ margin -- at all, and we could set UsableHeight = PageHeight here. -- Similarly if Ydelta/2 is larger than the hwBottomMargin -- we shouldn't need to add any /add/ margin. hwTopMargin = 0.1*inch hwBottomMargin = 0.5*inch hwLeftMargin = 0.1*inch hwRightMargin = 0.1*inch srcMargin = 0 addTopMargin = math.max(0, hwTopMargin - srcMargin) addBottomMargin = math.max(0, hwBottomMargin - srcMargin) addLeftMargin = math.max(0, hwLeftMargin - srcMargin) addRightMargin = math.max(0, hwRightMargin - srcMargin) -- When calculating wiggle room, assume paper will be used -- symmetrically. This is a nontrivial assumption, since -- e.g. we could use a paper cutter to chop off one edge -- and not the other ... but that would be beyond the -- scope of this analysis. Symmetry means that if we -- apply a margin to the recto page, we must apply the -- same margin to the verso page, even if the hardware -- would not require it. Hence the factors of 2 here: UsableHeight = PageHeight - 2*addTopMargin - 2*addBottomMargin UsableWidth = PageWidth - 2*addLeftMargin - 2*addRightMargin if(SourceWidth <= SourceHeight) then Scale = math.min(UsableHeight / (2*SourceWidth), UsableWidth / SourceHeight) rot = 90 Ywiggle = 0.5 * math.max(0, UsableHeight - 2*SourceWidth*Scale) Xwiggle = math.max(0, UsableWidth - SourceHeight*Scale) fudge = addTopMargin + 2*(addBottomMargin + Ywiggle) -- Apply a factor of /2 to Xwiggle here, -- because we want centering -- (not flush to right of sheet, i.e. bottom of page): -- Do not apply corresponding factor to Ywiggle, because -- we do want flush to top of sheet, i.e. right of page: xof = addLeftMargin + SourceHeight*Scale + Xwiggle/2 yofRtop = SourceWidth*Scale + fudge yofRbot = SourceWidth*Scale + fudge yofVtop = addBottomMargin + Ywiggle yofVbot = addBottomMargin + Ywiggle else Scale = math.min(UsableHeight / (2*SourceHeight), UsableWidth / SourceWidth) rot = 0 Ywiggle = 0.5 * math.max(0, UsableHeight - 2*SourceHeight*Scale) Xwiggle = math.max(0, UsableWidth - SourceWidth*Scale) fudge = addTopMargin + 2*(addBottomMargin + Ywiggle) xof = addLeftMargin + Xwiggle/2 yofRtop = SourceHeight*Scale + fudge yofRbot = SourceHeight*Scale + fudge yofVtop = addBottomMargin + Ywiggle yofVbot = addBottomMargin + Ywiggle end do rest = PageCount % 4 totp = PageCount if rest ~= 0 then totp = totp + ( 4 - rest) end -- "inc" counts input pages skipped as well as pages actually used: inc = 0 -- "outc" counts output pages: outc = 0; count = 0 imax = totp/4 middle = totp/2 while count < imax do -- We assume that podofoimpose will discard invalid records -- such as those with source page greater than PageCount -- print(totp, inc, outc, rot, xof, yofRtop, yofVtop, yofRbot, yofVbot) -- Top of sheet: (8 1) ... (6 3) if TopMode ~= 0 then -- We did all the interesting calculations in real units (above). -- We convert to nasty descaled units at the last moment: PushRecord(totp - inc, outc + 1, rot, xof/Scale, yofVtop/Scale) PushRecord(inc + 1, outc + 1, rot, xof/Scale, yofRtop/Scale) outc = outc + 1 end -- Bottom of sheet: if BottomMode ~= 0 then if BoStack ~= 0 then -- Reversed bottom: (4 5) ... (2 7) PushRecord(middle - inc, outc + 1, rot, xof/Scale, yofVbot/Scale) PushRecord(middle + 1 + inc, outc + 1, rot, xof/Scale, yofRbot/Scale) else -- Normal bottom: (2 7) ... (4 5) PushRecord(inc + 2, outc + 1, rot, xof/Scale, yofVbot/Scale) PushRecord(totp-(inc + 1), outc + 1, rot, xof/Scale, yofRbot/Scale) end outc = outc + 1 end count = count + 1 inc = inc + 2 end end podofo-0.9.5/tools/podofoimpose/plans/lua/Booklet-USletter-duplex.plan0000664000175000017500000001457211577110115025753 0ustar dominikdominik---lua ---imposition plan : Generic Booklet -- US letter paper -- 8.5 x 11 --- ---It is said generic as it will try to determine ---automatically how to fit the booklet onto US letter ---paper sheets, scaling pages if necessary. ---it is well suited for office documents for ---which you do not care too much about resulting ---imposition artefacts since it manages to save ---paper! --- -- print("Booklet") -- We output a booklet on US letter paper -- 8.5 x 11 -- Interface notes ..... ---- Evidently PageCount, SourceWidth, and SourceHeight are ---- passed to us from the C++ program when we are called. ---- Evidently we are required to provide values for ---- PageWidth, PageHeight, and Scale ... which are used by ---- the C++ program after we return. Scale defaults to 1. ---- ---- Note that these Page-related names are unfortunate, ---- because they do *not* correspond to the pages as defined ---- by the source, or to the pages in the final booklet. ---- Really PageHeight should be called SheetHeight and ---- PageWidth should be called SheetWidth or something ---- like that. ---- ---- Note that we calculate our offsets and margins in ----_real_ units, not scaled units. That is significant ---- PushRecord will scale its arguments, so we will need -----to descale the offsets in the call to PushRecord. -- Useful units, measured in local units (i.e. postscript points): inch = 72 mm = inch / 25.4 PageWidth = 8.5*inch PageHeight = 11*inch -- Turn on TopMode if you want to print the top side of each sheet -- Turn on BottomMode if you want to print the bottm side of each sheet -- Turn on TopMode and BottomMode if you want both, as for a duplex printer TopMode = 1 BottomMode = 1 -- Turn on BoStack if your non-duplex printer has the property -- that the first thing printed winds up at the bottom of the -- stack, face up. BoStack = 0 print("PageCount",PageCount) -- Note that we need to distinguish ---- the hw margins need to keep the printer happy ---- the /added/ margins we need to apply here. -- Worst case is when the source -- material bleeds right to the edge of its bounding box. -- Conversely, if the source material has a lot of margin -- already built into it, we may not need any /extra/ margin -- at all, and we could set UsableHeight = PageHeight here. -- Similarly if Ydelta/2 is larger than the hwBottomMargin -- we shouldn't need to add any /add/ margin. hwTopMargin = 0.1*inch hwBottomMargin = 0.5*inch hwLeftMargin = 0.1*inch hwRightMargin = 0.1*inch srcMargin = 0 addTopMargin = math.max(0, hwTopMargin - srcMargin) addBottomMargin = math.max(0, hwBottomMargin - srcMargin) addLeftMargin = math.max(0, hwLeftMargin - srcMargin) addRightMargin = math.max(0, hwRightMargin - srcMargin) -- When calculating wiggle room, assume paper will be used -- symmetrically. This is a nontrivial assumption, since -- e.g. we could use a paper cutter to chop off one edge -- and not the other ... but that would be beyond the -- scope of this analysis. Symmetry means that if we -- apply a margin to the recto page, we must apply the -- same margin to the verso page, even if the hardware -- would not require it. Hence the factors of 2 here: UsableHeight = PageHeight - 2*addTopMargin - 2*addBottomMargin UsableWidth = PageWidth - 2*addLeftMargin - 2*addRightMargin if(SourceWidth <= SourceHeight) then Scale = math.min(UsableHeight / (2*SourceWidth), UsableWidth / SourceHeight) rot = 90 Ywiggle = 0.5 * math.max(0, UsableHeight - 2*SourceWidth*Scale) Xwiggle = math.max(0, UsableWidth - SourceHeight*Scale) fudge = addTopMargin + 2*(addBottomMargin + Ywiggle) -- Apply a factor of /2 to Xwiggle here, -- because we want centering -- (not flush to right of sheet, i.e. bottom of page): -- Do not apply corresponding factor to Ywiggle, because -- we do want flush to top of sheet, i.e. right of page: xof = addLeftMargin + SourceHeight*Scale + Xwiggle/2 yofRtop = SourceWidth*Scale + fudge yofRbot = SourceWidth*Scale + fudge yofVtop = addBottomMargin + Ywiggle yofVbot = addBottomMargin + Ywiggle else Scale = math.min(UsableHeight / (2*SourceHeight), UsableWidth / SourceWidth) rot = 0 Ywiggle = 0.5 * math.max(0, UsableHeight - 2*SourceHeight*Scale) Xwiggle = math.max(0, UsableWidth - SourceWidth*Scale) fudge = addTopMargin + 2*(addBottomMargin + Ywiggle) xof = addLeftMargin + Xwiggle/2 yofRtop = SourceHeight*Scale + fudge yofRbot = SourceHeight*Scale + fudge yofVtop = addBottomMargin + Ywiggle yofVbot = addBottomMargin + Ywiggle end do rest = PageCount % 4 totp = PageCount if rest ~= 0 then totp = totp + ( 4 - rest) end -- "inc" counts input pages skipped as well as pages actually used: inc = 0 -- "outc" counts output pages: outc = 0; count = 0 imax = totp/4 middle = totp/2 while count < imax do -- We assume that podofoimpose will discard invalid records -- such as those with source page greater than PageCount -- print(totp, inc, outc, rot, xof, yofRtop, yofVtop, yofRbot, yofVbot) -- Top of sheet: (8 1) ... (6 3) if TopMode ~= 0 then -- We did all the interesting calculations in real units (above). -- We convert to nasty descaled units at the last moment: PushRecord(totp - inc, outc + 1, rot, xof/Scale, yofVtop/Scale) PushRecord(inc + 1, outc + 1, rot, xof/Scale, yofRtop/Scale) outc = outc + 1 end -- Bottom of sheet: if BottomMode ~= 0 then if BoStack ~= 0 then -- Reversed bottom: (4 5) ... (2 7) PushRecord(middle - inc, outc + 1, rot, xof/Scale, yofVbot/Scale) PushRecord(middle + 1 + inc, outc + 1, rot, xof/Scale, yofRbot/Scale) else -- Normal bottom: (2 7) ... (4 5) PushRecord(inc + 2, outc + 1, rot, xof/Scale, yofVbot/Scale) PushRecord(totp-(inc + 1), outc + 1, rot, xof/Scale, yofRbot/Scale) end outc = outc + 1 end count = count + 1 inc = inc + 2 end end podofo-0.9.5/tools/podofoimpose/plans/lua/Booklet.plan0000664000175000017500000000223711133352773022710 0ustar dominikdominik-- Booklet print("Booklet") -- We output an A4 booklet PageWidth = 595.27559 PageHeight = 841.88976 print("PageCount",PageCount) -- We assume that H > W -- Argh, we now can do better since we have "if" ;-) -- Scale = PageHeight / (2*SourceWidth) if(SourceWidth <= SourceHeight) then Scale = PageHeight / (2*SourceWidth) rot = 90 xof = SourceHeight yofRA = 0 yofRB = SourceWidth yofVA = 0 yofVB = SourceWidth else Scale = PageHeight / (2*SourceHeight) rot = 0 xof = 0; yofRA = 0 yofRB = SourceHeight yofVA = SourceHeight yofVB = 0 end do rest = PageCount % 4 totp = PageCount if rest ~= 0 then totp = totp + ( 4 - rest) end inc = 0 count = 0 imax = totp/4 while count < imax do -- We assume that podofoimpose will discard invalid records -- such as those with source page greater than PageCount -- print(totp, inc, rot, xof,yofRA, yofRA, yofVA, yofVB) -- Recto PushRecord(totp - inc , inc + 1 , rot, xof , yofRA) PushRecord(inc + 1 , inc + 1 , rot, xof , yofRB) -- Verso PushRecord(inc + 2 , inc + 2 , rot, xof , yofVA) PushRecord(totp-(inc + 1) , inc + 2 , rot, xof, yofVB) count = count + 1 inc = inc + 2 end endpodofo-0.9.5/tools/podofoimpose/plans/lua/Identity.plan0000664000175000017500000000030311133352773023072 0ustar dominikdominik-- Identity - a test script for podofoimpose -- Required PageWidth = SourceWidth PageHeight = SourceHeight -- Records i = 1 while i <= PageCount do PushRecord( i , i ,0,0,0) i = i + 1 end podofo-0.9.5/tools/podofoimpose/plans/lua/Test.plan0000664000175000017500000000027211133352773022225 0ustar dominikdominik-- Test PageHeight = SourceHeight PageWidth = SourceWidth print("SourceHeight",SourceHeight); PushRecord(1,1,0,0,0); PushRecord(1,3,0,0,0); PushRecord(1,5,0,0,0); PushRecord(1,7,0,0,0);podofo-0.9.5/tools/podofoimpose/lua_compat.h0000664000175000017500000000152512205457547021041 0ustar dominikdominikextern "C" { #include "lua.h" // Note: If you're missing these, you're using lua 5.0 and haven't installed // the extension libraries. #include "lualib.h" #include "lauxlib.h" } #if !defined(LUA_VERSION_NUM) // Old lua without numeric version #define LUA_VERSION_NUM 0 #endif // Handle an API difference in the lua_open call between // Lua 5.1 and Lua 5.2. #if LUA_VERSION_NUM >= 502 inline lua_State* imp_lua_open(void) { return luaL_newstate(); } #else inline lua_State* imp_lua_open(void) { return lua_open(); } #endif // Handle an API difference in the dofile and getn calls between // Lua 5.0 and Lua 5.1. #if LUA_VERSION_NUM >= 501 inline int imp_lua_dofile(lua_State* L, const char * path) { return luaL_dofile(L, path); } #else inline int imp_lua_dofile(lua_State* L, const char * path) { return lua_dofile(L, path); } #endif podofo-0.9.5/tools/podofoimpose/charpainter.cpp0000664000175000017500000000665410674015620021546 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Pierre Marchand * * pierre@moulindetouvois.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "charpainter.h" #include using std::vector; using std::ostream; using std::string; namespace { // write the digits of `n' to `d'. The digits are ordered by increasing // place value. void digits(int n, vector & d) { while ( n > 0 ) { d.push_back(n % 10); n = n / 10; } } }; // end anon namespace using namespace std; void CharPainter::paint(ostream & s, int n, double size, double x, double y) { // update working variables used by topleft() etc m_y = y; m_x = x; m_size = size; m_sh = m_size + m_y; m_midh = (m_size /2.0) + m_y; m_sw = (m_size /2.0) + m_x; switch(n) { case 1 : topright(s); bottomright(s); break; case 2 : top(s); topright(s); center(s); bottomleft(s); bottom(s); break; case 3 : top(s); topright(s); bottomright(s); bottom(s); center(s); break; case 4 : topleft(s); center(s); bottomright(s); topright(s); break; case 5 : top(s); topleft(s); center(s); bottomright(s); bottom(s); break; case 6 : top(s); topleft(s); center(s); bottomright(s); bottom(s); bottomleft(s); break; case 7 : top(s); topright(s); bottomright(s); break; case 8 : top(s); topleft(s); center(s); bottomright(s); bottom(s); bottomleft(s); topright(s); break; case 9 : top(s); topleft(s); center(s); bottomright(s); bottom(s); topright(s); break; case 0 : top(s); topleft(s); bottomright(s); bottom(s); bottomleft(s); topright(s); break; } s << "S\n"; } void CharPainter::multipaint(ostream& s, int n, double size, double x, double y) { vector d; digits(n, d); vector::const_reverse_iterator itEnd = d.rend(); int i = d.size() - 1; for ( vector::const_reverse_iterator it = d.rbegin(); it != itEnd; ++it, --i ) paint(s, *it, size, x + (size * i / 1.6), y ); } podofo-0.9.5/tools/podofoimpose/impositionplan.h0000664000175000017500000000476713013650710021756 0ustar dominikdominik// // C++ Interface: impositionplan // // Description: // // // Author: Pierre Marchand , (C) 2008 // // Copyright: See COPYING file that comes with this distribution // // #ifndef IMPOSITIONPLAN_H #define IMPOSITIONPLAN_H #include "podofo.h" #include #include #include #include namespace PoDoFo { namespace Impose { enum PlanReader { Legacy = 0, Lua = 1 }; struct SourceVars { double PageCount; double PageWidth; double PageHeight; }; class Util { public: static void trimmed_str ( std::string& s ) { std::string::iterator si ( s.begin() ); while ( si != s.end() ) { if ( ( *si ) == 0x20 ) si = s.erase ( si ); else if ( ( *si ) == 0x9 ) si = s.erase ( si ); else ++si; } } static std::string dToStr ( double d ) { char buffer [126]; sprintf ( buffer, "%.5f", d ); std::string ret ( buffer ); return ret; } static std::string iToStr ( int i ) { char buffer [126]; sprintf ( buffer, "%d", i ); std::string ret ( buffer ); return ret; } }; /** @author Pierre Marchand */ class PageRecord { public: PageRecord ( int s,int d,double r, double tx, double ty , int du = 0 ); PageRecord( ); ~PageRecord() {}; int sourcePage; int destPage; double rotate; double transX; double transY; int duplicateOf; bool isValid() const; /// needed by legacy loader - should be removed soon static double calc ( const std::string& s , const std::map& vars ); static double calc ( const std::vector& t ); void load ( const std::string& s, const std::map& vars ); }; class ImpositionPlan : public std::vector { public: ImpositionPlan(const SourceVars& sv); ~ImpositionPlan(); // legacy std::map vars; const SourceVars sourceVars; private: double m_destWidth; double m_destHeight; double m_scale; std::string m_boundingBox; public: bool valid() const; void setDestWidth ( double theValue ); double destWidth() const{return m_destWidth;} void setDestHeight ( double theValue ); double destHeight() const{return m_destHeight;} void setScale ( double theValue ); double scale() const{return m_scale;} void setBoundingBox( const std::string& theString ); std::string boundingBox()const{return m_boundingBox;} }; };}; // end of namespace #endif podofo-0.9.5/tools/podofoimpose/pdftranslator.cpp0000664000175000017500000003713713013650710022124 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Pierre Marchand * * pierre@moulindetouvois.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "pdftranslator.h" // #include "charpainter.h" #include "planreader_legacy.h" #ifdef PODOFO_HAVE_LUA #include "planreader_lua.h" #endif #include #include #include #include #include #include #include using std::ostringstream; using std::map; using std::vector; using std::string; using std::ifstream; using std::istream; using std::ostream; using std::endl; using std::runtime_error; #include //XXX namespace PoDoFo { namespace Impose { #define MAX_SOURCE_PAGES 5000 #define MAX_RECORD_SIZE 2048 bool PdfTranslator::checkIsPDF ( std::string path ) { ifstream in ( path.c_str(), ifstream::in ); if ( !in.good() ) throw runtime_error ( "setSource() failed to open input file" ); const int magicBufferLen = 5; char magicBuffer[magicBufferLen ]; in.read ( magicBuffer, magicBufferLen ); std::string magic ( magicBuffer , magicBufferLen ); in.close(); if ( magic.find ( "%PDF" ) < 5 ) return true; // throw runtime_error("First bytes of the file tend to indicate it is not a PDF file"); return false; } PdfTranslator::PdfTranslator ( ) { std::cerr<<"PdfTranslator::PdfTranslator"< 4 ) // at least ".pdf" because just test if ts is empty doesn't work. { multiSource.push_back ( ts ); std::cerr << "Appending "<< ts <<" to source" << endl; } } while ( !in.eof() ); in.close(); delete [] filenameBuffer; } std::cerr<< ++dbg <::const_iterator ms = multiSource.begin(); ms != multiSource.end(); ++ms ) { if ( ms == multiSource.begin() ) { // std::cerr << "First doc is "<< (*ms).c_str() << endl; try{ sourceDoc = new PdfMemDocument ( ( *ms ).c_str() ); } catch(PdfError& e) { std::cerr << "Unable to create Document: " << PdfError::ErrorMessage( e.GetError() ) << std::endl; return; } } else { PdfMemDocument mdoc ( ( *ms ).c_str() ); // std::cerr << "Appending "<< mdoc.GetPageCount() << " page(s) of " << *ms << endl; sourceDoc->InsertPages ( mdoc, 0, mdoc.GetPageCount() ); } } pcount = sourceDoc->GetPageCount(); // std::cerr << "Document has "<< pcount << " page(s) " << endl; if ( pcount > 0 ) // only here to avoid possible segfault, but PDF without page is not conform IIRC { PoDoFo::PdfRect rect ( sourceDoc->GetPage ( 0 )->GetMediaBox() ); // keep in mind it’s just a hint since PDF can have different page sizes in a same doc sourceWidth = rect.GetWidth() - rect.GetLeft(); sourceHeight = rect.GetHeight() - rect.GetBottom() ; } } void PdfTranslator::addToSource ( const std::string & source ) { // std::cerr<<"PdfTranslator::addToSource "<< source<InsertPages ( extraDoc, 0, extraDoc.GetPageCount() ); multiSource.push_back ( source ); } PdfObject* PdfTranslator::migrateResource ( PdfObject * obj ) { // std::cerr<<"PdfTranslator::migrateResource"<IsDictionary() ) { ret = targetDoc->GetObjects().CreateObject ( *obj ); TKeyMap resmap = obj->GetDictionary().GetKeys(); for ( TCIKeyMap itres = resmap.begin(); itres != resmap.end(); ++itres ) { PdfObject *o = itres->second; ret->GetDictionary().AddKey ( itres->first , migrateResource ( o ) ); } if ( obj->HasStream() ) { * ( ret->GetStream() ) = * ( obj->GetStream() ); } } else if ( obj->IsArray() ) { PdfArray carray ( obj->GetArray() ); PdfArray narray; for ( unsigned int ci = 0; ci < carray.GetSize(); ++ci ) { PdfObject *co ( migrateResource ( &carray[ci] ) ); narray.push_back ( *co ); } ret = targetDoc->GetObjects().CreateObject ( narray ); } else if ( obj->IsReference() ) { if ( migrateMap.find ( obj->GetReference().ToString() ) != migrateMap.end() ) { return migrateMap[obj->GetReference().ToString() ]; } PdfObject * o ( migrateResource ( sourceDoc->GetObjects().GetObject ( obj->GetReference() ) ) ); ret = new PdfObject ( o->Reference() ) ; } else { ret = new PdfObject ( *obj );//targetDoc->GetObjects().CreateObject(*obj); } migrateMap.insert ( std::pair ( obj->Reference().ToString(), ret ) ); return ret; } PdfObject* PdfTranslator::getInheritedResources ( PdfPage* page ) { // std::cerr<<"PdfTranslator::getInheritedResources"<GetObject(); while ( rparent && rparent->IsDictionary() ) { PdfObject *curRes = rparent->GetDictionary().GetKey ( PdfName ( "Resources" ) ); if ( curRes ) { res = migrateResource ( curRes ); } rparent = rparent->GetIndirectKey ( "Parent" ); } return res; } void PdfTranslator::setTarget ( const std::string & target ) { // std::cerr<<"PdfTranslator::setTarget "<GetPage ( i ); PdfMemoryOutputStream outMemStream ( 1 ); PdfXObject *xobj = new PdfXObject ( page->GetMediaBox(), targetDoc ); if ( page->GetContents()->HasStream() ) { page->GetContents()->GetStream()->GetFilteredCopy ( &outMemStream ); } else if ( page->GetContents()->IsArray() ) { PdfArray carray ( page->GetContents()->GetArray() ); for ( unsigned int ci = 0; ci < carray.GetSize(); ++ci ) { if ( carray[ci].HasStream() ) { carray[ci].GetStream()->GetFilteredCopy ( &outMemStream ); } else if ( carray[ci].IsReference() ) { PdfObject *co = sourceDoc->GetObjects().GetObject ( carray[ci].GetReference() ); while ( co != NULL ) { if ( co->IsReference() ) { co = sourceDoc->GetObjects().GetObject ( co->GetReference() ); } else if ( co->HasStream() ) { co->GetStream()->GetFilteredCopy ( &outMemStream ); break; } } } } } /// Its time to manage other keys of the page dictionary. std::vector pageKeys; std::vector::const_iterator itKey; pageKeys.push_back ( "Group" ); for ( itKey = pageKeys.begin(); itKey != pageKeys.end(); ++itKey ) { PoDoFo::PdfName keyname ( *itKey ); if ( page->GetObject()->GetDictionary().HasKey ( keyname ) ) { xobj->GetObject()->GetDictionary().AddKey ( keyname, migrateResource ( page->GetObject()->GetDictionary().GetKey ( keyname ) ) ); } } outMemStream.Close(); PdfMemoryInputStream inStream ( outMemStream.TakeBuffer(),outMemStream.GetLength() ); xobj->GetContents()->GetStream()->Set ( &inStream ); resources[i+1] = getInheritedResources ( page ); xobjects[i+1] = xobj; cropRect[i+1] = page->GetCropBox(); bleedRect[i+1] = page->GetBleedBox(); trimRect[i+1] = page->GetTrimBox(); artRect[i+1] = page->GetArtBox(); } targetDoc->SetPdfVersion ( sourceDoc->GetPdfVersion() ); PdfInfo *sInfo ( sourceDoc->GetInfo() ); PdfInfo *tInfo ( targetDoc->GetInfo() ); if ( sInfo->GetAuthor() != PdfString::StringNull ) tInfo->SetAuthor ( sInfo->GetAuthor() ); if ( sInfo->GetCreator() != PdfString::StringNull ) tInfo->SetCreator ( sInfo->GetCreator() ); if ( sInfo->GetSubject() != PdfString::StringNull ) tInfo->SetSubject ( sInfo->GetSubject() ); if ( sInfo->GetTitle() != PdfString::StringNull ) tInfo->SetTitle ( sInfo->GetTitle() ); if ( sInfo->GetKeywords() != PdfString::StringNull ) tInfo->SetKeywords ( sInfo->GetKeywords() ); if ( sInfo->GetTrapped() != PdfName::KeyNull ) tInfo->SetTrapped ( sInfo->GetTrapped() ); // PdfObject *scat( sourceDoc->GetCatalog() ); // PdfObject *tcat( targetDoc->GetCatalog() ); // TKeyMap catmap = scat->GetDictionary().GetKeys(); // for ( TCIKeyMap itc = catmap.begin(); itc != catmap.end(); ++itc ) // { // if(tcat->GetDictionary().GetKey(itc->first) == 0) // { // PdfObject *o = itc->second; // tcat->GetDictionary().AddKey (itc->first , migrateResource( o ) ); // } // } // delete sourceDoc; } void PdfTranslator::loadPlan ( const std::string & planFile , PoDoFo::Impose::PlanReader loader ) { // std::cerr<< "loadPlan" << planFile<valid() ) throw std::runtime_error ( "Unable to build a valid imposition plan" ); destWidth = planImposition->destWidth(); destHeight = planImposition->destHeight(); scaleFactor = planImposition->scale(); boundingBox = planImposition->boundingBox(); // std::cerr <<"Plan completed "<< planImposition.size() <* bbIndex = NULL; if(boundingBox.size() > 0) { if(boundingBox.find("crop") != std::string::npos) { bbIndex = &cropRect; } else if(boundingBox.find("bleed") != std::string::npos) { bbIndex = &bleedRect; } else if(boundingBox.find("trim") != std::string::npos) { bbIndex = &trimRect; } else if(boundingBox.find("art") != std::string::npos) { bbIndex = &artRect; } } typedef map > groups_t; groups_t groups; for ( unsigned int i = 0; i < planImposition->size(); ++i ) { groups[ ( *planImposition ) [i].destPage].push_back ( ( *planImposition ) [i] ); } unsigned int lastPlate(0); groups_t::const_iterator git = groups.begin(); const groups_t::const_iterator gitEnd = groups.end(); while ( git != gitEnd ) { PdfPage * newpage = NULL; // Allow "holes" in dest. pages sequence. unsigned int curPlate(git->first); while(lastPlate != curPlate) { newpage = targetDoc->CreatePage ( PdfRect ( 0.0, 0.0, destWidth, destHeight ) ); ++lastPlate; } // newpage->GetObject()->GetDictionary().AddKey ( PdfName ( "TrimBox" ), trimbox ); PdfDictionary xdict; ostringstream buffer; // Scale buffer << std::fixed << scaleFactor <<" 0 0 "<< scaleFactor <<" 0 0 cm\n"; for ( unsigned int i = 0; i < git->second.size(); ++i ) { PageRecord curRecord ( git->second[i] ); // std::cerr< 0) ? curRecord.duplicateOf : */curRecord.sourcePage ); PdfXObject *xo = xobjects[resourceIndex]; if(NULL != bbIndex) { PdfObject bb; // DominikS: Fix compilation using Visual Studio on Windows // bbIndex->at(resourceIndex).ToVariant( bb ); ((*bbIndex)[resourceIndex]).ToVariant( bb ); xo->GetObject()->GetDictionary().AddKey ( PdfName ( "BBox" ), bb ); } ostringstream op; op << "OriginalPage" << resourceIndex; xdict.AddKey ( PdfName ( op.str() ) , xo->GetObjectReference() ); if ( resources[resourceIndex] ) { if ( resources[resourceIndex]->IsDictionary() ) { TKeyMap resmap = resources[resourceIndex]->GetDictionary().GetKeys(); TCIKeyMap itres; for ( itres = resmap.begin(); itres != resmap.end(); ++itres ) { xo->GetResources()->GetDictionary().AddKey ( itres->first, itres->second ); } } else if ( resources[resourceIndex]->IsReference() ) { xo->GetObject()->GetDictionary().AddKey ( PdfName ( "Resources" ), resources[resourceIndex] ); } else std::cerr<<"ERROR Unknown type resource "<GetDataTypeString() << std::endl; } // Very primitive but it makes it easy to track down imposition plan into content stream. buffer << "q\n"; buffer << std::fixed << cosR <<" "<< sinR<<" "<<-sinR<<" "<< cosR<<" "<< tx <<" "<< ty << " cm\n"; buffer << "/OriginalPage" << resourceIndex << " Do\n"; buffer << "Q\n"; } } if (!newpage) PODOFO_RAISE_ERROR (ePdfError_ValueOutOfRange); string bufStr = buffer.str(); newpage->GetContentsForAppending()->GetStream()->Set ( bufStr.data(), bufStr.size() ); newpage->GetResources()->GetDictionary().AddKey ( PdfName ( "XObject" ), xdict ); ++git; } targetDoc->Write ( outFilePath.c_str() ); } }; }; // end of namespace podofo-0.9.5/tools/podofoimpose/podofoimpose.cpp0000664000175000017500000000722211306221052021730 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Pierre Marchand * * pierre@moulindetouvois.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "pdftranslator.h" #include #include #include #include using std::cerr; using std::endl; using std::strtod; using std::string; struct _params { string executablePath; string inFilePath; string outFilePath; string planFilePath; PoDoFo::Impose::PlanReader planReader; } params; void usage() { cerr << "Usage : " << params.executablePath << " Input Output Plan [Interpretor]" << endl; cerr << "***" << endl; cerr << "\tInput is a PDF file or a file which contains a list of PDF file paths" << endl<< endl; cerr << "\tOutput will be a PDF file" << endl<< endl; cerr << "\tPlan is an imposition plan file" <= 5 ) { std::string native ( "native" ); std::string lua ( "lua" ); std::string interpretor ( argv[4] ); if ( !interpretor.compare ( native ) ) params.planReader = PoDoFo::Impose::Legacy; else if ( !interpretor.compare ( lua ) ) params.planReader = PoDoFo::Impose::Lua; } return 0; } /** * Return values: * * 0 : success * 1 : bad command line arguments */ int main ( int argc, char *argv[] ) { #if 0 PoDoFo::PdfError::EnableDebug ( false ); PoDoFo::PdfError::EnableLogging ( false ); #endif int ret = parseCommandLine ( argc, argv ); if ( ret ) return ret; std::cerr<<"Source : "<setSource ( params.inFilePath ); translator->setTarget ( params.outFilePath ); translator->loadPlan ( params.planFilePath, params.planReader ); translator->impose(); } catch ( PoDoFo::PdfError & e ) { e.GetCallstack(); e.PrintErrorMsg(); return 3; } catch ( std::exception & e ) { cerr << e.what() << endl; } return 0; } podofo-0.9.5/tools/podofoimpose/planreader_lua.h0000664000175000017500000000221311332265042021651 0ustar dominikdominik// // C++ Header: planreader_lua // // Description: // // // Author: Pierre Marchand , (C) 2008 // // Copyright: See COPYING file that comes with this distribution // // #ifndef PLANREADERLUA_H #define PLANREADERLUA_H #include "impositionplan.h" #include struct lua_State; class LuaMachina { lua_State *L; public: LuaMachina(); ~LuaMachina(); inline lua_State* State() { return L; } }; // could be best to have a base class but we wont develop 36000 // readers after all. class PlanReader_Lua { LuaMachina L; public: PlanReader_Lua(const std::string & planfile, PoDoFo::Impose::ImpositionPlan* ip); ~PlanReader_Lua(); static int PushRecord(lua_State *L); private: PoDoFo::Impose::ImpositionPlan* plan; /** Ask if a variable is available in script global scope */ bool hasGlobal(const std::string& name); /** Get the value of the named global from the Lua environment */ double getNumber(const std::string& name); /** Set a global to the passed value */ void setNumber(const std::string& name, double value); std::string getString(const std::string& name); }; #endif podofo-0.9.5/tools/podofoimpose/README.html0000664000175000017500000002137011133352773020361 0ustar dominikdominik PodofoImpose - some words

PodofoImpose

PodofoImpose is a utility program which aims to provide a rather simple way to impose PDF documents. Originally written for my own use, it ended up in PoDoFo release as a show-case (don’t rely too much on it).

Plan (built-in)

PodofoImpose is driven by a PLAN file. This file describes how pages from a source PDF document have to be relayout into a target document. We’ll describe how this file must be formated.

Records

Most of the PLAN file is composed of record lines of the form:
source page; target page; rotation; horizontal translation; vertical translation;
Each element of the record can be a numeric value, a constant or an expression involving both numerics and constants.

Constants

Constants can be declared everywhere in the PLAN file except in loops. They are 8 bits char strings (except "=") with a leading "$" character which makes them easy to identify. Their value is always interpreted as a float through std::atof. You can "overload" a constant value by redeclaring it. They are declared in this form:
$MyConstant = 123.456
Note that a PLAN file is valid only if it contains 2 required constants which are "$PageWidth" and "$PageHeight", giving target document dimensions. Now support the "$ScaleFactor" constant -- means that the declared scale factor will be added to the current transformation matrix for each placed page. Constants declarations can hold expressions:
$MyConstant = $AnotherConst * .5;
Source document pages count is provided as "$PageCount". Source first page geometry is provided as "$SourceWidth" and "$SourceHeight", reflecting geometry given by the MediaBox.

Expressions

An expression is a set of basic mathematic operations +, -, *,/ and % (operands of modulo will be first rounded). As a convenience, we added the | as "max(a,b)" it’s mainly there to allow user to prevent division by 0.
$ValueA / ( $ValueB | 0.000001 )
Operations are executed from left to right without taking care of any kind of precedance. You can use parenthesis to enclose operations that need to be computed separetly. Example:
123.456 * ( $ConstantA - ( $ConstantB / 3.14 ) )

Loops

Loops allow users to programmatically generate records. While the concept itself is familiar to programmers I can imagine that regular users would feel not so easy with it. So let me introduce a simple example to explain the thing.
Let say we have a source document, A4 format, which has 1000 pages and we just want to position each page of the first half of the document on the center of an A3 plate.
A4onA3.plan
$PageWidth=842.6 $PageHeight=1195.2 ## SourceWidth & SourceHeight $sw=597.6 $sh=842.4 $page=1 <$PageCount/2[$page+1] $page; $page; 0; ($PageWidth-$sw)/2; ($PageHeight-$sh)/2; >
The loop is what’s enclosed by "<" and ">"characters, the second just indicates the end of the loop. The first first indicates how many iterations (loops) have to be performed — 500 here. Then comes the interesting part, constants which appear in parenthesis will be incremented by the value following the "+" (can be a minus one, in that case don’t turn the "+" into a "-", just prefix the value with "-" as in [$foo+-1.23]), which means in this example that at each iteration, $page will see its value increased by 1.
Constants (which finally turn into variables ;-)) must be declared before the loop. Many constants can be put in loop declaration, separate them with semicolons.
There is an experimental support of nested loops.

Running

Once you’ve wrote the PLAN file you can run the program:
podofoimpose source.pdf target.pdf plan.plan
Note the source can be either a PDF file or a text file which is a listing of PDF files. In this case, listed files will be first merged in order.

Plan (Lua)

PoDoFoImpose now supports Lua scripted plan files. Note that, mainly for security reasons, only the following modules are loaded: base, table, string, math. If you need more, just add luaopen_* calls to LuaMachina::LuaMachina().

Format

Records are pushed with:
PushRecord(source page, target page, rotation, x, y);
As for regular plan files, there are a couple of provided informations through global variables, specifically: "SourceWidth", "SourceHeight", "PageCount". You need to set "PageWidth" and "PageHeight". You may alter the global scale factor (from source to target) by setting "Scale".

Running

There is no format detection mechanism, so you need to append "lua" keyword to podofoimpose invocation when you want it to process a Lua script.

Examples

For Lua scripts, some samples can be found in directory tools/podofoimpose/plans/lua of PoDoFo sources tree.
Add a stamp to a document
Shame on me, don’t even have a real stamp at my "office". So I tried something and it worked! Say you have that official one page A4 doc, named official.pdf, on which you want to add a nice stamp. You have your stamp in the file stamp.pdf. You first have to create two files:
pdf.list
official.pdf stamp.pdf
stamponator.plan
$PageWidth=597.6 $PageHeight=842.4 # original page is left unchanged; 1; 1; 0; 0; 0; # positionning stamp is up to you! 2; 1; 0; 350; 100;
Now you can run:
podofoimpose pdf.list stamped-official.pdf stamponator.plan
Make a tiled poster
Printing a large graphic onto a set of little paper sheets can be handful. Doing it automatically is even better! Latest changes allow us to provide you with a quasi all-automatic solution. The only thing that you would want to change (apart from debugging) is the output paper size (here ISO-A4, "Europe oblige !").
poster.plan
##POSTER printed on tiled A4 paper sheets. # destination (A4) $PageWidth = 597.6 $PageHeight = 842.4 $sW = $SourceWidth $sH = $SourceHeight # with a little trick to get integers $rows = (($sH / $PageHeight) + 1) % (2 * (($sH / $PageHeight)+1)) $cols = (($sW / $PageWidth) + 1) % (2 * (($sW / $PageWidth )+1)) $hbox = ($sW / ($cols | 1)) $vbox = ($sH/ ($rows | 1)) $hm = ($PageWidth - $hbox ) / 2 $vm = ($PageHeight - $vbox ) / 2 $R = 1 $C = 1 <$rows[$R+1] <$cols[$C+1] 1; (($R - 1)*$cols) + $C; 0; $hm - (($C -1) * $hbox); $vm - (($R-1) * $vbox); > >
podofoimpose poster.pdf poster_tiled.pdf poster.plan
Etc.
podofo-0.9.5/tools/podofoimpose/pdftranslator.h0000664000175000017500000001133511332265042021563 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Pierre Marchand * * pierre@moulindetouvois.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef PDFTRANSLATOR_H #define PDFTRANSLATOR_H #include "podofo.h" #include "impositionplan.h" #include #include #include #include #include #include // using namespace PoDoFo; namespace PoDoFo { namespace Impose { /** PdfTranslator create a new PDF file which is the imposed version, following the imposition plan provided by the user, of the source PDF file. Pdftranslate does not really create a new PDF doc, it rather works on source doc, getting all page contents as XObjects and put these XObjects on new pages. At the end, it removes original pages from the doc, but since PoDoFo keeps them --- just removing from the pages tree ---, if it happens that you have a lot of content in content stream rather than in resources, you'll get a huge file. Usage is something like : p = new PdfTranslator; p->setSource("mydoc.pdf"); p->setTarget("myimposeddoc.pdf"); p->loadPlan("in4-32p.plan"); p->impose(); p->mailItToMyPrinterShop("job@proprint.com");//Would be great, doesn't it ? */ class PdfTranslator { public: PdfTranslator(); ~PdfTranslator() { } PdfMemDocument *sourceDoc; PdfMemDocument *targetDoc; /** Set the source document(s) to be imposed. Argument source is the path of the PDF file, or the path of a file containing a list of paths of PDF files... */ void setSource ( const std::string & source ); /** Another way to set many files as source document. Note that a source must be set before you call addToSource(). */ void addToSource ( const std::string & source ); /** Set the path of the file where the imposed PDF doc will be save. */ void setTarget ( const std::string & target ); /** Load an imposition plan file of form: widthOfSheet heightOfSheet sourcePage destPage rotation translationX translationY ... ... ... ... ... */ void loadPlan ( const std::string & planFile , PoDoFo::Impose::PlanReader loader ); /** When all is prepared, call it to do the job. */ void impose(); private: std::string inFilePath; std::string outFilePath; PdfReference globalResRef; ImpositionPlan *planImposition; std::map xobjects; std::map resources; std::map cropRect; std::map bleedRect; std::map trimRect; std::map artRect; std::map pDict; std::map virtualMap; // int maxPageDest; int duplicate; bool checkIsPDF ( std::string path ); PdfObject* getInheritedResources ( PdfPage* page ); void mergeResKey ( PdfObject *base, PdfName key, PdfObject *tomerge ); PdfObject* migrateResource(PdfObject * obj); void drawLine ( double x, double y, double xx, double yy, std::ostringstream & a ); void signature ( double x , double y, int sheet, const std::vector & pages, std::ostringstream & a ); // An attempt to allow nested loops // returns new position in records list. int sortLoop(std::vector& memfile, int numline); std::string useFont; PdfReference useFontRef; double extraSpace; std::vector multiSource; std::map migrateMap; public: int pcount; double sourceWidth; double sourceHeight; double destWidth; double destHeight; double scaleFactor; std::string boundingBox; }; };}; // end of namespace #endif podofo-0.9.5/tools/podofoimpose/sample.pdf0000664000175000017500000005742011044703333020510 0ustar dominikdominik%PDF-1.4 %Çì¢ 1 0 obj << /Type /Catalog /Outlines 3 0 R /Pages 4 0 R /Dests 5 0 R /AcroForm 6 0 R /Names 7 0 R /Threads 8 0 R /PageLayout /SinglePage /ViewerPreferences << /PageDirection /L2R >> >> endobj 2 0 obj << /Creator (Scribus 1.3.3.13svn) /Producer (Scribus PDF Library 1.3.3.13svn) /Title <> /Author <> /Keywords <> /CreationDate (D:20080801001624) /ModDate (D:20080801001624) /Trapped /False >> endobj 9 0 obj << /Type /XObject /Subtype /Form /FormType 1 /BBox [ 0.03600 -0.33900 0.47800 -1.01100 ] /Resources << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] >> /Length 188 /Filter /FlateDecode >> stream xÚ•A Ã0 ïyEÎ…IkËö{¥—þÿÚ(rRÛ…BofÐZ«¡ Dë1ï×B5õˆBÌÅ…RêTí±-Šê!Ôêð(z`!3m¿¤2͹…g›*Ç ËÔW’ôÀB¢ùî/à!üz±Ö¹F4¥œS¬s“Q"÷GØ¡rÚ9Q"·Ã‡³C¹­€…ë8ƒÒ@bÁgÓ… \;¢Ž}¯MÜNžgô'Øí¬Ûò88tË endstream endobj 10 0 obj << /Type /XObject /Subtype /Form /FormType 1 /BBox [ 0.10400 -0.35000 0.32100 -1.00000 ] /Resources << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] >> /Length 110 /Filter /FlateDecode >> stream xÚ}Á À †ï>EçÁÂÔ {ž`tÙû_·Ñ(Ë“||¿Šè‰ÑíÁc.wö=SX‚sçmüBÍ!Ñ%È¡Á (R äÐèÔÕr²J¨wˆë& ”óFG— ÂÜiïì@„ä® Ro endstream endobj 11 0 obj << /Type /XObject /Subtype /Form /FormType 1 /BBox [ 0.04500 -0.33900 0.46000 -1.00000 ] /Resources << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] >> /Length 203 /Filter /FlateDecode >> stream xÚ}’±à Dw¾"s¥FÆ ß©êÒÿ_°!0>ÝqÜ X)Àò¶+ä³ü Œ¨Xò lf¢±!=‚lzÒøL¢AÔèÈ<Ùä< b {à1ÖN‘“‹^€sI’rí”ç±í5ª&HÔk¡vÐ’V À3P’jM"ìÇ"‹:D<ƒ2ú^ã¼>ØõÀ·N § Gf´m©NÞ†èÑ^4:•Õ.  q£9>ãN¦Ë‡½›ù.Ÿ—ù0ÌŽ endstream endobj 12 0 obj << /Type /XObject /Subtype /Form /FormType 1 /BBox [ 0.04200 -0.33900 0.44800 -1.01100 ] /Resources << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] >> /Length 275 /Filter /FlateDecode >> stream xÚ}“MnÄ …÷9Ŭ+ òÎ3RÕÍÜ;€mÒ´+Ч÷ð‹í@!€ÇRÓÒ/ïqTk¿@Bç N@ó\àÕM¬ºkDª¿Ò l ¢ºi¡Byj¸²U CTÚÑH½ÓTý3›¥!×d¥H“ˆ·zš™ªf{…¸œÁ0¡–]ƒ€T&kÕ¦ ê —Î|f%ôî ›5Zgˆà ¬{¸k˜%ÖdXÝ[¨Z#(G‡ÑWdæ^`ÆÛQÿ‚iú[Såì¦Ð¬Ò÷`˜(¶<4œ5–‘”XØ0qŽV›Sü>â-G8‹Ww 4ŸAó½ZãC¾l„!¸þ¨¿Àëøy|‘µq endstream endobj 13 0 obj << /Type /XObject /Subtype /Form /FormType 1 /BBox [ 0.01500 -0.35000 0.49100 -1.00000 ] /Resources << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] >> /Length 203 /Filter /FlateDecode >> stream xÚ…ÒA„ Ð=§p=ɘB©èyHÌl¼ÿvPÀ±¥0®ÈËÿB 0{Hßô¶3\‹Ã€¤`^Ó -³Ù!\¥n&×€•îLݺìxM 4`¥šA !œ¥&¶@XHƒ³ÔÏÔÉ`¥šA†p¯“ùݶ€G©y]ˆæF)}RÍ‚ÞÔѧA4JÆ-˜Ðjp–ÜZÞAÉle\> ©G’#Í”ÀÁri-´lüÇb' wÊô€:¬¤LO…tÓþ2_q~ endstream endobj 14 0 obj << /Type /XObject /Subtype /Form /FormType 1 /BBox [ 0.04200 -0.35000 0.44600 -1.01100 ] /Resources << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] >> /Length 230 /Filter /FlateDecode >> stream xÚ}’1Ã0EwŸ¢s¥F€Á6ç‰Tuéý×:`ÚÄM;%zú>`X8g€Ë –,О f ýk:Ñ@¥Ð0ð@Ò¼p´."*îÁfꊣ&KuPqÚÂd :j­˜†ìÛ²ç¥ÈâÀâ15 #Ò%æÞLê€ÇfÔfùfªaRÜ/@ÜÇ `3±5Ì1–#¨M‡éƒ ºæsÛ‹PÜ)ã@¢~'Š!¥yz+ Øö¬çNƒU¨ƒQ6fšÐVe˜˜ø x§Ió~Á?ÀšþiâO`MËýš^Äø—É endstream endobj 15 0 obj << /Type /XObject /Subtype /Form /FormType 1 /BBox [ 0.03400 -0.34000 0.48000 -1.01100 ] /Resources << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] >> /Length 286 /Filter /FlateDecode >> stream xÚ}“9nÄ0 Eû9ÅÔÆ ¸ë<‚4¹-¤!Ù“Tø$ñ‹†ƒ‹<_pC[ü<à苵¯y‚2`i‹Ï&¡¥$2jJMÉ}æ xìÒ%°:‘À”€¢FAw`c1¤DhnŒ]~•ʼ*­ KTë^ù˘§t"žb—v_‹“œW0‚(¸×±ì)’Áˆ\ÙBº ø_0$ÊÛŒE?ºDÂH¢.)‘I"Šž> /Length 109 /Filter /FlateDecode >> stream xÚ}ÐA € …á½§p$ÏtÒÎ#D›î¿­)„Gwòñ?Pá@ °3\ ܇Ó@Òâ4(FiB¢!ðhÔbô6Ø"ƒw4x®'ŸÇÀ£¦‰k}$²<ê7õ;üFÍ—w ˜Ã«ÉRþ endstream endobj 17 0 obj << /Type /XObject /Subtype /Form /FormType 1 /BBox [ 0.03700 -0.33900 0.47600 -1.01100 ] /Resources << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] >> /Length 331 /Filter /FlateDecode >> stream xÚ•“MnÄ0…÷9Ŭ+5²ù3>ÏHU7½ÿ¶±×vF­ºJô‰øé”ïéD¬×ÏבÎL:£t&É(m€sS?‰ZLõÄÔAvÀê¢ Í §»^IÅQe«„Å@aZ¢„(PEOœÛSÞó™²`žAaÙb¨Hd‘(„²n¢_5Òx5E¥- ¿½Ê^‰ÑgÀ ZC4P.–Xë:mœAm(í[s&‚ÿŠ>›ŒÃc*±…ftp ZÄÄ!,¨ô*m•|­KLœ(=#BÄøtì®@q¬É@Õ¶QÖ~Ë º;+º½ûžÇß1/Dfiû·ã ] Ü!–pŠsýAâ»360yy©qôqy¹†ËÉç°‹Ÿb¬6§! Ô¾=FyíXg`îèS—;·ãŒïQ endstream endobj 18 0 obj << /Type /XObject /Subtype /Form /FormType 1 /BBox [ 0.04000 -0.33900 0.47800 -1.01100 ] /Resources << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] >> /Length 302 /Filter /FlateDecode >> stream xÚ}“MnÄ0…÷sЬ+5ógŸ§RÕMï¿­mÀr’¶»Ñ7< ï8¡)ÀñŽ' ôß/8êìè€%4f Æ?]Tx"8[³YCÞ¥Uškˆ˜ÀQ¯a«ì)E‰˜£q‹ÆD>^QÚÁa¾”5À]ì DS´Ö0%ÆÓx‰Ê¦­^kH¢‹u¨1¯¶ÝÐí_0E–›…]ê«#ª•o¥¾wÁ˜·•êKj&I¼Ü[¨^higfàÓ½+‚û©=À&ú³æÑרJâ-+&®;g’‰7¸Y eåõ–UI‰ër‡$oÔ"`̫ϡí`ZºÂ‹,Ùe~m]9$b Ñ<ÌmÉ"²ƒ™ø=Ìz€néñùöúï±ÃÝ endstream endobj 19 0 obj << /Type /XObject /Subtype /Form /FormType 1 /BBox [ 0 0 419.52756 595.27559 ] /Resources << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] >> /Length 95 /Filter /FlateDecode >> stream xÚ=Š1€0 w¿"/ˆ’¦-í Ø€1Á„èÀÄ÷I,Y§“ý@8ä0$r¦RÂÏe„²ôЋm'¡B“÷‚º )YæÍZ [Š©ÒÑзÓÊr5·+f||pð endstream endobj 20 0 obj << /Length 196 /Filter /FlateDecode >> stream xÚmPË Â0¼ïWì˜nÒlM®¢AP)x)Õ–b±V£"þ½I}PÄ,d6™É$BB-­`5äÙ²ð [t%®ðÒÓ„¯y×À¤ 0ðëß+@áë¯r¨…Ñ1×DĬ½Wwp”Â$*ñ G6F}ÑU^¢Œz»‡ê­Þhµ`kHCÙSö{OE³‡ÛçÅܵƒeYݹÓÇ-,ºŠšür-]vÊ«2k·u&3Ø?Ñè'šþ<„ùóM½hÁü ±‰Hm endstream endobj 21 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 22 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 20 0 R /Group 21 0 R >> endobj 23 0 obj << /Length 196 /Filter /FlateDecode >> stream xÚmPË Â0¼ïWì˜nÒlM®¢AP)x)Õ–b±V£"þ½I}PÄ,d6™É$BB-­`5äÙ²ð [t%®ðÒÓ„¯y×À¤ 0ðëß+@áë¯r¨…Ñ1×DĬ½Wwp”Â$*ñ G6F}ÑU^¢Œz»‡ê­Þhµ`kHCÙSö{OE³‡ÛçÅܵƒeYݹcÂq ‹®¢&¿\K—òªÌÚmÉLöO4ú‰¦?aþ|S/Z0®JHe endstream endobj 24 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 25 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 23 0 R /Group 24 0 R >> endobj 26 0 obj << /Length 195 /Filter /FlateDecode >> stream xÚmPA Â0¼ï+ö¦›4Û&WÑ‹ ¨<ˆ”ª¥(ÖjTÄß›T-EÌBf“™L2!$ÔÒ V)'È–…oØ¢+q‰'ž&|ÏÛ. …X­ýÞN€ðÐ)S-ŒŽ)¸&"fí½ÚƒÃ ÆP‰¿=²1ªCWy‰2ê㪷ú Õ‚­! eOÙï=MŸn_ìf®,Êê~,K50o+ª‹ë­tù¹¨Ê¼Ùr™·ìŸhôMÂüý¦^´`þ®²Hf endstream endobj 27 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 28 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 26 0 R /Group 27 0 R >> endobj 29 0 obj << /Length 196 /Filter /FlateDecode >> stream xÚmPË Â0¼ïWì˜nÒlM®¢AP)x)Õ–b±V£"þ½I}PÄ,d6™É$BB-­`5äÙ²ð [t%®ðÒÓ„¯y×À¤ 0ðëß+@áë¯r¨…Ñ1×DĬ½Wwp”Â$*ñ G6F}ÑU^¢Œz»‡ê­Þhµ`kHCÙSö{OE³‡ÛçÅܵƒeYݹc…ã]EM~¹–.;åU™µÛ:“™ ìŸhôMÂüù¦^´`þ¯Hg endstream endobj 30 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 31 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 29 0 R /Group 30 0 R >> endobj 32 0 obj << /Length 195 /Filter /FlateDecode >> stream xÚmPA Â0¼ï+ö¦›4[“«èET"¥ÚR,ÖjTÄß›h+EÌBf“™L2!$ÔÒ VCN- ß°EWàO =Mø™÷5\@ °Ùú½N°ú*‡ZSpMDÌÚ{½ŽV0Y •ø Ð#£¾èJ/QFµî¡z«­l É`({Ê~ï©höt‡,Ÿ»f°,Êû1sã¸Å»¢:»Þ —ž³²H›]•ÊTöO4ú‰¦»‡0wßÔ‹Ì_¯‚Hh endstream endobj 33 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 34 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 32 0 R /Group 33 0 R >> endobj 35 0 obj << /Length 196 /Filter /FlateDecode >> stream xÚmPË Â0¼ïWì˜nÒlM®¢AP)x)Õ–b±V£"þ½I}PÄ,d6™É$BB-­`5äÙ²ð [t%®ðÒÓ„¯y×À¤ 0ðëß+@áë¯r¨…Ñ1×DĬ½Wwp”Â$*ñ G6F}ÑU^¢Œz»‡ê­Þhµ`kHCÙSö{OE³‡ÛçÅܵƒeYݹcã]EM~¹–.;åU™µÛ:“™ ìŸhôMÂüù¦^´`þ¯êHi endstream endobj 36 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 37 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 35 0 R /Group 36 0 R >> endobj 38 0 obj << /Length 196 /Filter /FlateDecode >> stream xÚmPË Â0¼ïWì˜nÒlM®¢AP)x)Õ–b±V£"þ½I}PÄ,d6™É$BB-­`5äÙ²ð [t%®ðÒÓ„¯y×À¤ 0ðëß+@áë¯r¨…Ñ1×DĬ½Wwp”Â$*ñ G6F}ÑU^¢Œz»‡ê­Þhµ`kHCÙSö{OE³‡ÛçÅܵƒeYݹcÆq ‹®¢&¿\K—òªÌÚmÉLöO4ú‰¦?aþ|S/Z0°RHj endstream endobj 39 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 40 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 38 0 R /Group 39 0 R >> endobj 41 0 obj << /Length 195 /Filter /FlateDecode >> stream xÚmPË Â0¼ïWì˜nÒlM®¢AP<ˆ”jKQÔjTÄ¿wã‹"f!³ÉL&™Zí›.gÈž•4ì1T8Çh¡ _óz'ЊâÀ,–²W‚Á!n¿Ê®UΦ]3•²¯çÁÞ 3 e2¹Ù9óÅP‹Ä8óvÕZ½Ñ[ÅÞ‘Ž†º¥l÷B%£{Øå84iU_wEdý&ÏJöÅùR…üXÔUÞ¬¶¹ÎudÿD£ŸhöóæÏ7µ¢Eó°ºHk endstream endobj 42 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 43 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 41 0 R /Group 42 0 R >> endobj 44 0 obj << /Length 195 /Filter /FlateDecode >> stream xÚmPA Â0¼ï+ö¦›4Û&WÑ‹ ¨<ˆ”ª¥(ÖjTÄß›¨-EÌBf“™L2!$ÔÒ V)'È–…oØ¢+q‰'ž&üÌÛ. …X­ýÞN€ðÐ)S-ŒŽ)¸&"fí½Þ‡Œ3 ¡zdcT‡®òeÔ×=ToõE«[C2Êž²ß{*š>ݾØÍ\3X”ÕýX8NqÔÀü]Q]\o¥ËÏEUæÍæË\öO4ú‰¦Û‡0·ßÔ‹Ì_±"Hl endstream endobj 45 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 46 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 44 0 R /Group 45 0 R >> endobj 47 0 obj << /Length 213 /Filter /FlateDecode >> stream xÚ¥QÁj1½ÏWÌ4NâL6¹Š½‚Áƒ”eÛ]E»-¥o¢»ËR<Ù d&y/ïÁ !!k¯ÄdbQ¼¨8ˆÇPá¿@G˜ð¾àZQZø›÷xW‚ÁîzfÆÊñ˜’ªUcá¨u{8YÁë H 0vqÎô=Ô‘bœiÕS Nm÷¬Ä;ÒIP˜Ã9B£ùoØå"4/oUý½/{œ6°|Î]3+kí¿üÝÝ?ÕèPœ/UÈE]åÍÇ.×¹NèƒhéO´Ü!Ò}Ó Ú$~É=d— endstream endobj 48 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 49 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 47 0 R /Group 48 0 R >> endobj 50 0 obj << /Length 210 /Filter /FlateDecode >> stream xÚ­QËŠ1¼÷Wô˜édºcr÷² ¨D†Yg”uG£"þ½‰/ÙÓ²iHuR•j¨²öJL_,ŠñjœãèHÞ÷Õö ¥…gX,ã]?póRöY9Î)¹Z• G¯ÛÃÁ >f@ÊØ8#Šsæ…¡‰ãÌÃ=Uçô@ÏJ¼# uGÙí#•.a]VãÐö¦usú.{¶0ùÛtͬ¬µÿ1?U¶-Ç:»²©‹ökSèB'ö—hé-Z~!òü¦N´Éü É¥d˜ endstream endobj 51 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 52 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 50 0 R /Group 51 0 R >> endobj 53 0 obj << /Length 214 /Filter /FlateDecode >> stream xÚ¥QÁj1½ÏWÌ4;ÉÎd“«è¥PÐ"ô ²lë²(ê¶ÑRú÷MtwYÄ“Í@f’÷ò¼²öJL!Å‹Šƒx 5¾át„ ¯ûǾ@+J `µŽw0ø „»Y°rœSRµ*ŽZ—‡“%Ì–@ÊØh€±‹sf衉ãL§žjtêºg%Þ‘N‚zÄÏÊ^~öÚÌCûôZ7ßû*°Çi ‹ÇÜ5³²ÖþÇ_èêŸ*;T§sÊϪ©Ëö}WêR'ôN´t-÷Aˆôß4Š6‰ÿÆfd endstream endobj 54 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 55 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 53 0 R /Group 54 0 R >> endobj 56 0 obj << /Length 213 /Filter /FlateDecode >> stream xÚ¥QMk1½Ï¯˜?Ð8ÉÎd“«è¥PhEè¡È²ÖeQ´Û¦-â¿7ÙYÄ“f 3É{y^ Y{%&‹âEÅA<† ßñ t„ »ýó? ¥…GøXÅ» |ÂÝ…™³rœQRµ*ŽZíÃéæK el4ÀØÅ9s顎ãL¯žjtê»g%Þ‘N‚zÄÏš¼œÂ¶Ü¼†æiQÕÿû2°ÇYo÷¹kfe­}Ä_tçŸjr(ÿªP|—uU4ë]¡‹½-]EËC"Ã7¢MâgÆÎd‘ endstream endobj 57 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 58 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 56 0 R /Group 57 0 R >> endobj 59 0 obj << /Length 214 /Filter /FlateDecode >> stream xÚ¥QÁj1½ÏWÌ4;ÉÎd“«è¥PÐ"ô ²lë²(ê¶ÑRú÷MtwYÄ“Í@f’÷ò¼²öJL!Å‹Šƒx 5¾át„ ¯ûǾ@+J `µŽw0ø „»Y°rœSRµ*ŽZ—‡“%Ì–@ÊØh€±‹sf衉ãL§žjtêºg%Þ‘N‚zÄÏÊ^~öÚÌCûôZ7ßû*°Çi ‹ÇÜ5³²ÖþÇ_ÌÕ?Uv¨Nç:”ŸUS—íû®Ô¥Nèhé&Zîƒé¿imÿÇ6d’ endstream endobj 60 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 61 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 59 0 R /Group 60 0 R >> endobj 62 0 obj << /Length 213 /Filter /FlateDecode >> stream xÚ¥QÁj1½ÏWÌ'Ù™lr-z+ Š,[]–Šº[ŠoÒÕe‘žÚ d&y/ïÁ !!k¯ÄäbQ¼¨8ˆÇPã  #LØí›œA+J ¿ámï¶`p„»ž™³rœQRµ*ŽZ?_ ˜@ÊØh€±‹s¦ï¡‰ãÌ]=Õàtïž•xG: ês8Gh<¿†j»íhY7_û*°ÇI ¯s×ÌÊZûÉ:ÿTãCuù¬Cyªšºlßw¥.uB‰–ž¢åG"oD›ÄoÇžd“ endstream endobj 63 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 64 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 62 0 R /Group 63 0 R >> endobj 65 0 obj << /Length 214 /Filter /FlateDecode >> stream xÚ¥QÁj1½ÏWÌ4;ÉÎd“«è¥PÐ"ô ²lë²(ê¶ÑRú÷MtwYÄ“Í@f’÷ò¼²öJL!Å‹Šƒx 5¾át„ ¯ûǾ@+J `µŽw0ø „»Y°rœSRµ*ŽZ—‡“%Ì–@ÊØh€±‹sf衉ãL§žjtêºg%Þ‘N‚zÄÏÊ^~öÚÌCûôZ7ßû*°Çi ‹ÇÜ5³²ÖþÇ_øêŸ*;T§sÊϪ©Ëö}WêR'ôN´t-÷Aˆôß4Š6‰ÿÈd” endstream endobj 66 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 67 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 65 0 R /Group 66 0 R >> endobj 68 0 obj << /Length 214 /Filter /FlateDecode >> stream xÚ¥QÁj1½ÏWÌ4;ÉÎd“«è¥PÐ"ô ²lë²(ê¶ÑRú÷MtwYÄ“Í@f’÷ò¼²öJL!Å‹Šƒx 5¾át„ ¯ûǾ@+J `µŽw0ø „»Y°rœSRµ*ŽZ—‡“%Ì–@ÊØh€±‹sf衉ãL§žjtêºg%Þ‘N‚zÄÏÊ^~öÚÌCûôZ7ßû*°Çi ‹ÇÜ5³²ÖþÇ_äêŸ*;T§sÊϪ©Ëö}WêR'ôN´t-÷Aˆôß4Š6‰ÿÈnd• endstream endobj 69 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 70 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 68 0 R /Group 69 0 R >> endobj 71 0 obj << /Length 214 /Filter /FlateDecode >> stream xÚ¥QÁj1½ÏWÌ4;ÉÎÄä*z)jz(²¬ÝeQÔmSKéßwbUñ¤ÈLò^ÞƒBB¶Ñˆ‰G‰btˆ©ÅWÜU˜ðßÂ'XCyá¼-ô®‡@¸>3Gl—”U½)…Uëðp<‡éÈ8¯¨]Bpçž:¥¸àŽê¹§cl$²YИÃY¡âé7­êæ9õ/m÷½©Gœô0»ÍÝ2ïý=þšìÁ?W±­¿ömª>ê®­ú庲•Íè•hé"Z>!rú¦A´YüÈÖd– endstream endobj 72 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 73 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 71 0 R /Group 72 0 R >> endobj 74 0 obj << /Length 214 /Filter /FlateDecode >> stream xÚ¥QAjÃ0¼ï+ö‘Wò®,]Cs)Ò`È¡ã$Æ$Ôq«´”ü>RSzj´ ]iF30"$d하B,Šñ\ãt„ ¯û¶ƒЊÒÂoxyw;0ø„‡‘Y°rœSRµ*ŽZ?ç%,J el4ÀØÅ93öÐFŠq榞jrºuÏJ¼#õ„9#”=þÞ-C?[5í×[ØãCÏÿs×ÌÊZ{¿WÿTYWŸ>›P½×mSõ›C¥+Ð?¢¥_Ñò„ÈðM“h“øÉ>d— endstream endobj 75 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 76 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 74 0 R /Group 75 0 R >> endobj 77 0 obj << /Length 213 /Filter /FlateDecode >> stream xÚ¥QÁj1½ÏWÌ4NâL6¹Š½‚Áƒ”eÛ]E»-¥o¢»ËR<Ù d&y/ïÁ !!k¯ÄdbQ¼¨8ˆÇPá¿@G˜ð¾àZQZø›÷xW‚ÁîzfÆÊñ˜’ªUcá¨u{8YÁë H 0vqÎô=Ô‘bœiÕS Nm÷¬Ä;ÒIP˜Ã9B£ùoØå"4/oUý½/‚NX>ç®™•µö?þìîþ©F‡â|©B~,ê*o>v¹ÎuBDK¢å.‘î›Ñ&ñ+Áþd endstream endobj 78 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 79 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 77 0 R /Group 78 0 R >> endobj 80 0 obj << /Length 214 /Filter /FlateDecode >> stream xÚ¥QÁj1½ÏWÌ4;ÉÎd“«è¥PÐ"ô ²lë²(ê¶ÑRú÷MtwYÄ“Í@f’÷ò¼²öJL!Å‹Šƒx 5¾át„ ¯ûǾ@+J `µŽw0ø „»Y°rœSRµ*ŽZ—‡“%Ì–@ÊØh€±‹sf衉ãL§žjtêºg%Þ‘N‚zÄÏÊ^~öÚÌCûôZ7ßû*á´…ÅcîšYYkÿãÏþêŸ*;T§sÊϪ©Ëö}WêR'ôN´t-÷Aˆôß4Š6‰ÿÂfd endstream endobj 81 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 82 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 80 0 R /Group 81 0 R >> endobj 83 0 obj << /Length 207 /Filter /FlateDecode >> stream xÚ­QË Â0¼ïWì˜nÒlL®¢AP<ˆ”jKQÔjTÄ¿7ñEOb2›Ìd&„„Z:ÁªÍÙ± ;ô%Nq2Є}¹…HAqáfópW€Â>®ßʶV§]HY¯ûÃÎz ¡L€ÙZõF_‰²êé«qz¢Ó‚% eCÙì• ®~•C_·ÆeuÞäž »5Œ~›.µƘÌ•lóã©ôÙ>¯Ê¬^¬3™ÉÈ~‰–>¢Õ¯ ˜_ßÔˆ6šß¿'dˆ endstream endobj 84 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 85 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 83 0 R /Group 84 0 R >> endobj 86 0 obj << /Length 209 /Filter /FlateDecode >> stream xÚ¥QË Â0¼ïWì7i6&WÑ‹ ¨DJµ¥(j5*âß›ÔE¢Õ¯ ˜_ßÔˆ6Šß¿d‰ endstream endobj 87 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 88 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 86 0 R /Group 87 0 R >> endobj 89 0 obj << /Length 209 /Filter /FlateDecode >> stream xÚ¥QË Â0¼ïWì˜nÒlL®¢AP<ˆ”jKQÔjTÄ¿7ñEOš…ì&3™ !¡–N°j³Av,ÂÀ}‰SÜ 0ác_náRP\xÙ<Ü °„ë7³­…Õ)EU#RÖAëþ°3ÞH( 0t¶V½»¯EYõTÕ8=»Ó‚%eƒÙœ” ®~•C_·ÆeuÞäž »5Œ~s—Z cÌ_þêá+ÙæÇSé³}^•Y½Xg2“ý-}D«_A0¿¾©m¿¿÷dŠ endstream endobj 90 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 91 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 89 0 R /Group 90 0 R >> endobj 92 0 obj << /Length 209 /Filter /FlateDecode >> stream xÚ¥QË Â0¼ïWì˜nÒlL®¢AP<ˆ”ª¥(ÖjTÄ¿7ñEOš…ì&3™ !¡–N°j³Av,ÂÀ}SÜ 0ác_Vp)(.¼ÀlîV °„›7³­…Õ)EU#RÖAëþ°3ÞH( 0t¶V½»/EYõTÕ8=»Ó‚%eƒÙœ” ®~¯†¾n‹ò¼Í=vkýæ.µƘ¿üÓ‡¬¤Ê§Âgû¼,²z±Éd&#ú%ZúˆV¿‚`~}S#Ú(~À_d‹ endstream endobj 93 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 94 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 92 0 R /Group 93 0 R >> endobj 95 0 obj << /Length 213 /Filter /FlateDecode >> stream xÚ¥QÁj1½ÏWÌ4NâL6¹Š½‚Áƒ”eÛ]E»-¥o¢»ËR<Ù d&y/ïÁ !!k¯ÄdbQ¼¨8ˆÇPá¿@G˜ð¾àZQZø›÷xW‚ÁîzfÆÊñ˜’ªUcá¨u{8YÁë H 0vqÎô=Ô‘bœiÕS Nm÷¬Ä;ÒIP˜Ã9B£ùoØå"4/oUý½/‚NX>ç®™•µö_þ|÷O5:çKòcQWyó±Ëu®ú Zú-wAˆtß4ˆ6‰_ÀÇdŒ endstream endobj 96 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 97 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 95 0 R /Group 96 0 R >> endobj 98 0 obj << /Length 209 /Filter /FlateDecode >> stream xÚ¥QË Â0¼ïWì˜nÒlL®¢AP<ˆ”jKQÔjTÄ¿7ñEOš…ì&3™ !¡–N°j³Av,ÂÀ}‰SÜ 0ác_náRP\xÙ<Ü °„ë7³­…Õ)EU#RÖAëþ°3ÞH( 0t¶V½»¯EYõTÕ8=»Ó‚%eƒÙœ” ®~•C_·ÆeuÞäž »5Œ~s—Z cÌ_þüð•lóã©ôÙ>¯Ê¬^¬3™Éˆ~‰–>¢Õ¯ ˜_ßÔˆ6ŠßÁ/d endstream endobj 99 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 100 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 98 0 R /Group 99 0 R >> endobj 101 0 obj << /Length 209 /Filter /FlateDecode >> stream xÚ¥QË Â0¼ïWì˜nÒlL®¢AP<ˆ”jKQÔjTÄ¿7ñEOš…ì&3™ !¡–N°j³Av,ÂÀ}‰SÜ 0ác_náRP\xÙ<Ü °„ë7³­…Õ)EU#RÖAëþ°3ÞH( 0t¶V½»¯EYõTÕ8=»Ó‚%eƒÙœ” ®~•C_·ÆeuÞäž »5Œ~s—Z cÌ_þæá+ÙæÇSé³}^•Y½Xg2“ý-}D«_A0¿¾©m¿Á—dŽ endstream endobj 102 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 103 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 101 0 R /Group 102 0 R >> endobj 104 0 obj << /Length 209 /Filter /FlateDecode >> stream xÚ¥QË Â0¼ïWì7i6M®¢AP<ˆ”ª¥(ÖjTÄ¿7ñEOš…ì&3™ !¡–N°JÙ ;a`‡¾À)î@˜ð±/+8€^`6w+PØÂÍ›™jauBQÕˆ„uк?ìL 7Ê ­UïîË@QV=Õc5NÏî´`gIFAÙ`6çµW¿ÎWC_·ÆEyÞæž »5Œ~s—Z cÌ_þéÃ?V»Ê§Âgû¼,²z±Éd&#ú%ZúˆV¿‚`~}S#Ú(~Áÿd endstream endobj 105 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 106 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 104 0 R /Group 105 0 R >> endobj 107 0 obj << /Length 214 /Filter /FlateDecode >> stream xÚ¥QMk1½Ï¯˜?Ð8ÉÎd“«Ô‹ Ø"x²¬uY*êjÚRü÷&û!Ké©f o’™y/¼²öJL.ŋЉx ®ñ:– »ýýЊÒÂؼŻœáþÞ™³rœQbµ*Ž\íàt³26 `DqÎÜ1Ô±Å8Ó³§zô¬Ä;Ò‰P:Çy,M×ðQî–¡yz­êïCDãs/ÿS×ÌÊZûˆ>»N?ÅäX~~U¡8—uU4Û}¡‹öuXK¿¬åÁ‘á›FÖ&òÂæd endstream endobj 108 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 109 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 107 0 R /Group 108 0 R >> endobj 110 0 obj << /Length 214 /Filter /FlateDecode >> stream xÚ¥QMk1½Ï¯˜?Ð8ÉÎd“«è¥PhEè¡È²ÖeQ´Û¦-â¿7ÙYÄ“f o’™y/¼²öJL.ŋЉx ¾ãèX&ìöÏü€V”ácï6`ðw—Μ•ãŒ«U™päj§K˜/”±Q#Šsæ‚¡Ž-Æ™ž=ÅèÔ£g%Þ‘N„zÔ9Îciòr Ûróš§EUÿïË g ¼Ý§®™•µö}ö~ŠÉ¡üý«Bñ]ÖUѬw….Ú×ݰ–®¬åÁ‘á›FÖ&ò3ÃNd‘ endstream endobj 111 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 112 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 110 0 R /Group 111 0 R >> endobj 113 0 obj << /Length 209 /Filter /FlateDecode >> stream xÚ¥QM Â0 ½çWäXÓ®©íUô"*‚‘1ÝŠ:­ŠøïmçCöÕŽ Å…W˜/Â] @¸ywv´°:¡ÈjDÂ:pÕƒÝ)ô§@B™ €ÙZõF_†eÕ“=FãôD§;K2ÊFg3¥öðæ×Y>òUkR”—mæYb¯‚ñoêRkaŒùKŸú1Ú»ìt.|zÈÊ"­–›T¦õë¾XKÖê—̯ojXÉïÀd‰ endstream endobj 114 0 obj << /S /Transparency /CS /DeviceRGB >> endobj 115 0 obj << /Type /Page /Parent 4 0 R /MediaBox [0 0 419.52756 595.27559] /TrimBox [0 0 419.52756 595.27559] /Rotate 0 /Contents 113 0 R /Group 114 0 R >> endobj 116 0 obj << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] /XObject << /MyriadPro-Regular48 9 0 R /MyriadPro-Regular49 10 0 R /MyriadPro-Regular50 11 0 R /MyriadPro-Regular51 12 0 R /MyriadPro-Regular52 13 0 R /MyriadPro-Regular53 14 0 R /MyriadPro-Regular54 15 0 R /MyriadPro-Regular55 16 0 R /MyriadPro-Regular56 17 0 R /MyriadPro-Regular57 18 0 R /master_page_obj_1_1 19 0 R >> >> endobj 3 0 obj << /Type /Outlines /Count 0 >> endobj 4 0 obj << /Type /Pages /Kids [22 0 R 25 0 R 28 0 R 31 0 R 34 0 R 37 0 R 40 0 R 43 0 R 46 0 R 49 0 R 52 0 R 55 0 R 58 0 R 61 0 R 64 0 R 67 0 R 70 0 R 73 0 R 76 0 R 79 0 R 82 0 R 85 0 R 88 0 R 91 0 R 94 0 R 97 0 R 100 0 R 103 0 R 106 0 R 109 0 R 112 0 R 115 0 R ] /Count 32 /Resources 116 0 R >> endobj 5 0 obj << >> endobj 6 0 obj << /Fields [ ] >> endobj 7 0 obj << >> endobj 8 0 obj [] endobj xref 0 117 0000000000 65535 f 0000000015 00000 n 0000000207 00000 n 0000021397 00000 n 0000021443 00000 n 0000021745 00000 n 0000021766 00000 n 0000021800 00000 n 0000021822 00000 n 0000000414 00000 n 0000000822 00000 n 0000001153 00000 n 0000001577 00000 n 0000002073 00000 n 0000002497 00000 n 0000002948 00000 n 0000003455 00000 n 0000003785 00000 n 0000004337 00000 n 0000004860 00000 n 0000005165 00000 n 0000005434 00000 n 0000005488 00000 n 0000005648 00000 n 0000005917 00000 n 0000005971 00000 n 0000006131 00000 n 0000006399 00000 n 0000006453 00000 n 0000006613 00000 n 0000006882 00000 n 0000006936 00000 n 0000007096 00000 n 0000007364 00000 n 0000007418 00000 n 0000007578 00000 n 0000007847 00000 n 0000007901 00000 n 0000008061 00000 n 0000008330 00000 n 0000008384 00000 n 0000008544 00000 n 0000008812 00000 n 0000008866 00000 n 0000009026 00000 n 0000009294 00000 n 0000009348 00000 n 0000009508 00000 n 0000009794 00000 n 0000009848 00000 n 0000010008 00000 n 0000010291 00000 n 0000010345 00000 n 0000010505 00000 n 0000010792 00000 n 0000010846 00000 n 0000011006 00000 n 0000011292 00000 n 0000011346 00000 n 0000011506 00000 n 0000011793 00000 n 0000011847 00000 n 0000012007 00000 n 0000012293 00000 n 0000012347 00000 n 0000012507 00000 n 0000012794 00000 n 0000012848 00000 n 0000013008 00000 n 0000013295 00000 n 0000013349 00000 n 0000013509 00000 n 0000013796 00000 n 0000013850 00000 n 0000014010 00000 n 0000014297 00000 n 0000014351 00000 n 0000014511 00000 n 0000014797 00000 n 0000014851 00000 n 0000015011 00000 n 0000015298 00000 n 0000015352 00000 n 0000015512 00000 n 0000015792 00000 n 0000015846 00000 n 0000016006 00000 n 0000016288 00000 n 0000016342 00000 n 0000016502 00000 n 0000016784 00000 n 0000016838 00000 n 0000016998 00000 n 0000017280 00000 n 0000017334 00000 n 0000017494 00000 n 0000017780 00000 n 0000017834 00000 n 0000017994 00000 n 0000018276 00000 n 0000018330 00000 n 0000018491 00000 n 0000018774 00000 n 0000018829 00000 n 0000018992 00000 n 0000019275 00000 n 0000019330 00000 n 0000019493 00000 n 0000019781 00000 n 0000019836 00000 n 0000019999 00000 n 0000020287 00000 n 0000020342 00000 n 0000020505 00000 n 0000020788 00000 n 0000020843 00000 n 0000021006 00000 n trailer << /Size 117 /Root 1 0 R /Info 2 0 R /ID [<0B8271610621E4061F9B76A7DE7D539B><0B8271610621E4061F9B76A7DE7D539B>] >> startxref 21840 %%EOF podofo-0.9.5/tools/podofoimpose/planreader_lua.cpp0000664000175000017500000001060012205457547022220 0ustar dominikdominik// // C++ Implementation: planreader_lua // // Description: // // // Author: Pierre Marchand , (C) 2008 // // Copyright: See COPYING file that comes with this distribution // // #include "planreader_lua.h" #include #include // Note: this is *not* lua.hpp shipped with lua 5.1, it's a wrapper // header we use to handle version differences between lua 5.1 and lua // 5.0 . #include "lua_compat.h" LuaMachina::LuaMachina() { /* Init the Lua interpreter */ L = imp_lua_open(); if (!L) { throw std::runtime_error("Whoops! Failed to open lua!"); } /* Init the Lua libraries we want users to have access to. * Note that the `os' and `io' libraries MUST NOT be included, * as providing access to those libraries to the user would * make running plan files unsafe. */ luaopen_base(L); luaopen_table(L); luaopen_string(L); luaopen_math(L); } LuaMachina::~LuaMachina() { lua_close(L); } PlanReader_Lua::PlanReader_Lua(const std::string & planfile, PoDoFo::Impose::ImpositionPlan * ip) { // std::cerr<<"PlanReader_Lua::PlanReader_Lua "<< planfile <(this)); lua_setglobal(L.State(), "This"); setNumber("PageCount", plan->sourceVars.PageCount); setNumber("SourceWidth", plan->sourceVars.PageWidth ); setNumber("SourceHeight", plan->sourceVars.PageHeight); // imp_lua_dofile is a wrapper around luaL_dofile for Lua 5.0/5.1 compat. if(imp_lua_dofile(L.State(), planfile.c_str())) { std::cerr<<"Unable to process Lua script:\"" <setDestWidth(getNumber("PageWidth")); if(hasGlobal("PageHeight")) plan->setDestHeight(getNumber("PageHeight")); if(hasGlobal("Scale")) plan->setScale(getNumber("Scale")); if(hasGlobal("BoundingBox")) plan->setBoundingBox(getString("BoundingBox")); } } PlanReader_Lua::~ PlanReader_Lua() { } int PlanReader_Lua::PushRecord ( lua_State * L ) { /* TODO: check stack for space! I would be glad to do that, but I don’t know how - pm */ if ( ! ( lua_isnumber ( L, 1 ) && lua_isnumber ( L, 2 ) && lua_isnumber ( L, 3 ) && lua_isnumber ( L, 4 ) && lua_isnumber ( L, 5 ) ) ) { throw std::runtime_error ( "One or more arguments to PushRecord were not numbers" ); } /* Get the instance of the reader which runs the script */ lua_getglobal ( L , "This" ); if ( ! lua_islightuserdata ( L, -1 ) ) throw std::runtime_error ( "\"This\" is not valid" ); // ;-) PlanReader_Lua *that = static_cast ( lua_touserdata ( L, -1 ) ); lua_pop ( L, 1 ); // std::cerr<<"PlanReader_Lua::PushRecord "<plan->push_back ( P ); lua_pop ( L, 5 ); return 0; } double PlanReader_Lua::getNumber(const std::string & name) { lua_getglobal(L.State(), name.c_str()); if (!lua_isnumber(L.State(), -1)) { std::string errString = name + " is non-number"; throw std::runtime_error(errString.c_str()); } double d = lua_tonumber(L.State(), -1); lua_pop(L.State(), 1); return d; } void PlanReader_Lua::setNumber(const std::string & name, double value) { lua_pushnumber(L.State(), value); lua_setglobal(L.State(), name.c_str()); /* pops stack */ } bool PlanReader_Lua::hasGlobal(const std::string & name) { bool ret(true); lua_getglobal(L.State(), name.c_str()); if(lua_isnil(L.State(), -1) > 0) { ret = false; } lua_pop(L.State(), 1); return ret; } std::string PlanReader_Lua::getString(const std::string& name) { lua_getglobal(L.State(), name.c_str()); if (!lua_isstring(L.State(), -1)) { std::string errString = name + " is non-string"; throw std::runtime_error(errString.c_str()); } std::string s( lua_tostring(L.State(), -1) ); lua_pop(L.State(), 1); return s; } podofo-0.9.5/tools/podofoimpose/planreader_legacy.h0000664000175000017500000000111611075367546022355 0ustar dominikdominik// // C++ Interface: planreader_legacy // // Description: // // // Author: Pierre Marchand , (C) 2008 // // Copyright: See COPYING file that comes with this distribution // // #ifndef PLANREADER_LEGACY_H #define PLANREADER_LEGACY_H #include "impositionplan.h" #include #include class PlanReader_Legacy { public: PlanReader_Legacy(const std::string & plan, PoDoFo::Impose::ImpositionPlan* Imp); ~PlanReader_Legacy(){} private: PoDoFo::Impose::ImpositionPlan* I; int sortLoop(std::vector& memfile, int numline); }; #endif podofo-0.9.5/tools/podofoimpose/charpainter.h0000664000175000017500000000536710674015620021213 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2007 by Pierre Marchand * * pierre@moulindetouvois.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef CHARPAINTER_H #define CHARPAINTER_H /** @author Pierre Marchand */ #include class CharPainter{ public: CharPainter() { } ~CharPainter() { } void paint(std::ostream& s, int n, double size, double x, double y); // call paint() for each digit in the number `n' void multipaint(std::ostream& s, int n, double size, double x, double y); private: // some simple helpers for writing points // TODO: nothrow annotations inline void wdir(std::ostream& s, double x1, double y1, double x2, double y2) const { s << x1 << ' ' << y1 << " m\n" << x2 << ' ' << y2 << " l\n"; } inline void top(std::ostream& s) const { wdir(s, m_x, m_sh, m_sw, m_x); } inline void topright(std::ostream& s) const { wdir(s, m_sw, m_sh, m_sw, m_midh); } inline void bottomright(std::ostream& s) const { wdir(s, m_sw, m_midh, m_sw, m_y); } inline void bottom(std::ostream& s) const { wdir(s, m_x, m_y, m_sw, m_y); } inline void bottomleft(std::ostream&s) const { wdir(s, m_x, m_y, m_x, m_midh); } inline void topleft(std::ostream& s) const { wdir(s, m_x, m_midh, m_x, m_sh); } inline void center(std::ostream& s) const { wdir(s, m_x, m_midh, m_sw, m_midh); } // temporaries used by paint(...) double m_size; double m_x; double m_y; double m_sh; double m_sw; double m_midh; }; #endif podofo-0.9.5/tools/podofoimpose/sample.plan0000664000175000017500000000271511044703333020666 0ustar dominikdominik##### ISO A2 paper - ISO A5 pages - in16 x 2 ##### ## Here is a sample plan file for podofoimpose ## You should find sample.pdf along this file ## run "podofoimpose sample.pdf sample_imposed.pdf sample.plan" to try it. # $PageWidth & $PageHeight are required # reminder: # source page; destination page; rotation; Tx; Ty; $PageWidth=1190.55 $PageHeight=1683.78 # I’m lazy at typing :) $pw=1190.55 $ph=1683.78 # Plate 1 $plate=1 8; $plate; 270; 0; $ph; 1; $plate; 90; $pw; ($ph/4.0)*3.0; 9; $plate; 270; 0; ($ph/4.0) * 3.0; 16; $plate; 90; $pw; ($ph/4.0)*2.0; 12; $plate; 270; 0; ($ph/4.0)*2.0; 13; $plate; 90; $pw; $ph/4.0; 5; $plate; 270; 0; $ph/4.0; 4; $plate; 90; $pw; 0; # Plate 2 $plate=2 2; $plate; 270; 0; $ph; 7; $plate; 90; $pw; ($ph/4.0)*3.0; 15; $plate; 270; 0; ($ph/4.0)*3.0; 10; $plate; 90; $pw; ($ph/4.0)*2.0; 14; $plate; 270; 0; ($ph/4.0)*2.0; 11; $plate; 90; $pw; $ph/4.0; 3; $plate; 270; 0; $ph/4.0; 6; $plate; 90; $pw; 0; # Plate 3 $plate=3 24; $plate; 270; 0; $ph; 17; $plate; 90; $pw; ($ph/4.0)*3.0; 25; $plate; 270; 0; ($ph/4.0)*3.0; 32; $plate; 90; $pw; ($ph/4.0)*2.0; 28; $plate; 270; 0; ($ph/4.0)*2.0; 29; $plate; 90; $pw; $ph/4.0; 21; $plate; 270; 0; $ph/4.0; 20; $plate; 90; $pw; 0; # Plate 4 $plate=4 18; $plate; 270; 0; $ph; 23; $plate; 90; $pw; ($ph/4.0)*3.0; 31; $plate; 270; 0; ($ph/4.0)*3.0; 26; $plate; 90; $pw; ($ph/4.0)*2.0; 30; $plate; 270; 0; ($ph/4.0)*2.0; 27; $plate; 90; $pw; $ph/4.0; 19; $plate; 270; 0; $ph/4.0; 22; $plate; 90; $pw; 0; podofo-0.9.5/tools/podofoimgextract/0000775000175000017500000000000013044451161017400 5ustar dominikdominikpodofo-0.9.5/tools/podofoimgextract/CMakeLists.txt0000664000175000017500000000051310517314571022144 0ustar dominikdominikADD_EXECUTABLE(podofoimgextract ImageExtractor.cpp podofoimgextract.cpp) TARGET_LINK_LIBRARIES(podofoimgextract ${PODOFO_LIB}) SET_TARGET_PROPERTIES(podofoimgextract PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(podofoimgextract ${PODOFO_DEPEND_TARGET}) INSTALL(TARGETS podofoimgextract RUNTIME DESTINATION "bin") podofo-0.9.5/tools/podofoimgextract/ImageExtractor.h0000664000175000017500000000576011066250055022500 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _IMAGE_EXTRACTOR_H_ #define _IMAGE_EXTRACTOR_H_ #include using namespace PoDoFo; #ifndef MAX_PATH #define MAX_PATH 512 #endif // MAX_PATH /** This class uses the PoDoFo lib to parse * a PDF file and to write all images it finds * in this PDF document to a given directory. */ class ImageExtractor { public: ImageExtractor(); virtual ~ImageExtractor(); /** * \param pnNum pointer to an integer were * the number of processed images can be stored * or null if you do not want this information. */ void Init( const char* pszInput, const char* pszOutput, int* pnNum = NULL ); /** * \returns the number of succesfully extracted images */ inline int GetNumImagesExtracted() const; private: /** Extracts the image form the given PdfObject * which has to be an XObject with Subtype "Image" * \param pObject a handle to a PDF object * \param bJpeg if true extract as a jpeg, otherwise create a ppm * \returns ErrOk on success */ void ExtractImage( PoDoFo::PdfObject* pObject, bool bJpeg ); /** This function checks wether a file with the * given filename does exist. * \returns true if the file exists otherwise false */ bool FileExists( const char* pszFilename ); private: char* m_pszOutputDirectory; unsigned int m_nSuccess; unsigned int m_nCount; char m_szBuffer[MAX_PATH]; }; inline int ImageExtractor::GetNumImagesExtracted() const { return m_nSuccess; } #endif // _IMAGE_EXTRACTOR_H_ podofo-0.9.5/tools/podofoimgextract/podofoimgextract.cpp0000664000175000017500000000451311306221052023456 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "ImageExtractor.h" #include #include #ifdef _HAVE_CONFIG #include #endif // _HAVE_CONFIG void print_help() { printf("Usage: podofoimgextract [inputfile] [outputdirectory]\n\n"); printf("\nPoDoFo Version: %s\n\n", PODOFO_VERSION_STRING); } int main( int argc, char* argv[] ) { char* pszInput; char* pszOutput; int nNum = 0; ImageExtractor extractor; if( argc != 3 ) { print_help(); exit( -1 ); } pszInput = argv[1]; pszOutput = argv[2]; try { extractor.Init( pszInput, pszOutput, &nNum ); } catch( PdfError & e ) { fprintf( stderr, "Error: An error %i ocurred during processing the pdf file.\n", e.GetError() ); e.PrintErrorMsg(); return e.GetError(); } nNum = extractor.GetNumImagesExtracted(); printf("Extracted %i images sucessfully from the PDF file.\n", nNum ); return 0; } podofo-0.9.5/tools/podofoimgextract/podofoimgextract.vcproj0000664000175000017500000000714610475170454024223 0ustar dominikdominik podofo-0.9.5/tools/podofoimgextract/ImageExtractor.cpp0000664000175000017500000001231511336327135023031 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "ImageExtractor.h" #include #include #include #ifdef _MSC_VER #define snprintf _snprintf #endif ImageExtractor::ImageExtractor() : m_pszOutputDirectory( NULL ), m_nSuccess( 0 ), m_nCount( 0 ) { } ImageExtractor::~ImageExtractor() { } void ImageExtractor::Init( const char* pszInput, const char* pszOutput, int* pnNum ) { PdfObject* pObj = NULL; if( !pszInput || !pszOutput ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } PdfMemDocument document( pszInput ); m_pszOutputDirectory = const_cast(pszOutput); TCIVecObjects it = document.GetObjects().begin(); if( pnNum ) *pnNum = 0; while( it != document.GetObjects().end() ) { if( (*it)->IsDictionary() ) { PdfObject* pObjType = (*it)->GetDictionary().GetKey( PdfName::KeyType ); PdfObject* pObjSubType = (*it)->GetDictionary().GetKey( PdfName::KeySubtype ); if( ( pObjType && pObjType->IsName() && ( pObjType->GetName().GetName() == "XObject" ) ) || ( pObjSubType && pObjSubType->IsName() && ( pObjSubType->GetName().GetName() == "Image" ) ) ) { pObj = (*it)->GetDictionary().GetKey( PdfName::KeyFilter ); if( pObj && pObj->IsArray() && pObj->GetArray().GetSize() == 1 && pObj->GetArray()[0].IsName() && (pObj->GetArray()[0].GetName().GetName() == "DCTDecode") ) pObj = &pObj->GetArray()[0]; if( pObj && pObj->IsName() && ( pObj->GetName().GetName() == "DCTDecode" ) ) { // The only filter is JPEG -> create a JPEG file ExtractImage( *it, true ); } else { ExtractImage( *it, false ); } document.FreeObjectMemory( *it ); } } ++it; } } void ImageExtractor::ExtractImage( PdfObject* pObject, bool bJpeg ) { FILE* hFile = NULL; const char* pszExtension = bJpeg ? "jpg" : "ppm"; // Do not overwrite existing files: do { snprintf( m_szBuffer, MAX_PATH, "%s/pdfimage_%04i.%s", m_pszOutputDirectory, m_nCount++, pszExtension ); } while( FileExists( m_szBuffer ) ); hFile = fopen( m_szBuffer, "wb" ); if( !hFile ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } printf("-> Writing image object %s to the file: %s\n", pObject->Reference().ToString().c_str(), m_szBuffer); if( bJpeg ) { PdfMemStream* pStream = dynamic_cast(pObject->GetStream()); fwrite( pStream->Get(), pStream->GetLength(), sizeof(char), hFile ); } else { //long lBitsPerComponent = pObject->GetDictionary().GetKey( PdfName("BitsPerComponent" ) )->GetNumber(); // TODO: Handle colorspaces // Create a ppm image const char* pszPpmHeader = "P6\n# Image extracted by PoDoFo\n%li %li\n%li\n"; fprintf( hFile, pszPpmHeader, pObject->GetDictionary().GetKey( PdfName("Width" ) )->GetNumber(), pObject->GetDictionary().GetKey( PdfName("Height" ) )->GetNumber(), 255 ); char* pBuffer; pdf_long lLen; pObject->GetStream()->GetFilteredCopy( &pBuffer, &lLen ); fwrite( pBuffer, lLen, sizeof(char), hFile ); free( pBuffer ); } fclose( hFile ); ++m_nSuccess; } bool ImageExtractor::FileExists( const char* pszFilename ) { bool result = true; // if there is an error, it's probably because the file doesn't yet exist struct stat stBuf; if ( stat( pszFilename, &stBuf ) == -1 ) result = false; return result; } podofo-0.9.5/tools/podofoincrementalupdates/0000775000175000017500000000000013044451161021120 5ustar dominikdominikpodofo-0.9.5/tools/podofoincrementalupdates/CMakeLists.txt0000664000175000017500000000054311305305023023653 0ustar dominikdominikADD_EXECUTABLE(podofoincrementalupdates incrementalupdates.cpp) TARGET_LINK_LIBRARIES(podofoincrementalupdates ${PODOFO_LIB}) SET_TARGET_PROPERTIES(podofoincrementalupdates PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(podofoincrementalupdates ${PODOFO_DEPEND_TARGET}) INSTALL(TARGETS podofoincrementalupdates RUNTIME DESTINATION "bin") podofo-0.9.5/tools/podofoincrementalupdates/incrementalupdates.cpp0000664000175000017500000000707012715331116025520 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2009 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include using namespace PoDoFo; #ifdef _HAVE_CONFIG #include #endif // _HAVE_CONFIG void print_help() { printf("Usage: podofoincrementalupdates [-e N out.pdf] file.pdf\n\n"); printf(" This tool prints information of incremental updates to file.pdf.\n"); printf(" By default the number of incremental updates will be printed.\n"); printf(" -e N out.pdf\n"); printf(" Extract the Nth update from file.pdf and write it to out.pdf.\n"); printf("\nPoDoFo Version: %s\n\n", PODOFO_VERSION_STRING); } int get_info( const char* pszFilename ) { int nUpdates = 0; PdfVecObjects vecObjects; PdfParser parser( &vecObjects, pszFilename, true ); nUpdates = parser.GetNumberOfIncrementalUpdates(); printf( "%s\t=\t%i\t(Number of incremental updates)\n", pszFilename, nUpdates ); return nUpdates; } void extract(const char* PODOFO_UNUSED_PARAM(pszFilename), int PODOFO_UNUSED_PARAM(nExtract), const char* PODOFO_UNUSED_PARAM(pszOutputFilename)) { //int nUpdates = 0; PdfVecObjects vecObjects; PdfParser parser( &vecObjects ); //parser.ParseFile( pszOutputFilename, true, nExtract ); // TODO fprintf( stderr, "extraction is not implemented\n" ); exit( -2 ); } int main( int argc, char* argv[] ) { PdfError::EnableDebug( false ); if( argc != 2 && argc != 5 ) { print_help(); exit( -1 ); } try { const char* pszFilename; const char* pszOutputFilename; int nExtract = -1; if(argc == 2) { pszFilename = argv[1]; get_info(pszFilename); } else if(argc == 5) { nExtract = strtol(argv[2], NULL, 10); pszOutputFilename = argv[3]; pszFilename = argv[4]; extract(pszFilename, nExtract, pszOutputFilename); } } catch( PdfError & e ) { fprintf( stderr, "Error: An error %i ocurred during counting pages in the pdf file.\n", e.GetError() ); e.PrintErrorMsg(); return e.GetError(); } return 0; } podofo-0.9.5/tools/podofocrop/0000775000175000017500000000000013044451161016174 5ustar dominikdominikpodofo-0.9.5/tools/podofocrop/CMakeLists.txt0000664000175000017500000000042511426636344020747 0ustar dominikdominikADD_EXECUTABLE(podofocrop podofocrop.cpp) TARGET_LINK_LIBRARIES(podofocrop ${PODOFO_LIB}) SET_TARGET_PROPERTIES(podofocrop PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(podofocrop ${PODOFO_DEPEND_TARGET}) INSTALL(TARGETS podofocrop RUNTIME DESTINATION "bin") podofo-0.9.5/tools/podofocrop/podofocrop.cpp0000664000175000017500000001602113013650710021047 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #ifdef _WIN32 # include # ifdef GetObject # undef GetObject # endif #else # include # include # include #endif // _WIN32 using namespace PoDoFo; #ifdef _HAVE_CONFIG #include #endif // _HAVE_CONFIG void print_help() { printf("Usage: podofocrop input.pdf output.pdf\n"); printf(" This tool will crop all pages.\n"); printf(" It requires ghostscript to be in your PATH\n"); printf("\nPoDoFo Version: %s\n\n", PODOFO_VERSION_STRING); } void crop_page( PdfPage* pPage, const PdfRect & rCropBox ) { PdfVariant var; /* printf("%f %f %f %f\n", rCropBox.GetLeft(), rCropBox.GetBottom(), rCropBox.GetWidth(), rCropBox.GetHeight()); */ rCropBox.ToVariant( var ); pPage->GetObject()->GetDictionary().AddKey( PdfName("MediaBox"), var ); } std::string get_ghostscript_output( const char* pszInput ) { std::string sOutput; const int lBufferLen = 256; char buffer[lBufferLen]; #ifdef _WIN32 DWORD count; char cmd[lBufferLen]; STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); ZeroMemory( &pi, sizeof(pi) ); // Fenster nicht sichtbar si.dwFlags=STARTF_USESHOWWINDOW; si.wShowWindow=SW_HIDE; // Ausgabe umleiten HANDLE pipe; CreatePipe(&pipe, 0, 0, 0 ); si.dwFlags|=STARTF_USESTDHANDLES; //si.hStdOutput=pipe_wr; si.hStdError = pipe; _snprintf(cmd, lBufferLen, "gs -dSAFER -sDEVICE=bbox -sNOPAUSE -q %s -c quit", pszInput); printf("Running %s\n", cmd ); if( !CreateProcess( NULL, cmd, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi ) ) { printf("CreateProcess failed."); exit(1); } while( ReadFile(pipe,buffer,lBufferLen,&count,NULL) && GetLastError() != ERROR_BROKEN_PIPE && count > 0) { printf("%s",buffer); sOutput.append( buffer, count ); } // eigenes Handle schliessen CloseHandle(pipe); CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); #else pid_t pid; int p[2]; int count; pipe( p ); if( (pid = fork()) == 0 ) { // Child, launch ghostscript close( p[0] ); // Close unused read end dup2(p[1], 2); // redirect stderr to stdout dup2(p[1], 1); //printf("HELLO\n"); execlp( "gs", "gs", "-dSAFER", "-sDEVICE=bbox", "-sNOPAUSE", "-q", pszInput, "-c", "quit", NULL ); printf("Fatal error, cannot launch ghostscript\n"); exit(0); } else { close( p[1] ); // Close unused write end while( (count = read( p[0], buffer, lBufferLen )) > 0 ) { sOutput.append( buffer, count ); } wait(NULL); } #endif // _WIN32 return sOutput; } std::vector get_crop_boxes( const char* pszInput ) { std::vector rects; std::string sOutput = get_ghostscript_output( pszInput ); std::stringstream ss(sOutput); std::string sLine; PdfRect curRect; bool bHaveRect = false; while(std::getline(ss, sLine)) { if( strncmp( "%%BoundingBox: ", sLine.c_str(), 15 ) == 0 ) { int x, y, w, h; if( sscanf( sLine.c_str() + 15, "%i %i %i %i\n", &x, &y, &w, &h ) != 4 ) { printf( "Failed to read bounding box's four numbers from '%s'\n", sLine.c_str() + 15 ); exit( 1 ); } curRect = PdfRect( static_cast(x), static_cast(y), static_cast(w-x), static_cast(h-y) ); bHaveRect = true; } else if( strncmp( "%%HiResBoundingBox: ", sLine.c_str(), 17 ) == 0 ) { if( bHaveRect ) { // I have no idea, while gs writes BoundingBoxes twice to stdout .. printf("Using bounding box: [ %f %f %f %f ]\n", curRect.GetLeft(), curRect.GetBottom(), curRect.GetWidth(), curRect.GetHeight()); rects.push_back( curRect ); bHaveRect = false; } } } return rects; } int main( int argc, char* argv[] ) { PdfError::EnableDebug( false ); if( argc != 3 ) { print_help(); exit( -1 ); } const char* pszInput = argv[1]; const char* pszOutput = argv[2]; try { printf("Cropping file:\t%s\n", pszInput); printf("Writing to :\t%s\n", pszOutput); std::vector cropBoxes = get_crop_boxes( pszInput ); PdfMemDocument doc; doc.Load( pszInput ); if( static_cast(cropBoxes.size()) != doc.GetPageCount() ) { printf("Number of cropboxes obtained form ghostscript does not match with page count (%i, %i)\n", static_cast(cropBoxes.size()), doc.GetPageCount() ); PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } for( int i=0;i #include #include #include #include #include #include #include #include using namespace PoDoFo; static int print_errors_string( const char *str, size_t len, void *u ) { std::string *pstr = reinterpret_cast( u ); if( !pstr || !len || !str ) return 0; if( !pstr->empty() && (*pstr)[pstr->length() - 1] != '\n' ) *pstr += "\n"; *pstr += std::string( str, len ); // to continue return 1; } static void raise_podofo_error_with_opensslerror( const char *detail ) { std::string err; ERR_print_errors_cb( print_errors_string, &err ); if( err.empty() ) err = "Unknown OpenSSL error"; err = ": " + err; err = detail + err; PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, err.c_str() ); } static int pkey_password_cb( char *buf, int bufsize, int PODOFO_UNUSED_PARAM( rwflag ), void *userdata ) { const char *password = reinterpret_cast(userdata); if (!password) return 0; int res = strlen( password ); if (res > bufsize) res = bufsize; memcpy( buf, password, res ); return res; } static bool load_cert_and_key( const char *certfile, const char *pkeyfile, const char *pkey_password, X509 **out_cert, EVP_PKEY **out_pkey, pdf_int32 &min_signature_size ) { min_signature_size = 0; if( !certfile || !*certfile ) { std::cerr << "Certificate file not specified" << std::endl; return false; } if( !pkeyfile || !*pkeyfile ) { std::cerr << "Private key file not specified" << std::endl; return false; } // should not happen, but let's be paranoid if( !out_cert || !out_pkey ) { std::cerr << "Invalid call of load_cert_and_key" << std::endl; return false; } FILE *fp; fp = fopen( certfile, "rb" ); if( !fp ) { std::cerr << "Failed to open certificate file '" << certfile << "'" << std::endl; return false; } *out_cert = PEM_read_X509 (fp, NULL, NULL, NULL); if( fseeko( fp, 0, SEEK_END ) != -1 ) min_signature_size += ftello( fp ); else min_signature_size += 3072; fclose( fp ); if( !*out_cert ) { std::cerr << "Failed to decode certificate file '" << certfile << "'" << std::endl; std::string err; ERR_print_errors_cb( print_errors_string, &err ); if( !err.empty() ) std::cerr << err.c_str() << std::endl; return false; } fp = fopen( pkeyfile, "rb" ); if( !fp ) { X509_free( *out_cert ); *out_cert = NULL; std::cerr << "Failed to private key file '" << pkeyfile << "'" << std::endl; return false; } *out_pkey = PEM_read_PrivateKey( fp, NULL, pkey_password_cb, const_cast( pkey_password ) ); if( fseeko( fp, 0, SEEK_END ) != -1 ) min_signature_size += ftello( fp ); else min_signature_size += 1024; fclose( fp ); if( !*out_pkey ) { X509_free( *out_cert ); *out_cert = NULL; std::cerr << "Failed to decode private key file '" << pkeyfile << "'" << std::endl; std::string err; ERR_print_errors_cb( print_errors_string, &err ); if( !err.empty() ) std::cerr << err.c_str() << std::endl; return false; } return true; } static void sign_with_signer( PdfSignOutputDevice &signer, X509 *cert, EVP_PKEY *pkey ) { if( !cert ) PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "cert == NULL" ); if( !pkey ) PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "pkey == NULL" ); unsigned int uBufferLen = 65535, len; char *pBuffer; while( pBuffer = reinterpret_cast( podofo_malloc( sizeof( char ) * uBufferLen) ), !pBuffer ) { uBufferLen = uBufferLen / 2; if( !uBufferLen ) break; } if( !pBuffer ) PODOFO_RAISE_ERROR (ePdfError_OutOfMemory); int rc; BIO *mem = BIO_new( BIO_s_mem() ); if( !mem ) { podofo_free( pBuffer ); raise_podofo_error_with_opensslerror( "Failed to create input BIO" ); } unsigned int flags = PKCS7_DETACHED | PKCS7_BINARY; PKCS7 *pkcs7 = PKCS7_sign( cert, pkey, NULL, mem, flags ); if( !pkcs7 ) { BIO_free( mem ); podofo_free( pBuffer ); raise_podofo_error_with_opensslerror( "PKCS7_sign failed" ); } while( len = signer.ReadForSignature( pBuffer, uBufferLen ), len > 0 ) { rc = BIO_write( mem, pBuffer, len ); if( static_cast( rc ) != len ) { PKCS7_free( pkcs7 ); BIO_free( mem ); podofo_free( pBuffer ); raise_podofo_error_with_opensslerror( "BIO_write failed" ); } } podofo_free( pBuffer ); if( PKCS7_final( pkcs7, mem, flags ) <= 0 ) { PKCS7_free( pkcs7 ); BIO_free( mem ); raise_podofo_error_with_opensslerror( "PKCS7_final failed" ); } bool success = false; BIO *out = BIO_new( BIO_s_mem() ); if( !out ) { PKCS7_free( pkcs7 ); BIO_free( mem ); raise_podofo_error_with_opensslerror( "Failed to create output BIO" ); } char *outBuff = NULL; long outLen; i2d_PKCS7_bio( out, pkcs7 ); outLen = BIO_get_mem_data( out, &outBuff ); if( outLen > 0 && outBuff ) { if( static_cast( outLen ) > signer.GetSignatureSize() ) { PKCS7_free( pkcs7 ); BIO_free( out ); BIO_free( mem ); std::ostringstream oss; oss << "Requires at least " << outLen << " bytes for the signature, but reserved is only " << signer.GetSignatureSize() << " bytes"; PODOFO_RAISE_ERROR_INFO( ePdfError_ValueOutOfRange, oss.str().c_str() ); } PdfData signature( outBuff, outLen ); signer.SetSignature( signature ); success = true; } PKCS7_free( pkcs7 ); BIO_free( out ); BIO_free( mem ); if( !success ) raise_podofo_error_with_opensslerror( "Failed to get data from the output BIO" ); } static void print_help( bool bOnlyUsage ) { if( !bOnlyUsage ) { std::cout << "Digitally signs existing PDF file with the given certificate and private key." << std::endl; } std::cout << std::endl; std::cout << "Usage: podofosign [arguments]" << std::endl; std::cout << "The required arguments:" << std::endl; std::cout << " -in [inputfile] ... an input file to sign; if no -out is set, updates the input file" << std::endl; std::cout << " -cert [certfile] ... a file with a PEM-encoded certificate to include in the document" << std::endl; std::cout << " -pkey [pkeyfile] ... a file with a PEM-encoded private key to sign the document with" << std::endl; std::cout << "The optional arguments:" << std::endl; std::cout << " -out [outputfile] ... an output file to save the signed document to; cannot be the same as the input file" << std::endl; std::cout << " -password [password] ... a password to unlock the private key file" << std::endl; std::cout << " -reason [utf8-string] ... a UTF-8 encoded string with the reason of the signature; default reason is \"I agree\"" << std::endl; std::cout << " -sigsize [size] ... how many bytes to allocate for the signature; the default is derived from the certificate and private key file size" << std::endl; std::cout << " -field-name [name] ... field name to use; defaults to 'PoDoFoSignatureFieldXXX', where XXX is the object number" << std::endl; std::cout << " -field-use-existing ... whether to use existing signature field, if such named exists; the field type should be a signature" << std::endl; std::cout << " -annot-units [mm|inch] ... set units for the annotation positions; default is mm" << std::endl; std::cout << " -annot-position [page,left,top,width,height] ... where to place the annotation" << std::endl; std::cout << " page ... a 1-based page index (integer), where '1' means the first page, '2' the second, and so on" << std::endl; std::cout << " left,top,width,height ... a rectangle (in annot-units) where to place the annotation on the page (double)" << std::endl; std::cout << " -annot-print ... use that to have the annotation printable, otherwise it's not printed (the default is not to print it)" << std::endl; std::cout << " -annot-font [size,rrggbb,name] ... sets a font for the following annot-text; default is \"5,000000,Helvetica\" in mm" << std::endl; std::cout << " size ... the font size, in annot-units" << std::endl; std::cout << " rrggbb ... the font color, where rr is for red, gg for green and bb for blue, all two-digit hexa values between 00 and ff" << std::endl; std::cout << " name ... the font name to use; if a Base14 font is recognized, then it is used, instead of embedding a new font" << std::endl; std::cout << " -annot-text [left,top,utf8-string] ... a UTF-8 encoded string to add to the annotation" << std::endl; std::cout << " left,top ... the position (in annot-units, relative to annot-position) where to place the text (double)" << std::endl; std::cout << " text ... the actual UTF-8 encoded string to add to the annotation" << std::endl; std::cout << " -annot-image [left,top,width,height,filename] ... an image to add to the annotation" << std::endl; std::cout << " left,top,width,height ... a rectangle (in annot-units) where to place the image (double), relative to annot-position" << std::endl; std::cout << " filename ... a filname of the image to add" << std::endl; std::cout << "The annotation arguments can be repeated, except of the -annot-position and -annot-print, which can appear up to once." << std::endl; std::cout << "The -annot-print, -annot-font, -annot-text and -annot-image can appear only after -annot-position." << std::endl; std::cout << "All the left,top positions are treated with 0,0 being at the left-top of the page." << std::endl; std::cout << "No drawing is done when using existing field." << std::endl; } static double convert_to_pdf_units( const char *annot_units, double value ) { if( strcmp( annot_units, "mm" ) == 0 ) { return 72.0 * value / 25.4; } else if( strcmp( annot_units, "inch" ) == 0 ) { return 72.0 * value; } else { std::string err = "Unknown annotation unit '"; err += annot_units; err += "'"; PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidEnumValue, err.c_str() ); } } static bool parse_annot_position( const char *annot_position, const char *annot_units, int &annot_page, double &annot_left, double &annot_top, double &annot_width, double &annot_height ) { float fLeft, fTop, fWidth, fHeight; if( sscanf( annot_position, "%d,%f,%f,%f,%f", &annot_page, &fLeft, &fTop, &fWidth, &fHeight ) != 5 ) { return false; } annot_left = convert_to_pdf_units( annot_units, fLeft ); annot_top = convert_to_pdf_units( annot_units, fTop ); annot_width = convert_to_pdf_units( annot_units, fWidth ); annot_height = convert_to_pdf_units( annot_units, fHeight ); if( annot_page < 1) return false; annot_page--; return true; } static const char* skip_commas( const char* text, int ncommas ) { if( !text ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } const char *res = text; while( *res && ncommas > 0 ) { if( *res == ',' ) ncommas--; res++; } if( ncommas > 0 ) { std::string err = "The text '"; err += text; err += "' does not conform to the specified format (no enougt commas)"; PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, err.c_str() ); } return res; } static void draw_annotation( PdfDocument& document, PdfPainter& painter, int argc, char *argv[], const PdfRect &annot_rect ) { const char *annot_units = "mm"; double font_size = convert_to_pdf_units( "mm", 5.0 ); PdfColor font_color( 0.0, 0.0, 0.0 ); const char *font_name = "Helvetica"; bool bUpdateFont = true; int ii; for( ii = 1; ii < argc; ii++ ) { if( strcmp( argv[ii], "-annot-units" ) == 0 ) { annot_units = argv[ii + 1]; } else if( strcmp( argv[ii], "-annot-font" ) == 0 ) { float fSize; int rr, gg, bb; if( sscanf( argv[ii + 1], "%f,%02x%02x%02x,", &fSize, &rr, &gg, &bb ) != 4 ) { std::string err = "The value for -annot-font '"; err += argv[ii + 1]; err += "' doesn't conform to format 'size,rrggbb,name'"; PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, err.c_str() ); } font_size = convert_to_pdf_units( annot_units, fSize ); font_color = PdfColor( static_cast( rr ) / 255.0, static_cast( gg ) / 255.0, static_cast( bb ) / 255.0 ); font_name = skip_commas( argv[ii + 1], 2 ); bUpdateFont = true; } else if( strcmp( argv[ii], "-annot-text" ) == 0 ) { float fLeft, fTop; if( sscanf( argv[ii + 1], "%f,%f,", &fLeft, &fTop ) != 2 ) { std::string err = "The value for -annot-text '"; err += argv[ii + 1]; err += "' doesn't conform to format 'left,top,text'"; PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, err.c_str() ); } const char *text = skip_commas( argv[ii + 1], 2 ); if( bUpdateFont ) { PdfFont* pFont; pFont = document.CreateFont( font_name, false, false, false ); if( !pFont ) { std::string err = "Failed to create font '"; err += font_name; err += "'"; PODOFO_RAISE_ERROR_INFO( ePdfError_OutOfMemory, err.c_str() ); } pFont->SetFontSize( font_size ); painter.SetFont( pFont ); painter.SetColor( font_color ); } fLeft = convert_to_pdf_units( annot_units, fLeft ); fTop = convert_to_pdf_units( annot_units, fTop ); painter.DrawMultiLineText( fLeft, 0.0, annot_rect.GetWidth() - fLeft, annot_rect.GetHeight() - fTop, PdfString( reinterpret_cast( text ) )); } else if( strcmp( argv[ii], "-annot-image" ) == 0 ) { float fLeft, fTop, fWidth, fHeight; if( sscanf( argv[ii + 1], "%f,%f,%f,%f,", &fLeft, &fTop, &fWidth, &fHeight ) != 4 ) { std::string err = "The value for -annot-image '"; err += argv[ii + 1]; err += "' doesn't conform to format 'left,top,width,height,filename'"; PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDataType, err.c_str() ); } const char *filename = skip_commas( argv[ii + 1], 4 ); fLeft = convert_to_pdf_units( annot_units, fLeft ); fTop = convert_to_pdf_units( annot_units, fTop ); fWidth = convert_to_pdf_units( annot_units, fWidth ); fHeight = convert_to_pdf_units( annot_units, fHeight ); PdfImage image( &document ); image.LoadFromFile( filename ); double dScaleX = fWidth / image.GetWidth(); double dScaleY = fHeight / image.GetHeight(); painter.DrawImage( fLeft, annot_rect.GetHeight() - fTop - fHeight, &image, dScaleX, dScaleY ); } // these are the only parameters without additional value if( strcmp( argv[ii], "-annot-print" ) != 0 && strcmp( argv[ii], "-field-use-existing" ) != 0 ) ii++; } } static PdfObject* find_existing_signature_field( PdfAcroForm* pAcroForm, const PdfString& name ) { if( !pAcroForm ) PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); PdfObject* pFields = pAcroForm->GetObject()->GetDictionary().GetKey( PdfName( "Fields" ) ); if( pFields ) { if( pFields->GetDataType() == ePdfDataType_Reference ) pFields = pAcroForm->GetDocument()->GetObjects()->GetObject( pFields->GetReference() ); if( pFields && pFields->GetDataType() == ePdfDataType_Array ) { PdfArray &rArray = pFields->GetArray(); PdfArray::iterator it, end = rArray.end(); for( it = rArray.begin(); it != end; it++ ) { // require references in the Fields array if( it->GetDataType() == ePdfDataType_Reference ) { PdfObject *item = pAcroForm->GetDocument()->GetObjects()->GetObject( it->GetReference() ); if( item && item->GetDictionary().HasKey( PdfName( "T" ) ) && item->GetDictionary().GetKey( PdfName( "T" ) )->GetString() == name ) { // found a field with the same name const PdfObject *pFT = item->GetDictionary().GetKey( PdfName( "FT" ) ); if( !pFT && item->GetDictionary().HasKey( PdfName( "Parent" ) ) ) { const PdfObject *pTemp = item->GetIndirectKey( PdfName( "Parent" ) ); if( !pTemp ) { PODOFO_RAISE_ERROR( ePdfError_InvalidDataType ); } pFT = pTemp->GetDictionary().GetKey( PdfName( "FT" ) ); } if( !pFT ) { PODOFO_RAISE_ERROR( ePdfError_NoObject ); } const PdfName fieldType = pFT->GetName(); if( fieldType != PdfName( "Sig" ) ) { std::string err = "Existing field '"; err += name.GetString(); err += "' isn't of a signature type, but '"; err += fieldType.GetName().c_str(); err += "' instead"; PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidName, err.c_str() ); } return item; } } } } } return NULL; } #if 0 /* TODO */ static void update_default_appearance_streams( PdfAcroForm* pAcroForm ) { if( !pAcroForm || !pAcroForm->GetObject()->GetDictionary().HasKey( "Fields" ) || pAcroForm->GetObject()->GetDictionary().GetKey( "Fields" )->GetDataType() != ePdfDataType_Array ) return; PdfArray& rFields = pAcroForm->GetObject()->GetDictionary().GetKey( "Fields" )->GetArray(); PdfArray::iterator it, end = rFields.end(); for( it = rFields.begin(); it != end; it++ ) { if( it->GetDataType() == ePdfDataType_Reference ) { PdfObject *pObject = pAcroForm->GetDocument()->GetObjects()->GetObject( it->GetReference() ); if( !pObject || pObject->GetDataType() != ePdfDataType_Dictionary ) continue; PdfDictionary &rFielDict = pObject->GetDictionary(); if( rFielDict.HasKey( "FT" ) && rFielDict.GetKey( "FT" )->GetDataType() == ePdfDataType_Name && (rFielDict.GetKey( "FT" )->GetName() == PdfName( "Tx" ) || rFielDict.GetKey( "FT" )->GetName() == PdfName( "Ch" ) ) ) { PdfString rDA, rV, rDV; if( rFielDict.HasKey( "V" ) && ( rFielDict.GetKey( "V" )->GetDataType() == ePdfDataType_String || rFielDict.GetKey( "V" )->GetDataType() == ePdfDataType_HexString ) ) { rV = rFielDict.GetKey( "V" )->GetString(); } if( rFielDict.HasKey( "DV" ) && ( rFielDict.GetKey( "DV" )->GetDataType() == ePdfDataType_String || rFielDict.GetKey( "DV" )->GetDataType() == ePdfDataType_HexString ) ) { rDV = rFielDict.GetKey( "DV" )->GetString(); } if( rV.IsValid() && rV.GetCharacterLength() > 0 ) { rDV = rV; } if( !rDV.IsValid() || rDV.GetCharacterLength() <= 0 ) continue; if( rDV.GetLength() >= 2 && rDV.GetString()[0] == static_cast( 0xFE ) && rDV.GetString()[1] == static_cast( 0xFF ) ) { if( rDV.GetLength() == 2 ) continue; } if( rFielDict.HasKey( "DA" ) && rFielDict.GetKey( "DA" )->GetDataType() == ePdfDataType_String ) { rDA = rFielDict.GetKey( "DA" )->GetString(); } if( rFielDict.HasKey( "AP" ) && rFielDict.GetKey( "AP" )->GetDataType() == ePdfDataType_Dictionary && rFielDict.GetKey( "AP" )->GetDictionary().HasKey( "N" ) && rFielDict.GetKey( "AP" )->GetDictionary().GetKey( "N" )->GetDataType() == ePdfDataType_Reference ) { pObject = pAcroForm->GetDocument()->GetObjects()->GetObject( rFielDict.GetKey( "AP" )->GetDictionary().GetKey( "N" )->GetReference() ); if( pObject->GetDataType() == ePdfDataType_Dictionary && pObject->GetDictionary().HasKey( "Type" ) && pObject->GetDictionary().GetKey( "Type" )->GetDataType() == ePdfDataType_Name && pObject->GetDictionary().GetKey( "Type" )->GetName() == PdfName( "XObject" ) ) { PdfXObject xObject(pObject); PdfStream *pCanvas = xObject.GetContentsForAppending()->GetStream(); if( rFielDict.GetKey( "FT" )->GetName() == PdfName( "Tx" ) ) { pCanvas->BeginAppend(true); PdfRefCountedBuffer rBuffer; PdfOutputDevice rOutputDevice( &rBuffer ); rDV.Write( &rOutputDevice, ePdfWriteMode_Compact ); std::ostringstream oss; oss << "/Tx BMC" << std::endl; oss << "BT" << std::endl; if( rDA.IsValid() ) oss << rDA.GetString() << std::endl; oss << "2.0 2.0 Td" << std::endl; oss << rBuffer.GetBuffer() << " Tj" << std::endl; oss << "ET" << std::endl; oss << "EMC" << std::endl; pCanvas->Append( oss.str() ); pCanvas->EndAppend(); } else if( rFielDict.GetKey( "FT" )->GetName() == PdfName( "Ch" ) ) { } } } } } } } #endif int main( int argc, char* argv[] ) { const char *inputfile = NULL; const char *outputfile = NULL; const char *certfile = NULL; const char *pkeyfile = NULL; const char *password = NULL; const char *reason = "I agree"; const char *sigsizestr = NULL; const char *annot_units = "mm"; const char *annot_position = NULL; const char *field_name = NULL; int annot_page = 0; double annot_left = 0.0, annot_top = 0.0, annot_width = 0.0, annot_height = 0.0; bool annot_print = false; bool field_use_existing = false; int ii; PdfError::EnableDebug( false ); for( ii = 1; ii < argc; ii++ ) { const char **value = NULL; if( strcmp( argv[ii], "-in" ) == 0 ) { value = &inputfile; } else if( strcmp( argv[ii], "-out" ) == 0 ) { value = &outputfile; } else if( strcmp( argv[ii], "-cert" ) == 0 ) { value = &certfile; } else if( strcmp( argv[ii], "-pkey" ) == 0 ) { value = &pkeyfile; } else if( strcmp( argv[ii], "-password" ) == 0 ) { value = &password; } else if( strcmp( argv[ii], "-reason" ) == 0 ) { value = &reason; } else if( strcmp( argv[ii], "-sigsize" ) == 0 ) { value = &sigsizestr; } else if( strcmp( argv[ii], "-annot-units" ) == 0 ) { value = &annot_units; } else if( strcmp( argv[ii], "-annot-position" ) == 0 ) { if( annot_position ) { std::cerr << "Only one -annot-position can be specified" << std::endl; return -1; } value = &annot_position; } else if( strcmp( argv[ii], "-annot-print" ) == 0 ) { if( !annot_position ) { std::cerr << "Missing -annot-position argument, which should be defined before '" << argv[ii] << "'" << std::endl; return -2; } if( annot_print ) { std::cerr << "Only one -annot-print can be specified" << std::endl; return -1; } annot_print = !annot_print; continue; } else if( strcmp( argv[ii], "-annot-font" ) == 0 || strcmp( argv[ii], "-annot-text" ) == 0 || strcmp( argv[ii], "-annot-image" ) == 0 ) { if( !annot_position ) { std::cerr << "Missing -annot-position argument, which should be defined before '" << argv[ii] << "'" << std::endl; return -2; } // value is left NULL, these are parsed later } else if( strcmp( argv[ii], "-field-name" ) == 0 ) { value = &field_name; } else if( strcmp( argv[ii], "-field-use-existing" ) == 0 ) { if( field_use_existing ) { std::cerr << "Only one -field-use-existing can be specified" << std::endl; return -1; } field_use_existing = !field_use_existing; continue; } else { std::cerr << "Unknown argument '" << argv[ii] << "'" << std::endl; print_help( true ); return -3; } if( ii + 1 >= argc) { std::cerr << "Missing value for argument '" << argv[ii] << "'" << std::endl; print_help( true ); return -4; } if( value ) { *value = argv[ii + 1]; if( *value == annot_units && strcmp( annot_units, "mm" ) != 0 && strcmp( annot_units, "inch" ) != 0 ) { std::cerr << "Invalid -annot-units value '" << *value << "', only 'mm' and 'inch' are supported" << std::endl; return -5; } try { if( *value == annot_position && !parse_annot_position( annot_position, annot_units, annot_page, annot_left, annot_top, annot_width, annot_height ) ) { std::cerr << "Invalid -annot-position value '" << *value << "', expected format \"page,left,top,width,height\"" << std::endl; return -6; } } catch( PdfError & e ) { std::cerr << "Invalid -annot-position value '" << *value << "', expected format \"page,left,top,width,height\"" << std::endl; return -6; } } ii++; } if( !inputfile || !certfile || !pkeyfile ) { if( argc != 1 ) std::cerr << "Not all required arguments specified." << std::endl; print_help( true ); return -7; } int sigsize = -1; if( sigsizestr ) { sigsize = atoi( sigsizestr ); if( sigsize <= 0 ) { std::cerr << "Invalid value for signature size specified (" << sigsizestr << "), use a positive integer, please" << std::endl; return -8; } } if( outputfile && strcmp( outputfile, inputfile ) == 0) { // even I told you not to do it, you still specify the same output file // as the input file. Just ignore that. outputfile = NULL; } OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); ERR_load_PEM_strings(); ERR_load_ASN1_strings(); ERR_load_EVP_strings(); X509* cert = NULL; EVP_PKEY* pkey = NULL; pdf_int32 min_signature_size = 0; if( !load_cert_and_key( certfile, pkeyfile, password, &cert, &pkey, min_signature_size ) ) { return -9; } if( sigsize > 0 ) min_signature_size = sigsize; int result = 0; PdfSignatureField *pSignField = NULL; PdfAnnotation *pTemporaryAnnot = NULL; // for existing signature fields try { PdfMemDocument document; document.Load( inputfile, true ); if( !document.GetPageCount() ) PODOFO_RAISE_ERROR_INFO( ePdfError_PageNotFound, "The document has no page. Only documents with at least one page can be signed" ); PdfAcroForm* pAcroForm = document.GetAcroForm(); if( !pAcroForm ) PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "acroForm == NULL" ); if( !pAcroForm->GetObject()->GetDictionary().HasKey( PdfName( "SigFlags" ) ) || !pAcroForm->GetObject()->GetDictionary().GetKey( PdfName( "SigFlags" ) )->IsNumber() || pAcroForm->GetObject()->GetDictionary().GetKeyAsLong( PdfName( "SigFlags" ) ) != 3 ) { if( pAcroForm->GetObject()->GetDictionary().HasKey( PdfName( "SigFlags" ) ) ) pAcroForm->GetObject()->GetDictionary().RemoveKey( PdfName( "SigFlags" ) ); pdf_int64 val = 3; pAcroForm->GetObject()->GetDictionary().AddKey( PdfName( "SigFlags" ), PdfObject( val ) ); } if( pAcroForm->GetNeedAppearances() ) { #if 0 /* TODO */ update_default_appearance_streams( pAcroForm ); #endif pAcroForm->SetNeedAppearances( false ); } PdfOutputDevice outputDevice( outputfile ? outputfile : inputfile, outputfile != NULL ); PdfSignOutputDevice signer( &outputDevice ); PdfString name; PdfObject* pExistingSigField = NULL; if( field_name ) { name = PdfString( field_name ); pExistingSigField = find_existing_signature_field( pAcroForm, name ); if( pExistingSigField && !field_use_existing) { std::string err = "Signature field named '"; err += name.GetString(); err += "' already exists"; PODOFO_RAISE_ERROR_INFO( ePdfError_WrongDestinationType, err.c_str() ); } } else { char fldName[96]; // use bigger buffer to make sure sprintf does not overflow sprintf( fldName, "PodofoSignatureField%" PDF_FORMAT_INT64, static_cast( document.GetObjects().GetObjectCount() ) ); name = PdfString( fldName ); } if( pExistingSigField ) { if( !pExistingSigField->GetDictionary().HasKey( "P" ) ) { std::string err = "Signature field named '"; err += name.GetString(); err += "' doesn't have a page reference"; PODOFO_RAISE_ERROR_INFO( ePdfError_PageNotFound, err.c_str() ); } PdfPage* pPage; pPage = document.GetPagesTree()->GetPage( pExistingSigField->GetDictionary().GetKey( "P" )->GetReference() ); if( !pPage ) PODOFO_RAISE_ERROR( ePdfError_PageNotFound ); pTemporaryAnnot = new PdfAnnotation( pExistingSigField, pPage ); if( !pTemporaryAnnot ) PODOFO_RAISE_ERROR_INFO( ePdfError_OutOfMemory, "Cannot allocate annotation object for existing signature field" ); pSignField = new PdfSignatureField( pTemporaryAnnot ); if( !pSignField ) PODOFO_RAISE_ERROR_INFO( ePdfError_OutOfMemory, "Cannot allocate existing signature field object" ); pSignField->EnsureSignatureObject(); } else { PdfPage* pPage = document.GetPage( annot_page ); if( !pPage ) PODOFO_RAISE_ERROR( ePdfError_PageNotFound ); PdfRect annot_rect; if( annot_position ) { annot_rect = PdfRect( annot_left, pPage->GetPageSize().GetHeight() - annot_top - annot_height, annot_width, annot_height ); } PdfAnnotation* pAnnot = pPage->CreateAnnotation( ePdfAnnotation_Widget, annot_rect ); if( !pAnnot ) PODOFO_RAISE_ERROR_INFO( ePdfError_OutOfMemory, "Cannot allocate annotation object" ); if( annot_position && annot_print ) pAnnot->SetFlags( ePdfAnnotationFlags_Print ); else if( !annot_position && ( !field_name || !field_use_existing ) ) pAnnot->SetFlags( ePdfAnnotationFlags_Invisible | ePdfAnnotationFlags_Hidden ); pSignField = new PdfSignatureField( pAnnot, pAcroForm, &document ); if( !pSignField ) PODOFO_RAISE_ERROR_INFO( ePdfError_OutOfMemory, "Cannot allocate signature field object" ); if( annot_position ) { PdfRect annotSize( 0.0, 0.0, annot_rect.GetWidth(), annot_rect.GetHeight() ); PdfXObject sigXObject( annotSize, &document ); PdfPainter painter; try { painter.SetPage( &sigXObject ); /* Workaround Adobe's reader error 'Expected a dict object.' when the stream contains only one object which does Save()/Restore() on its own, like the image XObject. */ painter.Save(); painter.Restore(); draw_annotation( document, painter, argc, argv, annot_rect ); pSignField->SetAppearanceStream( &sigXObject ); } catch( PdfError & e ) { if( painter.GetPage() ) { try { painter.FinishPage(); } catch( ... ) { } } } painter.FinishPage(); } } // use large-enough buffer to hold the signature with the certificate signer.SetSignatureSize( min_signature_size ); pSignField->SetFieldName( name ); pSignField->SetSignatureReason( PdfString( reinterpret_cast( reason ) ) ); pSignField->SetSignatureDate( PdfDate() ); pSignField->SetSignature( *signer.GetSignatureBeacon() ); // The outputfile != NULL means that the write happens to a new file, // which will be truncated first and then the content of the inputfile // will be copied into the document, follwed by the changes. document.WriteUpdate( &signer, outputfile != NULL ); if( !signer.HasSignaturePosition() ) PODOFO_RAISE_ERROR_INFO( ePdfError_SignatureError, "Cannot find signature position in the document data" ); // Adjust ByteRange for signature signer.AdjustByteRange(); // Read data for signature and count it // We seek at the beginning of the file signer.Seek( 0 ); sign_with_signer( signer, cert, pkey ); signer.Flush(); } catch( PdfError & e ) { std::cerr << "Error: An error " << e.GetError() << " occurred during the sign of the pdf file:" << std::endl; e.PrintErrorMsg(); result = e.GetError(); } ERR_free_strings(); if( pSignField ) delete pSignField; if( pTemporaryAnnot ) delete pTemporaryAnnot; if( pkey ) EVP_PKEY_free( pkey ); if( cert ) X509_free( cert ); return result; } podofo-0.9.5/tools/podofouncompress/0000775000175000017500000000000013044451161017427 5ustar dominikdominikpodofo-0.9.5/tools/podofouncompress/podofouncompress.cpp0000664000175000017500000000473511460071654023556 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "Uncompress.h" #include #include #include using namespace PoDoFo; #ifdef _HAVE_CONFIG #include #endif // _HAVE_CONFIG void print_help() { printf("Usage: podofouncompress [inputfile] [outputfile]\n\n"); printf(" This tool removes all compression from the PDF file.\n"); printf(" It is useful for debugging errors in PDF files or analysing their structure.\n"); printf("\nPoDoFo Version: %s\n\n", PODOFO_VERSION_STRING); } int main( int argc, char* argv[] ) { char* pszInput; char* pszOutput; UnCompress unc; if( argc != 3 ) { print_help(); exit( -1 ); } pszInput = argv[1]; pszOutput = argv[2]; // try { unc.Init( pszInput, pszOutput ); /* } catch( PdfError & e ) { fprintf( stderr, "Error: An error %i ocurred during uncompressing the pdf file.\n", e.GetError() ); e.PrintErrorMsg(); return e.GetError(); } */ printf("%s was sucessfully uncompressed to: %s\n", pszInput, pszOutput ); return 0; } podofo-0.9.5/tools/podofouncompress/Uncompress.cpp0000664000175000017500000000706413013650710022275 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "Uncompress.h" #include using namespace PoDoFo; UnCompress::UnCompress() : m_pDocument( NULL ) { } UnCompress::~UnCompress() { delete m_pDocument; } void UnCompress::Init( const char* pszInput, const char* pszOutput ) { if( m_pDocument ) delete m_pDocument; m_pDocument = new PdfMemDocument( pszInput ); this->UncompressObjects(); PdfWriter writer( &(m_pDocument->GetObjects()), new PdfObject( *(m_pDocument->GetTrailer() ) ) ); writer.SetWriteMode( ePdfWriteMode_Clean ); writer.Write( pszOutput ); } void UnCompress::UncompressObjects() { TIVecObjects it = m_pDocument->GetObjects().begin(); while( it != m_pDocument->GetObjects().end() ) { printf("Reading %i %i R\n", (*it)->Reference().ObjectNumber(), (*it)->Reference().GenerationNumber() ); if( (*it)->HasStream() ) { try { printf("-> Uncompressing object %i %i\n", (*it)->Reference().ObjectNumber(), (*it)->Reference().GenerationNumber() ); PdfMemStream* pStream = dynamic_cast((*it)->GetStream()); if( !pStream ) PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); printf("-> Original Length: %" PDF_FORMAT_INT64 "\n", static_cast(pStream->GetLength()) ); try { pStream->Uncompress(); } catch( PdfError & e ) { if( e.GetError() == ePdfError_Flate ) { // Ignore ZLib errors fprintf( stderr, "WARNING: ZLib error ignored for this object.\n"); } else throw e; } printf("-> Uncompressed Length: %" PDF_FORMAT_INT64 "\n", static_cast(pStream->GetLength()) ); } catch( PdfError & e ) { e.PrintErrorMsg(); if( e.GetError() != ePdfError_UnsupportedFilter ) throw e; } } ++it; } } podofo-0.9.5/tools/podofouncompress/CMakeLists.txt0000664000175000017500000000050710517314571022176 0ustar dominikdominikADD_EXECUTABLE(podofouncompress Uncompress.cpp podofouncompress.cpp) TARGET_LINK_LIBRARIES(podofouncompress ${PODOFO_LIB}) SET_TARGET_PROPERTIES(podofouncompress PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(podofouncompress ${PODOFO_DEPEND_TARGET}) INSTALL(TARGETS podofouncompress RUNTIME DESTINATION "bin") podofo-0.9.5/tools/podofouncompress/Uncompress.h0000664000175000017500000000341110646124303021735 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _UNCOMPRESS_H_ #define _UNCOMPRESS_H_ #include using namespace PoDoFo; class UnCompress { public: UnCompress(); ~UnCompress(); void Init( const char* pszInput, const char* pszOutput ); private: void UncompressObjects(); private: PdfMemDocument* m_pDocument; }; #endif // _UNCOMPRESS_H_ podofo-0.9.5/tools/podofopdfinfo/0000775000175000017500000000000013044451161016656 5ustar dominikdominikpodofo-0.9.5/tools/podofopdfinfo/CMakeLists.txt0000664000175000017500000000046210517314571021425 0ustar dominikdominikADD_EXECUTABLE(podofopdfinfo pdfinfo.cpp podofopdfinfo.cpp) TARGET_LINK_LIBRARIES(podofopdfinfo ${PODOFO_LIB}) SET_TARGET_PROPERTIES(podofopdfinfo PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(podofopdfinfo ${PODOFO_DEPEND_TARGET}) INSTALL(TARGETS podofopdfinfo RUNTIME DESTINATION "bin") podofo-0.9.5/tools/podofopdfinfo/pdfinfo.cpp0000664000175000017500000002275611515074452021030 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "pdfinfo.h" PdfInfo::PdfInfo( const std::string& inPathname ) { mDoc = new PoDoFo::PdfMemDocument( inPathname.c_str() ); } PdfInfo::~PdfInfo() { if ( mDoc ) { delete mDoc; mDoc = NULL; } } void PdfInfo::OutputDocumentInfo( std::ostream& sOutStream ) { sOutStream << "\tPDF Version: " << PoDoFo::s_szPdfVersionNums[static_cast(mDoc->GetPdfVersion())] << std::endl; sOutStream << "\tPage Count: " << mDoc->GetPageCount() << std::endl; sOutStream << "\tPage Size: " << GuessFormat() << std::endl; sOutStream << std::endl; sOutStream << "\tFast Web View Enabled: " << (mDoc->IsLinearized() ? "Yes" : "No") << std::endl; sOutStream << "\tTagged: " << (static_cast(mDoc)->GetStructTreeRoot() != NULL ? "Yes" : "No") << std::endl; sOutStream << "\tEncrypted: " << (static_cast(mDoc)->GetEncrypted() ? "Yes" : "No") << std::endl; sOutStream << "\tPrinting Allowed: " << (mDoc->IsPrintAllowed() ? "Yes" : "No") << std::endl; sOutStream << "\tModification Allowed: " << (mDoc->IsEditAllowed() ? "Yes" : "No") << std::endl; sOutStream << "\tCopy&Paste Allowed: " << (mDoc->IsCopyAllowed() ? "Yes" : "No") << std::endl; sOutStream << "\tAdd/Modify Annotations Allowed: " << (mDoc->IsEditNotesAllowed() ? "Yes" : "No") << std::endl; sOutStream << "\tFill&Sign Allowed: " << (mDoc->IsFillAndSignAllowed() ? "Yes" : "No") << std::endl; sOutStream << "\tAccessibility Allowed: " << (mDoc->IsAccessibilityAllowed() ? "Yes" : "No") << std::endl; sOutStream << "\tDocument Assembly Allowed: " << (mDoc->IsDocAssemblyAllowed() ? "Yes" : "No") << std::endl; sOutStream << "\tHigh Quality Print Allowed: " << (mDoc->IsHighPrintAllowed() ? "Yes" : "No") << std::endl; } void PdfInfo::OutputInfoDict( std::ostream& sOutStream ) { if( !mDoc->GetInfo() ) sOutStream << "No info dictionary in this PDF file!" << std::endl; else { sOutStream << "\tAuthor: " << mDoc->GetInfo()->GetAuthor().GetStringUtf8() << std::endl; sOutStream << "\tCreator: " << mDoc->GetInfo()->GetCreator().GetStringUtf8() << std::endl; sOutStream << "\tSubject: " << mDoc->GetInfo()->GetSubject().GetStringUtf8() << std::endl; sOutStream << "\tTitle: " << mDoc->GetInfo()->GetTitle().GetStringUtf8() << std::endl; sOutStream << "\tKeywords: " << mDoc->GetInfo()->GetKeywords().GetStringUtf8() << std::endl; sOutStream << "\tTrapped: " << mDoc->GetInfo()->GetTrapped().GetEscapedName() << std::endl; } } void PdfInfo::OutputPageInfo( std::ostream& sOutStream ) { PoDoFo::PdfPage* curPage; PoDoFo::PdfAnnotation* curAnnot; PoDoFo::PdfVariant var; std::string str; int annotCount; int pgCount = mDoc->GetPageCount(); sOutStream << "Page Count: " << pgCount << std::endl; for ( int pg=0; pgGetPage( pg ); sOutStream << "->Internal Number:" << curPage->GetPageNumber() << std::endl; sOutStream << "->Object Number:" << curPage->GetObject()->Reference().ObjectNumber() << " " << curPage->GetObject()->Reference().GenerationNumber() << " R" << std::endl; curPage->GetMediaBox().ToVariant( var ); var.ToString( str ); annotCount = curPage->GetNumAnnots(); sOutStream << "\tMediaBox: " << str << std::endl; sOutStream << "\tRotation: " << curPage->GetRotation() << std::endl; sOutStream << "\t# of Annotations: " << annotCount << std::endl; for( int i=0; i < annotCount; i++ ) { curAnnot = curPage->GetAnnotation( i ); curAnnot->GetRect().ToVariant( var ); var.ToString( str ); sOutStream << std::endl; sOutStream << "\tAnnotation " << i << std::endl; sOutStream << "\t\tType: " << curAnnot->GetType() << std::endl; sOutStream << "\t\tContents: " << curAnnot->GetContents().GetStringUtf8() << std::endl; sOutStream << "\t\tTitle: " << curAnnot->GetTitle().GetStringUtf8() << std::endl; sOutStream << "\t\tFlags: " << curAnnot->GetFlags() << std::endl; sOutStream << "\t\tRect: " << str << std::endl; sOutStream << "\t\tOpen: " << (curAnnot->GetOpen() ? "true" : "false" ) << std::endl; if( curAnnot->GetType() == PoDoFo::ePdfAnnotation_Link ) { sOutStream << "\t\tLink Target: " << curAnnot->GetType() << std::endl; if( curAnnot->HasAction() && curAnnot->GetAction()->HasURI() ) sOutStream << "\t\tAction URI: " << curAnnot->GetAction()->GetURI().GetStringUtf8() << std::endl; } } } } void PdfInfo::OutputOutlines( std::ostream& sOutStream, PoDoFo::PdfOutlineItem* pItem, int level ) { PoDoFo::PdfOutlines* pOutlines; int i; if( !pItem ) { pOutlines = mDoc->GetOutlines( PoDoFo::ePdfDontCreateObject ); if ( !pOutlines || !pOutlines->First() ) { sOutStream << "\tNone Found" << std::endl; return; } pItem = pOutlines->First(); } for( i=0;i" << pItem->GetTitle().GetString(); PoDoFo::PdfDestination* pDest = pItem->GetDestination( mDoc ); if ( pDest ) { // then it's a destination PoDoFo::PdfPage* pPage = pDest->GetPage( mDoc ); if( pPage ) sOutStream << "\tDestination: Page #" << pPage->GetPageNumber(); else sOutStream << "\tDestination: Page #" << "???"; } else { // then it's one or more actions sOutStream << "\tAction: " << "???"; } sOutStream << std::endl; if( pItem->First() ) this->OutputOutlines( sOutStream, pItem->First(), level+1 ); if( pItem->Next() ) this->OutputOutlines( sOutStream, pItem->Next(), level ); } void PdfInfo::OutputOneName( std::ostream& sOutStream, PoDoFo::PdfNamesTree* inTreeObj, const std::string& inTitle, const std::string& inKey ) { sOutStream << "\t" << inTitle << std::endl; PoDoFo::PdfDictionary dict; inTreeObj->ToDictionary( PoDoFo::PdfName( inKey ), dict ); const PoDoFo::TKeyMap& keys = dict.GetKeys(); PoDoFo::TCIKeyMap it = keys.begin(); std::string str; while( it != keys.end() ) { (*it).second->ToString( str ); sOutStream << "\t-> " << (*it).first.GetName().c_str() << "=" << str << std::endl; ++it; } sOutStream << std::endl; } void PdfInfo::OutputNames( std::ostream& sOutStream ) { PoDoFo::PdfNamesTree* namesObj = mDoc->GetNamesTree( PoDoFo::ePdfDontCreateObject ); if ( namesObj ) { OutputOneName( sOutStream, namesObj, "Destinations", "Dests" ); OutputOneName( sOutStream, namesObj, "JavaScripts", "JavaScript" ); OutputOneName( sOutStream, namesObj, "Embedded Files", "EmbeddedFiles" ); } else { sOutStream << "\t\tNone Found" << std::endl; } } std::string PdfInfo::GuessFormat() { typedef std::pair Format; PoDoFo::PdfPage* curPage; int pgCount = mDoc->GetPageCount(); std::map< Format , int > sizes; std::map< Format , int >::iterator sIt; PoDoFo::PdfRect rect; for ( int pg=0; pgGetPage( pg ); rect = curPage->GetMediaBox(); Format s( rect.GetWidth() - rect.GetLeft(), rect.GetHeight() - rect.GetBottom()); sIt = sizes.find(s); if(sIt == sizes.end()) sizes.insert(std::pair(s,1)); else ++(sIt->second); } Format format; std::stringstream ss; if(sizes.size() == 1) { format = sizes.begin()->first; ss << format.first << " x " << format.second << " pts" ; } else { // We’re looking for the most represented format int max=0; for(sIt = sizes.begin();sIt != sizes.end(); ++sIt) { if(sIt->second > max) { max = sIt->second; format = sIt->first; } } ss << format.first << " x " << format.second << " pts "< #include class PdfInfo { public: PdfInfo( const std::string& inPathname ); virtual ~PdfInfo(); void OutputDocumentInfo( std::ostream& sOutStream ); void OutputInfoDict( std::ostream& sOutStream ); void OutputPageInfo( std::ostream& sOutStream ); void OutputOutlines( std::ostream& sOutStream, PoDoFo::PdfOutlineItem* pFirst = NULL, int level = 0 ); void OutputNames( std::ostream& sOutStream ); private: PoDoFo::PdfDocument* mDoc; void OutputOneName( std::ostream& sOutStream, PoDoFo::PdfNamesTree* inTreeObj, const std::string& inTitle, const std::string& inKey ); std::string GuessFormat(); }; #endif // _PDFINFO_H podofo-0.9.5/tools/podofopdfinfo/podofopdfinfo.cpp0000664000175000017500000001111711515074452022224 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2005 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include "pdfinfo.h" #include #include #ifdef _HAVE_CONFIG #include #endif // _HAVE_CONFIG void print_help() { printf("Usage: podofopdfinfo [DCPON] [inputfile] \n\n"); printf(" This tool displays information about the PDF file\n"); printf(" according to format instruction (if not provided, displays all).\n"); printf(" D displays Document Info.\n"); printf(" C displays Classic Metadata.\n"); printf(" P displays Page Info.\n"); printf(" O displays Outlines.\n"); printf(" N displays Names.\n"); printf("\nPoDoFo Version: %s\n\n", PODOFO_VERSION_STRING); } struct Format { bool document; // D bool classic; // C bool pages; // P bool outlines; // O bool names; // N Format():document(true),classic(true),pages(true),outlines(true),names(true){} }; Format ParseFormat(const std::string& fs) { Format ret; if(fs.find('D') == std::string::npos) ret.document = false; if(fs.find('C') == std::string::npos) ret.classic = false; if(fs.find('P') == std::string::npos) ret.pages = false; if(fs.find('O') == std::string::npos) ret.outlines = false; if(fs.find('N') == std::string::npos) ret.names = false; return ret; } int main( int argc, char* argv[] ) { #if 1 PoDoFo::PdfError::EnableDebug( false ); // turn it off to better view the output from this app! PoDoFo::PdfError::EnableLogging( false ); #endif if( (argc < 2) || (argc > 3) ) { print_help(); return ( -1 ); } char* pszInput = 0; Format format; std::string fName; if(argc == 2) { pszInput = argv[1]; } else if(argc == 3) { pszInput = argv[2]; format = ParseFormat(std::string(argv[1])); } if (pszInput!= NULL) { fName = pszInput; } //else leave empty try { PdfInfo myInfo( fName ); if(format.document) { std::cout << "Document Info" << std::endl; std::cout << "-------------" << std::endl; std::cout << "\tFile: " << fName << std::endl; myInfo.OutputDocumentInfo( std::cout ); std::cout << std::endl; } if(format.classic) { std::cout << "Classic Metadata" << std::endl; std::cout << "----------------" << std::endl; myInfo.OutputInfoDict( std::cout ); std::cout << std::endl; } if(format.pages) { std::cout << "Page Info" << std::endl; std::cout << "---------" << std::endl; myInfo.OutputPageInfo( std::cout ); } if(format.outlines) { std::cout << "Outlines" << std::endl; std::cout << "--------" << std::endl; myInfo.OutputOutlines( std::cout ); } if(format.names) { std::cout << "Names" << std::endl; std::cout << "-----" << std::endl; myInfo.OutputNames( std::cout ); } } catch( PoDoFo::PdfError & e ) { fprintf( stderr, "Error: An error %i ocurred during uncompressing the pdf file.\n", e.GetError() ); e.PrintErrorMsg(); return e.GetError(); } // std::cerr << "All information written sucessfully.\n" << std::endl << std::endl; return 0; } podofo-0.9.5/tools/podofotxtextract/0000775000175000017500000000000013044451161017443 5ustar dominikdominikpodofo-0.9.5/tools/podofotxtextract/podofotxtextract.cpp0000664000175000017500000000417011306221052023563 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "TextExtractor.h" #include #include #include #ifdef _HAVE_CONFIG #include #endif // _HAVE_CONFIG void print_help() { printf("Usage: podofotxtextract [inputfile]\n\n"); printf("\nPoDoFo Version: %s\n\n", PODOFO_VERSION_STRING); } int main( int argc, char* argv[] ) { char* pszInput; TextExtractor extractor; if( argc != 2 ) { print_help(); exit( -1 ); } pszInput = argv[1]; try { extractor.Init( pszInput ); } catch( PdfError & e ) { fprintf( stderr, "Error: An error %i ocurred during processing the pdf file.\n", e.GetError() ); e.PrintErrorMsg(); return e.GetError(); } return 0; } podofo-0.9.5/tools/podofotxtextract/CMakeLists.txt0000664000175000017500000000051311025247575022213 0ustar dominikdominikADD_EXECUTABLE(podofotxtextract TextExtractor.cpp podofotxtextract.cpp) TARGET_LINK_LIBRARIES(podofotxtextract ${PODOFO_LIB}) SET_TARGET_PROPERTIES(podofotxtextract PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(podofotxtextract ${PODOFO_DEPEND_TARGET}) INSTALL(TARGETS podofotxtextract RUNTIME DESTINATION "bin") podofo-0.9.5/tools/podofotxtextract/TextExtractor.cpp0000664000175000017500000001427112347347566023016 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "TextExtractor.h" #include TextExtractor::TextExtractor() { } TextExtractor::~TextExtractor() { } void TextExtractor::Init( const char* pszInput ) { if( !pszInput ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } PdfMemDocument document( pszInput ); int nCount = document.GetPageCount(); for( int i=0; iExtractText( &document, pPage ); } } void TextExtractor::ExtractText( PdfMemDocument* pDocument, PdfPage* pPage ) { const char* pszToken = NULL; PdfVariant var; EPdfContentsType eType; PdfContentsTokenizer tokenizer( pPage ); double dCurPosX = 0.0; double dCurPosY = 0.0; bool bTextBlock = false; PdfFont* pCurFont = NULL; std::stack stack; while( tokenizer.ReadNext( eType, pszToken, var ) ) { if( eType == ePdfContentsType_Keyword ) { // support 'l' and 'm' tokens if( strcmp( pszToken, "l" ) == 0 || strcmp( pszToken, "m" ) == 0 ) { dCurPosX = stack.top().GetReal(); stack.pop(); dCurPosY = stack.top().GetReal(); stack.pop(); } else if( strcmp( pszToken, "BT" ) == 0 ) { bTextBlock = true; // BT does not reset font // pCurFont = NULL; } else if( strcmp( pszToken, "ET" ) == 0 ) { if( !bTextBlock ) fprintf( stderr, "WARNING: Found ET without BT!\n" ); } if( bTextBlock ) { if( strcmp( pszToken, "Tf" ) == 0 ) { stack.pop(); PdfName fontName = stack.top().GetName(); PdfObject* pFont = pPage->GetFromResources( PdfName("Font"), fontName ); if( !pFont ) { PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidHandle, "Cannot create font!" ); } pCurFont = pDocument->GetFont( pFont ); if( !pCurFont ) { fprintf( stderr, "WARNING: Unable to create font for object %i %i R\n", pFont->Reference().ObjectNumber(), pFont->Reference().GenerationNumber() ); } } else if( strcmp( pszToken, "Tj" ) == 0 || strcmp( pszToken, "'" ) == 0 ) { AddTextElement( dCurPosX, dCurPosY, pCurFont, stack.top().GetString() ); stack.pop(); } else if( strcmp( pszToken, "\"" ) == 0 ) { AddTextElement( dCurPosX, dCurPosY, pCurFont, stack.top().GetString() ); stack.pop(); stack.pop(); // remove char spacing from stack stack.pop(); // remove word spacing from stack } else if( strcmp( pszToken, "TJ" ) == 0 ) { PdfArray array = stack.top().GetArray(); stack.pop(); for( int i=0; i(array.GetSize()); i++ ) { if( array[i].IsString() || array[i].IsHexString() ) AddTextElement( dCurPosX, dCurPosY, pCurFont, array[i].GetString() ); } } } } else if ( eType == ePdfContentsType_Variant ) { stack.push( var ); } else { // Impossible; type must be keyword or variant PODOFO_RAISE_ERROR( ePdfError_InternalLogic ); } } } void TextExtractor::AddTextElement( double dCurPosX, double dCurPosY, PdfFont* pCurFont, const PdfString & rString ) { if( !pCurFont ) { fprintf( stderr, "WARNING: Found text but do not have a current font: %s\n", rString.GetString() ); return; } if( !pCurFont->GetEncoding() ) { fprintf( stderr, "WARNING: Found text but do not have a current encoding: %s\n", rString.GetString() ); return; } // For now just write to console PdfString unicode = pCurFont->GetEncoding()->ConvertToUnicode( rString, pCurFont ); const char* pszData = unicode.GetStringUtf8().c_str(); while( *pszData ) { //printf("%02x", static_cast(*pszData) ); ++pszData; } printf("(%.3f,%.3f) %s \n", dCurPosX, dCurPosY, unicode.GetStringUtf8().c_str() ); } podofo-0.9.5/tools/podofotxtextract/TextExtractor.h0000664000175000017500000000516512320241653022442 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2008 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _TEXT_EXTRACTOR_H_ #define _TEXT_EXTRACTOR_H_ #include #include using namespace PoDoFo; #ifndef MAX_PATH #define MAX_PATH 512 #endif // MAX_PATH /** This class uses the PoDoFo lib to parse * a PDF file and to write all text it finds * in this PDF document to stdout. */ class TextExtractor { public: TextExtractor(); virtual ~TextExtractor(); void Init( const char* pszInput ); private: /** Extract all text from the given page * * \param pDocument the owning document * \param pPage extract the text of this page. */ void ExtractText( PdfMemDocument* pDocument, PdfPage* pPage ); /** Adds a text string to a list which can be sorted by * position on the page later, so that the whole structure * of the text including formatting can be reconstructed. * * \param dCurPosX x position of the text * \param dCurPosY y position of the text * \param pCurFont font of the text * \param rString the actual string */ void AddTextElement( double dCurPosX, double dCurPosY, PdfFont* pCurFont, const PdfString & rString ); }; #endif // _TEXT_EXTRACTOR_H_ podofo-0.9.5/tools/podofoxmp/0000775000175000017500000000000013044451161016035 5ustar dominikdominikpodofo-0.9.5/tools/podofoxmp/CMakeLists.txt0000664000175000017500000000041711430230735020576 0ustar dominikdominikADD_EXECUTABLE(podofoxmp podofoxmp.cpp) TARGET_LINK_LIBRARIES(podofoxmp ${PODOFO_LIB}) SET_TARGET_PROPERTIES(podofoxmp PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(podofoxmp ${PODOFO_DEPEND_TARGET}) INSTALL(TARGETS podofoxmp RUNTIME DESTINATION "bin") podofo-0.9.5/tools/podofoxmp/podofoxmp.cpp0000664000175000017500000001400713013650710020553 0ustar dominikdominik/*************************************************************************** * Copyright (C) 2010 by Ian Ashley * * Ian Ashley * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include #include #include #include #include #ifdef _MSC_VER #include #include #endif #include using namespace std; int main (int argc, char *argv[]) { using namespace PoDoFo; PoDoFo::PdfMemDocument *doc = NULL; int result = 0; try { PoDoFo::PdfError::EnableDebug(false); if (argc != 2 && argc != 4) { cout << "Syntax" << endl; cout << " " << argv[0] << " - display the XMP in a file (use \"-\" to specify stdin)" << endl; cout << "or" << endl; cout << " " << argv[0] << " <new pdf file> - create a new PDF with the XMP in" << endl; return EXIT_FAILURE; } if ( string("-") == argv[1] ) { cin >> std::noskipws; #ifdef _MSC_VER _setmode(_fileno(stdin), _O_BINARY); // @TODO: MSVC specific binary setmode -- not sure if other platforms need it cin.sync_with_stdio(); #endif istream_iterator<char> it(std::cin); istream_iterator<char> end; string buffer(it, end); doc = new PoDoFo::PdfMemDocument(); doc->Load( buffer.c_str(), (long)buffer.size() ); } else { doc = new PoDoFo::PdfMemDocument(argv[1]); } if (argc == 2) { PoDoFo::PdfObject *metadata; if ((metadata = doc->GetMetadata()) == NULL) cout << "No metadata" << endl; else { PoDoFo::PdfStream *str = metadata->GetStream(); if (str != NULL) { char *buf; PoDoFo::pdf_long len; str->GetFilteredCopy(&buf, &len); for (PoDoFo::pdf_long i = 0; i < len; ++i) printf("%c", buf[i]); printf("\n"); fflush(stdout); free(buf); } } } if (argc == 4) { char *xmpBuf; FILE *fp; if ((fp = fopen(argv[2], "rb")) == NULL) cout << "Cannot open " << argv[2] << endl; else { if( fseek( fp, 0, SEEK_END ) == -1 ) { fclose( fp ); PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to seek to the end of the file" ); } long xmpLen = ftell(fp); if( xmpLen == -1 ) { fclose( fp ); PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to read size of the file" ); } xmpBuf = new char[xmpLen]; if( !xmpBuf ) { fclose( fp ); PODOFO_RAISE_ERROR( ePdfError_OutOfMemory ); } if( fseek( fp, 0, SEEK_SET ) == -1 ) { delete [] xmpBuf; fclose( fp ); PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to seek to the beginning of the file" ); } if( static_cast<long>( fread( xmpBuf, 1, xmpLen, fp ) ) != xmpLen ) { delete [] xmpBuf; fclose( fp ); PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidDeviceOperation, "Failed to read whole file into the memory" ); } PoDoFo::PdfObject *metadata; if ((metadata = doc->GetMetadata()) != NULL) metadata->GetStream()->Set(xmpBuf, xmpLen, PoDoFo::TVecFilters()); else { metadata = doc->GetObjects().CreateObject("Metadata"); metadata->GetDictionary().AddKey(PoDoFo::PdfName("Subtype"), PoDoFo::PdfName("XML")); metadata->GetStream()->Set(xmpBuf, xmpLen, PoDoFo::TVecFilters()); doc->GetCatalog()->GetDictionary().AddKey(PoDoFo::PdfName("Metadata"), metadata->Reference()); } delete[] xmpBuf; doc->Write(argv[3]); } } } catch( PdfError & e ) { std::cerr << "Error: An error " << e.GetError() << " occurred during the sign of the pdf file:" << std::endl; e.PrintErrorMsg(); result = e.GetError(); } if( doc ) delete doc; return result; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/tools/podofobox/�����������������������������������������������������������������������0000775�0001750�0001750�00000000000�13044451161�016021� 5����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/tools/podofobox/CMakeLists.txt���������������������������������������������������������0000664�0001750�0001750�00000000435�11332333316�020562� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ADD_EXECUTABLE(podofobox podofobox.cpp boxsetter.cpp) TARGET_LINK_LIBRARIES(podofobox ${PODOFO_LIB}) SET_TARGET_PROPERTIES(podofobox PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(podofobox ${PODOFO_DEPEND_TARGET}) INSTALL(TARGETS podofobox RUNTIME DESTINATION "bin") �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/tools/podofobox/podofobox.cpp����������������������������������������������������������0000664�0001750�0001750�00000004667�11332333316�020540� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** * Copyright (C) 2010 by Pierre Marchand * * pierre@oep-h.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "podofo.h" #include <cstdlib> #include <string> #include <iostream> #include "boxsetter.h" void print_help() { std::cerr<<"Usage: podofobox [inputfile] [outpufile] [box] [left] [bottom] [width] [height]\n"; std::cerr<<"Box is one of media crop bleed trim art.\n"; std::cerr<<"Give values * 100 as integers (avoid locale headaches with strtod).\n\n"; std::cerr<<"\nPoDoFo Version: "<< PODOFO_VERSION_STRING <<"\n\n"; } int main( int argc, char* argv[] ) { if( argc != 8 ) { print_help(); exit( -1 ); } std::string input = argv[1]; std::string output = argv[2]; std::string box = argv[3]; double left = double(atol(argv[4])) /100.0; double bottom = double(atol(argv[5])) /100.0; double width = double(atol(argv[6])) /100.0; double height = double(atol(argv[7])) /100.0; PoDoFo::PdfRect rect( left , bottom, width, height ); try { BoxSetter bs(input, output, box, rect); } catch( PoDoFo::PdfError & e ) { std::cerr << "Error: An error "<< e.GetError() <<" ocurred during processing the pdf file\n"; e.PrintErrorMsg(); return e.GetError(); } return 0; } �������������������������������������������������������������������������podofo-0.9.5/tools/podofobox/boxsetter.cpp����������������������������������������������������������0000664�0001750�0001750�00000005315�12347347566�020572� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** * Copyright (C) 2010 by Pierre Marchand * * pierre@oep-h.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "boxsetter.h" BoxSetter::BoxSetter(const std::string& in, const std::string& out, const std::string& box, const PoDoFo::PdfRect& rect) :m_box(box), m_rect(rect) { PoDoFo::PdfMemDocument* source = new PoDoFo::PdfMemDocument(in.c_str()); int pcount(source->GetPageCount()); for ( int i = 0; i < pcount ; ++i ) { SetBox(source->GetPage ( i )); } source->Write(out.c_str()); } void BoxSetter::SetBox(PoDoFo::PdfPage *page) { if(!page) return; PoDoFo::PdfObject r; m_rect.ToVariant( r ); if(m_box.find("media") != std::string::npos) { page->GetObject()->GetDictionary().AddKey ( PoDoFo::PdfName ( "MediaBox" ), r ); } else if(m_box.find("crop") != std::string::npos) { page->GetObject()->GetDictionary().AddKey ( PoDoFo::PdfName ( "CropBox" ), r ); } else if(m_box.find("bleed") != std::string::npos) { page->GetObject()->GetDictionary().AddKey ( PoDoFo::PdfName ( "BleedBox" ), r ); } else if(m_box.find("trim") != std::string::npos) { page->GetObject()->GetDictionary().AddKey ( PoDoFo::PdfName ( "TrimBox" ), r ); } else if(m_box.find("art") != std::string::npos) { page->GetObject()->GetDictionary().AddKey ( PoDoFo::PdfName ( "ArtBox" ), r ); } // TODO check that box sizes are ordered } bool BoxSetter::CompareBox(const PoDoFo::PdfRect &rect1, const PoDoFo::PdfRect &rect2) { return rect1.ToString() == rect2.ToString(); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/tools/podofobox/boxsetter.h������������������������������������������������������������0000664�0001750�0001750�00000003432�11332333316�020212� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** * Copyright (C) 2010 by Pierre Marchand * * pierre@oep-h.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef BOXSETTER_H #define BOXSETTER_H #include "podofo.h" #include <string> class BoxSetter { BoxSetter(){} const std::string m_box; const PoDoFo::PdfRect m_rect; void SetBox(PoDoFo::PdfPage * page); bool CompareBox(const PoDoFo::PdfRect& rect1, const PoDoFo::PdfRect& rect2); public: BoxSetter(const std::string& in, const std::string& out, const std::string& box, const PoDoFo::PdfRect& rect); }; #endif // BOXSETTER_H ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/tools/podofocolor/���������������������������������������������������������������������0000775�0001750�0001750�00000000000�13044451161�016347� 5����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/tools/podofocolor/luaconverter.cpp�����������������������������������������������������0000664�0001750�0001750�00000017527�12205457547�021614� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "luaconverter.h" // Note: this is *not* lua.hpp shipped with lua 5.1, it's a wrapper // header we use to handle version differences between lua 5.1 and lua // 5.0 . #include "lua_compat.h" #include <stdexcept> #include <iostream> using namespace PoDoFo; #define FUNCTION_START_PAGE "start_page" #define FUNCTION_END_PAGE "end_page" #define FUNCTION_START_XOBJECT "start_xobject" #define FUNCTION_END_XOBJECT "end_xobject" #define FUNCTION_SET_STROKING_GRAY "set_stroking_color_gray" #define FUNCTION_SET_STROKING_RGB "set_stroking_color_rgb" #define FUNCTION_SET_STROKING_CMYK "set_stroking_color_cmyk" #define FUNCTION_SET_NON_STROKING_GRAY "set_non_stroking_color_gray" #define FUNCTION_SET_NON_STROKING_RGB "set_non_stroking_color_rgb" #define FUNCTION_SET_NON_STROKING_CMYK "set_non_stroking_color_cmyk" LuaMachina::LuaMachina() { /* Init the Lua interpreter */ L = imp_lua_open(); if (!L) { throw std::runtime_error("Whoops! Failed to open lua!"); } /* Init the Lua libraries we want users to have access to. * Note that the `os' and `io' libraries MUST NOT be included, * as providing access to those libraries to the user would * make running plan files unsafe. */ luaopen_base(L); luaopen_table(L); luaopen_string(L); luaopen_math(L); } LuaMachina::~LuaMachina() { lua_close(L); } LuaConverter::LuaConverter( const std::string & sLuaScript ) : IConverter() { if( imp_lua_dofile(m_machina.State(), sLuaScript.c_str()) ) { std::cerr << "Unable to process Lua script:\"" << lua_tostring(m_machina.State(), -1)<<"\"" << std::endl; } } LuaConverter::~LuaConverter() { } void LuaConverter::StartPage( PdfPage*, int nPageNumber ) { lua_getglobal( m_machina.State(), FUNCTION_START_PAGE ); lua_pushnumber( m_machina.State(), static_cast<double>(nPageNumber) ); // Lua 5.1 only //lua_pushinteger( m_machina.State(), nPageNumber ); lua_call( m_machina.State(), 1, 0 ); } void LuaConverter::EndPage( PdfPage*, int nPageNumber ) { lua_getglobal( m_machina.State(), FUNCTION_END_PAGE ); lua_pushnumber( m_machina.State(), static_cast<double>(nPageNumber) ); // Lua 5.1 only //lua_pushinteger( m_machina.State(), nPageNumber ); lua_call( m_machina.State(), 1, 0 ); } void LuaConverter::StartXObject( PdfXObject* ) { lua_getglobal( m_machina.State(), FUNCTION_START_XOBJECT ); lua_call( m_machina.State(), 0, 0 ); } void LuaConverter::EndXObject( PdfXObject* ) { lua_getglobal( m_machina.State(), FUNCTION_END_XOBJECT ); lua_call( m_machina.State(), 0, 0 ); } PdfColor LuaConverter::GetColorFromReturnValue(const char* pszFunctionName) { int top; double value; std::vector<double> colors; size_t len; luaL_checktype(m_machina.State(), 1, LUA_TTABLE); len = imp_lua_getn( m_machina.State(), -1 ); // Lua 5.1 only //len = lua_objlen( m_machina.State(), -1 ); for( int i = 1; i <= static_cast<int>(len); i++ ) { lua_rawgeti( m_machina.State(), -1, i ); top = lua_gettop( m_machina.State() ); value = static_cast<double>(lua_tonumber(m_machina.State(), top)); lua_pop(m_machina.State(), 1); colors.push_back( value ); } switch( len ) { case 1: return PdfColor( colors[0] ); case 3: return PdfColor( colors[0], colors[1], colors[2] ); case 4: return PdfColor( colors[0], colors[1], colors[2], colors[3] ); default: { PdfError::LogMessage( eLogSeverity_Error, "Array length is %i returned by %s.\n", len, pszFunctionName ); PODOFO_RAISE_ERROR_INFO( ePdfError_CannotConvertColor, "Arrays returned from Lua must be { g }, { r,g,b } or { c,m,y,k }!" ); break; } } return PdfColor(); } PdfColor LuaConverter::SetStrokingColorGray( const PdfColor & rColor ) { lua_getglobal( m_machina.State(), FUNCTION_SET_STROKING_GRAY ); lua_pushnumber( m_machina.State(), rColor.GetGrayScale() ); lua_call( m_machina.State(), 1, 1 ); return this->GetColorFromReturnValue( FUNCTION_SET_STROKING_GRAY ); } PdfColor LuaConverter::SetStrokingColorRGB( const PdfColor & rColor ) { lua_getglobal( m_machina.State(), FUNCTION_SET_STROKING_RGB ); lua_pushnumber( m_machina.State(), rColor.GetRed() ); lua_pushnumber( m_machina.State(), rColor.GetGreen() ); lua_pushnumber( m_machina.State(), rColor.GetBlue() ); lua_call( m_machina.State(), 3, 1 ); return this->GetColorFromReturnValue( FUNCTION_SET_STROKING_RGB ); } PdfColor LuaConverter::SetStrokingColorCMYK( const PdfColor & rColor ) { lua_getglobal( m_machina.State(), FUNCTION_SET_STROKING_CMYK ); lua_pushnumber( m_machina.State(), rColor.GetCyan() ); lua_pushnumber( m_machina.State(), rColor.GetMagenta() ); lua_pushnumber( m_machina.State(), rColor.GetYellow() ); lua_pushnumber( m_machina.State(), rColor.GetBlack() ); lua_call( m_machina.State(), 4, 1 ); return this->GetColorFromReturnValue( FUNCTION_SET_STROKING_CMYK ); } PdfColor LuaConverter::SetNonStrokingColorGray( const PdfColor & rColor ) { lua_getglobal( m_machina.State(), FUNCTION_SET_NON_STROKING_GRAY ); lua_pushnumber( m_machina.State(), rColor.GetGrayScale() ); lua_call( m_machina.State(), 1, 1 ); return this->GetColorFromReturnValue( FUNCTION_SET_NON_STROKING_GRAY ); } PdfColor LuaConverter::SetNonStrokingColorRGB( const PdfColor & rColor ) { lua_getglobal( m_machina.State(), FUNCTION_SET_NON_STROKING_RGB ); lua_pushnumber( m_machina.State(), rColor.GetRed() ); lua_pushnumber( m_machina.State(), rColor.GetGreen() ); lua_pushnumber( m_machina.State(), rColor.GetBlue() ); lua_call( m_machina.State(), 3, 1 ); return this->GetColorFromReturnValue( FUNCTION_SET_NON_STROKING_RGB ); } PdfColor LuaConverter::SetNonStrokingColorCMYK( const PdfColor & rColor ) { lua_getglobal( m_machina.State(), FUNCTION_SET_NON_STROKING_CMYK ); lua_pushnumber( m_machina.State(), rColor.GetCyan() ); lua_pushnumber( m_machina.State(), rColor.GetMagenta() ); lua_pushnumber( m_machina.State(), rColor.GetYellow() ); lua_pushnumber( m_machina.State(), rColor.GetBlack() ); lua_call( m_machina.State(), 4, 1 ); return this->GetColorFromReturnValue( FUNCTION_SET_NON_STROKING_CMYK ); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/tools/podofocolor/colorspace.h���������������������������������������������������������0000664�0001750�0001750�00000005206�11511141604�020650� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _COLORSPACE_H_ #define _COLORSPACE_H_ #include <podofo.h> /** * A more powerful representation * of a colorspace than EPdfColorSpace. * */ class ColorSpace { public: /** * Construct a DeviceGray ColorSpace */ ColorSpace(); /** * Construct a colorspace from a colorspace name */ ColorSpace(const PoDoFo::PdfName & rName); /** * Copy constructor */ ColorSpace(const ColorSpace & rhs); ~ColorSpace(); const ColorSpace & operator=(const ColorSpace & rhs); /** * Checks if this is a "simple" * colorspace (i.e. DeviceGray, DeviceRGB, DeviceCMYK). * \returns true if this is a simple colospace */ bool IsSimpleColorSpace() const; /** * Convert this object into an EPdfColorSpace * enum. * \returns enum value if possible or ePdfColorSpace_Unknown */ PoDoFo::EPdfColorSpace ConvertToPdfColorSpace() const; /** * Retrieve the internal name. * \return the internal name */ inline const PoDoFo::PdfName & GetName() const; private: PoDoFo::PdfName m_name; }; const PoDoFo::PdfName & ColorSpace::GetName() const { return m_name; } #endif // _COLORSPACE_H_ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/tools/podofocolor/CMakeLists.txt�������������������������������������������������������0000664�0001750�0001750�00000001146�11511141604�021104� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������SET(color_srcs podofocolor.cpp colorchanger.cpp colorspace.cpp graphicsstack.cpp iconverter.cpp dummyconverter.cpp grayscaleconverter.cpp ) SET(color_extra_libs) IF(LUA_FOUND) SET(color_extra_libs ${LUA_LIBRARIES}) SET(color_srcs ${color_srcs} luaconverter.cpp) ENDIF(LUA_FOUND) ADD_EXECUTABLE(podofocolor ${color_srcs} ) TARGET_LINK_LIBRARIES(podofocolor ${PODOFO_LIB} ${color_extra_libs} ) SET_TARGET_PROPERTIES(podofocolor PROPERTIES COMPILE_FLAGS "${PODOFO_CFLAGS}") ADD_DEPENDENCIES(podofocolor ${PODOFO_DEPEND_TARGET}) INSTALL(TARGETS podofocolor RUNTIME DESTINATION "bin") ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/tools/podofocolor/luaconverter.h�������������������������������������������������������0000664�0001750�0001750�00000012215�11506674437�021250� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _LUA_CONVERTER_H_ #define _LUA_CONVERTER_H_ #include "iconverter.h" struct lua_State; class LuaMachina { lua_State *L; public: LuaMachina(); ~LuaMachina(); inline lua_State* State() { return L; } }; /** * Converter that calls a lua script * to do the color conversions. */ class LuaConverter : public IConverter { public: LuaConverter( const std::string & sLuaScript ); virtual ~LuaConverter(); /** * A helper method that is called to inform the converter * when a new page is analyzed. * * @param pPage page object * @param nPageIndex index of the page in the document */ virtual void StartPage( PoDoFo::PdfPage* pPage, int nPageIndex ); /** * A helper method that is called to inform the converter * when a new page has been analyzed completely. * * @param pPage page object * @param nPageIndex index of the page in the document */ virtual void EndPage( PoDoFo::PdfPage* pPage, int nPageIndex ); /** * A helper method that is called to inform the converter * when a new xobjext is analyzed. * * @param pObj the xobject */ virtual void StartXObject( PoDoFo::PdfXObject* pObj ); /** * A helper method that is called to inform the converter * when a xobjext has been analyzed. * * @param pObj the xobject */ virtual void EndXObject( PoDoFo::PdfXObject* pObj ); /** * This method is called whenever a gray stroking color is set * using the 'G' PDF command. * * @param a grayscale color object * @returns a new color which should be set instead (any colorspace) */ virtual PoDoFo::PdfColor SetStrokingColorGray( const PoDoFo::PdfColor & rColor ); /** * This method is called whenever a RGB stroking color is set * using the 'RG' PDF command. * * @param a RGB color object * @returns a new color which should be set instead (any colorspace) */ virtual PoDoFo::PdfColor SetStrokingColorRGB( const PoDoFo::PdfColor & rColor ); /** * This method is called whenever a CMYK stroking color is set * using the 'K' PDF command. * * @param a CMYK color object * @returns a new color which should be set instead (any colorspace) */ virtual PoDoFo::PdfColor SetStrokingColorCMYK( const PoDoFo::PdfColor & rColor ); /** * This method is called whenever a gray non-stroking color is set * using the 'g' PDF command. * * @param a grayscale color object * @returns a new color which should be set instead (any colorspace) */ virtual PoDoFo::PdfColor SetNonStrokingColorGray( const PoDoFo::PdfColor & rColor ); /** * This method is called whenever a RGB non-stroking color is set * using the 'rg' PDF command. * * @param a RGB color object * @returns a new color which should be set instead (any colorspace) */ virtual PoDoFo::PdfColor SetNonStrokingColorRGB( const PoDoFo::PdfColor & rColor ); /** * This method is called whenever a CMYK non-stroking color is set * using the 'k' PDF command. * * @param a CMYK color object * @returns a new color which should be set instead (any colorspace) */ virtual PoDoFo::PdfColor SetNonStrokingColorCMYK( const PoDoFo::PdfColor & rColor ); private: /** * Create a PdfColor from an array returned on the stack * by a Lua function. * @param pszFunctionName name of Lua function for error reporting * @returns a PdfColor or throws a PdfError if color cannot be created */ PoDoFo::PdfColor GetColorFromReturnValue(const char* pszFunctionName); private: LuaMachina m_machina; }; #endif // _LUA_CONVERTER_H_ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/tools/podofocolor/dummyconverter.cpp���������������������������������������������������0000664�0001750�0001750�00000004666�11506670673�022166� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "dummyconverter.h" using namespace PoDoFo; DummyConverter::DummyConverter() : IConverter() { } DummyConverter::~DummyConverter() { } void DummyConverter::StartPage( PdfPage*, int ) { } void DummyConverter::EndPage( PdfPage*, int ) { } void DummyConverter::StartXObject( PdfXObject* ) { } void DummyConverter::EndXObject( PdfXObject* ) { } PdfColor DummyConverter::SetStrokingColorGray( const PdfColor & ) { return PdfColor( 1.0, 0.0, 0.0 ); } PdfColor DummyConverter::SetStrokingColorRGB( const PdfColor & ) { return PdfColor( 1.0, 0.0, 0.0 ); } PdfColor DummyConverter::SetStrokingColorCMYK( const PdfColor & ) { return PdfColor( 1.0, 0.0, 0.0 ); } PdfColor DummyConverter::SetNonStrokingColorGray( const PdfColor & ) { return PdfColor( 0.0, 1.0, 0.0 ); } PdfColor DummyConverter::SetNonStrokingColorRGB( const PdfColor & ) { return PdfColor( 0.0, 1.0, 0.0 ); } PdfColor DummyConverter::SetNonStrokingColorCMYK( const PdfColor & ) { return PdfColor( 0.0, 1.0, 0.0 ); } ��������������������������������������������������������������������������podofo-0.9.5/tools/podofocolor/lua_compat.h���������������������������������������������������������0000664�0001750�0001750�00000002252�12205457547�020661� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������extern "C" { #include "lua.h" // Note: If you're missing these, you're using lua 5.0 and haven't installed // the extension libraries. #include "lualib.h" #include "lauxlib.h" } #if !defined(LUA_VERSION_NUM) // Old lua without numeric version #define LUA_VERSION_NUM 0 #endif // Handle an API difference in the lua_open call between // Lua 5.1 and Lua 5.2. #if LUA_VERSION_NUM >= 502 inline lua_State* imp_lua_open(void) { return luaL_newstate(); } inline size_t imp_lua_objlen(lua_State *L, int index) { return lua_rawlen(L, index); } #else inline lua_State* imp_lua_open(void) { return lua_open(); } inline size_t imp_lua_objlen(lua_State *L, int index) { return lua_objlen(L, index); } #endif // Handle an API difference in the dofile and getn calls between // Lua 5.0 and Lua 5.1. #if LUA_VERSION_NUM >= 501 inline int imp_lua_dofile(lua_State* L, const char * path) { return luaL_dofile(L, path); } inline int imp_lua_getn(lua_State *L, int t) { return imp_lua_objlen(L, t); } #else inline int imp_lua_dofile(lua_State* L, const char * path) { return lua_dofile(L, path); } inline int imp_lua_getn(lua_State *L, int t) { return luaL_getn(L, t); } #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/tools/podofocolor/colorspace.cpp�������������������������������������������������������0000664�0001750�0001750�00000004440�11511141604�021202� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "colorspace.h" using namespace PoDoFo; ColorSpace::ColorSpace() : m_name("DeviceGray") { } ColorSpace::ColorSpace(const PdfName & rName) : m_name(rName) { } ColorSpace::ColorSpace(const ColorSpace & rhs) { this->operator=(rhs); } ColorSpace::~ColorSpace() { } const ColorSpace & ColorSpace::operator=(const ColorSpace & rhs) { m_name = rhs.m_name; return *this; } bool ColorSpace::IsSimpleColorSpace() const { EPdfColorSpace eColorSpace = this->ConvertToPdfColorSpace(); if( eColorSpace == ePdfColorSpace_DeviceGray || eColorSpace == ePdfColorSpace_DeviceRGB || eColorSpace == ePdfColorSpace_DeviceCMYK ) { return true; } else { return false; } } EPdfColorSpace ColorSpace::ConvertToPdfColorSpace() const { return PdfColor::GetColorSpaceForName(m_name); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/tools/podofocolor/podofocolor.cpp������������������������������������������������������0000664�0001750�0001750�00000007534�12716135311�021412� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "podofo.h" #include <cstdlib> #include <string> #include <iostream> #include "podofo_config.h" #include "colorchanger.h" #include "dummyconverter.h" #include "grayscaleconverter.h" #ifdef PODOFO_HAVE_LUA #include "luaconverter.h" #endif // PODOFO_HAVE_LUA static void print_help() { std::cerr << "Usage: podofocolor [converter] [inputfile] [outpufile]\n"; #ifdef PODOFO_HAVE_LUA std::cerr << "\t[converter] can be one of: dummy|grayscale|lua [planfile]\n"; #else std::cerr << "\t[converter] can be one of: dummy|grayscale\n"; #endif // PODOFO_HAVE_LUA std::cerr << "\tpodofocolor is a tool to change all colors in a PDF file based on a predefined or Lua description.\n"; std::cerr << "\nPoDoFo Version: "<< PODOFO_VERSION_STRING <<"\n\n"; } /** * @return a converter implementation or NULL if unknown */ static IConverter* ConverterForName( const std::string & converter, const std::string & lua ) { IConverter* pConverter = NULL; if( converter == "dummy" ) { pConverter = new DummyConverter(); } else if( converter == "grayscale" ) { pConverter = new GrayscaleConverter(); } #ifdef PODOFO_HAVE_LUA else if( converter == "lua" ) { pConverter = new LuaConverter( lua ); } #else PODOFO_UNUSED_PARAM( lua ) #endif // PODOFO_HAVE_LUA return pConverter; } int main( int argc, char* argv[] ) { if( !(argc == 4 || argc == 5) ) { print_help(); exit( -1 ); } std::string converter = argv[1]; std::string input = argv[2]; std::string output = argv[3]; std::string lua; if( argc == 4 && converter != "lua" ) { input = argv[2]; output = argv[3]; } #ifdef PODOFO_HAVE_LUA else if( argc == 5 && converter == "lua" ) { lua = argv[2]; input = argv[3]; output = argv[4]; } #endif // PODOFO_HAVE_LUA else { print_help(); exit( -3 ); } IConverter* pConverter = ConverterForName( converter, lua ); if( !pConverter ) { std::cerr << "Aborting! Unknown converter: " << converter << std::endl; print_help(); exit( -2 ); } try { ColorChanger cc(pConverter, input, output); cc.start(); } catch( PoDoFo::PdfError & e ) { std::cerr << "Error: An error "<< e.GetError() <<" ocurred during processing the pdf file\n"; e.PrintErrorMsg(); return e.GetError(); } delete pConverter; return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/tools/podofocolor/iconverter.cpp�������������������������������������������������������0000664�0001750�0001750�00000003016�11506670673�021247� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "iconverter.h" IConverter::IConverter() { } IConverter::~IConverter() { } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/tools/podofocolor/grayscaleconverter.cpp�����������������������������������������������0000664�0001750�0001750�00000005173�11506670673�022777� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "grayscaleconverter.h" GrayscaleConverter::GrayscaleConverter() : IConverter() { } GrayscaleConverter::~GrayscaleConverter() { } void GrayscaleConverter::StartPage( PoDoFo::PdfPage*, int ) { } void GrayscaleConverter::EndPage( PoDoFo::PdfPage*, int ) { } void GrayscaleConverter::StartXObject( PoDoFo::PdfXObject* ) { } void GrayscaleConverter::EndXObject( PoDoFo::PdfXObject* ) { } PoDoFo::PdfColor GrayscaleConverter::SetStrokingColorGray( const PoDoFo::PdfColor & rColor ) { return rColor; } PoDoFo::PdfColor GrayscaleConverter::SetStrokingColorRGB( const PoDoFo::PdfColor & rColor ) { return rColor.ConvertToGrayScale(); } PoDoFo::PdfColor GrayscaleConverter::SetStrokingColorCMYK( const PoDoFo::PdfColor & rColor ) { return rColor.ConvertToGrayScale(); } PoDoFo::PdfColor GrayscaleConverter::SetNonStrokingColorGray( const PoDoFo::PdfColor & rColor ) { return rColor.ConvertToGrayScale(); } PoDoFo::PdfColor GrayscaleConverter::SetNonStrokingColorRGB( const PoDoFo::PdfColor & rColor ) { return rColor.ConvertToGrayScale(); } PoDoFo::PdfColor GrayscaleConverter::SetNonStrokingColorCMYK( const PoDoFo::PdfColor & rColor ) { return rColor.ConvertToGrayScale(); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/tools/podofocolor/graphicsstack.cpp����������������������������������������������������0000664�0001750�0001750�00000004310�11506670673�021713� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "graphicsstack.h" using namespace PoDoFo; GraphicsStack::GraphicsStack() { // Initialize graphicsstack with default graphicsstack TGraphicsStackElement element; m_stack.push( element ); } GraphicsStack::~GraphicsStack() { } void GraphicsStack::Push() { PODOFO_RAISE_LOGIC_IF( m_stack.empty(), "Can push copy on graphicsstack! Stack is empty!" ); TGraphicsStackElement copy( m_stack.top() ); m_stack.push( copy ); } void GraphicsStack::Pop() { PODOFO_RAISE_LOGIC_IF( m_stack.empty(), "Can pop graphicsstack! Stack is empty!" ); m_stack.pop(); } GraphicsStack::TGraphicsStackElement & GraphicsStack::GetCurrentGraphicsState() { PODOFO_RAISE_LOGIC_IF( m_stack.empty(), "Can get current graphicsstate!" ); return m_stack.top(); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/tools/podofocolor/example.lua����������������������������������������������������������0000664�0001750�0001750�00000013771�11507066164�020525� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-- /*************************************************************************** -- * Copyright (C) 2010 by Dominik Seichter * -- * domseichter@web.de * -- * Stefan Huber * -- * sh@signalwerk.ch * -- * * -- * This program is free software; you can redistribute it and/or modify * -- * it under the terms of the GNU General Public License as published by * -- * the Free Software Foundation; either version 2 of the License, or * -- * (at your option) any later version. * -- * * -- * This program is distributed in the hope that it will be useful, * -- * but WITHOUT ANY WARRANTY; without even the implied warranty of * -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -- * GNU General Public License for more details. * -- * * -- * You should have received a copy of the GNU General Public License * -- * along with this program; if not, write to the * -- * Free Software Foundation, Inc., * -- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * -- ***************************************************************************/ function start_page (n) print( " -> Lua is parsing page:", n + 1) end function end_page (n) -- Do nothing end function start_xobjext () -- Do nothing end function end_xobject () -- Do nothing end -- This method is called whenever a gray stroking color is set -- using the 'G' PDF command. -- -- @param a grayscale color object -- @returns a new color which should be set instead (any colorspace) function set_stroking_color_gray (g) -- Convert all gray values to RGB red local a = { 1.0,0.0,0.0 } return a end -- This method is called whenever a rgb stroking color is set -- using the 'RG' PDF command. -- -- @param a rgb color object -- @returns a new color which should be set instead (any colorspace) function set_stroking_color_rgb (r,g,b) -- convert all black rgb values to cmyk, -- leave other as they are if r == 0 and g == 0 and b == 0 then return { 0.0, 0.0, 0.0, 1.0 } else return { r,g,b } end end -- This method is called whenever a cmyk stroking color is set -- using the 'K' PDF command. -- -- @param a cmyk color object -- @returns a new color which should be set instead (any colorspace) function set_stroking_color_cmyk (c,m,y,k) -- do not change color, -- just return input values again return { c,m,y,k } end -- This method is called whenever a gray non-stroking color is set -- using the 'g' PDF command. -- -- @param a grayscale color object -- @returns a new color which should be set instead (any colorspace) function set_non_stroking_color_gray (g) -- do not change color, -- just return input values again return { g } end -- This method is called whenever a rgb stroking color is set -- using the 'rg' PDF command. -- -- @param a rgb color object -- @returns a new color which should be set instead (any colorspace) function set_non_stroking_color_rgb (r,g,b) -- Handle stroking and non-stroking rgb values in the same way local c = set_stroking_color_rgb (r,g,b) return c end -- This method is called whenever a cmyk non-stroking color is set -- using the 'k' PDF command. -- -- @param a cmyk color object -- @returns a new color which should be set instead (any colorspace) function set_non_stroking_color_cmyk (c,m,y,k) -- do not change color, -- just return input values again return { c,m,y,k } end -- This method converts a given RGB color to CMYK -- The conversion is like a maximal -- under color removal -- http://en.wikipedia.org/wiki/Under_color_removal -- according to PoDoFo PdfColor::ConvertToCMYK() -- -- @param a rgb color object -- @returns the new CMYK color function ConvertRGBtoCMYK(r,g,b) -- local k = math.min( 1.0-r, math.min( 1.0-g, 1.0-b ) ) local k = math.min( 1.0-r, 1.0-g, 1.0-b ) local c = 0.0 local m = 0.0 local y = 0.0 if k < 1.0 then c = (1.0 - r - k) / (1.0 - k) m = (1.0 - g - k) / (1.0 - k) y = (1.0 - b - k) / (1.0 - k) end return { c, m, y, k } end -- This method converts a given RGB color to Gray -- according to PoDoFo PdfColor::ConvertToGrayScale() -- -- @param a rgb color object -- @returns the new GrayScale color function ConvertRGBtoGrayScale(r,g,b) return { 0.299*r + 0.587*g + 0.114*b } end -- Check if the given Color is nearly Gray -- IsNearlyGray(0.126,0.127,0.128, 0.002) = true -- IsNearlyGray(0.125,0.127,0.128, 0.002) = false -- -- @param a rgb color object plus a tolerance-value -- @returns true or false function IsNearlyGray(r,g,b,t) local min = math.min( r,g,b ) local max = math.max( r,g,b ) if max - min <= t and max - min >= -t then return true else return false end end -- Check if the given RGB Color1 is nearly RGB Color2 -- -- @param two rgb colors plus a tolerance-value -- @returns true or false function IsNearlyTheSameRGB(r1,g1,b1, r2,g2,b2, t) local rMin = math.min( r1,r2 ) local rMax = math.max( r1,r2 ) local rSame = false local gMin = math.min( g1,g2 ) local gMax = math.max( g1,g2 ) local gSame = false local bMin = math.min( b1,b2 ) local bMax = math.max( b1,b2 ) local bSame = false if rMax - rMin <= t and rMax - rMin >= -t then rSame = true end if gMax - gMin <= t and gMax - gMin >= -t then gSame = true end if bMax - bMin <= t and bMax - bMin >= -t then bSame = true end if rSame and gSame and bSame then return true else return false end end �������podofo-0.9.5/tools/podofocolor/iconverter.h���������������������������������������������������������0000664�0001750�0001750�00000011227�11506670673�020717� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _ICONVERTER_H_ #define _ICONVERTER_H_ #include <podofo.h> /** * Interface for a converter that can be used * together with a ColorChanger object * to convert colors in a PDF file. */ class IConverter { public: IConverter(); virtual ~IConverter(); /** * A helper method that is called to inform the converter * when a new page is analyzed. * * @param pPage page object * @param nPageIndex index of the page in the document */ virtual void StartPage( PoDoFo::PdfPage* pPage, int nPageIndex ) = 0; /** * A helper method that is called to inform the converter * when a new page has been analyzed completely. * * @param pPage page object * @param nPageIndex index of the page in the document */ virtual void EndPage( PoDoFo::PdfPage* pPage, int nPageIndex ) = 0; /** * A helper method that is called to inform the converter * when a new xobjext is analyzed. * * @param pObj the xobject */ virtual void StartXObject( PoDoFo::PdfXObject* pObj ) = 0; /** * A helper method that is called to inform the converter * when a xobjext has been analyzed. * * @param pObj the xobject */ virtual void EndXObject( PoDoFo::PdfXObject* pObj ) = 0; /** * This method is called whenever a gray stroking color is set * using the 'G' PDF command. * * @param a grayscale color object * @returns a new color which should be set instead (any colorspace) */ virtual PoDoFo::PdfColor SetStrokingColorGray( const PoDoFo::PdfColor & rColor ) = 0; /** * This method is called whenever a RGB stroking color is set * using the 'RG' PDF command. * * @param a RGB color object * @returns a new color which should be set instead (any colorspace) */ virtual PoDoFo::PdfColor SetStrokingColorRGB( const PoDoFo::PdfColor & rColor ) = 0; /** * This method is called whenever a CMYK stroking color is set * using the 'K' PDF command. * * @param a CMYK color object * @returns a new color which should be set instead (any colorspace) */ virtual PoDoFo::PdfColor SetStrokingColorCMYK( const PoDoFo::PdfColor & rColor ) = 0; /** * This method is called whenever a gray non-stroking color is set * using the 'g' PDF command. * * @param a grayscale color object * @returns a new color which should be set instead (any colorspace) */ virtual PoDoFo::PdfColor SetNonStrokingColorGray( const PoDoFo::PdfColor & rColor ) = 0; /** * This method is called whenever a RGB non-stroking color is set * using the 'rg' PDF command. * * @param a RGB color object * @returns a new color which should be set instead (any colorspace) */ virtual PoDoFo::PdfColor SetNonStrokingColorRGB( const PoDoFo::PdfColor & rColor ) = 0; /** * This method is called whenever a CMYK non-stroking color is set * using the 'k' PDF command. * * @param a CMYK color object * @returns a new color which should be set instead (any colorspace) */ virtual PoDoFo::PdfColor SetNonStrokingColorCMYK( const PoDoFo::PdfColor & rColor ) = 0; }; #endif // _ICONVERTER_H_ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/tools/podofocolor/graphicsstack.h������������������������������������������������������0000664�0001750�0001750�00000011534�11506670673�021366� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _GRAPHICSSTACK_H_ #define _GRAPHICSSTACK_H_ #include <stack> #include <podofo.h> class GraphicsStack { class TGraphicsStackElement { public: TGraphicsStackElement() : m_strokingColor( PoDoFo::PdfColor( 0.0 ) ), m_nonStrokingColor( PoDoFo::PdfColor( 0.0 ) ), m_eColorSpaceStroking( PoDoFo::ePdfColorSpace_DeviceGray ), m_eColorSpaceNonStroking( PoDoFo::ePdfColorSpace_DeviceGray ) { } TGraphicsStackElement( const TGraphicsStackElement & rhs ) { this->operator=(rhs); } const TGraphicsStackElement & operator=( const TGraphicsStackElement & rhs ) { m_strokingColor = rhs.m_strokingColor; m_nonStrokingColor = rhs.m_nonStrokingColor; m_eColorSpaceStroking = rhs.m_eColorSpaceStroking; m_eColorSpaceNonStroking = rhs.m_eColorSpaceNonStroking; return *this; } inline const PoDoFo::PdfColor & GetStrokingColor() { return m_strokingColor; } inline const PoDoFo::PdfColor & GetNonStrokingColor() { return m_nonStrokingColor; } inline PoDoFo::EPdfColorSpace GetStrokingColorSpace() { return m_eColorSpaceStroking; } inline PoDoFo::EPdfColorSpace GetNonStrokingColorSpace() { return m_eColorSpaceNonStroking; } inline void SetStrokingColor( const PoDoFo::PdfColor & c ) { m_strokingColor = c; } inline void SetNonStrokingColor( const PoDoFo::PdfColor & c ) { m_nonStrokingColor = c; } inline void SetStrokingColorSpace( PoDoFo::EPdfColorSpace eCS ) { m_eColorSpaceStroking = eCS; } inline void SetNonStrokingColorSpace( PoDoFo::EPdfColorSpace eCS ) { m_eColorSpaceNonStroking = eCS; } private: PoDoFo::PdfColor m_strokingColor; PoDoFo::PdfColor m_nonStrokingColor; PoDoFo::EPdfColorSpace m_eColorSpaceStroking; PoDoFo::EPdfColorSpace m_eColorSpaceNonStroking; }; public: GraphicsStack(); ~GraphicsStack(); void Push(); void Pop(); inline const PoDoFo::PdfColor & GetStrokingColor() { return GetCurrentGraphicsState().GetStrokingColor(); } inline const PoDoFo::PdfColor & GetNonStrokingColor() { return GetCurrentGraphicsState().GetNonStrokingColor(); } inline PoDoFo::EPdfColorSpace GetStrokingColorSpace() { return GetCurrentGraphicsState().GetStrokingColorSpace(); } inline PoDoFo::EPdfColorSpace GetNonStrokingColorSpace() { return GetCurrentGraphicsState().GetNonStrokingColorSpace(); } inline void SetStrokingColor( const PoDoFo::PdfColor & c ) { GetCurrentGraphicsState().SetStrokingColor( c ); } inline void SetNonStrokingColor( const PoDoFo::PdfColor & c ) { GetCurrentGraphicsState().SetNonStrokingColor( c ); } inline void SetStrokingColorSpace( PoDoFo::EPdfColorSpace eCS ) { GetCurrentGraphicsState().SetStrokingColorSpace( eCS ); } inline void SetNonStrokingColorSpace( PoDoFo::EPdfColorSpace eCS ) { GetCurrentGraphicsState().SetNonStrokingColorSpace( eCS ); } private: TGraphicsStackElement & GetCurrentGraphicsState(); private: std::stack<TGraphicsStackElement> m_stack; }; #endif // _GRAPHICSSTACK_H_ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/tools/podofocolor/grayscaleconverter.h�������������������������������������������������0000664�0001750�0001750�00000006755�11506670673�022453� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _GRAYSCALE_CONVERTER_H_ #define _GRAYSCALE_CONVERTER_H_ #include "iconverter.h" /** * A converter which converts every color to its grayscale value. */ class GrayscaleConverter : public IConverter { public: GrayscaleConverter(); virtual ~GrayscaleConverter(); /** * A helper method that is called to inform the converter * when a new page is analyzed. * * @param pPage page object * @param nPageIndex index of the page in the document */ virtual void StartPage( PoDoFo::PdfPage* pPage, int nPageIndex ); /** * A helper method that is called to inform the converter * when a new page has been analyzed completely. * * @param pPage page object * @param nPageIndex index of the page in the document */ virtual void EndPage( PoDoFo::PdfPage* pPage, int nPageIndex ); /** * A helper method that is called to inform the converter * when a new xobjext is analyzed. * * @param pObj the xobject */ virtual void StartXObject( PoDoFo::PdfXObject* pObj ); /** * A helper method that is called to inform the converter * when a xobjext has been analyzed. * * @param pObj the xobject */ virtual void EndXObject( PoDoFo::PdfXObject* pObj ); /** * This method is called whenever a gray stroking color is set * using the 'G' PDF command. * * @param a grayscale color object * @returns a new color which should be set instead (any colorspace) */ virtual PoDoFo::PdfColor SetStrokingColorGray( const PoDoFo::PdfColor & rColor ); virtual PoDoFo::PdfColor SetStrokingColorRGB( const PoDoFo::PdfColor & rColor ); virtual PoDoFo::PdfColor SetStrokingColorCMYK( const PoDoFo::PdfColor & rColor ); virtual PoDoFo::PdfColor SetNonStrokingColorGray( const PoDoFo::PdfColor & rColor ); virtual PoDoFo::PdfColor SetNonStrokingColorRGB( const PoDoFo::PdfColor & rColor ); virtual PoDoFo::PdfColor SetNonStrokingColorCMYK( const PoDoFo::PdfColor & rColor ); }; #endif // _GRAYSCALE_CONVERTER_H_ �������������������podofo-0.9.5/tools/podofocolor/colorchanger.cpp�����������������������������������������������������0000664�0001750�0001750�00000054112�12347347566�021546� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * x1 ***************************************************************************/ #include "colorchanger.h" #include <podofo.h> #include <iostream> #include <cstdlib> #include <iomanip> #include "graphicsstack.h" #include "iconverter.h" using namespace PoDoFo; static const ColorChanger::KWInfo kwInfo[] = { { ColorChanger::eKeyword_GraphicsStack_Push, "q", 0, "Save state" }, { ColorChanger::eKeyword_GraphicsStack_Pop, "Q", 0, "Restore state" }, { ColorChanger::eKeyword_SelectGray_Stroking, "G", 1, "Select gray stroking color" }, { ColorChanger::eKeyword_SelectRGB_Stroking, "RG", 3, "Select RGB stroking color" }, { ColorChanger::eKeyword_SelectCMYK_Stroking, "K", 4, "Select CMYK stroking color" }, { ColorChanger::eKeyword_SelectGray_NonStroking, "g", 1, "Select gray non-stroking color" }, { ColorChanger::eKeyword_SelectRGB_NonStroking, "rg", 3, "Select RGB non-stroking color" }, { ColorChanger::eKeyword_SelectCMYK_NonStroking, "k", 4, "Select CMYK non-stroking color" }, { ColorChanger::eKeyword_SelectColorSpace_Stroking, "CS", 1, "Select colorspace non-stroking color" }, { ColorChanger::eKeyword_SelectColorSpace_NonStroking, "cs", 1, "Select colorspace non-stroking color" }, { ColorChanger::eKeyword_SelectColor_Stroking, "SC", 1, "Select depending on current colorspace" }, { ColorChanger::eKeyword_SelectColor_NonStroking, "sc", 1, "Select depending on current colorspace" }, { ColorChanger::eKeyword_SelectColor_Stroking2, "SCN", 1, "Select depending on current colorspace (extended)" }, { ColorChanger::eKeyword_SelectColor_NonStroking2, "scn", 1, "Select depending on current colorspace (extended)" }, // Sentinel { ColorChanger::eKeyword_Undefined, "\0", 0, NULL } }; // PDF Commands, which modify colors according to PDFReference 1.7 // CS - select colorspace stroking (May need lookup in Colorspace key of resource directory) // cs - select colorspace non-stroking (May need lookup in Colorspace key of resource directory) // SC - select stroking color depending on colorspace // SCN - select stroking color for colorspaces including Separation, DeviceN, ICCBased // sc - select non-stroking color depending on colorspace // scn - select non-stroking color for colorspaces including Separation, DeviceN, ICCBased // G - select gray colorspace and gray stroking color // g - select gray colorspace and gray non stroking color // RG - select RGB colorspace and RGB stroking color // rg - select RGB colorspace and RGB non stroking color // K - select CMYK colorspace and CMYK stroking color // k - select CMYK colorspace and CMYK non stroking color // TODO: Allow to set default color and colorspace when starting a page // ColorSpaces and their default colors // DeviceColorSpaces // DeviceGray 0.0 // DeviceRGB 0.0 // DeviceCMYK 0.0 0.0 0.0 1.0 // CIE Based ColorSpaces // CalGray 0.0 // CalRGB 0.0 // Lab - all values 0.0 or closest according to range // ICCBased - all values 0.0 or closest according to range // Special ColorSpaces // Pattern - the value that causes nothing to be painted // Indexed 0 // Separation - all values 1.0 // DeviceN - all values 1.0 // GraphicsState entries and their default values // ColorSpace - DeviceGray // color stroking - black (see ColorSpace default values) // color non stroking - black (see ColorSpace default values) // Operations // q Push // Q Pop ColorChanger::ColorChanger( IConverter* pConvert, const std::string & sInput, const std::string & sOutput ) : m_pConverter( pConvert ), m_sInput( sInput ), m_sOutput( sOutput ) { if( !m_pConverter ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } } void ColorChanger::start() { PdfMemDocument input( m_sInput.c_str() ); for( int i = 0; i < input.GetPageCount(); i++ ) { std::cout << "Processing page " << std::setw(6) << (i+1) << "..." << std::endl << std::flush; PdfPage* pPage = input.GetPage( i ); PODOFO_RAISE_LOGIC_IF( !pPage, "Got null page pointer within valid page range" ); m_pConverter->StartPage( pPage, i ); this->ReplaceColorsInPage( pPage ); m_pConverter->EndPage( pPage, i ); } // Go through all XObjects PdfVecObjects::iterator it = input.GetObjects().begin(); while( it != input.GetObjects().end() ) { if( (*it)->IsDictionary() && (*it)->GetDictionary().HasKey( "Type") ) { if( PdfName("XObject") == (*it)->GetDictionary().GetKey("Type")->GetName() && (*it)->GetDictionary().HasKey("Subtype") && PdfName("Image") != (*it)->GetDictionary().GetKey("Subtype")->GetName() ) { std::cout << "Processing XObject " << (*it)->Reference().ObjectNumber() << " " << (*it)->Reference().GenerationNumber() << std::endl; PdfXObject xObject( *it ); m_pConverter->StartXObject( &xObject ); this->ReplaceColorsInPage( &xObject ); m_pConverter->EndXObject( &xObject ); } } ++it; } input.Write( m_sOutput.c_str() ); } void ColorChanger::ReplaceColorsInPage( PdfCanvas* pPage ) { EPdfContentsType t; const char* pszKeyword; PdfVariant var; bool bReadToken; GraphicsStack graphicsStack; PdfContentsTokenizer tokenizer( pPage ); std::vector<PdfVariant> args; PdfRefCountedBuffer buffer; PdfOutputDevice device( &buffer ); while( (bReadToken = tokenizer.ReadNext(t, pszKeyword, var)) ) { if (t == ePdfContentsType_Variant) { // arguments come before operators, but we want to group them up before // their operator. args.push_back(var); } else if (t == ePdfContentsType_ImageData) { // Handle inline images (Internally using PdfData) args.push_back(var); } else if (t == ePdfContentsType_Keyword) { const KWInfo* pInfo = FindKeyWordByName(pszKeyword); PdfColor color, newColor; int nNumArgs = pInfo->nNumArguments; EPdfColorSpace eColorSpace; switch( pInfo->eKeywordType ) { case eKeyword_GraphicsStack_Push: graphicsStack.Push(); break; case eKeyword_GraphicsStack_Pop: graphicsStack.Pop(); break; case eKeyword_SelectColorSpace_Stroking: eColorSpace = this->GetColorSpaceForName( args.back().GetName(), pPage ); eColorSpace = PdfColor::GetColorSpaceForName( args.back().GetName() ); args.pop_back(); graphicsStack.SetStrokingColorSpace( eColorSpace ); break; case eKeyword_SelectColorSpace_NonStroking: eColorSpace = PdfColor::GetColorSpaceForName( args.back().GetName() ); args.pop_back(); graphicsStack.SetNonStrokingColorSpace( eColorSpace ); break; case eKeyword_SelectGray_Stroking: case eKeyword_SelectRGB_Stroking: case eKeyword_SelectCMYK_Stroking: case eKeyword_SelectGray_NonStroking: case eKeyword_SelectRGB_NonStroking: case eKeyword_SelectCMYK_NonStroking: pszKeyword = this->ProcessColor( pInfo->eKeywordType, nNumArgs, args, graphicsStack ); break; case eKeyword_SelectColor_Stroking: case eKeyword_SelectColor_Stroking2: { /* PdfError::LogMessage( eLogSeverity_Information, "SCN called for colorspace: %s\n", PdfColor::GetNameForColorSpace( graphicsStack.GetStrokingColorSpace() ).GetName().c_str() ); */ int nTmpArgs; EKeywordType eTempKeyword; switch( graphicsStack.GetStrokingColorSpace() ) { case ePdfColorSpace_DeviceGray: nTmpArgs = 1; eTempKeyword = eKeyword_SelectGray_Stroking; break; case ePdfColorSpace_DeviceRGB: nTmpArgs = 3; eTempKeyword = eKeyword_SelectRGB_Stroking; break; case ePdfColorSpace_DeviceCMYK: nTmpArgs = 4; eTempKeyword = eKeyword_SelectCMYK_Stroking; break; case ePdfColorSpace_Separation: { PdfError::LogMessage( eLogSeverity_Error, "Separation color space not supported.\n" ); PODOFO_RAISE_ERROR( ePdfError_CannotConvertColor ); break; } case ePdfColorSpace_CieLab: { PdfError::LogMessage( eLogSeverity_Error, "CieLab color space not supported.\n" ); PODOFO_RAISE_ERROR( ePdfError_CannotConvertColor ); break; } case ePdfColorSpace_Indexed: { PdfError::LogMessage( eLogSeverity_Error, "Indexed color space not supported.\n" ); PODOFO_RAISE_ERROR( ePdfError_CannotConvertColor ); break; } case ePdfColorSpace_Unknown: default: { PODOFO_RAISE_ERROR( ePdfError_CannotConvertColor ); } } pszKeyword = this->ProcessColor( eTempKeyword, nTmpArgs, args, graphicsStack ); break; } case eKeyword_SelectColor_NonStroking: case eKeyword_SelectColor_NonStroking2: { /* PdfError::LogMessage( eLogSeverity_Information, "scn called for colorspace: %s\n", PdfColor::GetNameForColorSpace( graphicsStack.GetNonStrokingColorSpace() ).GetName().c_str() );*/ int nTmpArgs; EKeywordType eTempKeyword; switch( graphicsStack.GetNonStrokingColorSpace() ) { case ePdfColorSpace_DeviceGray: nTmpArgs = 1; eTempKeyword = eKeyword_SelectGray_NonStroking; break; case ePdfColorSpace_DeviceRGB: nTmpArgs = 3; eTempKeyword = eKeyword_SelectRGB_NonStroking; break; case ePdfColorSpace_DeviceCMYK: nTmpArgs = 4; eTempKeyword = eKeyword_SelectCMYK_NonStroking; break; case ePdfColorSpace_Separation: case ePdfColorSpace_CieLab: case ePdfColorSpace_Indexed: case ePdfColorSpace_Unknown: default: { PdfError::LogMessage( eLogSeverity_Error, "Unknown color space %i type.\n", graphicsStack.GetNonStrokingColorSpace() ); PODOFO_RAISE_ERROR( ePdfError_CannotConvertColor ); } } pszKeyword = this->ProcessColor( eTempKeyword, nTmpArgs, args, graphicsStack ); break; } case eKeyword_Undefined: //PdfError::LogMessage( eLogSeverity_Error, "Unknown keyword type.\n" ); break; default: break; } WriteArgumentsAndKeyword( args, pszKeyword, device ); } } // Write arguments if there are any left WriteArgumentsAndKeyword( args, NULL, device ); // Set new contents stream pPage->GetContentsForAppending()->GetStream()->Set( buffer.GetBuffer(), buffer.GetSize() ); } void ColorChanger::WriteArgumentsAndKeyword( std::vector<PdfVariant> & rArgs, const char* pszKeyword, PdfOutputDevice & rDevice ) { std::vector<PdfVariant>::const_iterator it = rArgs.begin(); while( it != rArgs.end() ) { (*it).Write( &rDevice, ePdfWriteMode_Compact ); ++it; } rArgs.clear(); if( pszKeyword ) { rDevice.Write( " ", 1 ); rDevice.Write( pszKeyword, strlen( pszKeyword ) ); rDevice.Write( "\n", 1 ); } } const ColorChanger::KWInfo* ColorChanger::FindKeyWordByName(const char* pszKeyword) { PODOFO_RAISE_LOGIC_IF( !pszKeyword, "Keyword cannot be NULL."); const KWInfo* pInfo = &(kwInfo[0]); while( pInfo->eKeywordType != eKeyword_Undefined ) { if( strcmp( pInfo->pszText, pszKeyword ) == 0 ) { return pInfo; } ++pInfo; } return pInfo; } void ColorChanger::PutColorOnStack( const PdfColor & rColor, std::vector<PdfVariant> & args ) { switch( rColor.GetColorSpace() ) { case ePdfColorSpace_DeviceGray: args.push_back( rColor.GetGrayScale() ); break; case ePdfColorSpace_DeviceRGB: args.push_back( rColor.GetRed() ); args.push_back( rColor.GetGreen() ); args.push_back( rColor.GetBlue() ); break; case ePdfColorSpace_DeviceCMYK: args.push_back( rColor.GetCyan() ); args.push_back( rColor.GetMagenta() ); args.push_back( rColor.GetYellow() ); args.push_back( rColor.GetBlack() ); break; case ePdfColorSpace_Separation: case ePdfColorSpace_CieLab: case ePdfColorSpace_Indexed: case ePdfColorSpace_Unknown: default: { PODOFO_RAISE_ERROR( ePdfError_CannotConvertColor ); } } } PdfColor ColorChanger::GetColorFromStack( int nArgs, std::vector<PdfVariant> & args ) { PdfColor color; double gray = -1.0; double red = -1.0, green = -1.0, blue = -1.0; double cyan = -1.0, magenta = -1.0, yellow = -1.0, black = -1.0; switch( nArgs ) { case 1: gray = args.back().GetReal(); args.pop_back(); color = PdfColor( gray ); break; case 3: blue = args.back().GetReal(); args.pop_back(); green = args.back().GetReal(); args.pop_back(); red = args.back().GetReal(); args.pop_back(); color = PdfColor( red, green, blue ); break; case 4: black = args.back().GetReal(); args.pop_back(); yellow = args.back().GetReal(); args.pop_back(); magenta = args.back().GetReal(); args.pop_back(); cyan = args.back().GetReal(); args.pop_back(); color = PdfColor( cyan, magenta, yellow, black ); break; } return color; } const char* ColorChanger::ProcessColor( EKeywordType eKeywordType, int nNumArgs, std::vector<PdfVariant> & args, GraphicsStack & rGraphicsStack ) { PdfColor newColor; bool bStroking = false; PdfColor color = this->GetColorFromStack( nNumArgs, args ); switch( eKeywordType ) { case eKeyword_SelectGray_Stroking: bStroking = true; rGraphicsStack.SetStrokingColorSpace( ePdfColorSpace_DeviceGray ); newColor = m_pConverter->SetStrokingColorGray( color ); break; case eKeyword_SelectRGB_Stroking: bStroking = true; rGraphicsStack.SetStrokingColorSpace( ePdfColorSpace_DeviceRGB ); newColor = m_pConverter->SetStrokingColorRGB( color ); break; case eKeyword_SelectCMYK_Stroking: bStroking = true; rGraphicsStack.SetStrokingColorSpace( ePdfColorSpace_DeviceCMYK ); newColor = m_pConverter->SetStrokingColorCMYK( color ); break; case eKeyword_SelectGray_NonStroking: rGraphicsStack.SetNonStrokingColorSpace( ePdfColorSpace_DeviceGray ); newColor = m_pConverter->SetNonStrokingColorGray( color ); break; case eKeyword_SelectRGB_NonStroking: rGraphicsStack.SetNonStrokingColorSpace( ePdfColorSpace_DeviceRGB ); newColor = m_pConverter->SetNonStrokingColorRGB( color ); break; case eKeyword_SelectCMYK_NonStroking: rGraphicsStack.SetNonStrokingColorSpace( ePdfColorSpace_DeviceCMYK ); newColor = m_pConverter->SetNonStrokingColorCMYK( color ); break; case eKeyword_GraphicsStack_Push: case eKeyword_GraphicsStack_Pop: case eKeyword_SelectColorSpace_Stroking: case eKeyword_SelectColorSpace_NonStroking: case eKeyword_SelectColor_Stroking: case eKeyword_SelectColor_Stroking2: case eKeyword_SelectColor_NonStroking: case eKeyword_SelectColor_NonStroking2: case eKeyword_Undefined: default: { PODOFO_RAISE_ERROR( ePdfError_CannotConvertColor ); } } this->PutColorOnStack( newColor, args ); if( bStroking ) { rGraphicsStack.SetStrokingColor( newColor ); } else { rGraphicsStack.SetNonStrokingColor( newColor ); } return this->GetKeywordForColor( newColor, bStroking ); } const char* ColorChanger::GetKeywordForColor( const PdfColor & rColor, bool bIsStroking ) { const char* pszKeyword = NULL; switch( rColor.GetColorSpace() ) { case ePdfColorSpace_DeviceGray: pszKeyword = ( bIsStroking ? "G" : "g" ); break; case ePdfColorSpace_DeviceRGB: pszKeyword = ( bIsStroking ? "RG" : "rg" ); break; case ePdfColorSpace_DeviceCMYK: pszKeyword = ( bIsStroking ? "K" : "k" ); break; case ePdfColorSpace_Separation: case ePdfColorSpace_CieLab: case ePdfColorSpace_Indexed: case ePdfColorSpace_Unknown: default: { PODOFO_RAISE_ERROR( ePdfError_CannotConvertColor ); } } return pszKeyword; } EPdfColorSpace ColorChanger::GetColorSpaceForName( const PdfName & rName, PdfCanvas* pPage ) { EPdfColorSpace eColorSpace = PdfColor::GetColorSpaceForName( rName ); if( eColorSpace == ePdfColorSpace_Unknown ) { // See if we can find it in the resource dictionary of the current page PdfObject* pResources = pPage->GetResources(); if( pResources != NULL && pResources->GetDictionary().HasKey( PdfName("ColorSpace") ) ) { PdfObject* pColorSpaces = pResources->GetIndirectKey( PdfName("ColorSpace") ); if( pColorSpaces != NULL && pColorSpaces->GetDictionary().HasKey( rName ) ) { PdfObject* pCS = pColorSpaces->GetIndirectKey( rName ); if( !pCS ) { PODOFO_RAISE_ERROR( ePdfError_InvalidHandle ); } else if( pCS->IsName() ) { return this->GetColorSpaceForName( pCS->GetName(), pPage ); } else if( pCS->IsArray() ) { return this->GetColorSpaceForArray( pCS->GetArray(), pPage ); } } } } return eColorSpace; } EPdfColorSpace ColorChanger::GetColorSpaceForArray( const PdfArray &, PdfCanvas* ) { EPdfColorSpace eColorSpace = ePdfColorSpace_Unknown; // CIE Based: [name dictionary] // CalGray // CalRGB // CalLab // ICCBased [name stream] // Special: // Pattern // Indexed [/Indexed base hival lookup] // Separation [/Separation name alternateSpace tintTransform] // DeviceN [/DeviceN names alternateSpace tintTransform] or // [/DeviceN names alternateSpace tintTransform attributes] // return eColorSpace; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/tools/podofocolor/dummyconverter.h�����������������������������������������������������0000664�0001750�0001750�00000006740�11506670673�021626� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _DUMMY_CONVERTER_H_ #define _DUMMY_CONVERTER_H_ #include "iconverter.h" /** * Dummy implementation of a converter, * which sets all colors to RGB red. */ class DummyConverter : public IConverter { public: DummyConverter(); virtual ~DummyConverter(); /** * A helper method that is called to inform the converter * when a new page is analyzed. * * @param pPage page object * @param nPageIndex index of the page in the document */ virtual void StartPage( PoDoFo::PdfPage* pPage, int nPageIndex ); /** * A helper method that is called to inform the converter * when a new page has been analyzed completely. * * @param pPage page object * @param nPageIndex index of the page in the document */ virtual void EndPage( PoDoFo::PdfPage* pPage, int nPageIndex ); /** * A helper method that is called to inform the converter * when a new xobjext is analyzed. * * @param pObj the xobject */ virtual void StartXObject( PoDoFo::PdfXObject* pObj ); /** * A helper method that is called to inform the converter * when a xobjext has been analyzed. * * @param pObj the xobject */ virtual void EndXObject( PoDoFo::PdfXObject* pObj ); /** * This method is called whenever a gray stroking color is set * using the 'G' PDF command. * * @param a grayscale color object * @returns a new color which should be set instead (any colorspace) */ virtual PoDoFo::PdfColor SetStrokingColorGray( const PoDoFo::PdfColor & rColor ); virtual PoDoFo::PdfColor SetStrokingColorRGB( const PoDoFo::PdfColor & rColor ); virtual PoDoFo::PdfColor SetStrokingColorCMYK( const PoDoFo::PdfColor & rColor ); virtual PoDoFo::PdfColor SetNonStrokingColorGray( const PoDoFo::PdfColor & rColor ); virtual PoDoFo::PdfColor SetNonStrokingColorRGB( const PoDoFo::PdfColor & rColor ); virtual PoDoFo::PdfColor SetNonStrokingColorCMYK( const PoDoFo::PdfColor & rColor ); }; #endif // _DUMMY_CONVERTER_H_ ��������������������������������podofo-0.9.5/tools/podofocolor/colorchanger.h�������������������������������������������������������0000664�0001750�0001750�00000011410�11511141604�021156� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*************************************************************************** * Copyright (C) 2010 by Dominik Seichter * * domseichter@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef _COLORCHANGER_H_ #define _COLORCHANGER_H_ #include <string> #include <vector> #include <podofo.h> class IConverter; class GraphicsStack; /** * This class provides a tool to change all colors * in a PDF file. */ class ColorChanger { public: enum EKeywordType { eKeyword_GraphicsStack_Push, eKeyword_GraphicsStack_Pop, eKeyword_SelectGray_Stroking, eKeyword_SelectRGB_Stroking, eKeyword_SelectCMYK_Stroking, eKeyword_SelectGray_NonStroking, eKeyword_SelectRGB_NonStroking, eKeyword_SelectCMYK_NonStroking, eKeyword_SelectColorSpace_Stroking, eKeyword_SelectColorSpace_NonStroking, eKeyword_SelectColor_Stroking, eKeyword_SelectColor_NonStroking, eKeyword_SelectColor_Stroking2, eKeyword_SelectColor_NonStroking2, eKeyword_Undefined = 0xffff }; /** * KWInfo describes a single PDF keyword's characteristics. See kwInfo[] . */ struct KWInfo { ColorChanger::EKeywordType eKeywordType; /// null-terminated keyword text const char pszText[6]; /// Number of arguments int nNumArguments; /// Short description text (optional, set to NULL if undesired). const char* pszDescription; }; /** * Construct a new colorchanger object * @param pConverter a converter which is applied to all color definitions * @param sInput the input PDF file * @param sOutput write output to this filename */ ColorChanger( IConverter* pConvert, const std::string & sInput, const std::string & sOutput ); /** * Start processing the input file. */ void start(); private: /** * Replace all colors in the given page. * @param pPage may not be NULL */ void ReplaceColorsInPage( PoDoFo::PdfCanvas* pPage ); /** * Convert a keyword name to a keyword typee * @param pszKeyword name of a keyword * @return the keyword type or eKeywordType_Undefined if unknown */ const KWInfo* FindKeyWordByName(const char* pszKeyword); PoDoFo::PdfColor GetColorFromStack( int nArgs, std::vector<PoDoFo::PdfVariant> & args ); void PutColorOnStack( const PoDoFo::PdfColor & rColor, std::vector<PoDoFo::PdfVariant> & args ); const char* ProcessColor( EKeywordType eKeywordType, int nNumArgs, std::vector<PoDoFo::PdfVariant> & args, GraphicsStack & rGraphicsStack ); const char* GetKeywordForColor( const PoDoFo::PdfColor & rColor, bool bIsStroking ); /** Write a list of arguments and optionally a keyword * to an output device * * @param rArgs list of arguments which will be written to rDevice (will be cleared afterwards). * @param pszKeyword a keyword or NULL to be written after the arguments * @param rDevice output device */ void WriteArgumentsAndKeyword( std::vector<PoDoFo::PdfVariant> & rArgs, const char* pszKeyword, PoDoFo::PdfOutputDevice & rDevice ); /** * unused */ PoDoFo::EPdfColorSpace GetColorSpaceForName( const PoDoFo::PdfName & rName, PoDoFo::PdfCanvas* pPage ); /** * unused */ PoDoFo::EPdfColorSpace GetColorSpaceForArray( const PoDoFo::PdfArray & rArray, PoDoFo::PdfCanvas* pPage ); private: IConverter* m_pConverter; std::string m_sInput; std::string m_sOutput; }; #endif // _COLORCHANGER_H_ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/AUTHORS��������������������������������������������������������������������������������0000664�0001750�0001750�00000000476�10674015620�013743� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������PoDoFo library, tools and tests: Dominik Seichter <domseichter@web.de> Leonard Rosenthol <leonardr@pdfsages.com> Craig Ringer <craig@postnewspapers.com.au> PoDoFoImpose: Contributed by Pierre Marchand <pierre@moulindetouvois.com> as `pdfimpose' Qt-to-STL conversion by Craig Ringer <craig@postnewspapers.com.au> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/vcincludes/����������������������������������������������������������������������������0000775�0001750�0001750�00000000000�13044451161�015021� 5����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/vcincludes/unistd.h��������������������������������������������������������������������0000664�0001750�0001750�00000000263�10517073142�016502� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * This file exists solely to keep VC++ happy * because it doesn't provide a <unistd.h> * and flex doesn't provide us with any way to * prevent the inclusion of it. */���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/COPYING.exception����������������������������������������������������������������������0000664�0001750�0001750�00000001524�12205463144�015716� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL library under certain conditions as described in each individual source file, and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than OpenSSL. If you modify file(s) with this exception, you may extend this exception to your version of the file(s), but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. If you delete this exception statement from all source files in the program, then also delete it here. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/ChangeLog������������������������������������������������������������������������������0000664�0001750�0001750�00000016013�11365057365�014451� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Version 0.8 See SVN ChangeLog Version 0.7 Fixed PdfPainter::ArcTo Fixed crash in FlateDecode and LZWDecode predictor functions Fixed writing of unicode PdfStrings with brackets (will be escaped now) Fixed encoding of bytes in PdfName Added many new unit tests Added methods to free object memory of objects that are not needed anymore (These objects will be re-read from disk if they are needed again) Fixed a crash when appending PDFs Added unicode support on Win32 (wchar_t* constructors and methods where apropriate, e.g. file handling) Fixed a memory leak in PdfStream Small optimizations in various places Fixed DCTDecode filter for CMYK images PdfReference is now immutable, which allows for various optimizations Fixed PdfInputDevice::Read to return now the correct number of bytes read Fixed a memory leak in PdfImmediateWriter/PdfStreamedDocument Fixed several minor parsing issues Fixed adding text to existing pages Added Lua5.1 plan file support to podofoimpose Several fixes in creating XObjects from pages Fixed a possible crash in PdfNamesTree Added support for setting colors in PdfAnnotations Added advanced text drawing support to PdfPainter Fixed parsing of Type1 fonts Fixed deletion of PdfAnnations (fixes a memory leak) Version 0.6 Many many changes :) See SVN log Version 0.5 Added support for Embedded Files (annotations & named objects) Added support for ExtGStates when drawing initially only supports basic transparency Fixed reading values from nametrees Added support for named destinations Fixed a memory leak in PdfDestination::GetPage Pages do not know their page number inside of the document Fixed reading PdfActions from PDF files Moved filter implementations to PdfFiltersPrivate.h Added PdfFilter::CanEncode and PdfFilter::CanDecode Simpliefid PoDoFos handling of XRef tables Version 0.4 PdfImage now supports creating an image stream from a "raw bitmap" which can also be optionally Flate compressed Added some new Page-related methods to PdfDocument Append - append one document to another InsertPages - insert a range of pages from one document to another DeletePages - delete a range of pages Added new tool podofomerge for merging two PDFs together Added methods to get & set a document's PageMode Added methods to set a document's FullScreen mode Added methods to set all the various ViewerPreferences for a document Added methods to set the document's PageLayout Added Outline support modified podofoinfo to display them, if present Added a PdfDestination class Added PdfNamesTree class for handling the global named objects modified podofoinfo to display them, if present PdfPainter can draw bezier curves Added XCode project for building on Mac OS X fixed up conditionals in font code to enable building on MacOSX - but no font loading, YET Added support for writing linearized PDF Added support for garbage collection of unused objects Simplified PdfObject constructor Improved annotation support Added support to encode names and various name testcases Fixed ascent and descent of fonts Improved PdfImage API Added support for the creation of file identifiers which makes PoDoFo created PDF files work in more different PDF workflows PdfImage optionally takes ownership of buffers Fixed a major parser bug: The parser expected all objects in object streams to be of type dictionary. Version 0.3 TOTAL revamp of PdfObject & PdfVariant to enable clean/consistent object handling; Added new PdfDocument object - new high level object for reading & writing a PDF doc; TOTAL revamp of the PdfDocument, PdfWriter & PdfParser relationship PdfDocument is now hub for both reading and writing a document it holds the PdfVecObjects - the others just reference them. TOTAL revamp of PdfPainter now uses PDF coordinates - UserUnits from bottom/left added PdfPainterMM for mm-based coords supports user-specified float precision and writes out floats in an optimal manner supports "appending" mode for drawing on existing documents Improved handling of the /Info dict for both reading and writing PDFs; Added new test app - podofopdfinfo, which will be used to dump metadata, etc. from a PDF; Added PdfError::DebugMessage() as the official way to write out debugging info; updated all other debugging msgs to use this; Added PdfError::DebugEnabled() to enable/disable display of debug messages; Added tracking of file size in PdfParser; Minor tweak to Linearization handling - to enable getting the status from a doc; Added getting GetPdfVersionAsString() to PdfWriter; Added new info/object getting methods to PdfDocument; bool IsLinearized(); size_t FileSize(); PdfObject* GetStructTreeRoot(); PdfObject* GetMetadata(); PdfObject* GetOutlines(); PdfObject* GetAcroForm(); Updated pdfinfo & podofopdfinfo to call the new PdfDocument methods; Added PdfDictionary and PdfArray classes; Added new PdfPagesTree (inside of PdfDocument.cpp) for handling walking a /Pages tree; Added new GetPageCount() method to PdfDocument; Modifications to PdfPage to attach it to a PdfDocument & construct from a PdfObject; Added new Legal and A3 standard page sizes; Changed page coordinates to be PDF unit-based instead of 1/1000mm; Changed PdfRect to use PDF units and also use bottom instead of top; Added ability to go between PdfRect and PdfArray & also get string version of a PdfRect; Added support for PdfPage to return all the standard boxes (Media, Crop, etc); Added support for fetching inherited values from pages (eg. boxes, rotation, etc.) Added more methods to PdfPage; GetRotation(); GetNumAnnots(); Use Exceptions now instead of error codes; Removed Init from PdfOutputDevice; Removed Init from PdfParser; Added LZW Filter support; Added PdfElement as base class for PdfAction, PdfAnnotation and PdfPage; Fixed podofoimageextract, podofotxt2pdf and podofopdfinfo; Removed PdfSimpleWriter in favour of PdfDocument; Headers are now installed in includedir/podofo/; Added a new WatermarkTest demonstrates how to read an existing PDF and draw on each page Version 0.2 Improved Documentation; Added SetInformation for additional error information to PdfError; Fixed the underline color of text; Introduced PdfReference class; Fixed PdfStream::GetFilteredCopy; Improved handling of DecodeParms for filters; Fixed PDF files with more than one DecodeParms dictionary in one object; Added on demand loading of objects to the PdfParser; Ported to windows by Leonard Rosenthol; On demand loading of objects is now the default; Refactored PdfFilter interface so that filters are cached; Fixed multiple connected XRef tables through /Prev keys in the trailer; Fixed a number of compiler warnings; Replaced char*'s with std::strings in a number of classes; Added std::ostream support to PdfOutputDevice; Improvements to the ImageExtractor tool; Refactored PdfVariant so that it is easier to use; Version 0.1 (11 June 2006) Initial release; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/NEWS�����������������������������������������������������������������������������������0000664�0001750�0001750�00000000000�10432364310�013344� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������podofo-0.9.5/COPYING.LIB����������������������������������������������������������������������������0000664�0001750�0001750�00000061334�10432364310�014326� 0����������������������������������������������������������������������������������������������������ustar �dominik�������������������������dominik���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the library's name and a brief idea of what it does.> Copyright (C) <year> <name of author> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. <signature of Ty Coon>, 1 April 1990 Ty Coon, President of Vice That's all there is to it! ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������